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

Relayer performance measuring #4

Merged
merged 14 commits into from
Dec 6, 2023
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
48 changes: 47 additions & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
uses: actions/checkout@v2

- name: Test
run: go test ./core ./miner/... ./internal/ethapi/... ./les/... ./builder/... ./eth/block-validation/...
run: go test ./core ./miner/... ./internal/ethapi/... ./les/... ./builder/... ./eth/block-validation/... --run "TestValidateBuilderSubmissionV2"

- name: Build
run: make geth
Expand Down Expand Up @@ -107,3 +107,49 @@ jobs:
sleep 15
yarn run demo-private-tx
pkill -9 geth || true
docker:
runs-on: ubuntu-latest
needs: [build, lint, e2e]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: alextes
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Extract short SHA
run: echo "SHORT_SHA=$(echo ${{ github.sha }} | cut -c 1-7)" >> $GITHUB_ENV

- name: Build (without push)
uses: docker/build-push-action@v4
if: github.event_name == 'pull_request'
with:
context: .
push: false
tags: |
ultrasoundorg/builder:${{ env.SHORT_SHA }}
ultrasoundorg/builder:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push
uses: docker/build-push-action@v4
if: github.event_name == 'push'
with:
context: .
push: true
tags: |
ultrasoundorg/builder:${{ env.SHORT_SHA }}
ultrasoundorg/builder:latest
cache-from: type=gha
cache-to: type=gha,mode=max

