mevshare

package
v0.0.0-...-3bbdf2b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2024 License: AGPL-3.0 Imports: 34 Imported by: 2

Documentation

Overview

Package mevshare implements mev share node Here is a full flow of data through the node:

bundle-relay-api -> API sends:

  • private transaction
  • mev share bundle

API -> SimQueue schedules simulation SimQueue -> SimulationWorker calls with the next simulation to process

SimulationWorker -> SimulationBackend is used to do simulation
SimulationWorker -> SimulationResultBackend is used to consume simulation result

SimulationResultBackend -> RedisHintBackend is used to send hint to hint-relay-api SimulationResultBackend -> BuilderBackend is used to send bundle to the builders

Index

Constants

View Source
const (
	MaxBlockOffset uint64 = 5
	MaxBlockRange  uint64 = 30
	MaxBodySize           = 50

	MaxNestingLevel = 1

	RefundPercent = 90

	HintGasPriceNumberPrecisionDigits = 3
	HintGasNumberPrecisionDigits      = 2
)
View Source
const (
	SendBundleEndpointName         = "mev_sendBundle"
	SimBundleEndpointName          = "mev_simBundle"
	CancelBundleByHashEndpointName = "mev_cancelBundleByHash"
)

Variables

View Source
var (
	ErrInvalidInclusion      = errors.New("invalid inclusion")
	ErrInvalidBundleBodySize = errors.New("invalid bundle body size")
	ErrInvalidBundleBody     = errors.New("invalid bundle body")
	ErrBackrunNotFound       = errors.New("backrun not found")
	ErrBackrunInvalidBundle  = errors.New("backrun invalid bundle")
	ErrBackrunInclusion      = errors.New("backrun invalid inclusion")

	ErrInternalServiceError = errors.New("mev-share service error")
)
View Source
var (
	ErrUnsupportedBundleVersion = errors.New("unsupported bundle version")
	ErrBundleTooDeep            = errors.New("bundle too deep")
	ErrInvalidBundleConstraints = errors.New("invalid bundle constraints")
	ErrInvalidBundlePrivacy     = errors.New("invalid bundle privacy")
)
View Source
var (
	ErrInvalidHintIntent = errors.New("invalid hint intent")
	ErrNilBundleMetadata = errors.New("bundle metadata is nil")
)
View Source
var (
	ErrBundleNotCancelled = errors.New("bundle not cancelled")
)
View Source
var ErrBundleNotFound = errors.New("bundle not found")
View Source
var ErrCannotExtractHints = errors.New("cannot extract hints")
View Source
var ErrCantConvertToRefRecBundle = errors.New("can't convert bundle to ref recipient bundle")
View Source
var ErrInvalidBuilder = errors.New("invalid builder specification")

Functions

func Intersect

func Intersect(a, b []string) []string

Intersect returns the intersection of two string arrays, without duplicates

func MergeBuilders

func MergeBuilders(topLevel, inner *MevBundlePrivacy)

MergeBuilders writes to the topLevel builder value of overlap between inner and topLevel

func MergeInclusionIntervals

func MergeInclusionIntervals(topLevel, inner *MevBundleInclusion) error

MergeInclusionIntervals writes to the topLevel inclusion value of overlap between inner and topLevel or return error if there is no overlap

func MergePrivacyBuilders

func MergePrivacyBuilders(bundle *SendMevBundleArgs)

MergePrivacyBuilders Sets privacy.builders to the intersection of all privacy.builders in the bundle

func RoundUpWithPrecision

func RoundUpWithPrecision(number *big.Int, precisionDigits int) *big.Int

RoundUpWithPrecision rounds number up leaving only precisionDigits non-zero examples: RoundUpWithPrecision(123456, 2) = 130000 RoundUpWithPrecision(111, 2) = 120 RoundUpWithPrecision(199, 2) = 120

func ValidateBundle

