Skip to content
This repository was archived by the owner on Dec 16, 2024. It is now read-only.
Open
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
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ help: Makefile
@echo " Choose a command run in go-ethereum:"
@sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /'
.PHONY: help

docker-image:
DOCKER_BUILDKIT=1 docker build --build-arg VERSION=${VERSION} . -t prof-project/prof-builder
2 changes: 1 addition & 1 deletion beacon/engine/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ func ExecutionPayloadV3ToBlockProf(payload *deneb.ExecutionPayload, profTxs [][]
Random: common.Hash(payload.PrevRandao),
Number: payload.BlockNumber,
GasLimit: payload.GasLimit,
GasUsed: payload.GasUsed,
GasUsed: 0, // This is overwritten in bundle-merger
Timestamp: payload.Timestamp,
ExtraData: payload.ExtraData,
BaseFeePerGas: payload.BaseFeePerGas.ToBig(),
Expand Down
16 changes: 16 additions & 0 deletions cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/eth"
blockvalidationapi "github.com/ethereum/go-ethereum/eth/block-validation"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/ethereum/go-ethereum/eth/ethconfig"
Expand Down Expand Up @@ -252,6 +253,21 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
return stack, backend
}

// makeFullNode loads geth configuration and creates the Ethereum backend.
func MakeFullNodeGethPROF(ctx *cli.Context) (ethapi.Backend, *eth.Ethereum) {
stack, cfg := makeConfigNode(ctx)
if ctx.IsSet(utils.OverrideCancun.Name) {
v := ctx.Uint64(utils.OverrideCancun.Name)
cfg.Eth.OverrideCancun = &v
}
if ctx.IsSet(utils.OverrideVerkle.Name) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
cfg.Eth.OverrideVerkle = &v
}
backend, eth := utils.RegisterEthService(stack, &cfg.Eth, &cfg.Builder)
return backend, eth
}

// dumpConfig is the dumpconfig command.
func dumpConfig(ctx *cli.Context) error {
_, cfg := makeConfigNode(ctx)
Expand Down
37 changes: 37 additions & 0 deletions cmd/geth/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

import (
"flag"
"testing"

"github.com/urfave/cli/v2"
)

func TestMakeConfigNode(t *testing.T) {
// Create a CLI context with the required flags
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
set.String("gcmode", "full", "Blockchain garbage collection mode")
set.String("crypto.kzg", "gokzg", "KZG library implementation to use")
ctx := cli.NewContext(app, set, nil)
// Set the flags
err := set.Set("gcmode", "full")
if err != nil {
t.Fatalf("Failed to set gcmode flag: %v", err)
}
err = set.Set("crypto.kzg", "gokzg")
if err != nil {
t.Fatalf("Failed to set crypto.kzg flag: %v", err)
}
// Call the function you want to test
// node, cfg := makeConfigNode(ctx)
backend, eth := MakeFullNodeGethPROF(ctx)
// Test backend
if backend == nil {
t.Fatal("Backend is nil")
}
// Test eth
if eth == nil {
t.Fatal("Ethereum object is nil")
}
}
119 changes: 77 additions & 42 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2454,15 +2454,37 @@ func (bc *BlockChain) SetBlockValidatorAndProcessorForTesting(v Validator, p Pro
func (bc *BlockChain) SimulateProfBlock(block *types.Block, feeRecipient common.Address, registeredGasLimit uint64, vmConfig vm.Config, useBalanceDiffProfit, excludeWithdrawals bool) (*uint256.Int, *types.Header, error) {
// NOTE : PBS part of the block is already validated, so no need to verify header here or check for reorgs. parent exists

// Add validation for nil block
if block == nil {
log.Error("SimulateProfBlock called with nil block")
return nil, nil, errors.New("nil block")
}

log.Info("Starting SimulateProfBlock",
"blockNumber", block.Number(),
"blockHash", block.Hash(),
"feeRecipient", feeRecipient,
"registeredGasLimit", registeredGasLimit)

parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, nil, errors.New("parent not found")
}

statedb, err := bc.StateAt(parent.Root)
if err != nil {
return nil, nil, err
}
log.Error("Parent header not found",
"parentHash", block.ParentHash(),
"parentNumber", block.NumberU64()-1)
return nil, nil, errors.New("parent not found")
}

log.Info("Found parent block",
"parentNumber", parent.Number,
"parentHash", parent.Hash(),
"parentRoot", parent.Root)

// Get state
statedb, err := bc.StateAt(parent.Root)
if err != nil {
log.Error("Failed to get state", "root", parent.Root, "err", err)
return nil, nil, err
}

// The chain importer is starting and stopping trie prefetchers. If a bad
// block or other error is hit however, an early return may not properly
Expand All @@ -2472,40 +2494,53 @@ func (bc *BlockChain) SimulateProfBlock(block *types.Block, feeRecipient common.

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

log.Info("FeeRecipient", "Before", feeRecipientBalanceBefore)

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

// TODO : check for registeredGasLimit hrere

feeRecipientBalanceDelta := new(uint256.Int).Set(statedb.GetBalance(feeRecipient))
log.Info("FeeRecipient", "After", feeRecipientBalanceDelta)
feeRecipientBalanceDelta.Sub(feeRecipientBalanceDelta, feeRecipientBalanceBefore)
log.Info("FeeRecipient", "Delta", feeRecipientBalanceDelta)
if excludeWithdrawals {
for _, w := range block.Withdrawals() {
if w.Address == feeRecipient {
amount := new(uint256.Int).Mul(new(uint256.Int).SetUint64(w.Amount), uint256.NewInt(params.GWei))
feeRecipientBalanceDelta.Sub(feeRecipientBalanceDelta, amount)
}
}
}
// create the new header
header := block.Header()
header.GasUsed = usedGas
rbloom := types.CreateBloom(receipts)
header.Bloom = rbloom
header.ReceiptHash = types.DeriveSha(receipts, trie.NewStackTrie(nil))
header.TxHash = types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil))
header.Root = statedb.IntermediateRoot(true /* TODO: assuming that EIP158 is enabled. TODO : get from the bc.validator's config which is private currently*/)