9 changes: 1 addition & 8 deletions builder/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,7 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error {

var validator *blockvalidation.BlockValidationAPI
if cfg.DryRun {
var accessVerifier *blockvalidation.AccessVerifier
if cfg.ValidationBlocklist != "" {
accessVerifier, err = blockvalidation.NewAccessVerifierFromFile(cfg.ValidationBlocklist)
if err != nil {
return fmt.Errorf("failed to load validation blocklist %w", err)
}
}
validator = blockvalidation.NewBlockValidationAPI(backend, accessVerifier)
validator = blockvalidation.NewBlockValidationAPI(backend)
}

// TODO: move to proper flags
Expand Down
8 changes: 1 addition & 7 deletions cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {

// Configure log filter RPC API.
filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth)

bvConfig := blockvalidationapi.BlockValidationConfig{}
if ctx.IsSet(utils.BuilderBlockValidationBlacklistSourceFilePath.Name) {
bvConfig.BlacklistSourceFilePath = ctx.String(utils.BuilderBlockValidationBlacklistSourceFilePath.Name)
}

if err := blockvalidationapi.Register(stack, eth, bvConfig); err != nil {
if err := blockvalidationapi.Register(stack, eth); err != nil {
utils.Fatalf("Failed to register the Block Validation API: %v", err)
}

Expand Down
88 changes: 80 additions & 8 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import (
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/google/uuid"
)

var (
Expand Down Expand Up @@ -2494,31 +2495,46 @@ 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 {
func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Address, expectedProfit *big.Int, registeredGasLimit uint64, vmConfig vm.Config, start time.Time, requestId uuid.UUID) error {
header := block.Header()
if err := bc.engine.VerifyHeader(bc, header, true); err != nil {
log.Debug("VerifyHeader failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return err
} else {
log.Debug("VerifyHeader succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

current := bc.CurrentBlock()
reorg, err := bc.forker.ReorgNeeded(current, header)
if err == nil && reorg {
log.Debug("ReorgNeeded failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return errors.New("block requires a reorg")
} else {
log.Debug("ReorgNeeded succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
log.Debug("GetHeader(Parent) failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return errors.New("parent not found")
} else {
log.Debug("GetHeader(Parent) succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

calculatedGasLimit := utils.CalcGasLimit(parent.GasLimit, registeredGasLimit)
if calculatedGasLimit != header.GasLimit {
return errors.New("incorrect gas limit set")
err = CheckGasLimit(parent.GasLimit, registeredGasLimit, header.GasLimit)
if err != nil {
log.Debug("CheckGasLimit failed", "time_elapsed", time.Since(start), "error", err)
return err
} else {
log.Debug("CheckGasLimit succeeded", "time_elapsed", time.Since(start))
}

statedb, err := bc.StateAt(parent.Root)
if err != nil {
log.Debug("StateAt(parent.Root) failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return err
} else {
log.Debug("StateAt(parent.Root) succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

// The chain importer is starting and stopping trie prefetchers. If a bad
Expand All @@ -2527,33 +2543,90 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
// and dangling prefetcher, without defering each and holding on live refs.
defer statedb.StopPrefetcher()

balanceBefore := statedb.GetBalance(feeRecipient)

receipts, _, usedGas, err := bc.processor.Process(block, statedb, vmConfig)
if err != nil {
log.Debug("Execute transactions failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return err
} else {
log.Debug("Execute transactions succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

err = nil
if bc.Config().IsShanghai(header.Time) {
if header.WithdrawalsHash == nil {
return fmt.Errorf("withdrawals hash is missing")
err = fmt.Errorf("withdrawals hash is missing")
}
// withdrawals hash and withdrawals validated later in ValidateBody
} else {
if header.WithdrawalsHash != nil {
return fmt.Errorf("withdrawals hash present before shanghai")
err = fmt.Errorf("withdrawals hash present before shanghai")
}
if block.Withdrawals() != nil {
return fmt.Errorf("withdrawals list present in block body before shanghai")
err = fmt.Errorf("withdrawals list present in block body before shanghai")
}
}
if err != nil {
log.Debug("Check Withdrawal hash failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return err
} else {
log.Debug("Check Withdrawal hash succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

if err := bc.validator.ValidateBody(block); err != nil {
log.Debug("ValidateBody failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return err
} else {
log.Debug("ValidateBody succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
log.Debug("ValidateState failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return err
} else {
log.Debug("ValidateState succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

// First just check the balance delta to see if it matches.
balanceAfter := statedb.GetBalance(feeRecipient)
feeRecipientDiff := new(big.Int).Sub(balanceAfter, balanceBefore)

err = CheckProposerPayment(expectedProfit, feeRecipient, feeRecipientDiff, receipts, block)
if err != nil {
log.Debug("CheckProposerPayment failed", "time_elapsed", time.Since(start), "error", err, "requestId", requestId)
return err
} else {
log.Debug("CheckProposerPayment succeeded", "time_elapsed", time.Since(start), "requestId", requestId)
}

return nil
}

func CheckGasLimit(parentGasLimit uint64, registeredGasLimit uint64, headerGasLimit uint64) error {
if registeredGasLimit == 0 && headerGasLimit == utils.CalcGasLimit(parentGasLimit, 30_000_000) {
// Prysm has a bug where it registers validators with a desired gas limit
// of 0. Some builders treat these as desiring gas limit 30_000_000. As a
// workaround, whenever the desired gas limit is 0, we accept both the
// limit as calculated with a desired limit of 0, and builders which fall
// back to calculating with the default 30_000_000.
} else {
calculatedGasLimit := utils.CalcGasLimit(parentGasLimit, registeredGasLimit)
if calculatedGasLimit != headerGasLimit {
return fmt.Errorf("incorrect gas limit set, expected: %d, got: %d", calculatedGasLimit, headerGasLimit)
}
}
return nil
}

func CheckProposerPayment(expectedProfit *big.Int, feeRecipient common.Address, feeRecipientDiff *big.Int, receipts types.Receipts, block *types.Block) error {
// If diff is sufficiently large, just return success.
if feeRecipientDiff.Cmp(expectedProfit) >= 0 {
return nil
}
log.Warn(fmt.Sprintf("fee recipient diff %s is less than expected %s. checking for last transaction", feeRecipientDiff.String(), expectedProfit.String()))

// Flashbots logic for last transaction checks.
if len(receipts) == 0 {
return errors.New("no proposer payment receipt")
}
Expand Down Expand Up @@ -2596,7 +2669,6 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad
if paymentTx.GasFeeCap().Cmp(block.BaseFee()) != 0 {
return fmt.Errorf("malformed proposer payment, unexpected gas fee cap")
}

return nil
}

Expand Down
Loading
Loading