func ValidateBundle(bundle *SendMevBundleArgs, currentBlock uint64, signer types.Signer) (hash common.Hash, unmatched bool, err error)

Types

type API

type API struct {
	// contains filtered or unexported fields
}

func NewAPI

func NewAPI(
	log *zap.Logger,
	scheduler SimScheduler, bundleStorage BundleStorage, eth EthClient, signer types.Signer,
	simBackends []SimulationBackend, simRateLimit rate.Limit, builders BuildersBackend, cancellationCache *RedisCancellationCache,
	sbundleValidDuration time.Duration,
) *API

func (*API) CancelBundleByHash

func (m *API) CancelBundleByHash(ctx context.Context, hash common.Hash) (err error)

CancelBundleByHash cancels a bundle by hash This method is not exposed on the bundle relay. However, it is used by the Flashbots bundle relay for now to handle the cancellation of private transactions.

func (*API) SendBundle

func (m *API) SendBundle(ctx context.Context, bundle SendMevBundleArgs) (_ SendMevBundleResponse, err error)

func (*API) SimBundle

func (m *API) SimBundle(ctx context.Context, bundle SendMevBundleArgs, aux SimMevBundleAuxArgs) (_ *SimMevBundleResponse, err error)

type BuilderAPI

type BuilderAPI uint8
const (
	BuilderAPIRefundRecipient BuilderAPI = iota
	BuilderAPIMevShareBeta1

	OrderflowHeaderName = "x-orderflow-origin"
)

type BuilderBackend

type BuilderBackend interface {
	String() string
	SendMatchedShareBundle(ctx context.Context, bundle *SendMevBundleArgs) error
	CancelBundleByHash(ctx context.Context, hash common.Hash) error
}

type BuildersBackend

type BuildersBackend struct {
	// contains filtered or unexported fields
}

func LoadBuilderConfig

func LoadBuilderConfig(file string) (BuildersBackend, error)

LoadBuilderConfig parses a builder config from a file

func (*BuildersBackend) CancelBundleByHash

func (b *BuildersBackend) CancelBundleByHash(ctx context.Context, logger *zap.Logger, hash common.Hash)

func (*BuildersBackend) SendBundle

func (b *BuildersBackend) SendBundle(ctx context.Context, logger *zap.Logger, bundle *SendMevBundleArgs, targetBlock uint64)

SendBundle sends a bundle to all builders. Bundles are sent to all builders in parallel.

type BuildersConfig

type BuildersConfig struct {
	Builders []struct {
		Name     string `yaml:"name"`
		URL      string `yaml:"url"`
		API      string `yaml:"api"`
		Internal bool   `yaml:"internal,omitempty"`
		Disabled bool   `yaml:"disabled,omitempty"`
	} `yaml:"builders"`
	OrderflowHeader      bool   `yaml:"orderflowHeader,omitempty"`
	OrderflowHeaderValue string `yaml:"orderflowHeaderValue,omitempty"`
}

type BundleStorage

type BundleStorage interface {
	GetBundleByMatchingHash(ctx context.Context, hash common.Hash) (*SendMevBundleArgs, error)
	CancelBundleByHash(ctx context.Context, hash common.Hash, signer common.Address) error
}

type CleanLog

type CleanLog struct {
	// address of the contract that generated the event
	Address common.Address `json:"address"`
	// list of topics provided by the contract.
	Topics []common.Hash `json:"topics"`
	// supplied by the contract, usually ABI-encoded
	Data hexutil.Bytes `json:"data"`
}

type DBBackend

type DBBackend struct {
	// contains filtered or unexported fields
}

func NewDBBackend

func NewDBBackend(postgresDSN string) (*DBBackend, error)

func (*DBBackend) CancelBundleByHash

func (b *DBBackend) CancelBundleByHash(ctx context.Context, hash common.Hash, signer common.Address) error

func (*DBBackend) Close

func (b *DBBackend) Close() error

func (*DBBackend) GetBundleByMatchingHash