// TODO : handle the case when usebalancediffprofit is false

return feeRecipientBalanceDelta, header, nil

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

log.Info("SimulateProfBlock - Used Gas", "usedGas", usedGas, "registeredGasLimit", registeredGasLimit)

// Enforce the registeredGasLimit
if usedGas > registeredGasLimit {
log.Error("Used gas exceeds registered gas limit", "usedGas", usedGas, "registeredGasLimit", registeredGasLimit)
return nil, nil, fmt.Errorf("used gas %d exceeds registered gas limit %d", usedGas, registeredGasLimit)
}

// Create new header and update ALL fields that depend on processing results
header := types.CopyHeader(block.Header())
header.GasUsed = usedGas
header.Bloom = types.CreateBloom(receipts)
header.Root = statedb.IntermediateRoot(true)
header.ReceiptHash = types.DeriveSha(receipts, trie.NewStackTrie(nil))

// Create new block with the updated header
newBlock := types.NewBlockWithHeader(header).WithBody(
block.Transactions(),
block.Uncles(),
).WithWithdrawals(block.Withdrawals())

// Now validate the state with all fields properly set
if err := bc.validator.ValidateState(newBlock, statedb, receipts, usedGas); err != nil {
log.Error("SimulateProfBlock - ValidateState failed", "err", err)
return nil, nil, err
}

// Calculate fee recipient changes
feeRecipientBalanceDelta := new(uint256.Int).Set(statedb.GetBalance(feeRecipient))
feeRecipientBalanceDelta.Sub(feeRecipientBalanceDelta, feeRecipientBalanceBefore)

if excludeWithdrawals {
for _, w := range newBlock.Withdrawals() {
if w.Address == feeRecipient {
amount := new(uint256.Int).Mul(new(uint256.Int).SetUint64(w.Amount), uint256.NewInt(params.GWei))
feeRecipientBalanceDelta.Sub(feeRecipientBalanceDelta, amount)
}
}
}

return feeRecipientBalanceDelta, header, nil
}

// ValidatePayload validates the payload of the block.
Expand All @@ -2527,7 +2562,7 @@ func (bc *BlockChain) ValidatePayload(block *types.Block, feeRecipient common.Ad

parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return errors.New("parent not found")
return errors.New("Validate Payload:parent not found")
}

