Skip to content

Commit

Permalink
GetPayloadV2 change (#6554)
Browse files Browse the repository at this point in the history
- calculates blockValue for updated engine_getPayloadV2 spec
- adds tests for pre/post Shanghai RawBody RLP
  • Loading branch information
revitteth committed Jan 11, 2023
1 parent 4bee05d commit 4d09a69
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 5 deletions.
59 changes: 54 additions & 5 deletions cmd/rpcdaemon/commands/engine_api.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
package commands

import (
"bytes"
"context"
"encoding/binary"
"fmt"
"math/big"

"github.com/holiman/uint256"
"github.com/ledgerwatch/log/v3"

"github.com/ledgerwatch/erigon-lib/gointerfaces"
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/hexutil"
cmath "github.com/ledgerwatch/erigon/common/math"
"github.com/ledgerwatch/erigon/common/u256"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/ethdb/privateapi"
"github.com/ledgerwatch/erigon/rlp"
"github.com/ledgerwatch/erigon/turbo/rpchelper"
"github.com/ledgerwatch/log/v3"
)

// ExecutionPayloadV1 represents an execution payload (aka block) without withdrawals
Expand Down Expand Up @@ -57,6 +62,12 @@ type ExecutionPayloadV2 struct {
Withdrawals []*types.Withdrawal `json:"withdrawals" gencodec:"required"`
}

// GetPayloadV2Response represents the response of the getPayloadV2 method
type GetPayloadV2Response struct {
ExecutionPayload ExecutionPayloadV2 `json:"executionPayload" gencodec:"required"`
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
}

// PayloadAttributes represent the attributes required to start assembling a payload
type ForkChoiceState struct {
HeadHash common.Hash `json:"headBlockHash" gencodec:"required"`
Expand Down Expand Up @@ -93,7 +104,7 @@ type EngineAPI interface {
ForkchoiceUpdatedV1(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributesV1) (map[string]interface{}, error)
ForkchoiceUpdatedV2(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributesV2) (map[string]interface{}, error)
GetPayloadV1(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayloadV1, error)
GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayloadV2, error)
GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*GetPayloadV2Response, error)
ExchangeTransitionConfigurationV1(ctx context.Context, transitionConfiguration *TransitionConfiguration) (*TransitionConfiguration, error)
}

Expand Down Expand Up @@ -375,7 +386,35 @@ func (e *EngineImpl) GetPayloadV1(ctx context.Context, payloadID hexutil.Bytes)
}, nil
}

func (e *EngineImpl) GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayloadV2, error) {
func getTxValueForBlockValue(transaction []byte, baseFee *big.Int) (*big.Int, error) {
// calculate blockValue by summing tips - see: https://github.com/ethereum/execution-apis/pull/314
s := rlp.NewStream(bytes.NewReader(transaction), uint64(len(transaction)))
t, err := types.DecodeTransaction(s)
if err != nil {
log.Error("Failed to decode transaction", "err", err)
return nil, err
}

// convert baseFee to uint256
baseFeeUint256, overflow := uint256.FromBig(baseFee)
if overflow {
log.Warn("baseFee overflow")
return nil, fmt.Errorf("baseFee overflow")
}

effectiveTip := uint256.NewInt(t.GetGas())
if t.GetFeeCap().Gt(baseFeeUint256) {
effectiveTip = cmath.Min256(t.GetTip(), new(uint256.Int).Sub(t.GetFeeCap(), baseFeeUint256))
} else {
effectiveTip = u256.Num0
}
amount := new(uint256.Int).SetUint64(t.GetGas())
amount.Mul(amount, effectiveTip) // gasUsed * effectiveTip = how much goes to the block producer (miner, validator)

return amount.ToBig(), nil
}

func (e *EngineImpl) GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes) (*GetPayloadV2Response, error) {
if e.internalCL {
log.Error("EXTERNAL CONSENSUS LAYER IS NOT ENABLED, PLEASE RESTART WITH FLAG --externalcl")
return nil, fmt.Errorf("engine api should not be used, restart with --externalcl")
Expand All @@ -397,12 +436,18 @@ func (e *EngineImpl) GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes)
baseFee = gointerfaces.ConvertH256ToUint256Int(payload.BaseFeePerGas).ToBig()
}

// Convert slice of hexutil.Bytes to a slice of slice of bytes
blockValue := big.NewInt(0)
transactions := make([]hexutil.Bytes, len(payload.Transactions))
for i, transaction := range payload.Transactions {
transactions[i] = transaction
txVal, err := getTxValueForBlockValue(transaction, baseFee)
if err != nil {
return nil, err
}
blockValue.Add(blockValue, txVal)
}
return &ExecutionPayloadV2{

epl := ExecutionPayloadV2{
ParentHash: gointerfaces.ConvertH256ToHash(payload.ParentHash),
FeeRecipient: gointerfaces.ConvertH160toAddress(payload.Coinbase),
StateRoot: gointerfaces.ConvertH256ToHash(payload.StateRoot),
Expand All @@ -418,6 +463,10 @@ func (e *EngineImpl) GetPayloadV2(ctx context.Context, payloadID hexutil.Bytes)
BlockHash: gointerfaces.ConvertH256ToHash(payload.BlockHash),
Transactions: transactions,
Withdrawals: privateapi.ConvertWithdrawalsFromRpc(ep.Withdrawals),
}
return &GetPayloadV2Response{
epl,
(*hexutil.Big)(blockValue),
}, nil
}

Expand Down
46 changes: 46 additions & 0 deletions core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package types

import (
"bytes"
"encoding/hex"
"encoding/json"
"math/big"
"reflect"
Expand Down Expand Up @@ -438,3 +439,48 @@ func TestWithdrawalsEncoding(t *testing.T) {

assert.Equal(t, block2, &decoded2)
}

func TestBlockRawBodyPreShanghai(t *testing.T) {
require := require.New(t)

const rawBodyForStorageRlp = "f901f4c0f901f0f901eda00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808080808080a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
bstring, _ := hex.DecodeString(rawBodyForStorageRlp)

body := new(RawBody)
rlp.DecodeBytes(bstring, body)

require.Nil(body.Withdrawals)
require.Equal(1, len(body.Uncles))
require.Equal(0, len(body.Transactions))
}

func TestBlockRawBodyPostShanghaiNoWithdrawals(t *testing.T) {
require := require.New(t)

const rawBodyForStorageRlp = "f901f5c0f901f0f901eda00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808080808080a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0"
bstring, _ := hex.DecodeString(rawBodyForStorageRlp)

body := new(RawBody)
rlp.DecodeBytes(bstring, body)

require.NotNil(body.Withdrawals)
require.Equal(0, len(body.Withdrawals))
require.Equal(1, len(body.Uncles))
require.Equal(0, len(body.Transactions))
}

func TestBlockRawBodyPostShanghaiWithdrawals(t *testing.T) {
require := require.New(t)

const rawBodyForStorageRlp = "f90230c0f901f0f901eda00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808080808080a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f83adc0f82157c94ff000000000000000000000000000000000000008203e8dc1082157d94ff000000000000000000000000000000000000008203e9"

bstring, _ := hex.DecodeString(rawBodyForStorageRlp)

body := new(RawBody)
rlp.DecodeBytes(bstring, body)

require.NotNil(body.Withdrawals)
require.Equal(1, len(body.Uncles))
require.Equal(0, len(body.Transactions))
require.Equal(2, len(body.Withdrawals))
}

0 comments on commit 4d09a69

Please sign in to comment.