func (b *DBBackend) GetBundleByMatchingHash(ctx context.Context, hash common.Hash) (*SendMevBundleArgs, error)

func (*DBBackend) InsertBundleForBuilder

func (b *DBBackend) InsertBundleForBuilder(ctx context.Context, bundle *SendMevBundleArgs, result *SimMevBundleResponse, targetBlock uint64) error

InsertBundleForBuilder inserts a bundle into the database for a builder to use Target block is the block the bundle is trying to get in. When it's called for the known bundle, we update the bundle with fresh simulation results and new target block.

func (*DBBackend) InsertBundleForStats

func (b *DBBackend) InsertBundleForStats(ctx context.Context, bundle *SendMevBundleArgs, result *SimMevBundleResponse) (known bool, err error)

InsertBundleForStats inserts a bundle into the database. When called for the second time for the known bundle, it will return known = true and update bundle simulation results with the last inserted simulation results.

func (*DBBackend) InsertHistoricalHint

func (b *DBBackend) InsertHistoricalHint(ctx context.Context, currentBlock uint64, hint *Hint) error

type DBSbundle

type DBSbundle struct {
	Hash               []byte         `db:"hash"`
	MatchingHash       []byte         `db:"matching_hash"`
	Signer             []byte         `db:"signer"`
	Cancelled          bool           `db:"cancelled"`
	AllowMatching      bool           `db:"allow_matching"`
	Prematched         bool           `db:"prematched"`
	ReceivedAt         time.Time      `db:"received_at"`
	SimSuccess         bool           `db:"sim_success"`
	SimError           sql.NullString `db:"sim_error"`
	SimulatedAt        sql.NullTime   `db:"simulated_at"`
	SimEffGasPrice     sql.NullString `db:"sim_eff_gas_price"`
	SimProfit          sql.NullString `db:"sim_profit"`
	SimRefundableValue sql.NullString `db:"sim_refundable_value"`
	SimGasUsed         sql.NullInt64  `db:"sim_gas_used"`
	// sum of all simulations gas used
	SimAllSimsGasUsed sql.NullInt64 `db:"sim_all_sims_gas_used"`
	// number of simulations that were run for this bundle
	SimTotalSimCount sql.NullInt64  `db:"sim_total_sim_count"`
	Body             []byte         `db:"body"`
	BodySize         int            `db:"body_size"`
	OriginID         sql.NullString `db:"origin_id"`
	InsertedAt       time.Time      `db:"inserted_at"`
}

type DBSbundleBody

type DBSbundleBody struct {
	Hash        []byte `db:"hash"`
	ElementHash []byte `db:"element_hash"`
	Idx         int    `db:"idx"`
	Type        int    `db:"type"`
}

type DBSbundleBuilder

type DBSbundleBuilder struct {
	Hash           []byte         `db:"hash"`
	Cancelled      bool           `db:"cancelled"`
	Block          int64          `db:"block"`
	MaxBlock       int64          `db:"max_block"`
	SimStateBlock  sql.NullInt64  `db:"sim_state_block"`
	SimEffGasPrice sql.NullString `db:"sim_eff_gas_price"`
	SimProfit      sql.NullString `db:"sim_profit"`
	Body           []byte         `db:"body"`
	InsertedAt     time.Time      `db:"inserted_at"`
}

type DBSbundleHistoricalHint

type DBSbundleHistoricalHint struct {
	ID         int64           `db:"id"`
	Block      int64           `db:"block"`
	Hint       json.RawMessage `db:"hint"`
	InsertedAt time.Time       `db:"inserted_at"`
}

type EthCachingClient

type EthCachingClient struct {
	// contains filtered or unexported fields
}

func NewCachingEthClient

func NewCachingEthClient(ethClient *ethclient.Client) *EthCachingClient

func (*EthCachingClient) BlockNumber

func (c *EthCachingClient) BlockNumber(ctx context.Context) (uint64, error)

