Builder: filter header with 0 bid and empty tx root (#11313)

* Filter header with 0 bid and empty root

* Check nil

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
terencechain 2022-08-25 11:24:02 -07:00 committed by GitHub
parent 1d07bffe11
commit 436792fe38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 6 deletions

View File

@ -64,6 +64,7 @@ go_library(
"//crypto/hash:go_default_library",
"//crypto/rand:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//monitoring/tracing:go_default_library",
"//network/forks:go_default_library",
"//proto/engine/v1:go_default_library",

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"math/big"
"time"
"github.com/pkg/errors"
@ -19,6 +20,7 @@ import (
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/runtime/version"
@ -108,6 +110,7 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Sl
if blocks.IsPreBellatrixVersion(b.Version()) {
return nil, nil
}
h, err := b.Block().Body().Execution()
if err != nil {
return nil, err
@ -120,6 +123,25 @@ func (vs *Server) getPayloadHeaderFromBuilder(ctx context.Context, slot types.Sl
if err != nil {
return nil, err
}
if bid == nil || bid.Message == nil {
return nil, errors.New("builder returned nil bid")
}
v := bid.Message.Value
if new(big.Int).SetBytes(bytesutil.ReverseByteOrder(v)).String() == "0" {
return nil, errors.New("builder returned header with 0 bid amount")
}
emptyRoot, err := ssz.TransactionsRoot([][]byte{})
if err != nil {
return nil, err
}
if bytesutil.ToBytes32(bid.Message.Header.TransactionsRoot) == emptyRoot {
return nil, errors.New("builder returned header with an empty tx root")
}
if !bytes.Equal(bid.Message.Header.ParentHash, h.BlockHash()) {
return nil, fmt.Errorf("incorrect parent hash %#x != %#x", bid.Message.Header.ParentHash, h.BlockHash())
}

View File

@ -97,6 +97,40 @@ func TestServer_buildHeaderBlock(t *testing.T) {
}
func TestServer_getPayloadHeader(t *testing.T) {
emptyRoot, err := ssz.TransactionsRoot([][]byte{})
require.NoError(t, err)
ti, err := slots.ToTime(uint64(time.Now().Unix()), 0)
require.NoError(t, err)
sk, err := bls.RandKey()
require.NoError(t, err)
bid := &ethpb.BuilderBid{
Header: &v1.ExecutionPayloadHeader{
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
TransactionsRoot: bytesutil.PadTo([]byte{1}, fieldparams.RootLength),
ParentHash: params.BeaconConfig().ZeroHash[:],
Timestamp: uint64(ti.Unix()),
},
Pubkey: sk.PublicKey().Marshal(),
Value: bytesutil.PadTo([]byte{1, 2, 3}, 32),
}
d := params.BeaconConfig().DomainApplicationBuilder
domain, err := signing.ComputeDomain(d, nil, nil)
require.NoError(t, err)
sr, err := signing.ComputeSigningRoot(bid, domain)
require.NoError(t, err)
sBid := &ethpb.SignedBuilderBid{
Message: bid,
Signature: sk.Sign(sr[:]).Marshal(),
}
require.NoError(t, err)
tests := []struct {
name string
head interfaces.SignedBeaconBlock
@ -131,7 +165,7 @@ func TestServer_getPayloadHeader(t *testing.T) {
err: "can't get header",
},
{
name: "get header correct",
name: "0 bid",
mock: &builderTest.MockBuilderService{
Bid: &ethpb.SignedBuilderBid{
Message: &ethpb.BuilderBid{
@ -140,7 +174,6 @@ func TestServer_getPayloadHeader(t *testing.T) {
},
},
},
ErrGetHeader: errors.New("can't get header"),
},
fetcher: &blockchainTest.ChainService{
Block: func() interfaces.SignedBeaconBlock {
@ -149,18 +182,55 @@ func TestServer_getPayloadHeader(t *testing.T) {
return wb
}(),
},
returnedHeader: &v1.ExecutionPayloadHeader{
BlockNumber: 123,
err: "builder returned header with 0 bid amount",
},
{
name: "invalid tx root",
mock: &builderTest.MockBuilderService{
Bid: &ethpb.SignedBuilderBid{
Message: &ethpb.BuilderBid{
Value: []byte{1},
Header: &v1.ExecutionPayloadHeader{
BlockNumber: 123,
TransactionsRoot: emptyRoot[:],
},
},
},
},
fetcher: &blockchainTest.ChainService{
Block: func() interfaces.SignedBeaconBlock {
wb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockBellatrix())
require.NoError(t, err)
return wb
}(),
},
err: "builder returned header with an empty tx root",
},
{
name: "can get header",
mock: &builderTest.MockBuilderService{
Bid: sBid,
},
fetcher: &blockchainTest.ChainService{
Block: func() interfaces.SignedBeaconBlock {
wb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockBellatrix())
require.NoError(t, err)
return wb
}(),
},
returnedHeader: bid.Header,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
vs := &Server{BlockBuilder: tc.mock, HeadFetcher: tc.fetcher}
vs := &Server{BlockBuilder: tc.mock, HeadFetcher: tc.fetcher, TimeFetcher: &blockchainTest.ChainService{
Genesis: time.Now(),
}}
h, err := vs.getPayloadHeaderFromBuilder(context.Background(), 0, 0)
if err != nil {
if tc.err != "" {
require.ErrorContains(t, tc.err, err)
} else {
require.NoError(t, err)
require.DeepEqual(t, tc.returnedHeader, h)
}
})