Skip to content

Commit

Permalink
Allow alternative methods of proposer payments in validation api (sim…
Browse files Browse the repository at this point in the history
…ple version). (#93)

* Allow alternative methods of proposer payments in validation api.

* allocate new int for balance
  • Loading branch information
dvush committed Aug 22, 2023
1 parent a8ab533 commit 03ed931
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 20 deletions.
7 changes: 7 additions & 0 deletions README.md
Expand Up @@ -136,6 +136,13 @@ $ geth --help
blocks. For example, if a slot is 12 seconds long, and the offset is 2 seconds,
the builder will submit blocks at 10 seconds into the slot.
[$FLASHBOTS_BUILDER_SUBMISSION_OFFSET]
--builder.validation_blacklist value
Path to file containing blacklisted addresses, json-encoded list of strings
--builder.validation_force_last_tx_payment (default: true)
Block validation API will enforce that the last tx in the block is payment to
the proposer.
--builder.validator_checks (default: false)
Enable the validator checks
Expand Down
2 changes: 2 additions & 0 deletions builder/config.go
Expand Up @@ -21,6 +21,7 @@ type Config struct {
RemoteRelayEndpoint string `toml:",omitempty"`
SecondaryRemoteRelayEndpoints []string `toml:",omitempty"`
ValidationBlocklist string `toml:",omitempty"`
ValidationForceLastTxPayment bool `toml:",omitempty"`
BuilderRateLimitDuration string `toml:",omitempty"`
BuilderRateLimitMaxBurst int `toml:",omitempty"`
BuilderRateLimitResubmitInterval string `toml:",omitempty"`
Expand Down Expand Up @@ -49,6 +50,7 @@ var DefaultConfig = Config{
RemoteRelayEndpoint: "",
SecondaryRemoteRelayEndpoints: nil,
ValidationBlocklist: "",
ValidationForceLastTxPayment: true,
BuilderRateLimitDuration: RateLimitIntervalDefault.String(),
BuilderRateLimitMaxBurst: RateLimitBurstDefault,
DiscardRevertibleTxOnErr: false,
Expand Down
2 changes: 1 addition & 1 deletion builder/service.go
Expand Up @@ -214,7 +214,7 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error {
return fmt.Errorf("failed to load validation blocklist %w", err)
}
}
validator = blockvalidation.NewBlockValidationAPI(backend, accessVerifier)
validator = blockvalidation.NewBlockValidationAPI(backend, accessVerifier, cfg.ValidationForceLastTxPayment)
}

// Set up builder rate limiter based on environment variables or CLI flags.
Expand Down
3 changes: 3 additions & 0 deletions cmd/geth/config.go
Expand Up @@ -177,6 +177,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
if ctx.IsSet(utils.BuilderBlockValidationBlacklistSourceFilePath.Name) {
bvConfig.BlacklistSourceFilePath = ctx.String(utils.BuilderBlockValidationBlacklistSourceFilePath.Name)
}
if ctx.IsSet(utils.BuilderBlockValidationForceLastTxPayment.Name) {
bvConfig.ForceLastTxPayment = ctx.Bool(utils.BuilderBlockValidationForceLastTxPayment.Name)
}

if err := blockvalidationapi.Register(stack, eth, bvConfig); err != nil {
utils.Fatalf("Failed to register the Block Validation API: %v", err)
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Expand Up @@ -162,6 +162,7 @@ var (
utils.BuilderPriceCutoffPercentFlag,
utils.BuilderEnableValidatorChecks,
utils.BuilderBlockValidationBlacklistSourceFilePath,
utils.BuilderBlockValidationForceLastTxPayment,
utils.BuilderEnableLocalRelay,
utils.BuilderSecondsInSlot,
utils.BuilderSlotsInEpoch,
Expand Down
7 changes: 7 additions & 0 deletions cmd/utils/flags.go
Expand Up @@ -735,6 +735,12 @@ var (
Aliases: []string{"builder.validation_blacklist"},
Category: flags.BuilderCategory,
}
BuilderBlockValidationForceLastTxPayment = &cli.BoolFlag{
Name: "builder.validation_force_last_tx_payment",
Usage: "Block validation API will enforce that the last tx in the block is payment to the proposer.",
Value: true,
Category: flags.BuilderCategory,
}
BuilderEnableLocalRelay = &cli.BoolFlag{
Name: "builder.local_relay",
Usage: "Enable the local relay",
Expand Down Expand Up @@ -1711,6 +1717,7 @@ func SetBuilderConfig(ctx *cli.Context, cfg *builder.Config) {
if ctx.IsSet(BuilderBlockValidationBlacklistSourceFilePath.Name) {
cfg.ValidationBlocklist = ctx.String(BuilderBlockValidationBlacklistSourceFilePath.Name)
}
cfg.ValidationForceLastTxPayment = ctx.Bool(BuilderBlockValidationForceLastTxPayment.Name)
cfg.BuilderRateLimitDuration = ctx.String(BuilderRateLimitDuration.Name)
cfg.BuilderRateLimitMaxBurst = ctx.Int(BuilderRateLimitMaxBurst.Name)
cfg.BuilderSubmissionOffset = ctx.Duration(BuilderSubmissionOffset.Name)
Expand Down
23 changes: 22 additions & 1 deletion core/blockchain.go
Expand Up @@ -2494,7 +2494,11 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro
bc.processor = p
}

func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Address, expectedProfit *big.Int, registeredGasLimit uint64, vmConfig vm.Config) error {
// ValidatePayload validates the payload of the block.
// It returns nil if the payload is valid, otherwise it returns an error.
// - `forceLastTxPayment` if set to true, proposer payment is assumed to be in the last transaction of the block
// otherwise we use proposer balance changes after the block to calculate proposer payment (see details in the code)
func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Address, expectedProfit *big.Int, registeredGasLimit uint64, vmConfig vm.Config, forceLastTxPayment bool) error {
header := block.Header()
if err := bc.engine.VerifyHeader(bc, header, true); err != nil {
return err
Expand Down Expand Up @@ -2527,11 +2531,16 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
// and dangling prefetcher, without defering each and holding on live refs.
defer statedb.StopPrefetcher()

feeRecipientBalanceBefore := new(big.Int).Set(statedb.GetBalance(feeRecipient))

receipts, _, usedGas, err := bc.processor.Process(block, statedb, vmConfig)
if err != nil {
return err
}

feeRecipientBalanceDelta := new(big.Int).Set(statedb.GetBalance(feeRecipient))
feeRecipientBalanceDelta.Sub(feeRecipientBalanceDelta, feeRecipientBalanceBefore)

if bc.Config().IsShanghai(header.Time) {
if header.WithdrawalsHash == nil {
return fmt.Errorf("withdrawals hash is missing")
Expand All @@ -2554,6 +2563,18 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
return err
}

// Validate proposer payment

if !forceLastTxPayment {
if feeRecipientBalanceDelta.Cmp(expectedProfit) >= 0 {
if feeRecipientBalanceDelta.Cmp(expectedProfit) > 0 {
log.Warn("builder claimed profit is lower than calculated profit", "expected", expectedProfit, "actual", feeRecipientBalanceDelta)
}
return nil
}
log.Warn("proposer payment not enough, trying last tx payment validation", "expected", expectedProfit, "actual", feeRecipientBalanceDelta)
}

if len(receipts) == 0 {
return errors.New("no proposer payment receipt")
}
Expand Down
17 changes: 11 additions & 6 deletions eth/block-validation/api.go
Expand Up @@ -88,6 +88,8 @@ func NewAccessVerifierFromFile(path string) (*AccessVerifier, error) {

type BlockValidationConfig struct {
BlacklistSourceFilePath string
// If set to true, proposer payment is assumed to be in the last transaction of the block.
ForceLastTxPayment bool
}

// Register adds catalyst APIs to the full node.
Expand All @@ -104,7 +106,7 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg BlockValidationConfig
stack.RegisterAPIs([]rpc.API{
{
Namespace: "flashbots",
Service: NewBlockValidationAPI(backend, accessVerifier),
Service: NewBlockValidationAPI(backend, accessVerifier, cfg.ForceLastTxPayment),
},
})
return nil
Expand All @@ -113,14 +115,17 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg BlockValidationConfig
type BlockValidationAPI struct {
eth *eth.Ethereum
accessVerifier *AccessVerifier
// If set to true, proposer payment is assumed to be in the last transaction of the block.
forceLastTxPayment bool
}

// NewConsensusAPI creates a new consensus api for the given backend.
// The underlying blockchain needs to have a valid terminal total difficulty set.
func NewBlockValidationAPI(eth *eth.Ethereum, accessVerifier *AccessVerifier) *BlockValidationAPI {
func NewBlockValidationAPI(eth *eth.Ethereum, accessVerifier *AccessVerifier, forceLastTxPayment bool) *BlockValidationAPI {
return &BlockValidationAPI{
eth: eth,
accessVerifier: accessVerifier,
eth: eth,
accessVerifier: accessVerifier,
forceLastTxPayment: forceLastTxPayment,
}
}

Expand Down Expand Up @@ -180,7 +185,7 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV1(params *BuilderBlockV
vmconfig = vm.Config{Tracer: tracer, Debug: true}
}

err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, params.RegisteredGasLimit, vmconfig)
err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, params.RegisteredGasLimit, vmconfig, api.forceLastTxPayment)
if err != nil {
log.Error("invalid payload", "hash", payload.BlockHash.String(), "number", payload.BlockNumber, "parentHash", payload.ParentHash.String(), "err", err)
return err
Expand Down Expand Up @@ -272,7 +277,7 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV2(params *BuilderBlockV
vmconfig = vm.Config{Tracer: tracer, Debug: true}
}

err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, params.RegisteredGasLimit, vmconfig)
err = api.eth.BlockChain().ValidatePayload(block, feeRecipient, expectedProfit, params.RegisteredGasLimit, vmconfig, api.forceLastTxPayment)
if err != nil {
log.Error("invalid payload", "hash", payload.BlockHash.String(), "number", payload.BlockNumber, "parentHash", payload.ParentHash.String(), "err", err)
return err
Expand Down

0 comments on commit 03ed931

Please sign in to comment.