BlockNumber returns the most recent block number, cached for 5 seconds

type EthClient

type EthClient interface {
	BlockNumber(ctx context.Context) (uint64, error)
}

type Hint

type Hint struct {
	Hash        common.Hash     `json:"hash"`
	Logs        []CleanLog      `json:"logs"`
	Txs         []TxHint        `json:"txs"`
	MevGasPrice *hexutil.Big    `json:"mevGasPrice,omitempty"`
	GasUsed     *hexutil.Uint64 `json:"gasUsed,omitempty"`
}

func ExtractHints

func ExtractHints(bundle *SendMevBundleArgs, simRes *SimMevBundleResponse, shareGasUsed, shareMevGasPrice bool) (Hint, error)

type HintBackend

type HintBackend interface {
	NotifyHint(ctx context.Context, hint *Hint) error
}

type HintIntent

type HintIntent uint8

HintIntent is a set of hint intents its marshalled as an array of strings

const (
	HintContractAddress HintIntent = 1 << iota
	HintFunctionSelector
	HintLogs
	HintCallData
	HintHash
	HintSpecialLogs
	HintTxHash
	HintNone = 0
)

func (*HintIntent) HasHint

func (b *HintIntent) HasHint(flag HintIntent) bool

func (HintIntent) MarshalJSON

func (b HintIntent) MarshalJSON() ([]byte, error)

func (*HintIntent) SetHint

func (b *HintIntent) SetHint(flag HintIntent)

func (*HintIntent) UnmarshalJSON

func (b *HintIntent) UnmarshalJSON(data []byte) error

type JSONRPCBuilder

type JSONRPCBuilder struct {
	// contains filtered or unexported fields
}

func NewJSONRPCBuilder

func NewJSONRPCBuilder(url string) *JSONRPCBuilder

func (*JSONRPCBuilder) CancelBundleByHash

func (b *JSONRPCBuilder) CancelBundleByHash(ctx context.Context, hash common.Hash) error

func (*JSONRPCBuilder) SendMatchedShareBundle

func (b *JSONRPCBuilder) SendMatchedShareBundle(ctx context.Context, bundle *SendMevBundleArgs) error

func (*JSONRPCBuilder) String

func (b *JSONRPCBuilder) String() string

type JSONRPCBuilderBackend

type JSONRPCBuilderBackend struct {
	Name   string
	Client jsonrpc.RPCClient
	API    BuilderAPI
}

func (*JSONRPCBuilderBackend) CancelBundleByHash

func (b *JSONRPCBuilderBackend) CancelBundleByHash(ctx context.Context, hash common.Hash) error

func (*JSONRPCBuilderBackend) SendBundle

func (b *JSONRPCBuilderBackend) SendBundle(ctx context.Context, bundle *SendMevBundleArgs) (err error)

type JSONRPCSimulationBackend

type JSONRPCSimulationBackend struct {
	// contains filtered or unexported fields
}

func NewJSONRPCSimulationBackend

func NewJSONRPCSimulationBackend(url string) *JSONRPCSimulationBackend

func (*JSONRPCSimulationBackend) SimulateBundle

type MevBundleBody

type MevBundleBody struct {
	Hash      *common.Hash       `json:"hash,omitempty"`
	Tx        *hexutil.Bytes     `json:"tx,omitempty"`
	Bundle    *SendMevBundleArgs `json:"bundle,omitempty"`
	CanRevert bool               `json:"canRevert,omitempty"`
}

type MevBundleInclusion

type MevBundleInclusion struct {
	BlockNumber hexutil.Uint64 `json:"block"`
	MaxBlock    hexutil.Uint64 `json:"maxBlock"`
}

type MevBundleMetadata

