blockValue should use gasUsed rather than gasLimit (#6875)

Fees going to the gas fee recipient should be based on the actual gas
used (available in the receipt) rather than the gas limit in a
transaction. This fixes Hive test "GetPayloadV2 Block Value".

Also `engine_getPayloadBodiesByRangeV1` params should be encoded as hex
strings.
This commit is contained in:
Andrew Ashikhmin 2023-02-14 16:05:27 +01:00 committed by GitHub
parent add5f80f43
commit 58fcc04575
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 43 additions and 30 deletions

View File

@ -489,7 +489,7 @@ func NewBackend(stack *node.Node, config *ethconfig.Config, logger log.Logger) (
}
// proof-of-stake mining
assembleBlockPOS := func(param *core.BlockBuilderParameters, interrupt *int32) (*types.Block, error) {
assembleBlockPOS := func(param *core.BlockBuilderParameters, interrupt *int32) (*types.BlockWithReceipts, error) {
miningStatePos := stagedsync.NewProposingState(&config.Miner)
miningStatePos.MiningConfig.Etherbase = param.SuggestedFeeRecipient
proposingSync := stagedsync.New(

View File

@ -85,7 +85,7 @@ type EngineAPI interface {
GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*GetPayloadV2Response, error)
ExchangeTransitionConfigurationV1(ctx context.Context, transitionConfiguration *TransitionConfiguration) (*TransitionConfiguration, error)
GetPayloadBodiesByHashV1(ctx context.Context, hashes []common.Hash) ([]*ExecutionPayloadBodyV1, error)
GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*ExecutionPayloadBodyV1, error)
GetPayloadBodiesByRangeV1(ctx context.Context, start, count hexutil.Uint64) ([]*ExecutionPayloadBodyV1, error)
}
// EngineImpl is implementation of the EngineAPI interface
@ -384,7 +384,7 @@ func (e *EngineImpl) GetPayloadBodiesByHashV1(ctx context.Context, hashes []comm
return convertExecutionPayloadV1(apiRes), nil
}
func (e *EngineImpl) GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*ExecutionPayloadBodyV1, error) {
func (e *EngineImpl) GetPayloadBodiesByRangeV1(ctx context.Context, start, count hexutil.Uint64) ([]*ExecutionPayloadBodyV1, error) {
if start == 0 || count == 0 {
return nil, &rpc.InvalidParamsError{Message: fmt.Sprintf("invalid start or count, start: %v count: %v", start, count)}
}
@ -392,7 +392,7 @@ func (e *EngineImpl) GetPayloadBodiesByRangeV1(ctx context.Context, start uint64
return nil, &privateapi.TooLargeRequestErr
}
apiRes, err := e.api.EngineGetPayloadBodiesByRangeV1(ctx, &remote.EngineGetPayloadBodiesByRangeV1Request{Start: start, Count: count})
apiRes, err := e.api.EngineGetPayloadBodiesByRangeV1(ctx, &remote.EngineGetPayloadBodiesByRangeV1Request{Start: uint64(start), Count: uint64(count)})
if err != nil {
return nil, err
}

View File

@ -1782,3 +1782,8 @@ func DecodeOnlyTxMetadataFromBody(payload []byte) (baseTxId uint64, txAmount uin
}
return
}
type BlockWithReceipts struct {
Block *Block
Receipts Receipts
}

View File

@ -514,7 +514,7 @@ func New(stack *node.Node, config *ethconfig.Config, logger log.Logger) (*Ethere
}
// proof-of-stake mining
assembleBlockPOS := func(param *core.BlockBuilderParameters, interrupt *int32) (*types.Block, error) {
assembleBlockPOS := func(param *core.BlockBuilderParameters, interrupt *int32) (*types.BlockWithReceipts, error) {
miningStatePos := stagedsync.NewProposingState(&config.Miner)
miningStatePos.MiningConfig.Etherbase = param.SuggestedFeeRecipient
proposingSync := stagedsync.New(

View File

@ -38,7 +38,7 @@ type MiningState struct {
MiningConfig *params.MiningConfig
PendingResultCh chan *types.Block
MiningResultCh chan *types.Block
MiningResultPOSCh chan *types.Block
MiningResultPOSCh chan *types.BlockWithReceipts
MiningBlock *MiningBlock
}
@ -56,7 +56,7 @@ func NewProposingState(cfg *params.MiningConfig) MiningState {
MiningConfig: cfg,
PendingResultCh: make(chan *types.Block, 1),
MiningResultCh: make(chan *types.Block, 1),
MiningResultPOSCh: make(chan *types.Block, 1),
MiningResultPOSCh: make(chan *types.BlockWithReceipts, 1),
MiningBlock: &MiningBlock{},
}
}

View File

@ -45,6 +45,7 @@ func SpawnMiningFinishStage(s *StageState, tx kv.RwTx, cfg MiningFinishCfg, quit
//}
block := types.NewBlock(current.Header, current.Txs, current.Uncles, current.Receipts, current.Withdrawals)
blockWithReceipts := &types.BlockWithReceipts{Block: block, Receipts: current.Receipts}
*current = MiningBlock{} // hack to clean global data
//sealHash := engine.SealHash(block.Header())
@ -56,7 +57,7 @@ func SpawnMiningFinishStage(s *StageState, tx kv.RwTx, cfg MiningFinishCfg, quit
//prev = sealHash
if cfg.miningState.MiningResultPOSCh != nil {
cfg.miningState.MiningResultPOSCh <- block
cfg.miningState.MiningResultPOSCh <- blockWithReceipts
return nil
}
// Tests may set pre-calculated nonce

View File

@ -517,11 +517,12 @@ func (s *EthBackendServer) getQuickPayloadStatusIfPossible(blockHash libcommon.H
}
// The expected value to be received by the feeRecipient in wei
func blockValue(block *types.Block, baseFee *uint256.Int) *uint256.Int {
func blockValue(br *types.BlockWithReceipts, baseFee *uint256.Int) *uint256.Int {
blockValue := uint256.NewInt(0)
for _, tx := range block.Transactions() {
gas := new(uint256.Int).SetUint64(tx.GetGas())
effectiveTip := tx.GetEffectiveGasTip(baseFee)
txs := br.Block.Transactions()
for i := range txs {
gas := new(uint256.Int).SetUint64(br.Receipts[i].GasUsed)
effectiveTip := txs[i].GetEffectiveGasTip(baseFee)
txValue := new(uint256.Int).Mul(gas, effectiveTip)
blockValue.Add(blockValue, txValue)
}
@ -549,11 +550,12 @@ func (s *EthBackendServer) EngineGetPayload(ctx context.Context, req *remote.Eng
return nil, &UnknownPayloadErr
}
block, err := builder.Stop()
blockWithReceipts, err := builder.Stop()
if err != nil {
log.Error("Failed to build PoS block", "err", err)
return nil, err
}
block := blockWithReceipts.Block
baseFee := new(uint256.Int)
baseFee.SetFromBig(block.Header().BaseFee)
@ -585,7 +587,7 @@ func (s *EthBackendServer) EngineGetPayload(ctx context.Context, req *remote.Eng
payload.Withdrawals = ConvertWithdrawalsToRpc(block.Withdrawals())
}
blockValue := blockValue(block, baseFee)
blockValue := blockValue(blockWithReceipts, baseFee)
return &remote.EngineGetPayloadResponse{
ExecutionPayload: payload,
BlockValue: gointerfaces.ConvertUint256IntToH256(blockValue),

View File

@ -5,60 +5,65 @@ import (
"sync/atomic"
"time"
"github.com/ledgerwatch/log/v3"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/log/v3"
)
type BlockBuilderFunc func(param *core.BlockBuilderParameters, interrupt *int32) (*types.Block, error)
type BlockBuilderFunc func(param *core.BlockBuilderParameters, interrupt *int32) (*types.BlockWithReceipts, error)
// BlockBuilder wraps a goroutine that builds Proof-of-Stake payloads (PoS "mining")
type BlockBuilder struct {
interrupt int32
syncCond *sync.Cond
block *types.Block
result *types.BlockWithReceipts
err error
}
func NewBlockBuilder(build BlockBuilderFunc, param *core.BlockBuilderParameters) *BlockBuilder {
b := new(BlockBuilder)
b.syncCond = sync.NewCond(new(sync.Mutex))
builder := new(BlockBuilder)
builder.syncCond = sync.NewCond(new(sync.Mutex))
go func() {
log.Info("Building block...")
t := time.Now()
block, err := build(param, &b.interrupt)
result, err := build(param, &builder.interrupt)
if err != nil {
log.Warn("Failed to build a block", "err", err)
} else {
block := result.Block
log.Info("Built block", "hash", block.Hash(), "height", block.NumberU64(), "txs", len(block.Transactions()), "gas used %", 100*float64(block.GasUsed())/float64(block.GasLimit()), "time", time.Since(t))
}
b.syncCond.L.Lock()
defer b.syncCond.L.Unlock()
b.block = block
b.err = err
b.syncCond.Broadcast()
builder.syncCond.L.Lock()
defer builder.syncCond.L.Unlock()
builder.result = result
builder.err = err
builder.syncCond.Broadcast()
}()
return b
return builder
}
func (b *BlockBuilder) Stop() (*types.Block, error) {
func (b *BlockBuilder) Stop() (*types.BlockWithReceipts, error) {
atomic.StoreInt32(&b.interrupt, 1)
b.syncCond.L.Lock()
defer b.syncCond.L.Unlock()
for b.block == nil && b.err == nil {
for b.result == nil && b.err == nil {
b.syncCond.Wait()
}
return b.block, b.err
return b.result, b.err
}
func (b *BlockBuilder) Block() *types.Block {
b.syncCond.L.Lock()
defer b.syncCond.L.Unlock()
return b.block
if b.result == nil {
return nil
}
return b.result.Block
}