Compare commits

..

9 Commits

Author SHA1 Message Date
terencechain
76b941b310 Update ropsten TTD (#10817)
Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-06-04 02:54:51 +00:00
Nishant Das
d099c2790b Add Back Timestamp Related Deposit Processing (#10806)
* use it

* add test

* fix

Co-authored-by: terencechain <terence@prysmaticlabs.com>
2022-06-04 01:58:03 +00:00
Potuz
2fc3d41ffa goppelganger -> doppelganger (#10816)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-06-03 22:53:58 +00:00
Jim McDonald
2e4174bdd6 Set fee recipient validator index as per spec. (#10814)
The beacon API specification states that the `validator_index` field of
the `fee_recipient` structure is a quoted string rather than a bare
integer.  This fixes up the encoding to match the spec.

Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
2022-06-03 21:52:17 +00:00
kasey
a170fd4bd6 Revert "Change name and return type of HighestSlotBlocksBelow (#10811)" (#10818)
This reverts commit 0e9dfe04a1.

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2022-06-03 18:36:06 +00:00
terencechain
3e36eacd1e Add registration DB methods (#10812) 2022-06-03 15:13:04 +00:00
kasey
0e9dfe04a1 Change name and return type of HighestSlotBlocksBelow (#10811)
* HighestSlotBlocksBelow to return a single value

* HighestSlotBlocksBelow->HighestBlockBelowSlot

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-06-03 07:16:34 +00:00
Radosław Kapka
302a5cf00b API SSZ content negotiation (#10760)
* API SSZ content negotiation

* custom code

* use raw string

* code review feedback

* remove duplicated test
2022-06-02 22:13:58 +00:00
kasey
c72f1af951 rewind cursor upon nil value (bucket) (#10802)
Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
Co-authored-by: Nishant Das <nishdas93@gmail.com>
2022-06-02 04:06:19 +00:00
26 changed files with 318 additions and 446 deletions

View File

@@ -1,7 +0,0 @@
package builder
import "github.com/pkg/errors"
var (
ErrNotRunning = errors.New("builder is not running")
)

View File

@@ -1,30 +0,0 @@
package builder
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
submitBlindedBlockLatency = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "submit_blinded_block_latency_milliseconds",
Help: "Captures RPC latency for submitting blinded block in milliseconds",
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
},
)
getHeaderLatency = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "get_header_latency_milliseconds",
Help: "Captures RPC latency for get header in milliseconds",
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
},
)
registerValidatorLatency = promauto.NewHistogram(
prometheus.HistogramOpts{
Name: "register_validator_latency_milliseconds",
Help: "Captures RPC latency for register validator in milliseconds",
Buckets: []float64{1, 2, 5, 10, 20, 50, 100, 200, 500, 1000},
},
)
)

View File

@@ -1,58 +0,0 @@
package builder
import (
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/network"
"github.com/prysmaticlabs/prysm/network/authorization"
"github.com/urfave/cli/v2"
)
type Option func(s *Service) error
// FlagOptions for builder service flag configurations.
func FlagOptions(c *cli.Context) ([]Option, error) {
endpoints := parseBuilderEndpoints(c)
opts := []Option{
WithBuilderEndpoints(endpoints),
}
return opts, nil
}
func WithBuilderEndpoints(endpoints []string) Option {
return func(s *Service) error {
stringEndpoints := dedupEndpoints(endpoints)
endpoints := make([]network.Endpoint, len(stringEndpoints))
for i, e := range stringEndpoints {
endpoints[i] = covertEndPoint(e)
}
s.cfg.builderEndpoint = endpoints[0] // Use the first one as the default.
return nil
}
}
func covertEndPoint(ep string) network.Endpoint {
return network.Endpoint{
Url: ep,
Auth: network.AuthorizationData{ // Not sure about authorization for now.
Method: authorization.None,
Value: "",
}}
}
func parseBuilderEndpoints(c *cli.Context) []string {
// Goal is to support multiple end points later.
return []string{c.String(flags.MevBuilderFlag.Name)}
}
func dedupEndpoints(endpoints []string) []string {
selectionMap := make(map[string]bool)
newEndpoints := make([]string, 0, len(endpoints))
for _, point := range endpoints {
if selectionMap[point] {
continue
}
newEndpoints = append(newEndpoints, point)
selectionMap[point] = true
}
return newEndpoints
}

View File

@@ -1,29 +0,0 @@
package builder
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/signing"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/time/slots"
)
func VerifyRegistrationSignature(
slot types.Slot,
fork *ethpb.Fork,
signed *ethpb.SignedValidatorRegistrationV1,
genesisRoot []byte,
) error {
if signed == nil || signed.Message == nil {
return errors.New("nil signed registration")
}
domain, err := signing.Domain(fork, slots.ToEpoch(slot), [4]byte{} /*TODO: Use registration signing domain */, genesisRoot)
if err != nil {
return err
}
if err := signing.VerifySigningRoot(signed, signed.Message.Pubkey, signed.Signature, domain); err != nil {
return signing.ErrSigFailedToVerify
}
return nil
}

View File

@@ -410,23 +410,23 @@ func (s *Store) HighestSlotBlocksBelow(ctx context.Context, slot types.Slot) ([]
c := bkt.Cursor()
// The documentation for Seek says:
// "If the key does not exist then the next key is used. If no keys follow, a nil key is returned."
sl, r := c.Seek(sk)
// So if there are slots in the index higher than the requested slot, sl will be equal to the key that is
// one higher than the value we want. If the slot argument is higher than the highest value in the index,
// we'll get a nil value for `sl`. In that case we'll go backwards from Cursor.Last().
if sl == nil {
sl, r = c.Last()
seekPast := func(ic *bolt.Cursor, k []byte) ([]byte, []byte) {
ik, iv := ic.Seek(k)
// So if there are slots in the index higher than the requested slot, sl will be equal to the key that is
// one higher than the value we want. If the slot argument is higher than the highest value in the index,
// we'll get a nil value for `sl`. In that case we'll go backwards from Cursor.Last().
if ik == nil {
return ic.Last()
}
return ik, iv
}
for {
// re loop condition: when .Prev() rewinds past the beginning off the collection, the loop will terminate,
// because `sl` will be nil. If we don't find a value for `root` before iteration ends,
// `root` will be the zero value, in which case this function will return the genesis block.
for sl, r := seekPast(c, sk); sl != nil; sl, r = c.Prev() {
if ctx.Err() != nil {
return ctx.Err()
}
// termination condition: when .Prev() rewinds past the beginning off the collection, key will be nil.
// breaking without setting `root` means `root` will be the zero value, so this function will return
// the genesis block.
if sl == nil {
break
}
if r == nil {
continue
}
@@ -437,7 +437,6 @@ func (s *Store) HighestSlotBlocksBelow(ctx context.Context, slot types.Slot) ([]
root = bytesutil.ToBytes32(r)
break
}
sl, r = c.Prev()
}
return nil
})
@@ -470,8 +469,20 @@ func (s *Store) FeeRecipientByValidatorID(ctx context.Context, id types.Validato
err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(feeRecipientBucket)
addr = bkt.Get(bytesutil.Uint64ToBytesBigEndian(uint64(id)))
// IF the fee recipient is not found in the standard fee recipient bucket, then
// check the registration bucket. The fee recipient may be there.
// This is to resolve imcompatility until we fully migrate to the registration bucket.
if addr == nil {
return errors.Wrapf(ErrNotFoundFeeRecipient, "validator id %d", id)
bkt = tx.Bucket(registrationBucket)
enc := bkt.Get(bytesutil.Uint64ToBytesBigEndian(uint64(id)))
if enc == nil {
return errors.Wrapf(ErrNotFoundFeeRecipient, "validator id %d", id)
}
reg := &ethpb.ValidatorRegistrationV1{}
if err := decode(ctx, enc, reg); err != nil {
return err
}
addr = reg.FeeRecipient
}
return nil
})
@@ -499,6 +510,48 @@ func (s *Store) SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []types
})
}
// RegistrationByValidatorID returns the validator registration object for a validator id.
// `ErrNotFoundFeeRecipient` is returned if the validator id is not found.
func (s *Store) RegistrationByValidatorID(ctx context.Context, id types.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error) {
ctx, span := trace.StartSpan(ctx, "BeaconDB.RegistrationByValidatorID")
defer span.End()
reg := &ethpb.ValidatorRegistrationV1{}
err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(registrationBucket)
enc := bkt.Get(bytesutil.Uint64ToBytesBigEndian(uint64(id)))
if enc == nil {
return errors.Wrapf(ErrNotFoundFeeRecipient, "validator id %d", id)
}
return decode(ctx, enc, reg)
})
return reg, err
}
// SaveRegistrationsByValidatorIDs saves the validator registrations for validator ids.
// Error is returned if `ids` and `registrations` are not the same length.
func (s *Store) SaveRegistrationsByValidatorIDs(ctx context.Context, ids []types.ValidatorIndex, regs []*ethpb.ValidatorRegistrationV1) error {
_, span := trace.StartSpan(ctx, "BeaconDB.SaveRegistrationsByValidatorIDs")
defer span.End()
if len(ids) != len(regs) {
return errors.New("ids and registrations must be the same length")
}
return s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(registrationBucket)
for i, id := range ids {
enc, err := encode(ctx, regs[i])
if err != nil {
return err
}
if err := bkt.Put(bytesutil.Uint64ToBytesBigEndian(uint64(id)), enc); err != nil {
return err
}
}
return nil
})
}
// blockRootsByFilter retrieves the block roots given the filter criteria.
func blockRootsByFilter(ctx context.Context, tx *bolt.Tx, f *filters.QueryFilter) ([][]byte, error) {
ctx, span := trace.StartSpan(ctx, "BeaconDB.blockRootsByFilter")

View File

@@ -693,4 +693,78 @@ func TestStore_FeeRecipientByValidatorID(t *testing.T) {
_, err = db.FeeRecipientByValidatorID(ctx, 3)
want := errors.Wrap(ErrNotFoundFeeRecipient, "validator id 3")
require.Equal(t, want.Error(), err.Error())
regs := []*ethpb.ValidatorRegistrationV1{
{
FeeRecipient: bytesutil.PadTo([]byte("a"), 20),
GasLimit: 1,
Timestamp: 2,
Pubkey: bytesutil.PadTo([]byte("b"), 48),
}}
require.NoError(t, db.SaveRegistrationsByValidatorIDs(ctx, []types.ValidatorIndex{3}, regs))
f, err = db.FeeRecipientByValidatorID(ctx, 3)
require.NoError(t, err)
require.Equal(t, common.Address{'a'}, f)
_, err = db.FeeRecipientByValidatorID(ctx, 4)
want = errors.Wrap(ErrNotFoundFeeRecipient, "validator id 4")
require.Equal(t, want.Error(), err.Error())
}
func TestStore_RegistrationsByValidatorID(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
ids := []types.ValidatorIndex{0, 0, 0}
regs := []*ethpb.ValidatorRegistrationV1{{}, {}, {}, {}}
require.ErrorContains(t, "ids and registrations must be the same length", db.SaveRegistrationsByValidatorIDs(ctx, ids, regs))
ids = []types.ValidatorIndex{0, 1, 2}
regs = []*ethpb.ValidatorRegistrationV1{
{
FeeRecipient: bytesutil.PadTo([]byte("a"), 20),
GasLimit: 1,
Timestamp: 2,
Pubkey: bytesutil.PadTo([]byte("b"), 48),
},
{
FeeRecipient: bytesutil.PadTo([]byte("c"), 20),
GasLimit: 3,
Timestamp: 4,
Pubkey: bytesutil.PadTo([]byte("d"), 48),
},
{
FeeRecipient: bytesutil.PadTo([]byte("e"), 20),
GasLimit: 5,
Timestamp: 6,
Pubkey: bytesutil.PadTo([]byte("f"), 48),
},
}
require.NoError(t, db.SaveRegistrationsByValidatorIDs(ctx, ids, regs))
f, err := db.RegistrationByValidatorID(ctx, 0)
require.NoError(t, err)
require.DeepEqual(t, &ethpb.ValidatorRegistrationV1{
FeeRecipient: bytesutil.PadTo([]byte("a"), 20),
GasLimit: 1,
Timestamp: 2,
Pubkey: bytesutil.PadTo([]byte("b"), 48),
}, f)
f, err = db.RegistrationByValidatorID(ctx, 1)
require.NoError(t, err)
require.DeepEqual(t, &ethpb.ValidatorRegistrationV1{
FeeRecipient: bytesutil.PadTo([]byte("c"), 20),
GasLimit: 3,
Timestamp: 4,
Pubkey: bytesutil.PadTo([]byte("d"), 48),
}, f)
f, err = db.RegistrationByValidatorID(ctx, 2)
require.NoError(t, err)
require.DeepEqual(t, &ethpb.ValidatorRegistrationV1{
FeeRecipient: bytesutil.PadTo([]byte("e"), 20),
GasLimit: 5,
Timestamp: 6,
Pubkey: bytesutil.PadTo([]byte("f"), 48),
}, f)
_, err = db.RegistrationByValidatorID(ctx, 3)
want := errors.Wrap(ErrNotFoundFeeRecipient, "validator id 3")
require.Equal(t, want.Error(), err.Error())
}

View File

@@ -70,6 +70,8 @@ func isSSZStorageFormat(obj interface{}) bool {
return true
case *ethpb.VoluntaryExit:
return true
case *ethpb.ValidatorRegistrationV1:
return true
default:
return false
}

View File

@@ -192,6 +192,7 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
migrationsBucket,
feeRecipientBucket,
registrationBucket,
)
}); err != nil {
log.WithField("elapsed", time.Since(start)).Error("Failed to update db and create buckets")

View File

@@ -19,6 +19,7 @@ var (
powchainBucket = []byte("powchain")
stateValidatorsBucket = []byte("state-validators")
feeRecipientBucket = []byte("fee-recipient")
registrationBucket = []byte("registration")
// Deprecated: This bucket was migrated in PR 6461. Do not use, except for migrations.
slotsHasObjectBucket = []byte("slots-has-objects")

View File

@@ -228,11 +228,6 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
log.Debugln("Starting Fork Choice")
beacon.startForkChoice()
log.Debugln("Registering builder service")
if err := beacon.registerBuilderService(); err != nil {
return nil, err
}
log.Debugln("Registering Blockchain Service")
if err := beacon.registerBlockchainService(); err != nil {
return nil, err
@@ -573,14 +568,6 @@ func (b *BeaconNode) fetchP2P() p2p.P2P {
return p
}
func (b *BeaconNode) fetchBuilderService() *builder.Service {
var s *builder.Service
if err := b.services.FetchService(&s); err != nil {
panic(err)
}
return s
}
func (b *BeaconNode) registerAttestationPool() error {
s, err := attestations.NewService(b.ctx, &attestations.Config{
Pool: b.attestationPool,
@@ -819,7 +806,6 @@ func (b *BeaconNode) registerRPCService() error {
AttestationReceiver: chainService,
GenesisTimeFetcher: chainService,
GenesisFetcher: chainService,
BlockBuilder: b.fetchBuilderService(),
OptimisticModeFetcher: chainService,
AttestationsPool: b.attestationPool,
ExitPool: b.exitPool,
@@ -984,12 +970,3 @@ func (b *BeaconNode) registerValidatorMonitorService() error {
}
return b.services.RegisterService(svc)
}
func (b *BeaconNode) registerBuilderService() error {
options := b.serviceFlagOpts.builderOpts
svc, err := builder.NewService(b.ctx, options...)
if err != nil {
return err
}
return b.services.RegisterService(svc)
}

View File

@@ -210,7 +210,7 @@ func (s *Service) retrieveHeaderInfo(ctx context.Context, bNum uint64) (*types.H
return nil, err
}
if blk == nil {
return nil, errors.New("header with the provided number does not exist")
return nil, errors.Errorf("header with the number %d does not exist", bNum)
}
if err := s.headerCache.AddHeader(blk); err != nil {
return nil, err

View File

@@ -369,12 +369,17 @@ func (s *Service) ETH1ConnectionErrors() []error {
// refers to the latest eth1 block which follows the condition: eth1_timestamp +
// SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time
func (s *Service) followedBlockHeight(_ context.Context) (uint64, error) {
latestValidBlock := uint64(0)
if s.latestEth1Data.BlockHeight > params.BeaconConfig().Eth1FollowDistance {
latestValidBlock = s.latestEth1Data.BlockHeight - params.BeaconConfig().Eth1FollowDistance
func (s *Service) followedBlockHeight(ctx context.Context) (uint64, error) {
followTime := params.BeaconConfig().Eth1FollowDistance * params.BeaconConfig().SecondsPerETH1Block
latestBlockTime := uint64(0)
if s.latestEth1Data.BlockTime > followTime {
latestBlockTime = s.latestEth1Data.BlockTime - followTime
}
return latestValidBlock, nil
blk, err := s.BlockByTimestamp(ctx, latestBlockTime)
if err != nil {
return 0, err
}
return blk.Number.Uint64(), nil
}
func (s *Service) initDepositCaches(ctx context.Context, ctrs []*ethpb.DepositContainer) error {

View File

@@ -81,7 +81,8 @@ func (g *goodNotifier) StateFeed() *event.Feed {
}
type goodFetcher struct {
backend *backends.SimulatedBackend
backend *backends.SimulatedBackend
blockNumMap map[uint64]*gethTypes.Header
}
func (_ *goodFetcher) Close() {}
@@ -104,12 +105,15 @@ func (g *goodFetcher) HeaderByHash(_ context.Context, hash common.Hash) (*gethTy
}
func (g *goodFetcher) HeaderByNumber(_ context.Context, number *big.Int) (*gethTypes.Header, error) {
if g.backend == nil {
if g.backend == nil && g.blockNumMap == nil {
return &gethTypes.Header{
Number: big.NewInt(15),
Time: 150,
}, nil
}
if g.blockNumMap != nil {
return g.blockNumMap[number.Uint64()], nil
}
var header *gethTypes.Header
if number == nil {
header = g.backend.Blockchain().CurrentHeader()
@@ -864,6 +868,28 @@ func TestService_CacheBlockHeaders(t *testing.T) {
assert.Equal(t, 5, rClient.numOfCalls)
}
func TestService_FollowBlock(t *testing.T) {
followTime := params.BeaconConfig().Eth1FollowDistance * params.BeaconConfig().SecondsPerETH1Block
followTime += 10000
bMap := make(map[uint64]*gethTypes.Header)
for i := uint64(3000); i > 0; i-- {
bMap[i] = &gethTypes.Header{
Number: big.NewInt(int64(i)),
Time: followTime + (i * 40),
}
}
s := &Service{
cfg: &config{eth1HeaderReqLimit: 1000},
eth1DataFetcher: &goodFetcher{blockNumMap: bMap},
headerCache: newHeaderCache(),
latestEth1Data: &ethpb.LatestETH1Data{BlockTime: (3000 * 40) + followTime, BlockHeight: 3000},
}
h, err := s.followedBlockHeight(context.Background())
assert.NoError(t, err)
// With a much higher blocktime, the follow height is respectively shortened.
assert.Equal(t, uint64(2283), h)
}
type slowRPCClient struct {
limit int
numOfCalls int

View File

@@ -10,7 +10,6 @@ go_library(
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/builder:go_default_library",
"//beacon-chain/cache:go_default_library",
"//beacon-chain/cache/depositcache:go_default_library",
"//beacon-chain/core/feed/block:go_default_library",

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"net/http"
"regexp"
"strconv"
"strings"
@@ -17,10 +18,15 @@ import (
)
const (
versionHeader = "Eth-Consensus-Version"
grpcVersionHeader = "Grpc-metadata-Eth-Consensus-Version"
versionHeader = "Eth-Consensus-Version"
grpcVersionHeader = "Grpc-metadata-Eth-Consensus-Version"
jsonMediaType = "application/json"
octetStreamMediaType = "application/octet-stream"
)
// match a number with optional decimals
var priorityRegex = regexp.MustCompile(`q=(\d+(?:\.\d+)?)`)
type sszConfig struct {
fileName string
responseJson sszResponse
@@ -99,7 +105,12 @@ func handleGetSSZ(
req *http.Request,
config sszConfig,
) (handled bool) {
if !sszRequested(req) {
ssz, err := sszRequested(req)
if err != nil {
apimiddleware.WriteError(w, apimiddleware.InternalServerError(err), nil)
return true
}
if !ssz {
return false
}
@@ -193,17 +204,42 @@ func handlePostSSZ(
return true
}
func sszRequested(req *http.Request) bool {
accept, ok := req.Header["Accept"]
if !ok {
return false
func sszRequested(req *http.Request) (bool, error) {
accept := req.Header.Values("Accept")
if len(accept) == 0 {
return false, nil
}
for _, v := range accept {
if v == "application/octet-stream" {
return true
types := strings.Split(accept[0], ",")
currentType, currentPriority := "", 0.0
for _, t := range types {
values := strings.Split(t, ";")
name := values[0]
if name != jsonMediaType && name != octetStreamMediaType {
continue
}
// no params specified
if len(values) == 1 {
priority := 1.0
if priority > currentPriority {
currentType, currentPriority = name, priority
}
continue
}
params := values[1]
match := priorityRegex.FindAllStringSubmatch(params, 1)
if len(match) != 1 {
continue
}
priority, err := strconv.ParseFloat(match[0][1], 32)
if err != nil {
return false, err
}
if priority > currentPriority {
currentType, currentPriority = name, priority
}
}
return false
return currentType == octetStreamMediaType, nil
}
func sszPosted(req *http.Request) bool {
@@ -214,7 +250,7 @@ func sszPosted(req *http.Request) bool {
if len(ct) != 1 {
return false
}
return ct[0] == "application/octet-stream"
return ct[0] == octetStreamMediaType
}
func prepareSSZRequestForProxying(m *apimiddleware.ApiProxyMiddleware, endpoint apimiddleware.Endpoint, req *http.Request) apimiddleware.ErrorJson {
@@ -252,7 +288,7 @@ func preparePostedSSZData(req *http.Request) apimiddleware.ErrorJson {
}
req.Body = io.NopCloser(bytes.NewBuffer(data))
req.ContentLength = int64(len(data))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-Type", jsonMediaType)
return nil
}
@@ -280,7 +316,7 @@ func writeSSZResponseHeaderAndBody(grpcResp *http.Response, w http.ResponseWrite
}
}
w.Header().Set("Content-Length", strconv.Itoa(len(respSsz)))
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Type", octetStreamMediaType)
w.Header().Set("Content-Disposition", "attachment; filename="+fileName)
w.Header().Set(versionHeader, respVersion)
if statusCodeHeader != "" {

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
@@ -34,28 +35,88 @@ func (t testSSZResponseJson) SSZData() string {
func TestSSZRequested(t *testing.T) {
t.Run("ssz_requested", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{"application/octet-stream"}
result := sszRequested(request)
request.Header["Accept"] = []string{octetStreamMediaType}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, true, result)
})
t.Run("multiple_content_types", func(t *testing.T) {
t.Run("ssz_content_type_first", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{"application/json", "application/octet-stream"}
result := sszRequested(request)
request.Header["Accept"] = []string{fmt.Sprintf("%s,%s", octetStreamMediaType, jsonMediaType)}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, true, result)
})
t.Run("ssz_content_type_preferred_1", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{fmt.Sprintf("%s;q=0.9,%s", jsonMediaType, octetStreamMediaType)}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, true, result)
})
t.Run("ssz_content_type_preferred_2", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{fmt.Sprintf("%s;q=0.95,%s;q=0.9", octetStreamMediaType, jsonMediaType)}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, true, result)
})
t.Run("other_content_type_preferred", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{fmt.Sprintf("%s,%s;q=0.9", jsonMediaType, octetStreamMediaType)}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("other_params", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{fmt.Sprintf("%s,%s;q=0.9,otherparam=xyz", jsonMediaType, octetStreamMediaType)}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("no_header", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
result := sszRequested(request)
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("empty_header", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("empty_header_value", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{""}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("other_content_type", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{"application/json"}
result := sszRequested(request)
request.Header["Accept"] = []string{"application/other"}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, false, result)
})
t.Run("garbage", func(t *testing.T) {
request := httptest.NewRequest("GET", "http://foo.example", nil)
request.Header["Accept"] = []string{"This is Sparta!!!"}
result, err := sszRequested(request)
require.NoError(t, err)
assert.Equal(t, false, result)
})
}
@@ -82,7 +143,7 @@ func TestPreparePostedSszData(t *testing.T) {
preparePostedSSZData(request)
assert.Equal(t, int64(19), request.ContentLength)
assert.Equal(t, "application/json", request.Header.Get("Content-Type"))
assert.Equal(t, jsonMediaType, request.Header.Get("Content-Type"))
}
func TestSerializeMiddlewareResponseIntoSSZ(t *testing.T) {
@@ -138,7 +199,7 @@ func TestWriteSSZResponseHeaderAndBody(t *testing.T) {
v, ok = writer.Header()["Content-Type"]
require.Equal(t, true, ok, "header not found")
require.Equal(t, 1, len(v), "wrong number of header values")
assert.Equal(t, "application/octet-stream", v[0])
assert.Equal(t, octetStreamMediaType, v[0])
v, ok = writer.Header()["Content-Disposition"]
require.Equal(t, true, ok, "header not found")
require.Equal(t, 1, len(v), "wrong number of header values")

View File

@@ -550,7 +550,7 @@ type indexedAttestationJson struct {
}
type feeRecipientJson struct {
ValidatorIndex uint64 `json:"validator_index"`
ValidatorIndex string `json:"validator_index"`
FeeRecipient string `json:"fee_recipient" hex:"true"`
}

View File

@@ -27,7 +27,6 @@ go_library(
deps = [
"//async/event:go_default_library",
"//beacon-chain/blockchain:go_default_library",
"//beacon-chain/builder:go_default_library",
"//beacon-chain/cache:go_default_library",
"//beacon-chain/cache/depositcache:go_default_library",
"//beacon-chain/core/altair:go_default_library",

View File

@@ -19,7 +19,6 @@ import (
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"github.com/prysmaticlabs/prysm/time/slots"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
@@ -58,7 +57,12 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
return nil, err
}
return vs.getBellatrixBeaconBlock(ctx, req)
blk, err := vs.getBellatrixBeaconBlock(ctx, req)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not fetch Bellatrix beacon block: %v", err)
}
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Bellatrix{Bellatrix: blk}}, nil
}
// GetBlock is called by a proposer during its assigned slot to request a block to sign
@@ -129,20 +133,9 @@ func (vs *Server) PrepareBeaconProposer(
return &emptypb.Empty{}, nil
}
// SubmitValidatorRegistration submits validator registration.
func (vs *Server) SubmitValidatorRegistration(context.Context, *ethpb.SignedValidatorRegistrationV1) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (vs *Server) proposeGenericBeaconBlock(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpb.ProposeResponse, error) {
ctx, span := trace.StartSpan(ctx, "ProposerServer.proposeGenericBeaconBlock")
defer span.End()
blk, err := vs.getBuilderBlock(ctx, blk)
if err != nil {
return nil, err
}
root, err := blk.Block().HashTreeRoot()
if err != nil {
return nil, fmt.Errorf("could not tree hash block: %v", err)
@@ -175,75 +168,6 @@ func (vs *Server) proposeGenericBeaconBlock(ctx context.Context, blk interfaces.
}, nil
}
func (vs *Server) getBuilderBlock(ctx context.Context, b interfaces.SignedBeaconBlock) (interfaces.SignedBeaconBlock, error) {
if b.Version() != version.BellatrixBlind {
return b, nil
}
if vs.BlockBuilder.Status() != nil {
return nil, status.Errorf(codes.FailedPrecondition, "Block builder is not running")
}
agg, err := b.Block().Body().SyncAggregate()
if err != nil {
return nil, err
}
h, err := b.Block().Body().ExecutionPayloadHeader()
if err != nil {
return nil, err
}
sb := &ethpb.SignedBlindedBeaconBlockBellatrix{
Block: &ethpb.BlindedBeaconBlockBellatrix{
Slot: b.Block().Slot(),
ProposerIndex: b.Block().ProposerIndex(),
ParentRoot: b.Block().ParentRoot(),
StateRoot: b.Block().StateRoot(),
Body: &ethpb.BlindedBeaconBlockBodyBellatrix{
RandaoReveal: b.Block().Body().RandaoReveal(),
Eth1Data: b.Block().Body().Eth1Data(),
Graffiti: b.Block().Body().Graffiti(),
ProposerSlashings: b.Block().Body().ProposerSlashings(),
AttesterSlashings: b.Block().Body().AttesterSlashings(),
Attestations: b.Block().Body().Attestations(),
Deposits: b.Block().Body().Deposits(),
VoluntaryExits: b.Block().Body().VoluntaryExits(),
SyncAggregate: agg,
ExecutionPayloadHeader: h,
},
},
Signature: nil,
}
payload, err := vs.BlockBuilder.SubmitBlindedBlock(ctx, sb)
if err != nil {
return nil, err
}
bb := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{
Slot: sb.Block.Slot,
ProposerIndex: sb.Block.ProposerIndex,
ParentRoot: sb.Block.ParentRoot,
StateRoot: sb.Block.StateRoot,
Body: &ethpb.BeaconBlockBodyBellatrix{
RandaoReveal: sb.Block.Body.RandaoReveal,
Eth1Data: sb.Block.Body.Eth1Data,
Graffiti: sb.Block.Body.Graffiti,
ProposerSlashings: sb.Block.Body.ProposerSlashings,
AttesterSlashings: sb.Block.Body.AttesterSlashings,
Attestations: sb.Block.Body.Attestations,
Deposits: sb.Block.Body.Deposits,
VoluntaryExits: sb.Block.Body.VoluntaryExits,
SyncAggregate: agg,
ExecutionPayload: payload,
},
},
Signature: nil,
}
wb, err := wrapper.WrappedSignedBeaconBlock(bb)
if err != nil {
return nil, err
}
return wb, nil
}
// computeStateRoot computes the state root after a block has been processed through a state transition and
// returns it to the validator client.
func (vs *Server) computeStateRoot(ctx context.Context, block interfaces.SignedBeaconBlock) ([]byte, error) {

View File

@@ -4,59 +4,18 @@ import (
"context"
"fmt"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition/interop"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockBellatrix, error) {
altairBlk, err := vs.buildAltairBeaconBlock(ctx, req)
if err != nil {
return nil, err
}
h, exists, err := vs.getBuilderHeader(ctx, req.Slot, altairBlk.ProposerIndex)
if err != nil {
return nil, err
}
if exists {
blk := &ethpb.BlindedBeaconBlockBellatrix{
Slot: altairBlk.Slot,
ProposerIndex: altairBlk.ProposerIndex,
ParentRoot: altairBlk.ParentRoot,
StateRoot: params.BeaconConfig().ZeroHash[:],
Body: &ethpb.BlindedBeaconBlockBodyBellatrix{
RandaoReveal: altairBlk.Body.RandaoReveal,
Eth1Data: altairBlk.Body.Eth1Data,
Graffiti: altairBlk.Body.Graffiti,
ProposerSlashings: altairBlk.Body.ProposerSlashings,
AttesterSlashings: altairBlk.Body.AttesterSlashings,
Attestations: altairBlk.Body.Attestations,
Deposits: altairBlk.Body.Deposits,
VoluntaryExits: altairBlk.Body.VoluntaryExits,
SyncAggregate: altairBlk.Body.SyncAggregate,
ExecutionPayloadHeader: h,
},
}
wsb, err := wrapper.WrappedSignedBeaconBlock(
&ethpb.SignedBlindedBeaconBlockBellatrix{Block: blk, Signature: make([]byte, 96)},
)
if err != nil {
return nil, err
}
stateRoot, err := vs.computeStateRoot(ctx, wsb)
if err != nil {
interop.WriteBlockToDisk(wsb, true /*failed*/)
return nil, fmt.Errorf("could not compute state root: %v", err)
}
blk.StateRoot = stateRoot
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_BlindedBellatrix{BlindedBellatrix: blk}}, nil
}
payload, err := vs.getExecutionPayload(ctx, req.Slot, altairBlk.ProposerIndex)
if err != nil {
return nil, err
@@ -93,33 +52,5 @@ func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockR
return nil, fmt.Errorf("could not compute state root: %v", err)
}
blk.StateRoot = stateRoot
return &ethpb.GenericBeaconBlock{Block: &ethpb.GenericBeaconBlock_Bellatrix{Bellatrix: blk}}, nil
}
func (vs *Server) getBuilderHeader(ctx context.Context, slot types.Slot, idx types.ValidatorIndex) (*ethpb.ExecutionPayloadHeader, bool, error) {
if vs.BlockBuilder.Status() != nil {
log.WithError(vs.BlockBuilder.Status()).Error("Could not get builder status")
return nil, false, nil
}
b, err := vs.HeadFetcher.HeadBlock(ctx)
if err != nil {
return nil, false, err
}
if blocks.IsPreBellatrixVersion(b.Version()) {
return nil, false, nil
}
h, err := b.Block().Body().ExecutionPayload()
if err != nil {
return nil, false, err
}
pk, err := vs.HeadFetcher.HeadValidatorIndexToPublicKey(ctx, idx)
if err != nil {
return nil, false, err
}
bid, err := vs.BlockBuilder.GetHeader(ctx, slot, bytesutil.ToBytes32(h.BlockHash), pk)
if err != nil {
log.WithError(err).Error("Could not get builder header")
return nil, false, nil
}
return bid.Message.Header, true, nil
return blk, nil
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/builder"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
@@ -70,7 +69,6 @@ type Server struct {
ReplayerBuilder stategen.ReplayerBuilder
BeaconDB db.HeadAccessDatabase
ExecutionEngineCaller powchain.EngineCaller
BlockBuilder builder.BlockBuilder
}
// WaitForActivation checks if a validator public key exists in the active validator registry of the current

View File

@@ -113,7 +113,7 @@ func (vs *Server) CheckDoppelGanger(ctx context.Context, req *ethpb.DoppelGanger
// Return early if we are in phase0.
if headState.Version() == version.Phase0 {
log.Info("Skipping goppelganger check for Phase 0")
log.Info("Skipping doppelganger check for Phase 0")
resp := &ethpb.DoppelGangerResponse{
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},

View File

@@ -14,7 +14,6 @@ import (
grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/beacon-chain/builder"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
@@ -91,7 +90,6 @@ type Config struct {
POWChainInfoFetcher powchain.ChainInfoFetcher
GenesisTimeFetcher blockchain.TimeFetcher
GenesisFetcher blockchain.GenesisFetcher
BlockBuilder builder.BlockBuilder
EnableDebugRPCEndpoints bool
MockEth1Votes bool
AttestationsPool attestations.Pool
@@ -218,7 +216,6 @@ func (s *Service) Start() {
ExecutionEngineCaller: s.cfg.ExecutionEngineCaller,
BeaconDB: s.cfg.BeaconDB,
ProposerSlotIndexCache: s.cfg.ProposerIdsCache,
BlockBuilder: s.cfg.BlockBuilder,
}
validatorServerV1 := &validator.Server{
HeadFetcher: s.cfg.HeadFetcher,

View File

@@ -32,7 +32,7 @@ func RopstenConfig() *BeaconChainConfig {
cfg.AltairForkVersion = []byte{0x80, 0x00, 0x00, 0x70}
cfg.BellatrixForkEpoch = 750
cfg.BellatrixForkVersion = []byte{0x80, 0x00, 0x00, 0x71}
cfg.TerminalTotalDifficulty = "100000000000000000000000"
cfg.TerminalTotalDifficulty = "50000000000000000"
cfg.DepositContractAddress = "0x6f22fFbC56eFF051aECF839396DD1eD9aD6BBA9D"
cfg.InitializeForkSchedule()
return cfg

View File

@@ -108,6 +108,7 @@ ssz_gen_marshal(
"BlindedBeaconBlockBellatrix",
"BlindedBeaconBlockBodyBellatrix",
"SignedValidatorRegistrationV1",
"ValidatorRegistrationV1",
],
)

View File

@@ -1,89 +0,0 @@
package client
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/config/params"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/time/slots"
"go.opencensus.io/trace"
"google.golang.org/protobuf/types/known/emptypb"
)
// SubmitBuilderValidatorRegistration submits builder validator registration
func SubmitBuilderValidatorRegistration(
ctx context.Context,
validatorClient ethpb.BeaconNodeValidatorClient,
nodeClient ethpb.NodeClient,
signer signingFunc,
reg *ethpb.ValidatorRegistrationV1,
) error {
ctx, span := trace.StartSpan(ctx, "validator.ProposeBuilderValidatorRegistration")
defer span.End()
genesisResponse, err := nodeClient.GetGenesis(ctx, &emptypb.Empty{})
if err != nil {
return errors.Wrap(err, "gRPC call to get genesis time failed")
}
ts := time.Unix(int64(reg.Timestamp), 0)
secs := int64(ts.Second()) - genesisResponse.GenesisTime.Seconds
currentSlot := types.Slot(uint64(secs) / params.BeaconConfig().SecondsPerSlot)
sig, err := signBuilderValidatorRegistration(ctx, currentSlot, validatorClient, signer, reg)
if err != nil {
return errors.Wrap(err, "failed to sign builder validator registration obj")
}
signedReg := &ethpb.SignedValidatorRegistrationV1{
Message: reg,
Signature: sig,
}
if _, err := validatorClient.SubmitValidatorRegistration(ctx, signedReg); err != nil {
return errors.Wrap(err, "could not submit signed registration to beacon node")
}
return nil
}
// Sings validator registration obj with proposer domain and private key.
func signBuilderValidatorRegistration(
ctx context.Context,
slot types.Slot,
validatorClient ethpb.BeaconNodeValidatorClient,
signer signingFunc,
reg *ethpb.ValidatorRegistrationV1,
) ([]byte, error) {
req := &ethpb.DomainRequest{
Epoch: slots.ToEpoch(slot),
Domain: []byte{},
}
domain, err := validatorClient.DomainData(ctx, req)
if err != nil {
return nil, errors.Wrap(err, domainDataErr)
}
if domain == nil {
return nil, errors.New(domainDataErr)
}
exitRoot, err := signing.ComputeSigningRoot(reg, domain.SignatureDomain)
if err != nil {
return nil, errors.Wrap(err, signingRootErr)
}
sig, err := signer(ctx, &validatorpb.SignRequest{
PublicKey: reg.Pubkey,
SigningRoot: exitRoot[:],
SignatureDomain: domain.SignatureDomain,
Object: &validatorpb.SignRequest_Registration{Registration: reg},
})
if err != nil {
return nil, errors.Wrap(err, signExitErr)
}
return sig.Marshal(), nil
}