type MevBundleMetadata struct {
	BundleHash   common.Hash    `json:"bundleHash,omitempty"`
	BodyHashes   []common.Hash  `json:"bodyHashes,omitempty"`
	Signer       common.Address `json:"signer,omitempty"`
	OriginID     string         `json:"originId,omitempty"`
	ReceivedAt   hexutil.Uint64 `json:"receivedAt,omitempty"`
	MatchingHash common.Hash    `json:"matchingHash,omitempty"`
	Prematched   bool           `json:"prematched"`
}

type MevBundlePrivacy

type MevBundlePrivacy struct {
	Hints      HintIntent `json:"hints,omitempty"`
	Builders   []string   `json:"builders,omitempty"`
	WantRefund *int       `json:"wantRefund,omitempty"`
}

type MevBundleValidity

type MevBundleValidity struct {
	Refund       []RefundConstraint `json:"refund,omitempty"`
	RefundConfig []RefundConfig     `json:"refundConfig,omitempty"`
}

type RedisCancellationCache

type RedisCancellationCache struct {
	// contains filtered or unexported fields
}

func NewRedisCancellationCache

func NewRedisCancellationCache(client *redis.Client, expireDuration time.Duration, keyPrefix string) *RedisCancellationCache

func (*RedisCancellationCache) Add

func (*RedisCancellationCache) DeleteAll

func (c *RedisCancellationCache) DeleteAll(ctx context.Context) error

DeleteAll deletes all the keys in the cache. It can be very slow and should only be used for testing.

func (*RedisCancellationCache) IsCancelled

func (c *RedisCancellationCache) IsCancelled(ctx context.Context, hash []common.Hash) (bool, error)

type RedisHintBackend

type RedisHintBackend struct {
	// contains filtered or unexported fields
}

func NewRedisHintBackend

func NewRedisHintBackend(redisClient *redis.Client, pubChannel string) *RedisHintBackend

func (*RedisHintBackend) NotifyHint

func (b *RedisHintBackend) NotifyHint(ctx context.Context, hint *Hint) error

type RefundConfig

type RefundConfig struct {
	Address common.Address `json:"address"`
	Percent int            `json:"percent"`
}

type RefundConstraint

type RefundConstraint struct {
	BodyIdx int `json:"bodyIdx"`
	Percent int `json:"percent"`
}

type SendMevBundleArgs

type SendMevBundleArgs struct {
	Version   string             `json:"version"`
	Inclusion MevBundleInclusion `json:"inclusion"`
	Body      []MevBundleBody    `json:"body"`
	Validity  MevBundleValidity  `json:"validity"`
	Privacy   *MevBundlePrivacy  `json:"privacy,omitempty"`
	Metadata  *MevBundleMetadata `json:"metadata,omitempty"`
}

type SendMevBundleResponse

type SendMevBundleResponse struct {
	BundleHash common.Hash `json:"bundleHash"`
}

type SendRefundRecBundleArgs

type SendRefundRecBundleArgs struct {
	BlockNumber       hexutil.Uint64  `json:"blockNumber"`
	Txs               []hexutil.Bytes `json:"txs"`
	RevertingTxHashes []common.Hash   `json:"revertingTxHashes,omitempty"`
	RefundPercent     *int            `json:"refundPercent,omitempty"`
	RefundRecipient   *common.Address `json:"refundRecipient,omitempty"`
}

func ConvertBundleToRefundRecipient

func ConvertBundleToRefundRecipient(bundle *SendMevBundleArgs) (res SendRefundRecBundleArgs, err error)

type SimMevBodyLogs

type SimMevBodyLogs struct {
	TxLogs     []*types.Log     `json:"txLogs,omitempty"`
	BundleLogs []SimMevBodyLogs `json:"bundleLogs,omitempty"`
}

type SimMevBundleAuxArgs

type SimMevBundleAuxArgs struct {
	ParentBlock *rpc.BlockNumberOrHash `json:"parentBlock"`
	// override the default values for the block header
	BlockNumber *hexutil.Big    `json:"blockNumber"`
	Coinbase    *common.Address `json:"coinbase"`
	Timestamp   *hexutil.Uint64 `json:"timestamp"`
	GasLimit    *hexutil.Uint64 `json:"gasLimit"`
	BaseFee     *hexutil.Big    `json:"baseFee"`
	Timeout     *int64          `json:"timeout"`
}