calculatedGasLimit := CalcGasLimit(parent.GasLimit, registeredGasLimit)
Expand Down
58 changes: 55 additions & 3 deletions eth/block-validation/api.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package blockvalidation

import (
"bytes"
"encoding/hex"
"encoding/json"
"errors"
Expand All @@ -25,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/holiman/uint256"
)
Expand Down Expand Up @@ -248,6 +250,15 @@ type ProfSimResp struct {
ExecutionPayload *builderApiDeneb.ExecutionPayloadAndBlobsBundle
}

func serializeBlock(block *types.Block) (string, error) {
var buf bytes.Buffer
err := rlp.Encode(&buf, block)
if err != nil {
return "", err
}
return hex.EncodeToString(buf.Bytes()), nil
}

func (api *BlockValidationAPI) AppendProfBundle(params *ProfSimReq) (*ProfSimResp, error) {
var err error
log.Info("PROF simulation called!")
Expand All @@ -269,7 +280,13 @@ func (api *BlockValidationAPI) AppendProfBundle(params *ProfSimReq) (*ProfSimRes
return nil, err
}

profValidationResp, err := api.validateProfBlock(block, params.ProposerFeeRecipient, params.RegisteredGasLimit)
// Serialize the block
blockData, err := serializeBlock(block)
if err != nil {
return nil, fmt.Errorf("failed to serialize block: %v", err)
}

profValidationResp, err := api.ValidateProfBlock(blockData, params.ProposerFeeRecipient, params.RegisteredGasLimit)
if err != nil {
log.Error("invalid payload", "hash", block.Hash, "number", block.NumberU64(), "parentHash", block.ParentHash, "err", err)
return nil, err
Expand Down Expand Up @@ -318,14 +335,49 @@ func (api *BlockValidationAPI) ValidateBuilderSubmissionV3(params *BuilderBlockV
}

// TODO : invalid profTransactions are not being filtered out currently, change the validateProfBlock method to pluck out the invalid transactions, blockhash would also change in that case
func (api *BlockValidationAPI) ValidateProfBlock(blockData string, proposerFeeRecipient common.Address, registeredGasLimit uint64) (*ProfSimResp, error) {
log.Info("VaPrBl: ValidateProfBlock called!")

func (api *BlockValidationAPI) ValidateProfBlock(profBlock *types.Block, proposerFeeRecipient common.Address, registeredGasLimit uint64) (*ProfSimResp, error) {
log.Info("validateProfBlock method called!")
// Decode the hex-encoded block data
blockBytes, err := hex.DecodeString(blockData)
if err != nil {
return nil, err
}

// Deserialize the block using RLP decoding
var profBlock *types.Block
err = rlp.DecodeBytes(blockBytes, &profBlock)
if err != nil {
return nil, err
}

log.Info("> VaPrBl: profBlock details", "profBlock", fmt.Sprintf("%+v", profBlock))
log.Info("> VaPrBl: proposerFeeRecipient", "proposerFeeRecipient", fmt.Sprintf("%+v", proposerFeeRecipient))
log.Info("> VaPrBl: registeredGasLimit", "registeredGasLimit", fmt.Sprintf("%+v", registeredGasLimit))

// Now 'block' has all the data, including the header
if profBlock.Header() == nil {
return nil, errors.New("block header is nil after deserialization")
}

// Now safe to call profBlock.Header()
header := profBlock.Header()
blockHash := profBlock.Hash()
blockNumber := header.Number.Uint64()

feeRecipient := common.BytesToAddress(proposerFeeRecipient[:])

var vmconfig vm.Config

log.Info("> VaPrBl: SimulateProfBlock params",
"block", blockHash,
"blockNumber", blockNumber,
"feeRecipient", feeRecipient,
"registeredGasLimit", registeredGasLimit,
"vmconfig", vmconfig,
"useBalanceDiff", true,
"excludeWithdrawals", true)

value, header, err := api.eth.BlockChain().SimulateProfBlock(profBlock, feeRecipient, registeredGasLimit, vmconfig, true /* prof uses balance diff*/, true /* exclude withdrawals */)

if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ require (
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46
github.com/gofrs/flock v0.8.1
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/protobuf v1.5.3
github.com/golang/protobuf v1.5.4
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/gofuzz v1.2.0
github.com/google/uuid v1.6.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
Expand Down