type SimMevBundleResponse

type SimMevBundleResponse struct {
	Success         bool             `json:"success"`
	Error           string           `json:"error,omitempty"`
	StateBlock      hexutil.Uint64   `json:"stateBlock"`
	MevGasPrice     hexutil.Big      `json:"mevGasPrice"`
	Profit          hexutil.Big      `json:"profit"`
	RefundableValue hexutil.Big      `json:"refundableValue"`
	GasUsed         hexutil.Uint64   `json:"gasUsed"`
	BodyLogs        []SimMevBodyLogs `json:"logs,omitempty"`
}

type SimQueue

type SimQueue struct {
	// contains filtered or unexported fields
}

func NewQueue

func NewQueue(
	log *zap.Logger, queue simqueue.Queue, eth EthClient, sim []SimulationBackend, simRes SimulationResult,
	workersPerNode int, backgroundWg *sync.WaitGroup, cancelCache *RedisCancellationCache,
) *SimQueue

func (*SimQueue) ScheduleBundleSimulation

func (q *SimQueue) ScheduleBundleSimulation(ctx context.Context, bundle *SendMevBundleArgs, highPriority bool) error

func (*SimQueue) Start

func (q *SimQueue) Start(ctx context.Context) *sync.WaitGroup

type SimScheduler

type SimScheduler interface {
	ScheduleBundleSimulation(ctx context.Context, bundle *SendMevBundleArgs, highPriority bool) error
}

type SimulationBackend

type SimulationBackend interface {
	SimulateBundle(ctx context.Context, bundle *SendMevBundleArgs, aux *SimMevBundleAuxArgs) (*SimMevBundleResponse, error)
}

SimulationBackend is an interface for simulating transactions There should be one simulation backend per worker node

type SimulationResult

type SimulationResult interface {
	SimulatedBundle(ctx context.Context, args *SendMevBundleArgs, result *SimMevBundleResponse, info simqueue.QueueItemInfo) error
}

SimulationResult is responsible for processing simulation results NOTE: That error should be returned only if simulation should be retried, for example if redis is down or none of the builders responded

type SimulationResultBackend

type SimulationResultBackend struct {
	// contains filtered or unexported fields
}

func NewSimulationResultBackend

func NewSimulationResultBackend(log *zap.Logger, hint HintBackend, builders BuildersBackend, eth EthClient, store Storage, shareGasUsed, shareMevGasPrice bool) *SimulationResultBackend

func (*SimulationResultBackend) ProcessHints

func (*SimulationResultBackend) SimulatedBundle

SimulatedBundle is called when simulation is done NOTE: we return error only if we want to retry the simulation

type SimulationWorker

type SimulationWorker struct {
	// contains filtered or unexported fields
}

func (*SimulationWorker) Process

func (w *SimulationWorker) Process(ctx context.Context, data []byte, info simqueue.QueueItemInfo) (err error)

type Storage

type Storage interface {
	InsertBundleForStats(ctx context.Context, bundle *SendMevBundleArgs, result *SimMevBundleResponse) (known bool, err error)
	InsertBundleForBuilder(ctx context.Context, bundle *SendMevBundleArgs, result *SimMevBundleResponse, targetBlock uint64) error
	InsertHistoricalHint(ctx context.Context, currentBlock uint64, hint *Hint) error
}

type TxHint

type TxHint struct {
	Hash             *common.Hash    `json:"hash,omitempty"`
	To               *common.Address `json:"to,omitempty"`
	FunctionSelector *hexutil.Bytes  `json:"functionSelector,omitempty"`
	CallData         *hexutil.Bytes  `json:"callData,omitempty"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL