mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
Compare commits
55 Commits
only-save-
...
execution-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a688811847 | ||
|
|
7c30533870 | ||
|
|
203a5b4a00 | ||
|
|
7654ffdcfc | ||
|
|
9ecf9c8b7e | ||
|
|
d6031ac386 | ||
|
|
bdb15c885d | ||
|
|
64c64f6ea7 | ||
|
|
5b003198a4 | ||
|
|
10170f1c30 | ||
|
|
d53f4295c9 | ||
|
|
2d99d58953 | ||
|
|
f7d3b5c510 | ||
|
|
337e5874b7 | ||
|
|
1eb10a076e | ||
|
|
c0f3946f58 | ||
|
|
901c11d7bb | ||
|
|
8f7a847944 | ||
|
|
8871525b66 | ||
|
|
e6f98c88fa | ||
|
|
8a060a78a3 | ||
|
|
2aebb0ce68 | ||
|
|
e7718be56f | ||
|
|
d79d4f7e69 | ||
|
|
73cbcf9599 | ||
|
|
c33acde64e | ||
|
|
8310d22a05 | ||
|
|
1bbaf0dd6b | ||
|
|
3060096233 | ||
|
|
6ec975c56d | ||
|
|
6df8a3648b | ||
|
|
5d06c14cec | ||
|
|
adc28dc30a | ||
|
|
3f230b8c9e | ||
|
|
c52462c6e9 | ||
|
|
57abf02e34 | ||
|
|
214b3bd46f | ||
|
|
e63de86fcd | ||
|
|
181c7932be | ||
|
|
c3ef0aad6e | ||
|
|
d723646e41 | ||
|
|
38747afd9b | ||
|
|
04a54a0435 | ||
|
|
44218a9c5b | ||
|
|
98f055ac75 | ||
|
|
30159fd4b7 | ||
|
|
d53f2c7661 | ||
|
|
5e53d6976e | ||
|
|
7fd2c08be3 | ||
|
|
6695e7c756 | ||
|
|
aeede2165d | ||
|
|
67a15183ca | ||
|
|
208dc80702 | ||
|
|
e80806d455 | ||
|
|
80d0a82f9b |
@@ -342,9 +342,9 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "4797a7e594a5b1f4c1c8080701613f3ee451b01ec0861499ea7d9b60877a6b23",
|
||||
sha256 = "98013b40922e54a64996da49b939e0a88fe2456f68eedc5aee4ceba0f8623f71",
|
||||
urls = [
|
||||
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v1.0.3/prysm-web-ui.tar.gz",
|
||||
"https://github.com/prysmaticlabs/prysm-web-ui/releases/download/v2.0.0/prysm-web-ui.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ go_library(
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//monitoring/tracing:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
@@ -20,7 +19,6 @@ go_library(
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
"@org_golang_x_sync//errgroup:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -13,15 +13,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
mathprysm "github.com/prysmaticlabs/prysm/math"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/monitoring/tracing"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,8 +31,6 @@ const (
|
||||
var errMalformedHostname = errors.New("hostname must include port, separated by one colon, like example.com:3500")
|
||||
var errMalformedRequest = errors.New("required request data are missing")
|
||||
|
||||
const registerValidatorBatchLimit = 100
|
||||
|
||||
// ClientOpt is a functional option for the Client type (http.Client wrapper)
|
||||
type ClientOpt func(*Client)
|
||||
|
||||
@@ -165,7 +160,9 @@ func (c *Client) do(ctx context.Context, method string, path string, body io.Rea
|
||||
}
|
||||
defer func() {
|
||||
closeErr := r.Body.Close()
|
||||
log.WithError(closeErr).Error("Failed to close response body")
|
||||
if closeErr != nil {
|
||||
log.WithError(closeErr).Error("Failed to close response body")
|
||||
}
|
||||
}()
|
||||
if r.StatusCode != http.StatusOK {
|
||||
err = non200Err(r)
|
||||
@@ -221,36 +218,26 @@ func (c *Client) GetHeader(ctx context.Context, slot types.Slot, parentHash [32]
|
||||
func (c *Client) RegisterValidator(ctx context.Context, svr []*ethpb.SignedValidatorRegistrationV1) error {
|
||||
ctx, span := trace.StartSpan(ctx, "builder.client.RegisterValidator")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("num_reqs", int64(len(svr))))
|
||||
|
||||
if len(svr) == 0 {
|
||||
err := errors.Wrap(errMalformedRequest, "empty validator registration list")
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
for i := 0; i < len(svr); i += registerValidatorBatchLimit {
|
||||
end := int(mathprysm.Min(uint64(len(svr)), uint64(i+registerValidatorBatchLimit))) // lint:ignore uintcast -- Request will never exceed int.
|
||||
vs := make([]*SignedValidatorRegistration, 0, registerValidatorBatchLimit)
|
||||
for j := i; j < end; j++ {
|
||||
vs = append(vs, &SignedValidatorRegistration{SignedValidatorRegistrationV1: svr[j]})
|
||||
}
|
||||
body, err := json.Marshal(vs)
|
||||
if err != nil {
|
||||
err := errors.Wrap(err, "error encoding the SignedValidatorRegistration value body in RegisterValidator")
|
||||
tracing.AnnotateError(span, err)
|
||||
}
|
||||
|
||||
eg.Go(func() error {
|
||||
ctx, span := trace.StartSpan(ctx, "builder.client.RegisterValidator.Go")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.Int64Attribute("reqs", int64(len(vs))))
|
||||
|
||||
_, err = c.do(ctx, http.MethodPost, postRegisterValidatorPath, bytes.NewBuffer(body))
|
||||
return err
|
||||
})
|
||||
vs := make([]*SignedValidatorRegistration, len(svr))
|
||||
for i := 0; i < len(svr); i++ {
|
||||
vs[i] = &SignedValidatorRegistration{SignedValidatorRegistrationV1: svr[i]}
|
||||
}
|
||||
body, err := json.Marshal(vs)
|
||||
if err != nil {
|
||||
err := errors.Wrap(err, "error encoding the SignedValidatorRegistration value body in RegisterValidator")
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return eg.Wait()
|
||||
_, err = c.do(ctx, http.MethodPost, postRegisterValidatorPath, bytes.NewBuffer(body))
|
||||
return err
|
||||
}
|
||||
|
||||
// SubmitBlindedBlock calls the builder API endpoint that binds the validator to the builder and submits the block.
|
||||
|
||||
@@ -3,7 +3,6 @@ package builder
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -109,52 +108,6 @@ func TestClient_RegisterValidator(t *testing.T) {
|
||||
require.NoError(t, c.RegisterValidator(ctx, []*eth.SignedValidatorRegistrationV1{reg}))
|
||||
}
|
||||
|
||||
func TestClient_RegisterValidator_Over100Requests(t *testing.T) {
|
||||
reqs := make([]*eth.SignedValidatorRegistrationV1, 301)
|
||||
for i := 0; i < len(reqs); i++ {
|
||||
reqs[i] = ð.SignedValidatorRegistrationV1{
|
||||
Message: ð.ValidatorRegistrationV1{
|
||||
FeeRecipient: ezDecode(t, params.BeaconConfig().EthBurnAddressHex),
|
||||
GasLimit: 23,
|
||||
Timestamp: 42,
|
||||
Pubkey: []byte(fmt.Sprint(i)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
var total int
|
||||
|
||||
ctx := context.Background()
|
||||
hc := &http.Client{
|
||||
Transport: roundtrip(func(r *http.Request) (*http.Response, error) {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, r.Body.Close())
|
||||
require.NoError(t, err)
|
||||
|
||||
recvd := make([]*SignedValidatorRegistration, 0)
|
||||
require.NoError(t, json.Unmarshal(body, &recvd))
|
||||
if len(recvd) > registerValidatorBatchLimit {
|
||||
t.Errorf("Number of requests (%d) exceeds limit (%d)", len(recvd), registerValidatorBatchLimit)
|
||||
}
|
||||
total += len(recvd)
|
||||
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewBuffer(nil)),
|
||||
Request: r.Clone(ctx),
|
||||
}, nil
|
||||
}),
|
||||
}
|
||||
c := &Client{
|
||||
hc: hc,
|
||||
baseURL: &url.URL{Host: "localhost:3500", Scheme: "http"},
|
||||
}
|
||||
|
||||
require.NoError(t, c.RegisterValidator(ctx, reqs))
|
||||
require.Equal(t, len(reqs), total)
|
||||
}
|
||||
|
||||
func TestClient_GetHeader(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
expectedPath := "/eth/v1/builder/header/23/0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2/0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a"
|
||||
|
||||
@@ -3,6 +3,7 @@ package async_test
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -16,7 +17,7 @@ func TestDebounce_NoEvents(t *testing.T) {
|
||||
eventsChan := make(chan interface{}, 100)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
interval := time.Second
|
||||
timesHandled := 0
|
||||
timesHandled := int32(0)
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
@@ -26,21 +27,21 @@ func TestDebounce_NoEvents(t *testing.T) {
|
||||
}()
|
||||
go func() {
|
||||
async.Debounce(ctx, interval, eventsChan, func(event interface{}) {
|
||||
timesHandled++
|
||||
atomic.AddInt32(×Handled, 1)
|
||||
})
|
||||
wg.Done()
|
||||
}()
|
||||
if util.WaitTimeout(wg, interval*2) {
|
||||
t.Fatalf("Test should have exited by now, timed out")
|
||||
}
|
||||
assert.Equal(t, 0, timesHandled, "Wrong number of handled calls")
|
||||
assert.Equal(t, int32(0), atomic.LoadInt32(×Handled), "Wrong number of handled calls")
|
||||
}
|
||||
|
||||
func TestDebounce_CtxClosing(t *testing.T) {
|
||||
eventsChan := make(chan interface{}, 100)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
interval := time.Second
|
||||
timesHandled := 0
|
||||
timesHandled := int32(0)
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
@@ -62,23 +63,23 @@ func TestDebounce_CtxClosing(t *testing.T) {
|
||||
}()
|
||||
go func() {
|
||||
async.Debounce(ctx, interval, eventsChan, func(event interface{}) {
|
||||
timesHandled++
|
||||
atomic.AddInt32(×Handled, 1)
|
||||
})
|
||||
wg.Done()
|
||||
}()
|
||||
if util.WaitTimeout(wg, interval*2) {
|
||||
t.Fatalf("Test should have exited by now, timed out")
|
||||
}
|
||||
assert.Equal(t, 0, timesHandled, "Wrong number of handled calls")
|
||||
assert.Equal(t, int32(0), atomic.LoadInt32(×Handled), "Wrong number of handled calls")
|
||||
}
|
||||
|
||||
func TestDebounce_SingleHandlerInvocation(t *testing.T) {
|
||||
eventsChan := make(chan interface{}, 100)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
interval := time.Second
|
||||
timesHandled := 0
|
||||
timesHandled := int32(0)
|
||||
go async.Debounce(ctx, interval, eventsChan, func(event interface{}) {
|
||||
timesHandled++
|
||||
atomic.AddInt32(×Handled, 1)
|
||||
})
|
||||
for i := 0; i < 100; i++ {
|
||||
eventsChan <- struct{}{}
|
||||
@@ -86,7 +87,7 @@ func TestDebounce_SingleHandlerInvocation(t *testing.T) {
|
||||
// We should expect 100 rapid fire changes to only have caused
|
||||
// 1 handler to trigger after the debouncing period.
|
||||
time.Sleep(interval * 2)
|
||||
assert.Equal(t, 1, timesHandled, "Wrong number of handled calls")
|
||||
assert.Equal(t, int32(1), atomic.LoadInt32(×Handled), "Wrong number of handled calls")
|
||||
cancel()
|
||||
}
|
||||
|
||||
@@ -94,23 +95,23 @@ func TestDebounce_MultipleHandlerInvocation(t *testing.T) {
|
||||
eventsChan := make(chan interface{}, 100)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
interval := time.Second
|
||||
timesHandled := 0
|
||||
timesHandled := int32(0)
|
||||
go async.Debounce(ctx, interval, eventsChan, func(event interface{}) {
|
||||
timesHandled++
|
||||
atomic.AddInt32(×Handled, 1)
|
||||
})
|
||||
for i := 0; i < 100; i++ {
|
||||
eventsChan <- struct{}{}
|
||||
}
|
||||
require.Equal(t, 0, timesHandled, "Events must prevent from handler execution")
|
||||
require.Equal(t, int32(0), atomic.LoadInt32(×Handled), "Events must prevent from handler execution")
|
||||
|
||||
// By this time the first event should be triggered.
|
||||
time.Sleep(2 * time.Second)
|
||||
assert.Equal(t, 1, timesHandled, "Wrong number of handled calls")
|
||||
assert.Equal(t, int32(1), atomic.LoadInt32(×Handled), "Wrong number of handled calls")
|
||||
|
||||
// Second event.
|
||||
eventsChan <- struct{}{}
|
||||
time.Sleep(2 * time.Second)
|
||||
assert.Equal(t, 2, timesHandled, "Wrong number of handled calls")
|
||||
assert.Equal(t, int32(2), atomic.LoadInt32(×Handled), "Wrong number of handled calls")
|
||||
|
||||
cancel()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package async_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -11,15 +12,15 @@ import (
|
||||
func TestEveryRuns(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
i := 0
|
||||
i := int32(0)
|
||||
async.RunEvery(ctx, 100*time.Millisecond, func() {
|
||||
i++
|
||||
atomic.AddInt32(&i, 1)
|
||||
})
|
||||
|
||||
// Sleep for a bit and ensure the value has increased.
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
if i == 0 {
|
||||
if atomic.LoadInt32(&i) == 0 {
|
||||
t.Error("Counter failed to increment with ticker")
|
||||
}
|
||||
|
||||
@@ -28,12 +29,12 @@ func TestEveryRuns(t *testing.T) {
|
||||
// Sleep for a bit to let the cancel take place.
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
last := i
|
||||
last := atomic.LoadInt32(&i)
|
||||
|
||||
// Sleep for a bit and ensure the value has not increased.
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
if i != last {
|
||||
if atomic.LoadInt32(&i) != last {
|
||||
t.Error("Counter incremented after stop")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ go_library(
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/forks/bellatrix:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/wrapper:go_default_library",
|
||||
|
||||
@@ -4,9 +4,9 @@ import "github.com/pkg/errors"
|
||||
|
||||
var (
|
||||
// ErrInvalidPayload is returned when the payload is invalid
|
||||
ErrInvalidPayload = errors.New("received an INVALID payload from execution engine")
|
||||
ErrInvalidPayload = invalidBlock{error: errors.New("received an INVALID payload from execution engine")}
|
||||
// ErrInvalidBlockHashPayloadStatus is returned when the payload has invalid block hash.
|
||||
ErrInvalidBlockHashPayloadStatus = errors.New("received an INVALID_BLOCK_HASH payload from execution engine")
|
||||
ErrInvalidBlockHashPayloadStatus = invalidBlock{error: errors.New("received an INVALID_BLOCK_HASH payload from execution engine")}
|
||||
// ErrUndefinedExecutionEngineError is returned when the execution engine returns an error that is not defined
|
||||
ErrUndefinedExecutionEngineError = errors.New("received an undefined ee error")
|
||||
// errNilFinalizedInStore is returned when a nil finalized checkpt is returned from store.
|
||||
@@ -30,7 +30,7 @@ var (
|
||||
// errWSBlockNotFoundInEpoch is returned when a block is not found in the WS cache or DB within epoch.
|
||||
errWSBlockNotFoundInEpoch = errors.New("weak subjectivity root not found in db within epoch")
|
||||
// errNotDescendantOfFinalized is returned when a block is not a descendant of the finalized checkpoint
|
||||
errNotDescendantOfFinalized = invalidBlock{errors.New("not descendant of finalized checkpoint")}
|
||||
errNotDescendantOfFinalized = invalidBlock{error: errors.New("not descendant of finalized checkpoint")}
|
||||
)
|
||||
|
||||
// An invalid block is the block that fails state transition based on the core protocol rules.
|
||||
@@ -41,16 +41,17 @@ var (
|
||||
// The block violates certain fork choice rules (before finalized slot, not finalized ancestor)
|
||||
type invalidBlock struct {
|
||||
error
|
||||
root [32]byte
|
||||
}
|
||||
|
||||
type invalidBlockError interface {
|
||||
Error() string
|
||||
InvalidBlock() bool
|
||||
BlockRoot() [32]byte
|
||||
}
|
||||
|
||||
// InvalidBlock returns true for `invalidBlock`.
|
||||
func (e invalidBlock) InvalidBlock() bool {
|
||||
return true
|
||||
// BlockRoot returns the invalid block root.
|
||||
func (e invalidBlock) BlockRoot() [32]byte {
|
||||
return e.root
|
||||
}
|
||||
|
||||
// IsInvalidBlock returns true if the error has `invalidBlock`.
|
||||
@@ -58,9 +59,22 @@ func IsInvalidBlock(e error) bool {
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
d, ok := e.(invalidBlockError)
|
||||
_, ok := e.(invalidBlockError)
|
||||
if !ok {
|
||||
return IsInvalidBlock(errors.Unwrap(e))
|
||||
}
|
||||
return d.InvalidBlock()
|
||||
return true
|
||||
}
|
||||
|
||||
// InvalidBlockRoot returns the invalid block root. If the error
|
||||
// doesn't have an invalid blockroot. [32]byte{} is returned.
|
||||
func InvalidBlockRoot(e error) [32]byte {
|
||||
if e == nil {
|
||||
return [32]byte{}
|
||||
}
|
||||
d, ok := e.(invalidBlockError)
|
||||
if !ok {
|
||||
return [32]byte{}
|
||||
}
|
||||
return d.BlockRoot()
|
||||
}
|
||||
|
||||
@@ -8,10 +8,18 @@ import (
|
||||
)
|
||||
|
||||
func TestIsInvalidBlock(t *testing.T) {
|
||||
require.Equal(t, false, IsInvalidBlock(ErrInvalidPayload))
|
||||
err := invalidBlock{ErrInvalidPayload}
|
||||
require.Equal(t, true, IsInvalidBlock(ErrInvalidPayload)) // Already wrapped.
|
||||
err := invalidBlock{error: ErrInvalidPayload}
|
||||
require.Equal(t, true, IsInvalidBlock(err))
|
||||
|
||||
newErr := errors.Wrap(err, "wrap me")
|
||||
require.Equal(t, true, IsInvalidBlock(newErr))
|
||||
}
|
||||
|
||||
func TestInvalidBlockRoot(t *testing.T) {
|
||||
require.Equal(t, [32]byte{}, InvalidBlockRoot(ErrUndefinedExecutionEngineError))
|
||||
require.Equal(t, [32]byte{}, InvalidBlockRoot(ErrInvalidPayload))
|
||||
|
||||
err := invalidBlock{error: ErrInvalidPayload, root: [32]byte{'a'}}
|
||||
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(err))
|
||||
}
|
||||
|
||||
@@ -39,24 +39,27 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
|
||||
headBlk := arg.headBlock
|
||||
if headBlk == nil || headBlk.IsNil() || headBlk.Body().IsNil() {
|
||||
return nil, errors.New("nil head block")
|
||||
log.Error("Head block is nil")
|
||||
return nil, nil
|
||||
}
|
||||
// Must not call fork choice updated until the transition conditions are met on the Pow network.
|
||||
isExecutionBlk, err := blocks.IsExecutionBlock(headBlk.Body())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not determine if block is execution block")
|
||||
log.WithError(err).Error("Could not determine if head block is execution block")
|
||||
return nil, nil
|
||||
}
|
||||
if !isExecutionBlk {
|
||||
return nil, nil
|
||||
}
|
||||
headPayload, err := headBlk.Body().ExecutionPayload()
|
||||
headPayload, err := headBlk.Body().Execution()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get execution payload")
|
||||
log.WithError(err).Error("Could not get execution payload for head block")
|
||||
return nil, nil
|
||||
}
|
||||
finalizedHash := s.ForkChoicer().FinalizedPayloadBlockHash()
|
||||
justifiedHash := s.ForkChoicer().JustifiedPayloadBlockHash()
|
||||
fcs := &enginev1.ForkchoiceState{
|
||||
HeadBlockHash: headPayload.BlockHash,
|
||||
HeadBlockHash: headPayload.BlockHash(),
|
||||
SafeBlockHash: justifiedHash[:],
|
||||
FinalizedBlockHash: finalizedHash[:],
|
||||
}
|
||||
@@ -64,7 +67,8 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
nextSlot := s.CurrentSlot() + 1 // Cache payload ID for next slot proposer.
|
||||
hasAttr, attr, proposerId, err := s.getPayloadAttribute(ctx, arg.headState, nextSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get payload attribute")
|
||||
log.WithError(err).Error("Could not get head payload attribute")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, attr)
|
||||
@@ -74,32 +78,41 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
forkchoiceUpdatedOptimisticNodeCount.Inc()
|
||||
log.WithFields(logrus.Fields{
|
||||
"headSlot": headBlk.Slot(),
|
||||
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash)),
|
||||
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash())),
|
||||
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash[:])),
|
||||
}).Info("Called fork choice updated with optimistic block")
|
||||
return payloadID, s.optimisticCandidateBlock(ctx, headBlk)
|
||||
err := s.optimisticCandidateBlock(ctx, headBlk)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Optimistic block failed to be candidate")
|
||||
}
|
||||
return payloadID, nil
|
||||
case powchain.ErrInvalidPayloadStatus:
|
||||
newPayloadInvalidNodeCount.Inc()
|
||||
headRoot := arg.headRoot
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, headRoot, bytesutil.ToBytes32(headBlk.ParentRoot()), bytesutil.ToBytes32(lastValidHash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
log.WithError(err).Error("Could not set head root to invalid")
|
||||
return nil, nil
|
||||
}
|
||||
if err := s.removeInvalidBlockAndState(ctx, invalidRoots); err != nil {
|
||||
return nil, err
|
||||
log.WithError(err).Error("Could not remove invalid block and state")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
r, err := s.cfg.ForkChoiceStore.Head(ctx, s.justifiedBalances.balances)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
log.WithError(err).Error("Could not get head root")
|
||||
return nil, nil
|
||||
}
|
||||
b, err := s.getBlock(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
log.WithError(err).Error("Could not get head block")
|
||||
return nil, nil
|
||||
}
|
||||
st, err := s.cfg.StateGen.StateByRoot(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
log.WithError(err).Error("Could not get head state")
|
||||
return nil, nil
|
||||
}
|
||||
pid, err := s.notifyForkchoiceUpdate(ctx, ¬ifyForkchoiceUpdateArg{
|
||||
headState: st,
|
||||
@@ -107,7 +120,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
headBlock: b.Block(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, err // Returning err because it's recursive here.
|
||||
}
|
||||
|
||||
if err := s.saveHead(ctx, r, b, st); err != nil {
|
||||
@@ -120,17 +133,19 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
"invalidCount": len(invalidRoots),
|
||||
"newHeadRoot": fmt.Sprintf("%#x", bytesutil.Trunc(r[:])),
|
||||
}).Warn("Pruned invalid blocks")
|
||||
return pid, ErrInvalidPayload
|
||||
return pid, invalidBlock{error: ErrInvalidPayload, root: arg.headRoot}
|
||||
|
||||
default:
|
||||
return nil, errors.WithMessage(ErrUndefinedExecutionEngineError, err.Error())
|
||||
log.WithError(err).Error(ErrUndefinedExecutionEngineError)
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
forkchoiceUpdatedValidNodeCount.Inc()
|
||||
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, arg.headRoot); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set block to valid")
|
||||
log.WithError(err).Error("Could not set head root to valid")
|
||||
return nil, nil
|
||||
}
|
||||
if hasAttr { // If the forkchoice update call has an attribute, update the proposer payload ID cache.
|
||||
if hasAttr && payloadID != nil { // If the forkchoice update call has an attribute, update the proposer payload ID cache.
|
||||
var pId [8]byte
|
||||
copy(pId[:], payloadID[:])
|
||||
s.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(nextSlot, proposerId, pId)
|
||||
@@ -148,11 +163,11 @@ func (s *Service) getPayloadHash(ctx context.Context, root []byte) ([32]byte, er
|
||||
if blocks.IsPreBellatrixVersion(blk.Block().Version()) {
|
||||
return params.BeaconConfig().ZeroHash, nil
|
||||
}
|
||||
payload, err := blk.Block().Body().ExecutionPayload()
|
||||
payload, err := blk.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not get execution payload")
|
||||
}
|
||||
return bytesutil.ToBytes32(payload.BlockHash), nil
|
||||
return bytesutil.ToBytes32(payload.BlockHash()), nil
|
||||
}
|
||||
|
||||
// notifyForkchoiceUpdate signals execution engine on a new payload.
|
||||
@@ -173,14 +188,14 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
body := blk.Block().Body()
|
||||
enabled, err := blocks.IsExecutionEnabledUsingHeader(postStateHeader, body)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(invalidBlock{err}, "could not determine if execution is enabled")
|
||||
return false, errors.Wrap(invalidBlock{error: err}, "could not determine if execution is enabled")
|
||||
}
|
||||
if !enabled {
|
||||
return true, nil
|
||||
}
|
||||
payload, err := body.ExecutionPayload()
|
||||
payload, err := body.Execution()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(invalidBlock{err}, "could not get execution payload")
|
||||
return false, errors.Wrap(invalidBlock{error: err}, "could not get execution payload")
|
||||
}
|
||||
lastValidHash, err := s.cfg.ExecutionEngineCaller.NewPayload(ctx, payload)
|
||||
switch err {
|
||||
@@ -191,7 +206,7 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
newPayloadOptimisticNodeCount.Inc()
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": blk.Block().Slot(),
|
||||
"payloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash)),
|
||||
"payloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash())),
|
||||
}).Info("Called new payload with optimistic block")
|
||||
return false, s.optimisticCandidateBlock(ctx, blk.Block())
|
||||
case powchain.ErrInvalidPayloadStatus:
|
||||
@@ -212,10 +227,10 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
"blockRoot": fmt.Sprintf("%#x", root),
|
||||
"invalidCount": len(invalidRoots),
|
||||
}).Warn("Pruned invalid blocks")
|
||||
return false, invalidBlock{ErrInvalidPayload}
|
||||
return false, ErrInvalidPayload
|
||||
case powchain.ErrInvalidBlockHashPayloadStatus:
|
||||
newPayloadInvalidNodeCount.Inc()
|
||||
return false, invalidBlock{ErrInvalidBlockHashPayloadStatus}
|
||||
return false, ErrInvalidBlockHashPayloadStatus
|
||||
default:
|
||||
return false, errors.WithMessage(ErrUndefinedExecutionEngineError, err.Error())
|
||||
}
|
||||
|
||||
@@ -75,10 +75,6 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
newForkchoiceErr error
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "nil block",
|
||||
errString: "nil head block",
|
||||
},
|
||||
{
|
||||
name: "phase0 block",
|
||||
blk: func() interfaces.BeaconBlock {
|
||||
@@ -192,6 +188,10 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
_, err = service.notifyForkchoiceUpdate(ctx, arg)
|
||||
if tt.errString != "" {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
if tt.errString == ErrInvalidPayload.Error() {
|
||||
require.Equal(t, true, IsInvalidBlock(err))
|
||||
require.Equal(t, tt.headRoot, InvalidBlockRoot(err)) // Head root should be invalid. Not block root!
|
||||
}
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@@ -330,7 +330,9 @@ func Test_NotifyForkchoiceUpdateRecursive_Protoarray(t *testing.T) {
|
||||
headRoot: brg,
|
||||
}
|
||||
_, err = service.notifyForkchoiceUpdate(ctx, a)
|
||||
require.ErrorIs(t, ErrInvalidPayload, err)
|
||||
require.Equal(t, true, IsInvalidBlock(err))
|
||||
require.Equal(t, brf, InvalidBlockRoot(err))
|
||||
|
||||
// Ensure Head is D
|
||||
headRoot, err = fcs.Head(ctx, service.justifiedBalances.balances)
|
||||
require.NoError(t, err)
|
||||
@@ -473,7 +475,9 @@ func Test_NotifyForkchoiceUpdateRecursive_DoublyLinkedTree(t *testing.T) {
|
||||
headRoot: brg,
|
||||
}
|
||||
_, err = service.notifyForkchoiceUpdate(ctx, a)
|
||||
require.ErrorIs(t, ErrInvalidPayload, err)
|
||||
require.Equal(t, true, IsInvalidBlock(err))
|
||||
require.Equal(t, brf, InvalidBlockRoot(err))
|
||||
|
||||
// Ensure Head is D
|
||||
headRoot, err = fcs.Head(ctx, service.justifiedBalances.balances)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -45,12 +45,16 @@ func logStateTransitionData(b interfaces.BeaconBlock) error {
|
||||
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
|
||||
}
|
||||
if b.Version() == version.Bellatrix {
|
||||
p, err := b.Body().ExecutionPayload()
|
||||
p, err := b.Body().Execution()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log = log.WithField("payloadHash", fmt.Sprintf("%#x", bytesutil.Trunc(p.BlockHash)))
|
||||
log = log.WithField("txCount", len(p.Transactions))
|
||||
log = log.WithField("payloadHash", fmt.Sprintf("%#x", bytesutil.Trunc(p.BlockHash())))
|
||||
txs, err := p.Transactions()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log = log.WithField("txCount", len(txs))
|
||||
}
|
||||
log.Info("Finished applying state transition")
|
||||
return nil
|
||||
@@ -98,18 +102,18 @@ func logPayload(block interfaces.BeaconBlock) error {
|
||||
if !isExecutionBlk {
|
||||
return nil
|
||||
}
|
||||
payload, err := block.Body().ExecutionPayload()
|
||||
payload, err := block.Body().Execution()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if payload.GasLimit == 0 {
|
||||
if payload.GasLimit() == 0 {
|
||||
return errors.New("gas limit should not be 0")
|
||||
}
|
||||
gasUtilized := float64(payload.GasUsed) / float64(payload.GasLimit)
|
||||
gasUtilized := float64(payload.GasUsed()) / float64(payload.GasLimit())
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"blockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash)),
|
||||
"parentHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.ParentHash)),
|
||||
"blockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash())),
|
||||
"parentHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.ParentHash())),
|
||||
"blockNumber": payload.BlockNumber,
|
||||
"gasUtilized": fmt.Sprintf("%.2f", gasUtilized),
|
||||
}).Debug("Synced new payload")
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -41,17 +40,17 @@ func (s *Service) validateMergeBlock(ctx context.Context, b interfaces.SignedBea
|
||||
if err := wrapper.BeaconBlockIsNil(b); err != nil {
|
||||
return err
|
||||
}
|
||||
payload, err := b.Block().Body().ExecutionPayload()
|
||||
payload, err := b.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if payload == nil {
|
||||
if payload.IsNil() {
|
||||
return errors.New("nil execution payload")
|
||||
}
|
||||
if err := validateTerminalBlockHash(b.Block().Slot(), payload); err != nil {
|
||||
return errors.Wrap(err, "could not validate terminal block hash")
|
||||
}
|
||||
mergeBlockParentHash, mergeBlockTD, err := s.getBlkParentHashAndTD(ctx, payload.ParentHash)
|
||||
mergeBlockParentHash, mergeBlockTD, err := s.getBlkParentHashAndTD(ctx, payload.ParentHash())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get merge block parent hash and total difficulty")
|
||||
}
|
||||
@@ -66,12 +65,12 @@ func (s *Service) validateMergeBlock(ctx context.Context, b interfaces.SignedBea
|
||||
if !valid {
|
||||
err := fmt.Errorf("invalid TTD, configTTD: %s, currentTTD: %s, parentTTD: %s",
|
||||
params.BeaconConfig().TerminalTotalDifficulty, mergeBlockTD, mergeBlockParentTD)
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": b.Block().Slot(),
|
||||
"mergeBlockHash": common.BytesToHash(payload.ParentHash).String(),
|
||||
"mergeBlockHash": common.BytesToHash(payload.ParentHash()).String(),
|
||||
"mergeBlockParentHash": common.BytesToHash(mergeBlockParentHash).String(),
|
||||
"terminalTotalDifficulty": params.BeaconConfig().TerminalTotalDifficulty,
|
||||
"mergeBlockTotalDifficulty": mergeBlockTD,
|
||||
@@ -110,14 +109,14 @@ func (s *Service) getBlkParentHashAndTD(ctx context.Context, blkHash []byte) ([]
|
||||
// assert compute_epoch_at_slot(block.slot) >= TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH
|
||||
// assert block.body.execution_payload.parent_hash == TERMINAL_BLOCK_HASH
|
||||
// return
|
||||
func validateTerminalBlockHash(blkSlot types.Slot, payload *enginev1.ExecutionPayload) error {
|
||||
func validateTerminalBlockHash(blkSlot types.Slot, payload interfaces.ExecutionData) error {
|
||||
if bytesutil.ToBytes32(params.BeaconConfig().TerminalBlockHash.Bytes()) == [32]byte{} {
|
||||
return nil
|
||||
}
|
||||
if params.BeaconConfig().TerminalBlockHashActivationEpoch > slots.ToEpoch(blkSlot) {
|
||||
return errors.New("terminal block hash activation epoch not reached")
|
||||
}
|
||||
if !bytes.Equal(payload.ParentHash, params.BeaconConfig().TerminalBlockHash.Bytes()) {
|
||||
if !bytes.Equal(payload.ParentHash(), params.BeaconConfig().TerminalBlockHash.Bytes()) {
|
||||
return errors.New("parent hash does not match terminal block hash")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -211,16 +211,22 @@ func Test_getBlkParentHashAndTD(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_validateTerminalBlockHash(t *testing.T) {
|
||||
require.NoError(t, validateTerminalBlockHash(1, &enginev1.ExecutionPayload{}))
|
||||
wrapped, err := wrapper.WrappedExecutionPayload(&enginev1.ExecutionPayload{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, validateTerminalBlockHash(1, wrapped))
|
||||
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.TerminalBlockHash = [32]byte{0x01}
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
require.ErrorContains(t, "terminal block hash activation epoch not reached", validateTerminalBlockHash(1, &enginev1.ExecutionPayload{}))
|
||||
require.ErrorContains(t, "terminal block hash activation epoch not reached", validateTerminalBlockHash(1, wrapped))
|
||||
|
||||
cfg.TerminalBlockHashActivationEpoch = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
require.ErrorContains(t, "parent hash does not match terminal block hash", validateTerminalBlockHash(1, &enginev1.ExecutionPayload{}))
|
||||
require.ErrorContains(t, "parent hash does not match terminal block hash", validateTerminalBlockHash(1, wrapped))
|
||||
|
||||
require.NoError(t, validateTerminalBlockHash(1, &enginev1.ExecutionPayload{ParentHash: cfg.TerminalBlockHash.Bytes()}))
|
||||
wrapped, err = wrapper.WrappedExecutionPayload(&enginev1.ExecutionPayload{
|
||||
ParentHash: cfg.TerminalBlockHash.Bytes(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, validateTerminalBlockHash(1, wrapped))
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/forks/bellatrix"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
@@ -97,7 +96,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.onBlock")
|
||||
defer span.End()
|
||||
if err := wrapper.BeaconBlockIsNil(signed); err != nil {
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
b := signed.Block()
|
||||
|
||||
@@ -118,7 +117,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
}
|
||||
postState, err := transition.ExecuteStateTransition(ctx, preState, signed)
|
||||
if err != nil {
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
postStateVersion, postStateHeader, err := getStateVersionAndPayload(postState)
|
||||
if err != nil {
|
||||
@@ -126,7 +125,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
}
|
||||
isValidPayload, err := s.notifyNewPayload(ctx, postStateVersion, postStateHeader, signed)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not verify new payload: %v", err)
|
||||
return errors.Wrap(err, "could not validate new payload")
|
||||
}
|
||||
if isValidPayload {
|
||||
if err := s.validateMergeTransitionBlock(ctx, preStateVersion, preStateHeader, signed); err != nil {
|
||||
@@ -184,7 +183,9 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Could not update head")
|
||||
}
|
||||
s.notifyEngineIfChangedHead(ctx, headRoot)
|
||||
if err := s.notifyEngineIfChangedHead(ctx, headRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.pruneCanonicalAttsFromPool(ctx, blockRoot, signed); err != nil {
|
||||
return err
|
||||
@@ -293,7 +294,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
}
|
||||
|
||||
if err := wrapper.BeaconBlockIsNil(blks[0]); err != nil {
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
b := blks[0].Block()
|
||||
|
||||
@@ -341,7 +342,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
|
||||
set, preState, err = transition.ExecuteStateTransitionNoVerifyAnySig(ctx, preState, b)
|
||||
if err != nil {
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
// Save potential boundary states.
|
||||
if slots.IsEpochStart(preState.Slot()) {
|
||||
@@ -362,7 +363,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []interfaces.SignedBeac
|
||||
}
|
||||
verify, err := sigSet.Verify()
|
||||
if err != nil {
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
if !verify {
|
||||
return errors.New("batch block signature verification failed")
|
||||
@@ -585,11 +586,15 @@ func (s *Service) validateMergeTransitionBlock(ctx context.Context, stateVersion
|
||||
}
|
||||
|
||||
// Skip validation if block has an empty payload.
|
||||
payload, err := blk.Block().Body().ExecutionPayload()
|
||||
payload, err := blk.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
if bellatrix.IsEmptyPayload(payload) {
|
||||
isEmpty, err := wrapper.IsEmptyExecutionData(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isEmpty {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ func (s *Service) VerifyFinalizedBlkDescendant(ctx context.Context, root [32]byt
|
||||
bytesutil.Trunc(root[:]), fSlot, bytesutil.Trunc(bFinalizedRoot),
|
||||
bytesutil.Trunc(fRoot[:]))
|
||||
tracing.AnnotateError(span, err)
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -129,7 +129,7 @@ func (s *Service) verifyBlkFinalizedSlot(b interfaces.BeaconBlock) error {
|
||||
}
|
||||
if finalizedSlot >= b.Slot() {
|
||||
err = fmt.Errorf("block is equal or earlier than finalized block, slot %d < slot %d", b.Slot(), finalizedSlot)
|
||||
return invalidBlock{err}
|
||||
return invalidBlock{error: err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1489,9 +1489,11 @@ func Test_getStateVersionAndPayload(t *testing.T) {
|
||||
name: "bellatrix state",
|
||||
st: func() state.BeaconState {
|
||||
s, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, s.SetLatestExecutionPayloadHeader(&enginev1.ExecutionPayloadHeader{
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(&enginev1.ExecutionPayloadHeader{
|
||||
BlockNumber: 1,
|
||||
}))
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
return s
|
||||
}(),
|
||||
version: version.Bellatrix,
|
||||
@@ -1543,6 +1545,7 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
|
||||
name: "state older than Bellatrix, nil payload",
|
||||
stateVersion: 1,
|
||||
payload: nil,
|
||||
errString: "attempted to wrap nil",
|
||||
},
|
||||
{
|
||||
name: "state older than Bellatrix, empty payload",
|
||||
@@ -1569,6 +1572,7 @@ func Test_validateMergeTransitionBlock(t *testing.T) {
|
||||
name: "state is Bellatrix, nil payload",
|
||||
stateVersion: 2,
|
||||
payload: nil,
|
||||
errString: "attempted to wrap nil",
|
||||
},
|
||||
{
|
||||
name: "state is Bellatrix, empty payload",
|
||||
|
||||
@@ -166,33 +166,35 @@ func (s *Service) UpdateHead(ctx context.Context) error {
|
||||
}).Debug("Head changed due to attestations")
|
||||
}
|
||||
s.headLock.RUnlock()
|
||||
s.notifyEngineIfChangedHead(ctx, newHeadRoot)
|
||||
if err := s.notifyEngineIfChangedHead(ctx, newHeadRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// This calls notify Forkchoice Update in the event that the head has changed
|
||||
func (s *Service) notifyEngineIfChangedHead(ctx context.Context, newHeadRoot [32]byte) {
|
||||
func (s *Service) notifyEngineIfChangedHead(ctx context.Context, newHeadRoot [32]byte) error {
|
||||
s.headLock.RLock()
|
||||
if newHeadRoot == [32]byte{} || s.headRoot() == newHeadRoot {
|
||||
s.headLock.RUnlock()
|
||||
return
|
||||
return nil
|
||||
}
|
||||
s.headLock.RUnlock()
|
||||
|
||||
if !s.hasBlockInInitSyncOrDB(ctx, newHeadRoot) {
|
||||
log.Debug("New head does not exist in DB. Do nothing")
|
||||
return // We don't have the block, don't notify the engine and update head.
|
||||
return nil // We don't have the block, don't notify the engine and update head.
|
||||
}
|
||||
|
||||
newHeadBlock, err := s.getBlock(ctx, newHeadRoot)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get new head block")
|
||||
return
|
||||
return nil
|
||||
}
|
||||
headState, err := s.cfg.StateGen.StateByRoot(ctx, newHeadRoot)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get state from db")
|
||||
return
|
||||
return nil
|
||||
}
|
||||
arg := ¬ifyForkchoiceUpdateArg{
|
||||
headState: headState,
|
||||
@@ -201,11 +203,12 @@ func (s *Service) notifyEngineIfChangedHead(ctx context.Context, newHeadRoot [32
|
||||
}
|
||||
_, err = s.notifyForkchoiceUpdate(s.ctx, arg)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("could not notify forkchoice update")
|
||||
return err
|
||||
}
|
||||
if err := s.saveHead(ctx, newHeadRoot, newHeadBlock, headState); err != nil {
|
||||
log.WithError(err).Error("could not save head")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// This processes fork choice attestations from the pool to account for validator votes and fork choice.
|
||||
|
||||
@@ -131,7 +131,7 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
service.cfg.ProposerSlotIndexCache = cache.NewProposerPayloadIDsCache()
|
||||
service.notifyEngineIfChangedHead(ctx, service.headRoot())
|
||||
require.NoError(t, service.notifyEngineIfChangedHead(ctx, service.headRoot()))
|
||||
hookErr := "could not notify forkchoice update"
|
||||
invalidStateErr := "Could not get state from db"
|
||||
require.LogsDoNotContain(t, hook, invalidStateErr)
|
||||
@@ -139,7 +139,7 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
|
||||
gb, err := wrapper.WrappedSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.saveInitSyncBlock(ctx, [32]byte{'a'}, gb))
|
||||
service.notifyEngineIfChangedHead(ctx, [32]byte{'a'})
|
||||
require.NoError(t, service.notifyEngineIfChangedHead(ctx, [32]byte{'a'}))
|
||||
require.LogsContain(t, hook, invalidStateErr)
|
||||
|
||||
hook.Reset()
|
||||
@@ -164,7 +164,7 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
|
||||
state: st,
|
||||
}
|
||||
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(2, 1, [8]byte{1})
|
||||
service.notifyEngineIfChangedHead(ctx, r1)
|
||||
require.NoError(t, service.notifyEngineIfChangedHead(ctx, r1))
|
||||
require.LogsDoNotContain(t, hook, invalidStateErr)
|
||||
require.LogsDoNotContain(t, hook, hookErr)
|
||||
|
||||
@@ -182,7 +182,7 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
|
||||
state: st,
|
||||
}
|
||||
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(2, 1, [8]byte{1})
|
||||
service.notifyEngineIfChangedHead(ctx, r1)
|
||||
require.NoError(t, service.notifyEngineIfChangedHead(ctx, r1))
|
||||
require.LogsDoNotContain(t, hook, invalidStateErr)
|
||||
require.LogsDoNotContain(t, hook, hookErr)
|
||||
vId, payloadID, has := service.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(2)
|
||||
@@ -192,7 +192,7 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
|
||||
|
||||
// Test zero headRoot returns immediately.
|
||||
headRoot := service.headRoot()
|
||||
service.notifyEngineIfChangedHead(ctx, [32]byte{})
|
||||
require.NoError(t, service.notifyEngineIfChangedHead(ctx, [32]byte{}))
|
||||
require.Equal(t, service.headRoot(), headRoot)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ go_library(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/forks/bellatrix:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/wrapper:go_default_library",
|
||||
@@ -89,7 +88,6 @@ go_test(
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/forks/bellatrix:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/wrapper:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/forks/bellatrix"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
@@ -39,7 +38,15 @@ func IsMergeTransitionComplete(st state.BeaconState) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !bellatrix.IsEmptyHeader(h), nil
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(h)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isEmpty, err := wrapper.IsEmptyExecutionData(wrappedHeader)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !isEmpty, nil
|
||||
}
|
||||
|
||||
// IsMergeTransitionBlockUsingPreStatePayloadHeader returns true if the input block is the terminal merge block.
|
||||
@@ -49,7 +56,15 @@ func IsMergeTransitionBlockUsingPreStatePayloadHeader(h *enginev1.ExecutionPaylo
|
||||
if h == nil || body == nil {
|
||||
return false, errors.New("nil header or block body")
|
||||
}
|
||||
if !bellatrix.IsEmptyHeader(h) {
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(h)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isEmpty, err := wrapper.IsEmptyExecutionData(wrappedHeader)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !isEmpty {
|
||||
return false, nil
|
||||
}
|
||||
return IsExecutionBlock(body)
|
||||
@@ -64,7 +79,7 @@ func IsExecutionBlock(body interfaces.BeaconBlockBody) (bool, error) {
|
||||
if body == nil {
|
||||
return false, errors.New("nil block body")
|
||||
}
|
||||
payload, err := body.ExecutionPayload()
|
||||
payload, err := body.Execution()
|
||||
switch {
|
||||
case errors.Is(err, wrapper.ErrUnsupportedField):
|
||||
return false, nil
|
||||
@@ -72,7 +87,11 @@ func IsExecutionBlock(body interfaces.BeaconBlockBody) (bool, error) {
|
||||
return false, err
|
||||
default:
|
||||
}
|
||||
return !bellatrix.IsEmptyPayload(payload), nil
|
||||
isEmpty, err := wrapper.IsEmptyExecutionData(payload)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !isEmpty, nil
|
||||
}
|
||||
|
||||
// IsExecutionEnabled returns true if the beacon chain can begin executing.
|
||||
@@ -98,7 +117,15 @@ func IsExecutionEnabled(st state.BeaconState, body interfaces.BeaconBlockBody) (
|
||||
// IsExecutionEnabledUsingHeader returns true if the execution is enabled using post processed payload header and block body.
|
||||
// This is an optimized version of IsExecutionEnabled where beacon state is not required as an argument.
|
||||
func IsExecutionEnabledUsingHeader(header *enginev1.ExecutionPayloadHeader, body interfaces.BeaconBlockBody) (bool, error) {
|
||||
if !bellatrix.IsEmptyHeader(header) {
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(header)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isEmpty, err := wrapper.IsEmptyExecutionData(wrappedHeader)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !isEmpty {
|
||||
return true, nil
|
||||
}
|
||||
return IsExecutionBlock(body)
|
||||
@@ -116,7 +143,7 @@ func IsPreBellatrixVersion(v int) bool {
|
||||
// # Verify consistency of the parent hash with respect to the previous execution payload header
|
||||
// if is_merge_complete(state):
|
||||
// assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||
func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload *enginev1.ExecutionPayload) error {
|
||||
func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload interfaces.ExecutionData) error {
|
||||
complete, err := IsMergeTransitionComplete(st)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -129,7 +156,7 @@ func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload *enginev1.E
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(payload.ParentHash, header.BlockHash) {
|
||||
if !bytes.Equal(payload.ParentHash(), header.BlockHash) {
|
||||
return errors.New("incorrect block hash")
|
||||
}
|
||||
return nil
|
||||
@@ -143,20 +170,20 @@ func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload *enginev1.E
|
||||
// assert payload.random == get_randao_mix(state, get_current_epoch(state))
|
||||
// # Verify timestamp
|
||||
// assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
|
||||
func ValidatePayload(st state.BeaconState, payload *enginev1.ExecutionPayload) error {
|
||||
func ValidatePayload(st state.BeaconState, payload interfaces.ExecutionData) error {
|
||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bytes.Equal(payload.PrevRandao, random) {
|
||||
if !bytes.Equal(payload.PrevRandao(), random) {
|
||||
return ErrInvalidPayloadPrevRandao
|
||||
}
|
||||
t, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if payload.Timestamp != uint64(t.Unix()) {
|
||||
if payload.Timestamp() != uint64(t.Unix()) {
|
||||
return ErrInvalidPayloadTimeStamp
|
||||
}
|
||||
return nil
|
||||
@@ -194,27 +221,29 @@ func ValidatePayload(st state.BeaconState, payload *enginev1.ExecutionPayload) e
|
||||
// block_hash=payload.block_hash,
|
||||
// transactions_root=hash_tree_root(payload.transactions),
|
||||
// )
|
||||
func ProcessPayload(st state.BeaconState, payload *enginev1.ExecutionPayload) (state.BeaconState, error) {
|
||||
func ProcessPayload(st state.BeaconState, payload interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
if err := ValidatePayloadWhenMergeCompletes(st, payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ValidatePayload(st, payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
header, err := bellatrix.PayloadToHeader(payload)
|
||||
header, err := wrapper.PayloadToHeader(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := st.SetLatestExecutionPayloadHeader(header); err != nil {
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := st.SetLatestExecutionPayloadHeader(wrappedHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// ValidatePayloadHeaderWhenMergeCompletes validates the payload header when the merge completes.
|
||||
func ValidatePayloadHeaderWhenMergeCompletes(st state.BeaconState, header *enginev1.ExecutionPayloadHeader) error {
|
||||
func ValidatePayloadHeaderWhenMergeCompletes(st state.BeaconState, header interfaces.ExecutionData) error {
|
||||
// Skip validation if the state is not merge compatible.
|
||||
complete, err := IsMergeTransitionComplete(st)
|
||||
if err != nil {
|
||||
@@ -228,20 +257,20 @@ func ValidatePayloadHeaderWhenMergeCompletes(st state.BeaconState, header *engin
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(header.ParentHash, h.BlockHash) {
|
||||
if !bytes.Equal(header.ParentHash(), h.BlockHash) {
|
||||
return ErrInvalidPayloadBlockHash
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidatePayloadHeader validates the payload header.
|
||||
func ValidatePayloadHeader(st state.BeaconState, header *enginev1.ExecutionPayloadHeader) error {
|
||||
func ValidatePayloadHeader(st state.BeaconState, header interfaces.ExecutionData) error {
|
||||
// Validate header's random mix matches with state in current epoch
|
||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(header.PrevRandao, random) {
|
||||
if !bytes.Equal(header.PrevRandao(), random) {
|
||||
return ErrInvalidPayloadPrevRandao
|
||||
}
|
||||
|
||||
@@ -250,22 +279,20 @@ func ValidatePayloadHeader(st state.BeaconState, header *enginev1.ExecutionPaylo
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if header.Timestamp != uint64(t.Unix()) {
|
||||
if header.Timestamp() != uint64(t.Unix()) {
|
||||
return ErrInvalidPayloadTimeStamp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessPayloadHeader processes the payload header.
|
||||
func ProcessPayloadHeader(st state.BeaconState, header *enginev1.ExecutionPayloadHeader) (state.BeaconState, error) {
|
||||
func ProcessPayloadHeader(st state.BeaconState, header interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
if err := ValidatePayloadHeaderWhenMergeCompletes(st, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ValidatePayloadHeader(st, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := st.SetLatestExecutionPayloadHeader(header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -278,9 +305,9 @@ func GetBlockPayloadHash(blk interfaces.BeaconBlock) ([32]byte, error) {
|
||||
if IsPreBellatrixVersion(blk.Version()) {
|
||||
return payloadHash, nil
|
||||
}
|
||||
payload, err := blk.Body().ExecutionPayload()
|
||||
payload, err := blk.Body().Execution()
|
||||
if err != nil {
|
||||
return payloadHash, err
|
||||
}
|
||||
return bytesutil.ToBytes32(payload.BlockHash), nil
|
||||
return bytesutil.ToBytes32(payload.BlockHash()), nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/forks/bellatrix"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/ssz"
|
||||
@@ -160,7 +159,9 @@ func Test_IsMergeComplete(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(tt.payload))
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(tt.payload)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
got, err := blocks.IsMergeTransitionComplete(st)
|
||||
require.NoError(t, err)
|
||||
if got != tt.want {
|
||||
@@ -442,7 +443,9 @@ func Test_IsExecutionEnabled(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(tt.header))
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(tt.header)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Body.ExecutionPayload = tt.payload
|
||||
body, err := wrapper.WrappedBeaconBlockBody(blk.Block.Body)
|
||||
@@ -567,8 +570,12 @@ func Test_ValidatePayloadWhenMergeCompletes(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(tt.header))
|
||||
err := blocks.ValidatePayloadWhenMergeCompletes(st, tt.payload)
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(tt.header)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(tt.payload)
|
||||
require.NoError(t, err)
|
||||
err = blocks.ValidatePayloadWhenMergeCompletes(st, wrappedPayload)
|
||||
if err != nil {
|
||||
require.Equal(t, tt.err.Error(), err.Error())
|
||||
} else {
|
||||
@@ -616,7 +623,9 @@ func Test_ValidatePayload(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := blocks.ValidatePayload(st, tt.payload)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(tt.payload)
|
||||
require.NoError(t, err)
|
||||
err = blocks.ValidatePayload(st, wrappedPayload)
|
||||
if err != nil {
|
||||
require.Equal(t, tt.err.Error(), err.Error())
|
||||
} else {
|
||||
@@ -664,12 +673,14 @@ func Test_ProcessPayload(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st, err := blocks.ProcessPayload(st, tt.payload)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(tt.payload)
|
||||
require.NoError(t, err)
|
||||
st, err := blocks.ProcessPayload(st, wrappedPayload)
|
||||
if err != nil {
|
||||
require.Equal(t, tt.err.Error(), err.Error())
|
||||
} else {
|
||||
require.Equal(t, tt.err, err)
|
||||
want, err := bellatrix.PayloadToHeader(tt.payload)
|
||||
want, err := wrapper.PayloadToHeader(wrappedPayload)
|
||||
require.Equal(t, tt.err, err)
|
||||
got, err := st.LatestExecutionPayloadHeader()
|
||||
require.NoError(t, err)
|
||||
@@ -717,7 +728,9 @@ func Test_ProcessPayloadHeader(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st, err := blocks.ProcessPayloadHeader(st, tt.header)
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(tt.header)
|
||||
require.NoError(t, err)
|
||||
st, err := blocks.ProcessPayloadHeader(st, wrappedHeader)
|
||||
if err != nil {
|
||||
require.Equal(t, tt.err.Error(), err.Error())
|
||||
} else {
|
||||
@@ -768,7 +781,9 @@ func Test_ValidatePayloadHeader(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := blocks.ValidatePayloadHeader(st, tt.header)
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(tt.header)
|
||||
require.NoError(t, err)
|
||||
err = blocks.ValidatePayloadHeader(st, wrappedHeader)
|
||||
require.Equal(t, tt.err, err)
|
||||
})
|
||||
}
|
||||
@@ -777,7 +792,9 @@ func Test_ValidatePayloadHeader(t *testing.T) {
|
||||
func Test_ValidatePayloadHeaderWhenMergeCompletes(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
emptySt := st.Copy()
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(&enginev1.ExecutionPayloadHeader{BlockHash: []byte{'a'}}))
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(&enginev1.ExecutionPayloadHeader{BlockHash: []byte{'a'}})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
tests := []struct {
|
||||
name string
|
||||
state state.BeaconState
|
||||
@@ -816,7 +833,9 @@ func Test_ValidatePayloadHeaderWhenMergeCompletes(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := blocks.ValidatePayloadHeaderWhenMergeCompletes(tt.state, tt.header)
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(tt.header)
|
||||
require.NoError(t, err)
|
||||
err = blocks.ValidatePayloadHeaderWhenMergeCompletes(tt.state, wrappedHeader)
|
||||
require.Equal(t, tt.err, err)
|
||||
})
|
||||
}
|
||||
@@ -824,7 +843,9 @@ func Test_ValidatePayloadHeaderWhenMergeCompletes(t *testing.T) {
|
||||
|
||||
func Test_PayloadToHeader(t *testing.T) {
|
||||
p := emptyPayload()
|
||||
h, err := bellatrix.PayloadToHeader(p)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(p)
|
||||
require.NoError(t, err)
|
||||
h, err := wrapper.PayloadToHeader(wrappedPayload)
|
||||
require.NoError(t, err)
|
||||
txRoot, err := ssz.TransactionsRoot(p.Transactions)
|
||||
require.NoError(t, err)
|
||||
@@ -863,7 +884,9 @@ func Test_PayloadToHeader(t *testing.T) {
|
||||
|
||||
func BenchmarkBellatrixComplete(b *testing.B) {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(b, 1)
|
||||
require.NoError(b, st.SetLatestExecutionPayloadHeader(emptyPayloadHeader()))
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(emptyPayloadHeader())
|
||||
require.NoError(b, err)
|
||||
require.NoError(b, st.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
||||
@@ -290,24 +290,17 @@ func ProcessBlockForStateRoot(
|
||||
return nil, errors.Wrap(err, "could not check if execution is enabled")
|
||||
}
|
||||
if enabled {
|
||||
executionData, err := blk.Body().Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if blk.IsBlinded() {
|
||||
header, err := blk.Body().ExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = b.ProcessPayloadHeader(state, header)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution payload header")
|
||||
}
|
||||
state, err = b.ProcessPayloadHeader(state, executionData)
|
||||
} else {
|
||||
payload, err := blk.Body().ExecutionPayload()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = b.ProcessPayload(state, payload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution payload")
|
||||
}
|
||||
state, err = b.ProcessPayload(state, executionData)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution data")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ type ReadOnlyDatabase interface {
|
||||
PowchainData(ctx context.Context) (*ethpb.ETH1ChainData, error)
|
||||
// Fee reicipients operations.
|
||||
FeeRecipientByValidatorID(ctx context.Context, id types.ValidatorIndex) (common.Address, error)
|
||||
RegistrationByValidatorID(ctx context.Context, id types.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error)
|
||||
// origin checkpoint sync support
|
||||
OriginCheckpointBlockRoot(ctx context.Context) ([32]byte, error)
|
||||
BackfillBlockRoot(ctx context.Context) ([32]byte, error)
|
||||
|
||||
@@ -39,6 +39,8 @@ go_library(
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/wrapper:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
"//contracts/deposit:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -46,10 +48,19 @@ type ForkchoiceUpdatedResponse struct {
|
||||
PayloadId *pb.PayloadIDBytes `json:"payloadId"`
|
||||
}
|
||||
|
||||
// ExecutionPayloadReconstructor defines a service that can reconstruct a full beacon
|
||||
// block with an execution payload from a signed beacon block and a connection
|
||||
// to an execution client's engine API.
|
||||
type ExecutionPayloadReconstructor interface {
|
||||
ReconstructFullBellatrixBlock(
|
||||
ctx context.Context, blindedBlock interfaces.SignedBeaconBlock,
|
||||
) (interfaces.SignedBeaconBlock, error)
|
||||
}
|
||||
|
||||
// EngineCaller defines a client that can interact with an Ethereum
|
||||
// execution node's engine service via JSON-RPC.
|
||||
type EngineCaller interface {
|
||||
NewPayload(ctx context.Context, payload *pb.ExecutionPayload) ([]byte, error)
|
||||
NewPayload(ctx context.Context, payload interfaces.ExecutionData) ([]byte, error)
|
||||
ForkchoiceUpdated(
|
||||
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
|
||||
) (*pb.PayloadIDBytes, []byte, error)
|
||||
@@ -62,7 +73,7 @@ type EngineCaller interface {
|
||||
}
|
||||
|
||||
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
||||
func (s *Service) NewPayload(ctx context.Context, payload *pb.ExecutionPayload) ([]byte, error) {
|
||||
func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionData) ([]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.NewPayload")
|
||||
defer span.End()
|
||||
start := time.Now()
|
||||
@@ -73,7 +84,11 @@ func (s *Service) NewPayload(ctx context.Context, payload *pb.ExecutionPayload)
|
||||
ctx, cancel := context.WithDeadline(ctx, d)
|
||||
defer cancel()
|
||||
result := &pb.PayloadStatus{}
|
||||
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payload)
|
||||
payloadPb, ok := payload.Proto().(*pb.ExecutionPayload)
|
||||
if !ok {
|
||||
return nil, errors.New("execution data must be an execution payload")
|
||||
}
|
||||
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payloadPb)
|
||||
if err != nil {
|
||||
return nil, handleRPCError(err)
|
||||
}
|
||||
@@ -290,6 +305,80 @@ func (s *Service) ExecutionBlockByHash(ctx context.Context, hash common.Hash) (*
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// ReconstructFullBellatrixBlock takes in a blinded beacon block and reconstructs
|
||||
// a beacon block with a full execution payload via the engine API.
|
||||
func (s *Service) ReconstructFullBellatrixBlock(
|
||||
ctx context.Context, blindedBlock interfaces.SignedBeaconBlock,
|
||||
) (interfaces.SignedBeaconBlock, error) {
|
||||
if err := wrapper.BeaconBlockIsNil(blindedBlock); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot reconstruct bellatrix block from nil data")
|
||||
}
|
||||
if !blindedBlock.Block().IsBlinded() {
|
||||
return nil, errors.New("can only reconstruct block from blinded block format")
|
||||
}
|
||||
header, err := blindedBlock.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
executionBlockHash := common.BytesToHash(header.BlockHash())
|
||||
executionBlock, err := s.ExecutionBlockByHash(ctx, executionBlockHash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not fetch execution block with txs by hash %#x: %v", executionBlockHash, err)
|
||||
}
|
||||
if executionBlock == nil {
|
||||
return nil, fmt.Errorf("received nil execution block for request by hash %#x", executionBlockHash)
|
||||
}
|
||||
payload, err := fullPayloadFromExecutionBlock(header, executionBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fullBlock, err := wrapper.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reconstructedExecutionPayloadCount.Add(1)
|
||||
return fullBlock, nil
|
||||
}
|
||||
|
||||
func fullPayloadFromExecutionBlock(
|
||||
header interfaces.ExecutionData, block *pb.ExecutionBlock,
|
||||
) (*pb.ExecutionPayload, error) {
|
||||
if header.IsNil() || block == nil {
|
||||
return nil, errors.New("execution block and header cannot be nil")
|
||||
}
|
||||
if !bytes.Equal(header.BlockHash(), block.Hash[:]) {
|
||||
return nil, fmt.Errorf(
|
||||
"block hash field in execution header %#x does not match execution block hash %#x",
|
||||
header.BlockHash(),
|
||||
block.Hash,
|
||||
)
|
||||
}
|
||||
txs := make([][]byte, len(block.Transactions))
|
||||
for i, tx := range block.Transactions {
|
||||
txBin, err := tx.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txs[i] = txBin
|
||||
}
|
||||
return &pb.ExecutionPayload{
|
||||
ParentHash: header.ParentHash(),
|
||||
FeeRecipient: header.FeeRecipient(),
|
||||
StateRoot: header.StateRoot(),
|
||||
ReceiptsRoot: header.ReceiptsRoot(),
|
||||
LogsBloom: header.LogsBloom(),
|
||||
PrevRandao: header.PrevRandao(),
|
||||
BlockNumber: header.BlockNumber(),
|
||||
GasLimit: header.GasLimit(),
|
||||
GasUsed: header.GasUsed(),
|
||||
Timestamp: header.Timestamp(),
|
||||
ExtraData: header.ExtraData(),
|
||||
BaseFeePerGas: header.BaseFeePerGas(),
|
||||
BlockHash: block.Hash[:],
|
||||
Transactions: txs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Handles errors received from the RPC server according to the specification.
|
||||
func handleRPCError(err error) error {
|
||||
if err == nil {
|
||||
@@ -332,7 +421,7 @@ func handleRPCError(err error) error {
|
||||
if !ok {
|
||||
return errors.Wrapf(err, "got an unexpected error in JSON-RPC response")
|
||||
}
|
||||
return errors.Wrapf(ErrServer, "%v", errWithData.ErrorData())
|
||||
return errors.Wrapf(ErrServer, "%v", errWithData.Error())
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
gethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/holiman/uint256"
|
||||
@@ -19,13 +20,16 @@ import (
|
||||
mocks "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
_ = ExecutionPayloadReconstructor(&Service{})
|
||||
_ = EngineCaller(&Service{})
|
||||
_ = EngineCaller(&mocks.EngineClient{})
|
||||
)
|
||||
@@ -61,7 +65,9 @@ func TestClient_IPC(t *testing.T) {
|
||||
require.Equal(t, true, ok)
|
||||
req, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
latestValidHash, err := srv.NewPayload(ctx, req)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(req)
|
||||
require.NoError(t, err)
|
||||
latestValidHash, err := srv.NewPayload(ctx, wrappedPayload)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, bytesutil.ToBytes32(want.LatestValidHash), bytesutil.ToBytes32(latestValidHash))
|
||||
})
|
||||
@@ -226,7 +232,9 @@ func TestClient_HTTP(t *testing.T) {
|
||||
client := newPayloadSetup(t, want, execPayload)
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.NewPayload(ctx, execPayload)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(execPayload)
|
||||
require.NoError(t, err)
|
||||
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want.LatestValidHash, resp)
|
||||
})
|
||||
@@ -238,7 +246,9 @@ func TestClient_HTTP(t *testing.T) {
|
||||
client := newPayloadSetup(t, want, execPayload)
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.NewPayload(ctx, execPayload)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(execPayload)
|
||||
require.NoError(t, err)
|
||||
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||
require.ErrorIs(t, ErrAcceptedSyncingPayloadStatus, err)
|
||||
require.DeepEqual(t, []uint8(nil), resp)
|
||||
})
|
||||
@@ -250,7 +260,9 @@ func TestClient_HTTP(t *testing.T) {
|
||||
client := newPayloadSetup(t, want, execPayload)
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.NewPayload(ctx, execPayload)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(execPayload)
|
||||
require.NoError(t, err)
|
||||
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||
require.ErrorIs(t, ErrInvalidBlockHashPayloadStatus, err)
|
||||
require.DeepEqual(t, []uint8(nil), resp)
|
||||
})
|
||||
@@ -262,7 +274,9 @@ func TestClient_HTTP(t *testing.T) {
|
||||
client := newPayloadSetup(t, want, execPayload)
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.NewPayload(ctx, execPayload)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(execPayload)
|
||||
require.NoError(t, err)
|
||||
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||
require.ErrorIs(t, ErrInvalidPayloadStatus, err)
|
||||
require.DeepEqual(t, want.LatestValidHash, resp)
|
||||
})
|
||||
@@ -274,7 +288,9 @@ func TestClient_HTTP(t *testing.T) {
|
||||
client := newPayloadSetup(t, want, execPayload)
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.NewPayload(ctx, execPayload)
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(execPayload)
|
||||
require.NoError(t, err)
|
||||
resp, err := client.NewPayload(ctx, wrappedPayload)
|
||||
require.ErrorIs(t, ErrUnknownPayloadStatus, err)
|
||||
require.DeepEqual(t, []uint8(nil), resp)
|
||||
})
|
||||
@@ -386,6 +402,101 @@ func TestClient_HTTP(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestReconstructFullBellatrixBlock(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
t.Run("nil block", func(t *testing.T) {
|
||||
service := &Service{}
|
||||
|
||||
_, err := service.ReconstructFullBellatrixBlock(ctx, nil)
|
||||
require.ErrorContains(t, "nil data", err)
|
||||
})
|
||||
t.Run("only blinded block", func(t *testing.T) {
|
||||
want := "can only reconstruct block from blinded block format"
|
||||
service := &Service{}
|
||||
bellatrixBlock := util.NewBeaconBlockBellatrix()
|
||||
wrapped, err := wrapper.WrappedSignedBeaconBlock(bellatrixBlock)
|
||||
require.NoError(t, err)
|
||||
_, err = service.ReconstructFullBellatrixBlock(ctx, wrapped)
|
||||
require.ErrorContains(t, want, err)
|
||||
})
|
||||
t.Run("properly reconstructs block with correct payload", func(t *testing.T) {
|
||||
fix := fixtures()
|
||||
payload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
jsonPayload := make(map[string]interface{})
|
||||
tx := gethtypes.NewTransaction(
|
||||
0,
|
||||
common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
|
||||
big.NewInt(0), 0, big.NewInt(0),
|
||||
nil,
|
||||
)
|
||||
txs := []*gethtypes.Transaction{tx}
|
||||
encodedBinaryTxs := make([][]byte, 1)
|
||||
var err error
|
||||
encodedBinaryTxs[0], err = txs[0].MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
payload.Transactions = encodedBinaryTxs
|
||||
jsonPayload["transactions"] = txs
|
||||
num := big.NewInt(1)
|
||||
encodedNum := hexutil.EncodeBig(num)
|
||||
jsonPayload["hash"] = hexutil.Encode(payload.BlockHash)
|
||||
jsonPayload["parentHash"] = common.BytesToHash([]byte("parent"))
|
||||
jsonPayload["sha3Uncles"] = common.BytesToHash([]byte("uncles"))
|
||||
jsonPayload["miner"] = common.BytesToAddress([]byte("miner"))
|
||||
jsonPayload["stateRoot"] = common.BytesToHash([]byte("state"))
|
||||
jsonPayload["transactionsRoot"] = common.BytesToHash([]byte("txs"))
|
||||
jsonPayload["receiptsRoot"] = common.BytesToHash([]byte("receipts"))
|
||||
jsonPayload["logsBloom"] = gethtypes.BytesToBloom([]byte("bloom"))
|
||||
jsonPayload["gasLimit"] = hexutil.EncodeUint64(1)
|
||||
jsonPayload["gasUsed"] = hexutil.EncodeUint64(2)
|
||||
jsonPayload["timestamp"] = hexutil.EncodeUint64(3)
|
||||
jsonPayload["number"] = encodedNum
|
||||
jsonPayload["extraData"] = common.BytesToHash([]byte("extra"))
|
||||
jsonPayload["totalDifficulty"] = "0x123456"
|
||||
jsonPayload["difficulty"] = encodedNum
|
||||
jsonPayload["size"] = encodedNum
|
||||
jsonPayload["baseFeePerGas"] = encodedNum
|
||||
|
||||
wrappedPayload, err := wrapper.WrappedExecutionPayload(payload)
|
||||
require.NoError(t, err)
|
||||
header, err := wrapper.PayloadToHeader(wrappedPayload)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
defer func() {
|
||||
require.NoError(t, r.Body.Close())
|
||||
}()
|
||||
respJSON := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": jsonPayload,
|
||||
}
|
||||
require.NoError(t, json.NewEncoder(w).Encode(respJSON))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||
require.NoError(t, err)
|
||||
defer rpcClient.Close()
|
||||
|
||||
service := &Service{}
|
||||
service.rpcClient = rpcClient
|
||||
blindedBlock := util.NewBlindedBeaconBlockBellatrix()
|
||||
|
||||
blindedBlock.Block.Body.ExecutionPayloadHeader = header
|
||||
wrapped, err := wrapper.WrappedSignedBeaconBlock(blindedBlock)
|
||||
require.NoError(t, err)
|
||||
reconstructed, err := service.ReconstructFullBellatrixBlock(ctx, wrapped)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := reconstructed.Block().Body().Execution()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, payload, got.Proto())
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -873,6 +984,57 @@ func fixtures() map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_fullPayloadFromExecutionBlock(t *testing.T) {
|
||||
type args struct {
|
||||
header *pb.ExecutionPayloadHeader
|
||||
block *pb.ExecutionBlock
|
||||
}
|
||||
wantedHash := common.BytesToHash([]byte("foo"))
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *pb.ExecutionPayload
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "block hash field in header and block hash mismatch",
|
||||
args: args{
|
||||
header: &pb.ExecutionPayloadHeader{
|
||||
BlockHash: []byte("foo"),
|
||||
},
|
||||
block: &pb.ExecutionBlock{
|
||||
Hash: common.BytesToHash([]byte("bar")),
|
||||
},
|
||||
},
|
||||
err: "does not match execution block hash",
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
args: args{
|
||||
header: &pb.ExecutionPayloadHeader{
|
||||
BlockHash: wantedHash[:],
|
||||
},
|
||||
block: &pb.ExecutionBlock{
|
||||
Hash: wantedHash,
|
||||
},
|
||||
},
|
||||
want: &pb.ExecutionPayload{
|
||||
BlockHash: wantedHash[:],
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
wrapped, err := wrapper.WrappedExecutionPayloadHeader(tt.args.header)
|
||||
got, err := fullPayloadFromExecutionBlock(wrapped, tt.args.block)
|
||||
if (err != nil) && !strings.Contains(err.Error(), tt.err) {
|
||||
t.Fatalf("Wanted err %s got %v", tt.err, err)
|
||||
}
|
||||
require.DeepEqual(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type testEngineService struct{}
|
||||
|
||||
func (*testEngineService) NoArgsRets() {}
|
||||
|
||||
@@ -31,4 +31,8 @@ var (
|
||||
Buckets: []float64{25, 50, 100, 200, 500, 1000, 2000, 4000},
|
||||
},
|
||||
)
|
||||
reconstructedExecutionPayloadCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "reconstructed_execution_payload_count",
|
||||
Help: "Count the number of execution payloads that are reconstructed using JSON-RPC from payload headers",
|
||||
})
|
||||
)
|
||||
|
||||
@@ -18,6 +18,7 @@ go_library(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
)
|
||||
@@ -32,7 +33,7 @@ type EngineClient struct {
|
||||
}
|
||||
|
||||
// NewPayload --
|
||||
func (e *EngineClient) NewPayload(_ context.Context, _ *pb.ExecutionPayload) ([]byte, error) {
|
||||
func (e *EngineClient) NewPayload(_ context.Context, _ interfaces.ExecutionData) ([]byte, error) {
|
||||
return e.NewPayloadResp, e.ErrNewPayload
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ func TestGetSpec(t *testing.T) {
|
||||
config.BellatrixForkEpoch = 101
|
||||
config.ShardingForkVersion = []byte("ShardingForkVersion")
|
||||
config.ShardingForkEpoch = 102
|
||||
config.CapellaForkVersion = []byte("CapellaForkVersion")
|
||||
config.CapellaForkEpoch = 103
|
||||
config.BLSWithdrawalPrefixByte = byte('b')
|
||||
config.GenesisDelay = 24
|
||||
config.SecondsPerSlot = 25
|
||||
@@ -133,7 +135,7 @@ func TestGetSpec(t *testing.T) {
|
||||
resp, err := server.GetSpec(context.Background(), &emptypb.Empty{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 99, len(resp.Data))
|
||||
assert.Equal(t, 101, len(resp.Data))
|
||||
for k, v := range resp.Data {
|
||||
switch k {
|
||||
case "CONFIG_NAME":
|
||||
@@ -202,6 +204,10 @@ func TestGetSpec(t *testing.T) {
|
||||
assert.Equal(t, "0x"+hex.EncodeToString([]byte("ShardingForkVersion")), v)
|
||||
case "SHARDING_FORK_EPOCH":
|
||||
assert.Equal(t, "102", v)
|
||||
case "CAPELLA_FORK_VERSION":
|
||||
assert.Equal(t, "0x"+hex.EncodeToString([]byte("CapellaForkVersion")), v)
|
||||
case "CAPELLA_FORK_EPOCH":
|
||||
assert.Equal(t, "103", v)
|
||||
case "MIN_ANCHOR_POW_BLOCK_DIFFICULTY":
|
||||
assert.Equal(t, "1000", v)
|
||||
case "BLS_WITHDRAWAL_PREFIX":
|
||||
|
||||
@@ -133,8 +133,8 @@ func (vs *Server) GetProposerDuties(ctx context.Context, req *ethpbv1.ProposerDu
|
||||
|
||||
cs := vs.TimeFetcher.CurrentSlot()
|
||||
currentEpoch := slots.ToEpoch(cs)
|
||||
if req.Epoch > currentEpoch {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "Request epoch %d can not be greater than current epoch %d", req.Epoch, currentEpoch)
|
||||
if req.Epoch > currentEpoch+1 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "Request epoch %d can not be greater than next epoch %d", req.Epoch, currentEpoch+1)
|
||||
}
|
||||
|
||||
s, err := vs.HeadFetcher.HeadState(ctx)
|
||||
@@ -177,7 +177,7 @@ func (vs *Server) GetProposerDuties(ctx context.Context, req *ethpbv1.ProposerDu
|
||||
return duties[i].Slot < duties[j].Slot
|
||||
})
|
||||
|
||||
root, err := proposalDependentRoot(s, req.Epoch)
|
||||
root, err := vs.proposalDependentRoot(ctx, s, req.Epoch)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get dependent root: %v", err)
|
||||
}
|
||||
@@ -912,7 +912,7 @@ func attestationDependentRoot(s state.BeaconState, epoch types.Epoch) ([]byte, e
|
||||
|
||||
// proposalDependentRoot is get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch) - 1)
|
||||
// or the genesis block root in the case of underflow.
|
||||
func proposalDependentRoot(s state.BeaconState, epoch types.Epoch) ([]byte, error) {
|
||||
func (vs *Server) proposalDependentRoot(ctx context.Context, s state.BeaconState, epoch types.Epoch) ([]byte, error) {
|
||||
var dependentRootSlot types.Slot
|
||||
if epoch == 0 {
|
||||
dependentRootSlot = 0
|
||||
@@ -923,10 +923,21 @@ func proposalDependentRoot(s state.BeaconState, epoch types.Epoch) ([]byte, erro
|
||||
}
|
||||
dependentRootSlot = epochStartSlot.Sub(1)
|
||||
}
|
||||
root, err := helpers.BlockRootAtSlot(s, dependentRootSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get block root")
|
||||
var root []byte
|
||||
var err error
|
||||
// Per spec, if the dependent root epoch is greater than current epoch, use the head root.
|
||||
if dependentRootSlot >= s.Slot() {
|
||||
root, err = vs.HeadFetcher.HeadRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
root, err = helpers.BlockRootAtSlot(s, dependentRootSlot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get block root")
|
||||
}
|
||||
}
|
||||
|
||||
return root, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -366,11 +366,11 @@ func TestGetProposerDuties(t *testing.T) {
|
||||
t.Run("Epoch out of bound", func(t *testing.T) {
|
||||
currentEpoch := slots.ToEpoch(bs.Slot())
|
||||
req := ðpbv1.ProposerDutiesRequest{
|
||||
Epoch: currentEpoch + 1,
|
||||
Epoch: currentEpoch + 2,
|
||||
}
|
||||
_, err := vs.GetProposerDuties(ctx, req)
|
||||
require.NotNil(t, err)
|
||||
assert.ErrorContains(t, fmt.Sprintf("Request epoch %d can not be greater than current epoch %d", currentEpoch+1, currentEpoch), err)
|
||||
assert.ErrorContains(t, fmt.Sprintf("Request epoch %d can not be greater than next epoch %d", currentEpoch+2, currentEpoch+1), err)
|
||||
})
|
||||
|
||||
t.Run("execution optimistic", func(t *testing.T) {
|
||||
|
||||
@@ -3,10 +3,12 @@ package validator
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition/interop"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
coreBlock "github.com/prysmaticlabs/prysm/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
@@ -19,20 +21,32 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// blockBuilderTimeout is the maximum amount of time allowed for a block builder to respond to a
|
||||
// block request. This value is known as `BUILDER_PROPOSAL_DELAY_TOLERANCE` in builder spec.
|
||||
const blockBuilderTimeout = 1 * time.Second
|
||||
|
||||
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
|
||||
altairBlk, err := vs.buildAltairBeaconBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
builderReady, b, err := vs.getAndBuildHeaderBlock(ctx, altairBlk)
|
||||
if err != nil {
|
||||
// In the event of an error, the node should fall back to default execution engine for building block.
|
||||
log.WithError(err).Error("Default back to local execution client")
|
||||
} else if builderReady {
|
||||
return b, nil
|
||||
registered, err := vs.validatorRegistered(ctx, altairBlk.ProposerIndex)
|
||||
if registered && err == nil {
|
||||
builderReady, b, err := vs.getAndBuildHeaderBlock(ctx, altairBlk)
|
||||
if err != nil {
|
||||
// In the event of an error, the node should fall back to default execution engine for building block.
|
||||
log.WithError(err).Error("Failed to build a block from external builder, falling " +
|
||||
"back to local execution client")
|
||||
} else if builderReady {
|
||||
return b, nil
|
||||
}
|
||||
} else if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": req.Slot,
|
||||
"validatorIndex": altairBlk.ProposerIndex,
|
||||
}).Errorf("Could not determine validator has registered. Default to local execution client: %v", err)
|
||||
}
|
||||
|
||||
payload, err := vs.getExecutionPayload(ctx, req.Slot, altairBlk.ProposerIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -85,7 +99,7 @@ func (vs *Server) getPayloadHeader(ctx context.Context, slot types.Slot, idx typ
|
||||
if blocks.IsPreBellatrixVersion(b.Version()) {
|
||||
return nil, nil
|
||||
}
|
||||
h, err := b.Block().Body().ExecutionPayload()
|
||||
h, err := b.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -93,7 +107,7 @@ func (vs *Server) getPayloadHeader(ctx context.Context, slot types.Slot, idx typ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bid, err := vs.BlockBuilder.GetHeader(ctx, slot, bytesutil.ToBytes32(h.BlockHash), pk)
|
||||
bid, err := vs.BlockBuilder.GetHeader(ctx, slot, bytesutil.ToBytes32(h.BlockHash()), pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -164,10 +178,14 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, err := b.Block().Body().ExecutionPayloadHeader()
|
||||
h, err := b.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
||||
if !ok {
|
||||
return nil, errors.New("execution data must be execution payload header")
|
||||
}
|
||||
sb := ðpb.SignedBlindedBeaconBlockBellatrix{
|
||||
Block: ðpb.BlindedBeaconBlockBellatrix{
|
||||
Slot: b.Block().Slot(),
|
||||
@@ -184,7 +202,7 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe
|
||||
Deposits: b.Block().Body().Deposits(),
|
||||
VoluntaryExits: b.Block().Body().VoluntaryExits(),
|
||||
SyncAggregate: agg,
|
||||
ExecutionPayloadHeader: h,
|
||||
ExecutionPayloadHeader: header,
|
||||
},
|
||||
},
|
||||
Signature: b.Signature(),
|
||||
@@ -221,8 +239,8 @@ func (vs *Server) unblindBuilderBlock(ctx context.Context, b interfaces.SignedBe
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"blockHash": fmt.Sprintf("%#x", h.BlockHash),
|
||||
"feeRecipient": fmt.Sprintf("%#x", h.FeeRecipient),
|
||||
"blockHash": fmt.Sprintf("%#x", h.BlockHash()),
|
||||
"feeRecipient": fmt.Sprintf("%#x", h.FeeRecipient()),
|
||||
"gasUsed": h.GasUsed,
|
||||
"slot": b.Block().Slot(),
|
||||
"txs": len(payload.Transactions),
|
||||
@@ -251,11 +269,14 @@ func (vs *Server) readyForBuilder(ctx context.Context) (bool, error) {
|
||||
|
||||
// Get and builder header block. Returns a boolean status, built block and error.
|
||||
// If the status is false that means builder the header block is disallowed.
|
||||
// This routine is time limited by `blockBuilderTimeout`.
|
||||
func (vs *Server) getAndBuildHeaderBlock(ctx context.Context, b *ethpb.BeaconBlockAltair) (bool, *ethpb.GenericBeaconBlock, error) {
|
||||
// No op. Builder is not defined. User did not specify a user URL. We should use local EE.
|
||||
if vs.BlockBuilder == nil || !vs.BlockBuilder.Configured() {
|
||||
return false, nil, nil
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, blockBuilderTimeout)
|
||||
defer cancel()
|
||||
// Does the protocol allow for builder at this current moment. Builder is only allowed post merge after finalization.
|
||||
ready, err := vs.readyForBuilder(ctx)
|
||||
if err != nil {
|
||||
@@ -280,3 +301,18 @@ func (vs *Server) getAndBuildHeaderBlock(ctx context.Context, b *ethpb.BeaconBlo
|
||||
}
|
||||
return true, gb, nil
|
||||
}
|
||||
|
||||
// validatorRegistered returns true if validator with index `id` was previously registered in the database.
|
||||
func (vs *Server) validatorRegistered(ctx context.Context, id types.ValidatorIndex) (bool, error) {
|
||||
if vs.BeaconDB == nil {
|
||||
return false, errors.New("nil beacon db")
|
||||
}
|
||||
_, err := vs.BeaconDB.RegistrationByValidatorID(ctx, id)
|
||||
switch {
|
||||
case errors.Is(err, kv.ErrNotFoundFeeRecipient):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
prysmtime "github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
|
||||
@@ -24,6 +26,7 @@ import (
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
v1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
@@ -561,6 +564,12 @@ func TestServer_GetBellatrixBeaconBlock_BuilderCase(t *testing.T) {
|
||||
wbr1, err := wb1.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, wb1))
|
||||
|
||||
random, err := helpers.RandaoMix(beaconState, prysmtime.CurrentEpoch(beaconState))
|
||||
require.NoError(t, err)
|
||||
|
||||
tstamp, err := slots.ToTime(beaconState.GenesisTime(), bellatrixSlot+1)
|
||||
require.NoError(t, err)
|
||||
h := &v1.ExecutionPayloadHeader{
|
||||
BlockNumber: 123,
|
||||
GasLimit: 456,
|
||||
@@ -570,17 +579,18 @@ func TestServer_GetBellatrixBeaconBlock_BuilderCase(t *testing.T) {
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
PrevRandao: random,
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
||||
ExtraData: make([]byte, 0),
|
||||
Timestamp: uint64(tstamp.Unix()),
|
||||
}
|
||||
|
||||
proposerServer := &Server{
|
||||
FinalizationFetcher: &blockchainTest.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Root: wbr1[:]}},
|
||||
HeadFetcher: &blockchainTest.ChainService{State: beaconState, Root: parentRoot[:], Optimistic: false, Block: wb1},
|
||||
TimeFetcher: &blockchainTest.ChainService{Genesis: time.Now()},
|
||||
TimeFetcher: &blockchainTest.ChainService{Genesis: time.Unix(int64(beaconState.GenesisTime()), 0)},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
BlockReceiver: &blockchainTest.ChainService{},
|
||||
HeadUpdater: &blockchainTest.ChainService{},
|
||||
@@ -603,6 +613,8 @@ func TestServer_GetBellatrixBeaconBlock_BuilderCase(t *testing.T) {
|
||||
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, proposerServer.BeaconDB.SaveRegistrationsByValidatorIDs(ctx, []types.ValidatorIndex{40},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: bytesutil.PadTo([]byte{}, fieldparams.FeeRecipientLength), Pubkey: bytesutil.PadTo([]byte{}, fieldparams.BLSPubkeyLength)}}))
|
||||
block, err := proposerServer.getBellatrixBeaconBlock(ctx, ðpb.BlockRequest{
|
||||
Slot: bellatrixSlot + 1,
|
||||
RandaoReveal: randaoReveal,
|
||||
@@ -613,3 +625,29 @@ func TestServer_GetBellatrixBeaconBlock_BuilderCase(t *testing.T) {
|
||||
require.LogsContain(t, hook, "Computed state root")
|
||||
require.DeepEqual(t, h, bellatrixBlk.BlindedBellatrix.Body.ExecutionPayloadHeader) // Payload header should equal.
|
||||
}
|
||||
|
||||
func TestServer_validatorRegistered(t *testing.T) {
|
||||
proposerServer := &Server{}
|
||||
ctx := context.Background()
|
||||
|
||||
reg, err := proposerServer.validatorRegistered(ctx, 0)
|
||||
require.ErrorContains(t, "nil beacon db", err)
|
||||
require.Equal(t, false, reg)
|
||||
|
||||
proposerServer.BeaconDB = dbTest.SetupDB(t)
|
||||
reg, err = proposerServer.validatorRegistered(ctx, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, reg)
|
||||
|
||||
f := bytesutil.PadTo([]byte{}, fieldparams.FeeRecipientLength)
|
||||
p := bytesutil.PadTo([]byte{}, fieldparams.BLSPubkeyLength)
|
||||
require.NoError(t, proposerServer.BeaconDB.SaveRegistrationsByValidatorIDs(ctx, []types.ValidatorIndex{0, 1},
|
||||
[]*ethpb.ValidatorRegistrationV1{{FeeRecipient: f, Pubkey: p}, {FeeRecipient: f, Pubkey: p}}))
|
||||
|
||||
reg, err = proposerServer.validatorRegistered(ctx, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, reg)
|
||||
reg, err = proposerServer.validatorRegistered(ctx, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, reg)
|
||||
}
|
||||
|
||||
@@ -105,11 +105,11 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
||||
switch finalizedBlock.Version() {
|
||||
case version.Phase0, version.Altair: // Blocks before Bellatrix don't have execution payloads. Use zeros as the hash.
|
||||
default:
|
||||
finalizedPayload, err := finalizedBlock.Block().Body().ExecutionPayload()
|
||||
finalizedPayload, err := finalizedBlock.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalizedBlockHash = finalizedPayload.BlockHash
|
||||
finalizedBlockHash = finalizedPayload.BlockHash()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"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"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -47,7 +48,9 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
}))
|
||||
|
||||
transitionSt, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, transitionSt.SetLatestExecutionPayloadHeader(&pb.ExecutionPayloadHeader{BlockNumber: 1}))
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(&pb.ExecutionPayloadHeader{BlockNumber: 1})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, transitionSt.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
b2pb := util.NewBeaconBlockBellatrix()
|
||||
b2r, err := b2pb.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
@@ -144,7 +147,9 @@ func TestServer_getExecutionPayload_UnexpectedFeeRecipient(t *testing.T) {
|
||||
}))
|
||||
|
||||
transitionSt, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, transitionSt.SetLatestExecutionPayloadHeader(&pb.ExecutionPayloadHeader{BlockNumber: 1}))
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(&pb.ExecutionPayloadHeader{BlockNumber: 1})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, transitionSt.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
b2pb := util.NewBeaconBlockBellatrix()
|
||||
b2r, err := b2pb.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -11,6 +11,7 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -83,7 +84,7 @@ type WriteOnlyBeaconState interface {
|
||||
SetSlashings(val []uint64) error
|
||||
UpdateSlashingsAtIndex(idx, val uint64) error
|
||||
AppendHistoricalRoots(root [32]byte) error
|
||||
SetLatestExecutionPayloadHeader(payload *enginev1.ExecutionPayloadHeader) error
|
||||
SetLatestExecutionPayloadHeader(payload interfaces.ExecutionData) error
|
||||
}
|
||||
|
||||
// ReadOnlyValidator defines a struct which only has read access to validator methods.
|
||||
|
||||
@@ -64,6 +64,7 @@ go_library(
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
@@ -113,6 +114,7 @@ go_test(
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/wrapper:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -180,7 +181,9 @@ func TestComputeFieldRootsWithHasher_Bellatrix(t *testing.T) {
|
||||
require.NoError(t, beaconState.SetInactivityScores([]uint64{1, 2, 3}))
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(syncCommittee("current")))
|
||||
require.NoError(t, beaconState.SetNextSyncCommittee(syncCommittee("next")))
|
||||
require.NoError(t, beaconState.SetLatestExecutionPayloadHeader(executionPayloadHeader()))
|
||||
wrappedHeader, err := wrapper.WrappedExecutionPayloadHeader(executionPayloadHeader())
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
|
||||
v1State, ok := beaconState.(*v3.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
_ "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
)
|
||||
|
||||
// SetLatestExecutionPayloadHeader for the beacon state.
|
||||
func (b *BeaconState) SetLatestExecutionPayloadHeader(val *enginev1.ExecutionPayloadHeader) error {
|
||||
func (b *BeaconState) SetLatestExecutionPayloadHeader(val interfaces.ExecutionData) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
if b.version == version.Phase0 || b.version == version.Altair {
|
||||
return errNotSupported("SetLatestExecutionPayloadHeader", b.version)
|
||||
}
|
||||
|
||||
b.latestExecutionPayloadHeader = val
|
||||
header, ok := val.Proto().(*enginev1.ExecutionPayloadHeader)
|
||||
if !ok {
|
||||
return errors.New("value must be an execution payload header")
|
||||
}
|
||||
b.latestExecutionPayloadHeader = header
|
||||
b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeader)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ go_library(
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
|
||||
@@ -2,7 +2,7 @@ package v1
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -57,6 +57,6 @@ func (*BeaconState) SetInactivityScores(_ []uint64) error {
|
||||
}
|
||||
|
||||
// SetLatestExecutionPayloadHeader is not supported for phase 0 beacon state.
|
||||
func (*BeaconState) SetLatestExecutionPayloadHeader(_ *enginev1.ExecutionPayloadHeader) error {
|
||||
func (*BeaconState) SetLatestExecutionPayloadHeader(_ interfaces.ExecutionData) error {
|
||||
return errors.New("SetLatestExecutionPayloadHeader is not supported for phase 0 beacon state")
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ go_library(
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
|
||||
@@ -2,7 +2,7 @@ package v2
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -22,6 +22,6 @@ func (*BeaconState) RotateAttestations() error {
|
||||
}
|
||||
|
||||
// SetLatestExecutionPayloadHeader is not supported for hard fork 1 beacon state.
|
||||
func (*BeaconState) SetLatestExecutionPayloadHeader(_ *enginev1.ExecutionPayloadHeader) error {
|
||||
func (*BeaconState) SetLatestExecutionPayloadHeader(_ interfaces.ExecutionData) error {
|
||||
return errors.New("SetLatestExecutionPayloadHeader is not supported for hard fork 1 beacon state")
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ go_library(
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package v3
|
||||
|
||||
import enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
)
|
||||
|
||||
// SetLatestExecutionPayloadHeader for the beacon state.
|
||||
func (b *BeaconState) SetLatestExecutionPayloadHeader(val *enginev1.ExecutionPayloadHeader) error {
|
||||
func (b *BeaconState) SetLatestExecutionPayloadHeader(val interfaces.ExecutionData) error {
|
||||
if !b.hasInnerState() {
|
||||
return ErrNilInnerState
|
||||
}
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.state.LatestExecutionPayloadHeader = val
|
||||
header, ok := val.Proto().(*enginev1.ExecutionPayloadHeader)
|
||||
if !ok {
|
||||
return errors.New("value must be an execution payload header")
|
||||
}
|
||||
b.state.LatestExecutionPayloadHeader = header
|
||||
b.markFieldAsDirty(latestExecutionPayloadHeader)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -170,8 +170,12 @@ func (s *Service) processPendingBlocks(ctx context.Context) error {
|
||||
|
||||
if err := s.cfg.chain.ReceiveBlock(ctx, b, blkRoot); err != nil {
|
||||
if blockchain.IsInvalidBlock(err) {
|
||||
tracing.AnnotateError(span, err)
|
||||
s.setBadBlock(ctx, blkRoot)
|
||||
r := blockchain.InvalidBlockRoot(err)
|
||||
if r != [32]byte{} {
|
||||
s.setBadBlock(ctx, r) // Setting head block as bad.
|
||||
} else {
|
||||
s.setBadBlock(ctx, blkRoot)
|
||||
}
|
||||
}
|
||||
log.Debugf("Could not process block from slot %d: %v", b.Block().Slot(), err)
|
||||
|
||||
|
||||
@@ -31,8 +31,13 @@ func (s *Service) beaconBlockSubscriber(ctx context.Context, msg proto.Message)
|
||||
|
||||
if err := s.cfg.chain.ReceiveBlock(ctx, signed, root); err != nil {
|
||||
if blockchain.IsInvalidBlock(err) {
|
||||
interop.WriteBlockToDisk(signed, true /*failed*/)
|
||||
s.setBadBlock(ctx, root)
|
||||
r := blockchain.InvalidBlockRoot(err)
|
||||
if r != [32]byte{} {
|
||||
s.setBadBlock(ctx, r) // Setting head block as bad.
|
||||
} else {
|
||||
interop.WriteBlockToDisk(signed, true /*failed*/)
|
||||
s.setBadBlock(ctx, root)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -283,14 +283,14 @@ func (s *Service) validateBellatrixBeaconBlock(ctx context.Context, parentState
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
payload, err := body.ExecutionPayload()
|
||||
payload, err := body.Execution()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if payload == nil {
|
||||
if payload.IsNil() {
|
||||
return errors.New("execution payload is nil")
|
||||
}
|
||||
if payload.Timestamp != uint64(t.Unix()) {
|
||||
if payload.Timestamp() != uint64(t.Unix()) {
|
||||
return errors.New("incorrect timestamp")
|
||||
}
|
||||
|
||||
|
||||
@@ -324,19 +324,6 @@ var (
|
||||
Value: false,
|
||||
}
|
||||
|
||||
// FeeRecipientConfigFileFlag defines the path or URL to a file with proposer config.
|
||||
FeeRecipientConfigFileFlag = &cli.StringFlag{
|
||||
Name: "fee-recipient-config-file",
|
||||
Usage: "DEPRECATED, please use proposer-settings-file",
|
||||
Value: "",
|
||||
}
|
||||
// FeeRecipientConfigURLFlag defines the path or URL to a file with proposer config.
|
||||
FeeRecipientConfigURLFlag = &cli.StringFlag{
|
||||
Name: "fee-recipient-config-url",
|
||||
Usage: "DEPRECATED, please use proposer-settings-url",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
// ProposerSettingsFlag defines the path or URL to a file with proposer config.
|
||||
ProposerSettingsFlag = &cli.StringFlag{
|
||||
Name: "proposer-settings-file",
|
||||
|
||||
@@ -75,8 +75,6 @@ var appFlags = []cli.Flag{
|
||||
// Consensys' Web3Signer flags
|
||||
flags.Web3SignerURLFlag,
|
||||
flags.Web3SignerPublicValidatorKeysFlag,
|
||||
flags.FeeRecipientConfigFileFlag,
|
||||
flags.FeeRecipientConfigURLFlag,
|
||||
flags.SuggestedFeeRecipientFlag,
|
||||
flags.ProposerSettingsURLFlag,
|
||||
flags.ProposerSettingsFlag,
|
||||
|
||||
@@ -109,8 +109,6 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.EnableDutyCountDown,
|
||||
flags.Web3SignerURLFlag,
|
||||
flags.Web3SignerPublicValidatorKeysFlag,
|
||||
flags.FeeRecipientConfigFileFlag,
|
||||
flags.FeeRecipientConfigURLFlag,
|
||||
flags.ProposerSettingsFlag,
|
||||
flags.ProposerSettingsURLFlag,
|
||||
flags.SuggestedFeeRecipientFlag,
|
||||
|
||||
@@ -138,15 +138,18 @@ type BeaconChainConfig struct {
|
||||
SlashingProtectionPruningEpochs types.Epoch // SlashingProtectionPruningEpochs defines a period after which all prior epochs are pruned in the validator database.
|
||||
|
||||
// Fork-related values.
|
||||
GenesisForkVersion []byte `yaml:"GENESIS_FORK_VERSION" spec:"true"` // GenesisForkVersion is used to track fork version between state transitions.
|
||||
AltairForkVersion []byte `yaml:"ALTAIR_FORK_VERSION" spec:"true"` // AltairForkVersion is used to represent the fork version for altair.
|
||||
AltairForkEpoch types.Epoch `yaml:"ALTAIR_FORK_EPOCH" spec:"true"` // AltairForkEpoch is used to represent the assigned fork epoch for altair.
|
||||
BellatrixForkVersion []byte `yaml:"BELLATRIX_FORK_VERSION" spec:"true"` // BellatrixForkVersion is used to represent the fork version for bellatrix.
|
||||
BellatrixForkEpoch types.Epoch `yaml:"BELLATRIX_FORK_EPOCH" spec:"true"` // BellatrixForkEpoch is used to represent the assigned fork epoch for bellatrix.
|
||||
ShardingForkVersion []byte `yaml:"SHARDING_FORK_VERSION" spec:"true"` // ShardingForkVersion is used to represent the fork version for sharding.
|
||||
ShardingForkEpoch types.Epoch `yaml:"SHARDING_FORK_EPOCH" spec:"true"` // ShardingForkEpoch is used to represent the assigned fork epoch for sharding.
|
||||
ForkVersionSchedule map[[fieldparams.VersionLength]byte]types.Epoch // Schedule of fork epochs by version.
|
||||
ForkVersionNames map[[fieldparams.VersionLength]byte]string // Human-readable names of fork versions.
|
||||
GenesisForkVersion []byte `yaml:"GENESIS_FORK_VERSION" spec:"true"` // GenesisForkVersion is used to track fork version between state transitions.
|
||||
AltairForkVersion []byte `yaml:"ALTAIR_FORK_VERSION" spec:"true"` // AltairForkVersion is used to represent the fork version for altair.
|
||||
AltairForkEpoch types.Epoch `yaml:"ALTAIR_FORK_EPOCH" spec:"true"` // AltairForkEpoch is used to represent the assigned fork epoch for altair.
|
||||
BellatrixForkVersion []byte `yaml:"BELLATRIX_FORK_VERSION" spec:"true"` // BellatrixForkVersion is used to represent the fork version for bellatrix.
|
||||
BellatrixForkEpoch types.Epoch `yaml:"BELLATRIX_FORK_EPOCH" spec:"true"` // BellatrixForkEpoch is used to represent the assigned fork epoch for bellatrix.
|
||||
ShardingForkVersion []byte `yaml:"SHARDING_FORK_VERSION" spec:"true"` // ShardingForkVersion is used to represent the fork version for sharding.
|
||||
ShardingForkEpoch types.Epoch `yaml:"SHARDING_FORK_EPOCH" spec:"true"` // ShardingForkEpoch is used to represent the assigned fork epoch for sharding.
|
||||
CapellaForkVersion []byte `yaml:"CAPELLA_FORK_VERSION" spec:"true"` // CapellaForkVersion is used to represent the fork version for capella.
|
||||
CapellaForkEpoch types.Epoch `yaml:"CAPELLA_FORK_EPOCH" spec:"true"` // CapellaForkEpoch is used to represent the assigned fork epoch for capella.
|
||||
|
||||
ForkVersionSchedule map[[fieldparams.VersionLength]byte]types.Epoch // Schedule of fork epochs by version.
|
||||
ForkVersionNames map[[fieldparams.VersionLength]byte]string // Human-readable names of fork versions.
|
||||
|
||||
// Weak subjectivity values.
|
||||
SafetyDecay uint64 // SafetyDecay is defined as the loss in the 1/3 consensus safety margin of the casper FFG mechanism.
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var placeholderFields = []string{"UPDATE_TIMEOUT", "INTERVALS_PER_SLOT", "CAPELLA_FORK_VERSION", "CAPELLA_FORK_EPOCH"}
|
||||
var placeholderFields = []string{"UPDATE_TIMEOUT", "INTERVALS_PER_SLOT"}
|
||||
|
||||
func TestLoadConfigFile(t *testing.T) {
|
||||
// See https://media.githubusercontent.com/media/ethereum/consensus-spec-tests/master/tests/minimal/config/phase0.yaml
|
||||
|
||||
@@ -203,6 +203,8 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
AltairForkEpoch: mainnetAltairForkEpoch,
|
||||
BellatrixForkVersion: []byte{2, 0, 0, 0},
|
||||
BellatrixForkEpoch: mainnetBellatrixForkEpoch,
|
||||
CapellaForkVersion: []byte{3, 0, 0, 0},
|
||||
CapellaForkEpoch: math.MaxUint64,
|
||||
ShardingForkVersion: []byte{4, 0, 0, 0},
|
||||
ShardingForkEpoch: math.MaxUint64,
|
||||
|
||||
|
||||
@@ -84,6 +84,8 @@ func MinimalSpecConfig() *BeaconChainConfig {
|
||||
minimalConfig.AltairForkEpoch = math.MaxUint64
|
||||
minimalConfig.BellatrixForkVersion = []byte{2, 0, 0, 1}
|
||||
minimalConfig.BellatrixForkEpoch = math.MaxUint64
|
||||
minimalConfig.CapellaForkVersion = []byte{3, 0, 0, 1}
|
||||
minimalConfig.CapellaForkEpoch = math.MaxUint64
|
||||
minimalConfig.ShardingForkVersion = []byte{4, 0, 0, 1}
|
||||
minimalConfig.ShardingForkEpoch = math.MaxUint64
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["execution_payload.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/consensus-types/forks/bellatrix",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,130 +0,0 @@
|
||||
package bellatrix
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/ssz"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
)
|
||||
|
||||
// PayloadToHeader converts `payload` into execution payload header format.
|
||||
func PayloadToHeader(payload *enginev1.ExecutionPayload) (*enginev1.ExecutionPayloadHeader, error) {
|
||||
txRoot, err := ssz.TransactionsRoot(payload.Transactions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &enginev1.ExecutionPayloadHeader{
|
||||
ParentHash: bytesutil.SafeCopyBytes(payload.ParentHash),
|
||||
FeeRecipient: bytesutil.SafeCopyBytes(payload.FeeRecipient),
|
||||
StateRoot: bytesutil.SafeCopyBytes(payload.StateRoot),
|
||||
ReceiptsRoot: bytesutil.SafeCopyBytes(payload.ReceiptsRoot),
|
||||
LogsBloom: bytesutil.SafeCopyBytes(payload.LogsBloom),
|
||||
PrevRandao: bytesutil.SafeCopyBytes(payload.PrevRandao),
|
||||
BlockNumber: payload.BlockNumber,
|
||||
GasLimit: payload.GasLimit,
|
||||
GasUsed: payload.GasUsed,
|
||||
Timestamp: payload.Timestamp,
|
||||
ExtraData: bytesutil.SafeCopyBytes(payload.ExtraData),
|
||||
BaseFeePerGas: bytesutil.SafeCopyBytes(payload.BaseFeePerGas),
|
||||
BlockHash: bytesutil.SafeCopyBytes(payload.BlockHash),
|
||||
TransactionsRoot: txRoot[:],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func IsEmptyPayload(p *enginev1.ExecutionPayload) bool {
|
||||
if p == nil {
|
||||
return true
|
||||
}
|
||||
if !bytes.Equal(p.ParentHash, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.FeeRecipient, make([]byte, fieldparams.FeeRecipientLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.StateRoot, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.ReceiptsRoot, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.LogsBloom, make([]byte, fieldparams.LogsBloomLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.PrevRandao, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.BaseFeePerGas, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(p.BlockHash, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if len(p.Transactions) != 0 {
|
||||
return false
|
||||
}
|
||||
if len(p.ExtraData) != 0 {
|
||||
return false
|
||||
}
|
||||
if p.BlockNumber != 0 {
|
||||
return false
|
||||
}
|
||||
if p.GasLimit != 0 {
|
||||
return false
|
||||
}
|
||||
if p.GasUsed != 0 {
|
||||
return false
|
||||
}
|
||||
if p.Timestamp != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func IsEmptyHeader(h *enginev1.ExecutionPayloadHeader) bool {
|
||||
if !bytes.Equal(h.ParentHash, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.FeeRecipient, make([]byte, fieldparams.FeeRecipientLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.StateRoot, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.ReceiptsRoot, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.LogsBloom, make([]byte, fieldparams.LogsBloomLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.PrevRandao, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.BaseFeePerGas, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.BlockHash, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if !bytes.Equal(h.TransactionsRoot, make([]byte, fieldparams.RootLength)) {
|
||||
return false
|
||||
}
|
||||
if len(h.ExtraData) != 0 {
|
||||
return false
|
||||
}
|
||||
if h.BlockNumber != 0 {
|
||||
return false
|
||||
}
|
||||
if h.GasLimit != 0 {
|
||||
return false
|
||||
}
|
||||
if h.GasUsed != 0 {
|
||||
return false
|
||||
}
|
||||
if h.Timestamp != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -10,7 +10,6 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
||||
@@ -3,7 +3,6 @@ package interfaces
|
||||
import (
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -62,6 +61,30 @@ type BeaconBlockBody interface {
|
||||
IsNil() bool
|
||||
HashTreeRoot() ([32]byte, error)
|
||||
Proto() proto.Message
|
||||
ExecutionPayload() (*enginev1.ExecutionPayload, error)
|
||||
ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeader, error)
|
||||
Execution() (ExecutionData, error)
|
||||
}
|
||||
|
||||
// ExecutionData represents execution layer information that is contained
|
||||
// within post-Bellatrix beacon block bodies.
|
||||
type ExecutionData interface {
|
||||
ssz.Marshaler
|
||||
ssz.Unmarshaler
|
||||
ssz.HashRoot
|
||||
IsNil() bool
|
||||
Proto() proto.Message
|
||||
ParentHash() []byte
|
||||
FeeRecipient() []byte
|
||||
StateRoot() []byte
|
||||
ReceiptsRoot() []byte
|
||||
LogsBloom() []byte
|
||||
PrevRandao() []byte
|
||||
BlockNumber() uint64
|
||||
GasLimit() uint64
|
||||
GasUsed() uint64
|
||||
Timestamp() uint64
|
||||
ExtraData() []byte
|
||||
BaseFeePerGas() []byte
|
||||
BlockHash() []byte
|
||||
Transactions() ([][]byte, error)
|
||||
TransactionsRoot() ([]byte, error)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ go_library(
|
||||
deps = [
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -199,11 +198,7 @@ func (BeaconBlockBody) Proto() proto.Message {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (BeaconBlockBody) ExecutionPayload() (*enginev1.ExecutionPayload, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (BeaconBlockBody) ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeader, error) {
|
||||
func (BeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
|
||||
@@ -8,15 +8,18 @@ go_library(
|
||||
"beacon_block_bellatrix.go",
|
||||
"beacon_block_phase0.go",
|
||||
"blinded_beacon_block_bellatrix.go",
|
||||
"execution.go",
|
||||
"metadata.go",
|
||||
"mutator.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/consensus-types/wrapper",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//consensus-types/forks/bellatrix:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/metadata:go_default_library",
|
||||
@@ -37,11 +40,12 @@ go_test(
|
||||
"beacon_block_phase0_test.go",
|
||||
"beacon_block_test.go",
|
||||
"blinded_beacon_block_bellatrix_test.go",
|
||||
"execution_test.go",
|
||||
],
|
||||
deps = [
|
||||
":go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//consensus-types/forks/bellatrix:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/forks/bellatrix"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -158,7 +157,7 @@ func BuildSignedBeaconBlockFromExecutionPayload(
|
||||
return nil, err
|
||||
}
|
||||
b := blk.Block()
|
||||
payloadHeader, err := b.Body().ExecutionPayloadHeader()
|
||||
payloadHeader, err := b.Body().Execution()
|
||||
switch {
|
||||
case errors.Is(err, ErrUnsupportedField):
|
||||
return nil, errors.Wrap(err, "can only build signed beacon block from blinded format")
|
||||
@@ -218,7 +217,7 @@ func WrapSignedBlindedBeaconBlock(blk interfaces.SignedBeaconBlock) (interfaces.
|
||||
return blk, nil
|
||||
}
|
||||
b := blk.Block()
|
||||
payload, err := b.Body().ExecutionPayload()
|
||||
payload, err := b.Body().Execution()
|
||||
switch {
|
||||
case errors.Is(err, ErrUnsupportedField):
|
||||
return nil, ErrUnsupportedSignedBeaconBlock
|
||||
@@ -230,7 +229,7 @@ func WrapSignedBlindedBeaconBlock(blk interfaces.SignedBeaconBlock) (interfaces.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header, err := bellatrix.PayloadToHeader(payload)
|
||||
header, err := PayloadToHeader(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
@@ -313,12 +312,7 @@ func (w altairBeaconBlockBody) Proto() proto.Message {
|
||||
return w.b
|
||||
}
|
||||
|
||||
// ExecutionPayload is a stub.
|
||||
func (w altairBeaconBlockBody) ExecutionPayload() (*enginev1.ExecutionPayload, error) {
|
||||
// Execution is a stub.
|
||||
func (w altairBeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
|
||||
return nil, errors.Wrapf(ErrUnsupportedField, "ExecutionPayload for %T", w)
|
||||
}
|
||||
|
||||
// ExecutionPayloadHeader is a stub.
|
||||
func (w altairBeaconBlockBody) ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeader, error) {
|
||||
return nil, errors.Wrapf(ErrUnsupportedField, "ExecutionPayloadHeader for %T", w)
|
||||
}
|
||||
|
||||
@@ -351,6 +351,6 @@ func TestAltairBeaconBlock_ExecutionPayloadHeader(t *testing.T) {
|
||||
}
|
||||
wsb, err := wrapper.WrappedSignedBeaconBlock(sb)
|
||||
require.NoError(t, err)
|
||||
_, err = wsb.Block().Body().ExecutionPayloadHeader()
|
||||
_, err = wsb.Block().Body().Execution()
|
||||
require.ErrorContains(t, "unsupported field for block type", err)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
@@ -308,12 +307,7 @@ func (w bellatrixBeaconBlockBody) Proto() proto.Message {
|
||||
return w.b
|
||||
}
|
||||
|
||||
// ExecutionPayload returns the Execution payload of the block body.
|
||||
func (w bellatrixBeaconBlockBody) ExecutionPayload() (*enginev1.ExecutionPayload, error) {
|
||||
return w.b.ExecutionPayload, nil
|
||||
}
|
||||
|
||||
// ExecutionPayloadHeader is a stub.
|
||||
func (w bellatrixBeaconBlockBody) ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeader, error) {
|
||||
return nil, errors.Wrapf(ErrUnsupportedField, "ExecutionPayloadHeader for %T", w)
|
||||
// Execution returns the Execution payload of the block body.
|
||||
func (w bellatrixBeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
|
||||
return WrappedExecutionPayload(w.b.ExecutionPayload)
|
||||
}
|
||||
|
||||
@@ -352,9 +352,9 @@ func TestBellatrixBeaconBlockBody_ExecutionPayload(t *testing.T) {
|
||||
wbb, err := wrapper.WrappedBeaconBlockBody(body)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := wbb.ExecutionPayload()
|
||||
got, err := wbb.Execution()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, payloads, got)
|
||||
assert.DeepEqual(t, payloads, got.Proto())
|
||||
}
|
||||
|
||||
func TestBellatrixBeaconBlock_PbGenericBlock(t *testing.T) {
|
||||
@@ -392,10 +392,14 @@ func TestBellatrixBeaconBlock_PbBlindedBellatrixBlock(t *testing.T) {
|
||||
|
||||
func TestBellatrixBeaconBlock_ExecutionPayloadHeader(t *testing.T) {
|
||||
sb := ðpb.SignedBeaconBlockBellatrix{
|
||||
Block: ðpb.BeaconBlockBellatrix{Slot: 66},
|
||||
Block: ðpb.BeaconBlockBellatrix{Slot: 66, Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
ExecutionPayload: &enginev1.ExecutionPayload{},
|
||||
}},
|
||||
}
|
||||
wsb, err := wrapper.WrappedSignedBeaconBlock(sb)
|
||||
require.NoError(t, err)
|
||||
_, err = wsb.Block().Body().ExecutionPayloadHeader()
|
||||
exec, err := wsb.Block().Body().Execution()
|
||||
require.NoError(t, err)
|
||||
_, err = exec.TransactionsRoot()
|
||||
require.ErrorContains(t, "unsupported field for block type", err)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
@@ -301,12 +300,7 @@ func (w Phase0BeaconBlockBody) Proto() proto.Message {
|
||||
return w.b
|
||||
}
|
||||
|
||||
// ExecutionPayload is a stub.
|
||||
func (w Phase0BeaconBlockBody) ExecutionPayload() (*enginev1.ExecutionPayload, error) {
|
||||
// Execution is a stub.
|
||||
func (w Phase0BeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
|
||||
return nil, errors.Wrapf(ErrUnsupportedField, "ExecutionPayload for %T", w)
|
||||
}
|
||||
|
||||
// ExecutionPayloadHeader is a stub.
|
||||
func (w Phase0BeaconBlockBody) ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeader, error) {
|
||||
return nil, errors.Wrapf(ErrUnsupportedField, "ExecutionPayloadHeader for %T", w)
|
||||
}
|
||||
|
||||
@@ -82,6 +82,6 @@ func TestPhase0BeaconBlock_ExecutionPayloadHeader(t *testing.T) {
|
||||
}
|
||||
wsb, err := wrapper.WrappedSignedBeaconBlock(sb)
|
||||
require.NoError(t, err)
|
||||
_, err = wsb.Block().Body().ExecutionPayloadHeader()
|
||||
_, err = wsb.Block().Body().Execution()
|
||||
require.ErrorContains(t, "unsupported field for block type", err)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/forks/bellatrix"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
@@ -36,7 +35,9 @@ func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) {
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
}
|
||||
header, err := bellatrix.PayloadToHeader(payload)
|
||||
wrapped, err := wrapper.WrappedExecutionPayload(payload)
|
||||
require.NoError(t, err)
|
||||
header, err := wrapper.PayloadToHeader(wrapped)
|
||||
require.NoError(t, err)
|
||||
blindedBlock := util.NewBlindedBeaconBlockBellatrix()
|
||||
|
||||
@@ -61,7 +62,9 @@ func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) {
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
}
|
||||
header, err := bellatrix.PayloadToHeader(payload)
|
||||
wrapped, err := wrapper.WrappedExecutionPayload(payload)
|
||||
require.NoError(t, err)
|
||||
header, err := wrapper.PayloadToHeader(wrapped)
|
||||
require.NoError(t, err)
|
||||
blindedBlock := util.NewBlindedBeaconBlockBellatrix()
|
||||
blindedBlock.Block.Body.ExecutionPayloadHeader = header
|
||||
@@ -71,9 +74,9 @@ func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) {
|
||||
builtBlock, err := wrapper.BuildSignedBeaconBlockFromExecutionPayload(blk, payload)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := builtBlock.Block().Body().ExecutionPayload()
|
||||
got, err := builtBlock.Block().Body().Execution()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, payload, got)
|
||||
require.DeepEqual(t, payload, got.Proto())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -104,7 +107,9 @@ func TestWrapSignedBlindedBeaconBlock(t *testing.T) {
|
||||
bellatrixBlk := util.NewBeaconBlockBellatrix()
|
||||
bellatrixBlk.Block.Body.ExecutionPayload = payload
|
||||
|
||||
want, err := bellatrix.PayloadToHeader(payload)
|
||||
wrapped, err := wrapper.WrappedExecutionPayload(payload)
|
||||
require.NoError(t, err)
|
||||
want, err := wrapper.PayloadToHeader(wrapped)
|
||||
require.NoError(t, err)
|
||||
|
||||
blk, err := wrapper.WrappedSignedBeaconBlock(bellatrixBlk)
|
||||
@@ -112,9 +117,9 @@ func TestWrapSignedBlindedBeaconBlock(t *testing.T) {
|
||||
builtBlock, err := wrapper.WrapSignedBlindedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := builtBlock.Block().Body().ExecutionPayloadHeader()
|
||||
got, err := builtBlock.Block().Body().Execution()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, got)
|
||||
require.DeepEqual(t, want, got.Proto())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
@@ -309,12 +308,6 @@ func (w blindedBeaconBlockBodyBellatrix) Proto() proto.Message {
|
||||
return w.b
|
||||
}
|
||||
|
||||
// ExecutionPayload returns the execution payload of the block body.
|
||||
func (w blindedBeaconBlockBodyBellatrix) ExecutionPayload() (*enginev1.ExecutionPayload, error) {
|
||||
return nil, errors.Wrapf(ErrUnsupportedField, "ExecutionPayload for %T", w)
|
||||
}
|
||||
|
||||
// ExecutionPayloadHeader returns the execution payload header of the block body.
|
||||
func (w blindedBeaconBlockBodyBellatrix) ExecutionPayloadHeader() (*enginev1.ExecutionPayloadHeader, error) {
|
||||
return w.b.ExecutionPayloadHeader, nil
|
||||
func (w blindedBeaconBlockBodyBellatrix) Execution() (interfaces.ExecutionData, error) {
|
||||
return WrappedExecutionPayloadHeader(w.b.ExecutionPayloadHeader)
|
||||
}
|
||||
|
||||
@@ -365,7 +365,9 @@ func TestBellatrixBlindedBeaconBlockBody_ExecutionPayloadHeader(t *testing.T) {
|
||||
wbb, err := wrapper.WrappedBeaconBlockBody(body)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = wbb.ExecutionPayload()
|
||||
exec, err := wbb.Execution()
|
||||
require.NoError(t, err)
|
||||
_, err = exec.Transactions()
|
||||
require.ErrorContains(t, wrapper.ErrUnsupportedField.Error(), err)
|
||||
}
|
||||
|
||||
|
||||
371
consensus-types/wrapper/execution.go
Normal file
371
consensus-types/wrapper/execution.go
Normal file
@@ -0,0 +1,371 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
fastssz "github.com/prysmaticlabs/fastssz"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/ssz"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// executionPayload is a convenience wrapper around a beacon block body's execution payload data structure
|
||||
// This wrapper allows us to conform to a common interface so that beacon
|
||||
// blocks for future forks can also be applied across Prysm without issues.
|
||||
type executionPayload struct {
|
||||
p *enginev1.ExecutionPayload
|
||||
}
|
||||
|
||||
// WrappedExecutionPayload is a constructor which wraps a protobuf execution payload into an interface.
|
||||
func WrappedExecutionPayload(p *enginev1.ExecutionPayload) (interfaces.ExecutionData, error) {
|
||||
w := executionPayload{p: p}
|
||||
if w.IsNil() {
|
||||
return nil, ErrNilObjectWrapped
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// IsNil checks if the underlying data is nil.
|
||||
func (e executionPayload) IsNil() bool {
|
||||
return e.p == nil
|
||||
}
|
||||
|
||||
// MarshalSSZ --
|
||||
func (e executionPayload) MarshalSSZ() ([]byte, error) {
|
||||
return e.p.MarshalSSZ()
|
||||
}
|
||||
|
||||
// MarshalSSZTo --
|
||||
func (e executionPayload) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
return e.p.MarshalSSZTo(dst)
|
||||
}
|
||||
|
||||
// SizeSSZ --
|
||||
func (e executionPayload) SizeSSZ() int {
|
||||
return e.p.SizeSSZ()
|
||||
}
|
||||
|
||||
// UnmarshalSSZ --
|
||||
func (e executionPayload) UnmarshalSSZ(buf []byte) error {
|
||||
return e.p.UnmarshalSSZ(buf)
|
||||
}
|
||||
|
||||
// HashTreeRoot --
|
||||
func (e executionPayload) HashTreeRoot() ([32]byte, error) {
|
||||
return e.p.HashTreeRoot()
|
||||
}
|
||||
|
||||
// HashTreeRootWith --
|
||||
func (e executionPayload) HashTreeRootWith(hh *fastssz.Hasher) error {
|
||||
return e.p.HashTreeRootWith(hh)
|
||||
}
|
||||
|
||||
// Proto --
|
||||
func (e executionPayload) Proto() proto.Message {
|
||||
return e.p
|
||||
}
|
||||
|
||||
// ParentHash --
|
||||
func (e executionPayload) ParentHash() []byte {
|
||||
return e.p.ParentHash
|
||||
}
|
||||
|
||||
// FeeRecipient --
|
||||
func (e executionPayload) FeeRecipient() []byte {
|
||||
return e.p.FeeRecipient
|
||||
}
|
||||
|
||||
// StateRoot --
|
||||
func (e executionPayload) StateRoot() []byte {
|
||||
return e.p.StateRoot
|
||||
}
|
||||
|
||||
// ReceiptsRoot --
|
||||
func (e executionPayload) ReceiptsRoot() []byte {
|
||||
return e.p.ReceiptsRoot
|
||||
}
|
||||
|
||||
// LogsBloom --
|
||||
func (e executionPayload) LogsBloom() []byte {
|
||||
return e.p.LogsBloom
|
||||
}
|
||||
|
||||
// PrevRandao --
|
||||
func (e executionPayload) PrevRandao() []byte {
|
||||
return e.p.PrevRandao
|
||||
}
|
||||
|
||||
// BlockNumber --
|
||||
func (e executionPayload) BlockNumber() uint64 {
|
||||
return e.p.BlockNumber
|
||||
}
|
||||
|
||||
// GasLimit --
|
||||
func (e executionPayload) GasLimit() uint64 {
|
||||
return e.p.GasLimit
|
||||
}
|
||||
|
||||
// GasUsed --
|
||||
func (e executionPayload) GasUsed() uint64 {
|
||||
return e.p.GasUsed
|
||||
}
|
||||
|
||||
// Timestamp --
|
||||
func (e executionPayload) Timestamp() uint64 {
|
||||
return e.p.Timestamp
|
||||
}
|
||||
|
||||
// ExtraData --
|
||||
func (e executionPayload) ExtraData() []byte {
|
||||
return e.p.ExtraData
|
||||
}
|
||||
|
||||
// BaseFeePerGas --
|
||||
func (e executionPayload) BaseFeePerGas() []byte {
|
||||
return e.p.BaseFeePerGas
|
||||
}
|
||||
|
||||
// BlockHash --
|
||||
func (e executionPayload) BlockHash() []byte {
|
||||
return e.p.BlockHash
|
||||
}
|
||||
|
||||
// Transactions --
|
||||
func (e executionPayload) Transactions() ([][]byte, error) {
|
||||
return e.p.Transactions, nil
|
||||
}
|
||||
|
||||
// TransactionsRoot --
|
||||
func (executionPayload) TransactionsRoot() ([]byte, error) {
|
||||
return nil, ErrUnsupportedField
|
||||
}
|
||||
|
||||
// executionPayloadHeader is a convenience wrapper around a blinded beacon block body's execution header data structure
|
||||
// This wrapper allows us to conform to a common interface so that beacon
|
||||
// blocks for future forks can also be applied across Prysm without issues.
|
||||
type executionPayloadHeader struct {
|
||||
p *enginev1.ExecutionPayloadHeader
|
||||
}
|
||||
|
||||
// WrappedExecutionPayloadHeader is a constructor which wraps a protobuf execution header into an interface.
|
||||
func WrappedExecutionPayloadHeader(p *enginev1.ExecutionPayloadHeader) (interfaces.ExecutionData, error) {
|
||||
w := executionPayloadHeader{p: p}
|
||||
if w.IsNil() {
|
||||
return nil, ErrNilObjectWrapped
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// IsNil checks if the underlying data is nil.
|
||||
func (e executionPayloadHeader) IsNil() bool {
|
||||
return e.p == nil
|
||||
}
|
||||
|
||||
// MarshalSSZ --
|
||||
func (e executionPayloadHeader) MarshalSSZ() ([]byte, error) {
|
||||
return e.p.MarshalSSZ()
|
||||
}
|
||||
|
||||
// MarshalSSZTo --
|
||||
func (e executionPayloadHeader) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
return e.p.MarshalSSZTo(dst)
|
||||
}
|
||||
|
||||
// SizeSSZ --
|
||||
func (e executionPayloadHeader) SizeSSZ() int {
|
||||
return e.p.SizeSSZ()
|
||||
}
|
||||
|
||||
// UnmarshalSSZ --
|
||||
func (e executionPayloadHeader) UnmarshalSSZ(buf []byte) error {
|
||||
return e.p.UnmarshalSSZ(buf)
|
||||
}
|
||||
|
||||
// HashTreeRoot --
|
||||
func (e executionPayloadHeader) HashTreeRoot() ([32]byte, error) {
|
||||
return e.p.HashTreeRoot()
|
||||
}
|
||||
|
||||
// HashTreeRootWith --
|
||||
func (e executionPayloadHeader) HashTreeRootWith(hh *fastssz.Hasher) error {
|
||||
return e.p.HashTreeRootWith(hh)
|
||||
}
|
||||
|
||||
// Proto --
|
||||
func (e executionPayloadHeader) Proto() proto.Message {
|
||||
return e.p
|
||||
}
|
||||
|
||||
// ParentHash --
|
||||
func (e executionPayloadHeader) ParentHash() []byte {
|
||||
return e.p.ParentHash
|
||||
}
|
||||
|
||||
// FeeRecipient --
|
||||
func (e executionPayloadHeader) FeeRecipient() []byte {
|
||||
return e.p.FeeRecipient
|
||||
}
|
||||
|
||||
// StateRoot --
|
||||
func (e executionPayloadHeader) StateRoot() []byte {
|
||||
return e.p.StateRoot
|
||||
}
|
||||
|
||||
// ReceiptsRoot --
|
||||
func (e executionPayloadHeader) ReceiptsRoot() []byte {
|
||||
return e.p.ReceiptsRoot
|
||||
}
|
||||
|
||||
// LogsBloom --
|
||||
func (e executionPayloadHeader) LogsBloom() []byte {
|
||||
return e.p.LogsBloom
|
||||
}
|
||||
|
||||
// PrevRandao --
|
||||
func (e executionPayloadHeader) PrevRandao() []byte {
|
||||
return e.p.PrevRandao
|
||||
}
|
||||
|
||||
// BlockNumber --
|
||||
func (e executionPayloadHeader) BlockNumber() uint64 {
|
||||
return e.p.BlockNumber
|
||||
}
|
||||
|
||||
// GasLimit --
|
||||
func (e executionPayloadHeader) GasLimit() uint64 {
|
||||
return e.p.GasLimit
|
||||
}
|
||||
|
||||
// GasUsed --
|
||||
func (e executionPayloadHeader) GasUsed() uint64 {
|
||||
return e.p.GasUsed
|
||||
}
|
||||
|
||||
// Timestamp --
|
||||
func (e executionPayloadHeader) Timestamp() uint64 {
|
||||
return e.p.Timestamp
|
||||
}
|
||||
|
||||
// ExtraData --
|
||||
func (e executionPayloadHeader) ExtraData() []byte {
|
||||
return e.p.ExtraData
|
||||
}
|
||||
|
||||
// BaseFeePerGas --
|
||||
func (e executionPayloadHeader) BaseFeePerGas() []byte {
|
||||
return e.p.BaseFeePerGas
|
||||
}
|
||||
|
||||
// BlockHash --
|
||||
func (e executionPayloadHeader) BlockHash() []byte {
|
||||
return e.p.BlockHash
|
||||
}
|
||||
|
||||
// Transactions --
|
||||
func (executionPayloadHeader) Transactions() ([][]byte, error) {
|
||||
return nil, ErrUnsupportedField
|
||||
}
|
||||
|
||||
// TransactionsRoot --
|
||||
func (e executionPayloadHeader) TransactionsRoot() ([]byte, error) {
|
||||
return e.p.TransactionsRoot, nil
|
||||
}
|
||||
|
||||
// PayloadToHeader converts `payload` into execution payload header format.
|
||||
func PayloadToHeader(payload interfaces.ExecutionData) (*enginev1.ExecutionPayloadHeader, error) {
|
||||
txs, err := payload.Transactions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txRoot, err := ssz.TransactionsRoot(txs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &enginev1.ExecutionPayloadHeader{
|
||||
ParentHash: bytesutil.SafeCopyBytes(payload.ParentHash()),
|
||||
FeeRecipient: bytesutil.SafeCopyBytes(payload.FeeRecipient()),
|
||||
StateRoot: bytesutil.SafeCopyBytes(payload.StateRoot()),
|
||||
ReceiptsRoot: bytesutil.SafeCopyBytes(payload.ReceiptsRoot()),
|
||||
LogsBloom: bytesutil.SafeCopyBytes(payload.LogsBloom()),
|
||||
PrevRandao: bytesutil.SafeCopyBytes(payload.PrevRandao()),
|
||||
BlockNumber: payload.BlockNumber(),
|
||||
GasLimit: payload.GasLimit(),
|
||||
GasUsed: payload.GasUsed(),
|
||||
Timestamp: payload.Timestamp(),
|
||||
ExtraData: bytesutil.SafeCopyBytes(payload.ExtraData()),
|
||||
BaseFeePerGas: bytesutil.SafeCopyBytes(payload.BaseFeePerGas()),
|
||||
BlockHash: bytesutil.SafeCopyBytes(payload.BlockHash()),
|
||||
TransactionsRoot: txRoot[:],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IsEmptyExecutionData checks if an execution data is empty underneath. If a single field has
|
||||
// a non-zero value, this function will return false.
|
||||
func IsEmptyExecutionData(data interfaces.ExecutionData) (bool, error) {
|
||||
if !bytes.Equal(data.ParentHash(), make([]byte, fieldparams.RootLength)) {
|
||||
return false, nil
|
||||
}
|
||||
if !bytes.Equal(data.FeeRecipient(), make([]byte, fieldparams.FeeRecipientLength)) {
|
||||
return false, nil
|
||||
}
|
||||
if !bytes.Equal(data.StateRoot(), make([]byte, fieldparams.RootLength)) {
|
||||
return false, nil
|
||||
}
|
||||
if !bytes.Equal(data.ReceiptsRoot(), make([]byte, fieldparams.RootLength)) {
|
||||
return false, nil
|
||||
}
|
||||
if !bytes.Equal(data.LogsBloom(), make([]byte, fieldparams.LogsBloomLength)) {
|
||||
return false, nil
|
||||
}
|
||||
if !bytes.Equal(data.PrevRandao(), make([]byte, fieldparams.RootLength)) {
|
||||
return false, nil
|
||||
}
|
||||
if !bytes.Equal(data.BaseFeePerGas(), make([]byte, fieldparams.RootLength)) {
|
||||
return false, nil
|
||||
}
|
||||
if !bytes.Equal(data.BlockHash(), make([]byte, fieldparams.RootLength)) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
txs, err := data.Transactions()
|
||||
switch {
|
||||
case errors.Is(err, ErrUnsupportedField):
|
||||
case err != nil:
|
||||
return false, err
|
||||
default:
|
||||
if len(txs) != 0 {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
txsRoot, err := data.TransactionsRoot()
|
||||
switch {
|
||||
case errors.Is(err, ErrUnsupportedField):
|
||||
case err != nil:
|
||||
return false, err
|
||||
default:
|
||||
if !bytes.Equal(txsRoot, make([]byte, fieldparams.RootLength)) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
if len(data.ExtraData()) != 0 {
|
||||
return false, nil
|
||||
}
|
||||
if data.BlockNumber() != 0 {
|
||||
return false, nil
|
||||
}
|
||||
if data.GasLimit() != 0 {
|
||||
return false, nil
|
||||
}
|
||||
if data.GasUsed() != 0 {
|
||||
return false, nil
|
||||
}
|
||||
if data.Timestamp() != 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
124
consensus-types/wrapper/execution_test.go
Normal file
124
consensus-types/wrapper/execution_test.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package wrapper_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestWrapExecutionPayload(t *testing.T) {
|
||||
data := &enginev1.ExecutionPayload{GasUsed: 54}
|
||||
wsb, err := wrapper.WrappedExecutionPayload(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(t, data, wsb.Proto())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadHeader(t *testing.T) {
|
||||
data := &enginev1.ExecutionPayloadHeader{GasUsed: 54}
|
||||
wsb, err := wrapper.WrappedExecutionPayloadHeader(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(t, data, wsb.Proto())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayload_IsNil(t *testing.T) {
|
||||
_, err := wrapper.WrappedExecutionPayload(nil)
|
||||
require.Equal(t, wrapper.ErrNilObjectWrapped, err)
|
||||
|
||||
data := &enginev1.ExecutionPayload{GasUsed: 54}
|
||||
wsb, err := wrapper.WrappedExecutionPayload(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, false, wsb.IsNil())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadHeader_IsNil(t *testing.T) {
|
||||
_, err := wrapper.WrappedExecutionPayloadHeader(nil)
|
||||
require.Equal(t, wrapper.ErrNilObjectWrapped, err)
|
||||
|
||||
data := &enginev1.ExecutionPayloadHeader{GasUsed: 54}
|
||||
wsb, err := wrapper.WrappedExecutionPayloadHeader(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, false, wsb.IsNil())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayload_SSZ(t *testing.T) {
|
||||
wsb := createWrappedPayload(t)
|
||||
rt, err := wsb.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, rt)
|
||||
|
||||
var b []byte
|
||||
b, err = wsb.MarshalSSZTo(b)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, len(b))
|
||||
encoded, err := wsb.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, wsb.SizeSSZ())
|
||||
assert.NoError(t, wsb.UnmarshalSSZ(encoded))
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadHeader_SSZ(t *testing.T) {
|
||||
wsb := createWrappedPayloadHeader(t)
|
||||
rt, err := wsb.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, rt)
|
||||
|
||||
var b []byte
|
||||
b, err = wsb.MarshalSSZTo(b)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, len(b))
|
||||
encoded, err := wsb.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, wsb.SizeSSZ())
|
||||
assert.NoError(t, wsb.UnmarshalSSZ(encoded))
|
||||
}
|
||||
|
||||
func createWrappedPayload(t testing.TB) interfaces.ExecutionData {
|
||||
wsb, err := wrapper.WrappedExecutionPayload(&enginev1.ExecutionPayload{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
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),
|
||||
BlockNumber: 0,
|
||||
GasLimit: 0,
|
||||
GasUsed: 0,
|
||||
Timestamp: 0,
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return wsb
|
||||
}
|
||||
|
||||
func createWrappedPayloadHeader(t testing.TB) interfaces.ExecutionData {
|
||||
wsb, err := wrapper.WrappedExecutionPayloadHeader(&enginev1.ExecutionPayloadHeader{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
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),
|
||||
BlockNumber: 0,
|
||||
GasLimit: 0,
|
||||
GasUsed: 0,
|
||||
Timestamp: 0,
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return wsb
|
||||
}
|
||||
@@ -5,6 +5,42 @@ load("@prysm//tools/go:def.bzl", "go_test")
|
||||
# gazelle:exclude mainnet_scenario_e2e_test.go
|
||||
# gazelle:exclude minimal_scenario_e2e_test.go
|
||||
|
||||
# Presubmit tests represent the group of endtoend tests that are run on pull
|
||||
# requests and must be passing before a pull request can merge.
|
||||
test_suite(
|
||||
name = "presubmit",
|
||||
tags = [
|
||||
"manual",
|
||||
],
|
||||
tests = [
|
||||
":go_default_test",
|
||||
],
|
||||
)
|
||||
|
||||
# Postsubmit tests represent the group of endtoend tests that are run after a
|
||||
# pull request has merged.
|
||||
test_suite(
|
||||
name = "postsubmit",
|
||||
tags = [
|
||||
"manual",
|
||||
],
|
||||
tests = [
|
||||
":go_mainnet_test",
|
||||
],
|
||||
)
|
||||
|
||||
# Scenario tests are run infrequently in CI to test specific scenarios.
|
||||
test_suite(
|
||||
name = "scenario_tests",
|
||||
tags = [
|
||||
"manual",
|
||||
],
|
||||
tests = [
|
||||
":go_mainnet_scenario_test",
|
||||
":go_minimal_scenario_test",
|
||||
],
|
||||
)
|
||||
|
||||
common_deps = [
|
||||
"//api/client/beacon:go_default_library",
|
||||
"//beacon-chain/blockchain/testing:go_default_library",
|
||||
|
||||
@@ -73,7 +73,7 @@ func (s *BeaconNodeSet) Start(ctx context.Context) error {
|
||||
}
|
||||
s.config.PeerIDs = s.ids
|
||||
}
|
||||
// All nodes stated, close channel, so that all services waiting on a set, can proceed.
|
||||
// All nodes started, close channel, so that all services waiting on a set, can proceed.
|
||||
close(s.started)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -34,11 +34,9 @@ func NewProxySet() *ProxySet {
|
||||
|
||||
// Start starts all the proxies in set.
|
||||
func (s *ProxySet) Start(ctx context.Context) error {
|
||||
|
||||
totalNodeCount := e2e.TestParams.BeaconNodeCount + e2e.TestParams.LighthouseBeaconNodeCount
|
||||
nodes := make([]e2etypes.ComponentRunner, totalNodeCount)
|
||||
for i := 0; i < totalNodeCount; i++ {
|
||||
// We start indexing nodes from 1 because the miner has an implicit 0 index.
|
||||
nodes[i] = NewProxy(i)
|
||||
}
|
||||
s.proxies = nodes
|
||||
|
||||
@@ -63,7 +63,7 @@ func (s *LighthouseBeaconNodeSet) Start(ctx context.Context) error {
|
||||
// Wait for all nodes to finish their job (blocking).
|
||||
// Once nodes are ready passed in handler function will be called.
|
||||
return helpers.WaitOnNodes(ctx, nodes, func() {
|
||||
// All nodes stated, close channel, so that all services waiting on a set, can proceed.
|
||||
// All nodes started, close channel, so that all services waiting on a set, can proceed.
|
||||
close(s.started)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (s *LighthouseValidatorNodeSet) Start(ctx context.Context) error {
|
||||
// Wait for all nodes to finish their job (blocking).
|
||||
// Once nodes are ready passed in handler function will be called.
|
||||
return helpers.WaitOnNodes(ctx, nodes, func() {
|
||||
// All nodes stated, close channel, so that all services waiting on a set, can proceed.
|
||||
// All nodes started, close channel, so that all services waiting on a set, can proceed.
|
||||
close(s.started)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func (s *ValidatorNodeSet) Start(ctx context.Context) error {
|
||||
// Wait for all nodes to finish their job (blocking).
|
||||
// Once nodes are ready passed in handler function will be called.
|
||||
return helpers.WaitOnNodes(ctx, nodes, func() {
|
||||
// All nodes stated, close channel, so that all services waiting on a set, can proceed.
|
||||
// All nodes started, close channel, so that all services waiting on a set, can proceed.
|
||||
close(s.started)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func (m *engineMock) GetPayload(context.Context, [8]byte) (*pb.ExecutionPayload,
|
||||
func (m *engineMock) ForkchoiceUpdated(context.Context, *pb.ForkchoiceState, *pb.PayloadAttributes) (*pb.PayloadIDBytes, []byte, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
func (m *engineMock) NewPayload(context.Context, *pb.ExecutionPayload) ([]byte, error) {
|
||||
func (m *engineMock) NewPayload(context.Context, interfaces.ExecutionData) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ go_library(
|
||||
],
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//validator/accounts/iface:go_default_library",
|
||||
"//validator/client/iface:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/iface"
|
||||
iface2 "github.com/prysmaticlabs/prysm/validator/client/iface"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
@@ -190,3 +191,8 @@ func (_ MockValidator) PushProposerSettings(_ context.Context, _ keymanager.IKey
|
||||
func (_ MockValidator) SetPubKeyToValidatorIndexMap(_ context.Context, _ keymanager.IKeymanager) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// SignValidatorRegistrationRequest for mocking
|
||||
func (_ MockValidator) SignValidatorRegistrationRequest(_ context.Context, _ iface2.SigningFunc, _ *ethpb.ValidatorRegistrationV1) (*ethpb.SignedValidatorRegistrationV1, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ go_library(
|
||||
deps = [
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -7,6 +7,9 @@ import (
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/crypto/bls"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
)
|
||||
|
||||
@@ -59,4 +62,8 @@ type Validator interface {
|
||||
HandleKeyReload(ctx context.Context, newKeys [][fieldparams.BLSPubkeyLength]byte) (bool, error)
|
||||
CheckDoppelGanger(ctx context.Context) error
|
||||
PushProposerSettings(ctx context.Context, km keymanager.IKeymanager) error
|
||||
SignValidatorRegistrationRequest(ctx context.Context, signer SigningFunc, newValidatorRegistration *ethpb.ValidatorRegistrationV1) (*ethpb.SignedValidatorRegistrationV1, error)
|
||||
}
|
||||
|
||||
// SigningFunc interface defines a type for the a function that signs a message
|
||||
type SigningFunc func(context.Context, *validatorpb.SignRequest) (bls.Signature, error)
|
||||
|
||||
@@ -27,8 +27,6 @@ import (
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
type signingFunc func(context.Context, *validatorpb.SignRequest) (bls.Signature, error)
|
||||
|
||||
const domainDataErr = "could not get domain data"
|
||||
const signingRootErr = "could not get signing root"
|
||||
const signExitErr = "could not sign voluntary exit proposal"
|
||||
@@ -147,19 +145,24 @@ func (v *validator) ProposeBlock(ctx context.Context, slot types.Slot, pubKey [f
|
||||
)
|
||||
|
||||
if blk.Version() == version.Bellatrix {
|
||||
p, err := blk.Block().Body().ExecutionPayload()
|
||||
p, err := blk.Block().Body().Execution()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get execution payload")
|
||||
return
|
||||
}
|
||||
txs, err := p.Transactions()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get execution payload transactions")
|
||||
return
|
||||
}
|
||||
log = log.WithFields(logrus.Fields{
|
||||
"payloadHash": fmt.Sprintf("%#x", bytesutil.Trunc(p.BlockHash)),
|
||||
"parentHash": fmt.Sprintf("%#x", bytesutil.Trunc(p.ParentHash)),
|
||||
"payloadHash": fmt.Sprintf("%#x", bytesutil.Trunc(p.BlockHash())),
|
||||
"parentHash": fmt.Sprintf("%#x", bytesutil.Trunc(p.ParentHash())),
|
||||
"blockNumber": p.BlockNumber,
|
||||
"txCount": len(p.Transactions),
|
||||
"txCount": len(txs),
|
||||
})
|
||||
if p.GasLimit != 0 {
|
||||
log = log.WithField("gasUtilized", float64(p.GasUsed)/float64(p.GasLimit))
|
||||
if p.GasLimit() != 0 {
|
||||
log = log.WithField("gasUtilized", float64(p.GasUsed())/float64(p.GasLimit()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +187,7 @@ func ProposeExit(
|
||||
ctx context.Context,
|
||||
validatorClient ethpb.BeaconNodeValidatorClient,
|
||||
nodeClient ethpb.NodeClient,
|
||||
signer signingFunc,
|
||||
signer iface.SigningFunc,
|
||||
pubKey []byte,
|
||||
) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.ProposeExit")
|
||||
@@ -281,7 +284,7 @@ func (v *validator) signBlock(ctx context.Context, pubKey [fieldparams.BLSPubkey
|
||||
func signVoluntaryExit(
|
||||
ctx context.Context,
|
||||
validatorClient ethpb.BeaconNodeValidatorClient,
|
||||
signer signingFunc,
|
||||
signer iface.SigningFunc,
|
||||
pubKey []byte,
|
||||
exit *ethpb.VoluntaryExit,
|
||||
) ([]byte, error) {
|
||||
|
||||
@@ -3,11 +3,14 @@ package client
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/validator/client/iface"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -15,40 +18,26 @@ import (
|
||||
func SubmitValidatorRegistration(
|
||||
ctx context.Context,
|
||||
validatorClient ethpb.BeaconNodeValidatorClient,
|
||||
signer signingFunc,
|
||||
regs []*ethpb.ValidatorRegistrationV1,
|
||||
signedRegs []*ethpb.SignedValidatorRegistrationV1,
|
||||
) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.SubmitBuilderValidatorRegistration")
|
||||
defer span.End()
|
||||
|
||||
if len(regs) == 0 {
|
||||
if len(signedRegs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
signedRegs := make([]*ethpb.SignedValidatorRegistrationV1, len(regs))
|
||||
for i, reg := range regs {
|
||||
sig, err := signValidatorRegistration(ctx, signer, reg)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("failed to sign builder validator registration obj")
|
||||
continue
|
||||
}
|
||||
signedRegs[i] = ðpb.SignedValidatorRegistrationV1{
|
||||
Message: reg,
|
||||
Signature: sig,
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := validatorClient.SubmitValidatorRegistration(ctx, ðpb.SignedValidatorRegistrationsV1{
|
||||
Messages: signedRegs,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "could not submit signed registrations to beacon node")
|
||||
}
|
||||
|
||||
log.Infoln("Submitted builder validator registration settings for custom builders")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sings validator registration obj with the proposer domain and private key.
|
||||
func signValidatorRegistration(ctx context.Context, signer signingFunc, reg *ethpb.ValidatorRegistrationV1) ([]byte, error) {
|
||||
func signValidatorRegistration(ctx context.Context, signer iface.SigningFunc, reg *ethpb.ValidatorRegistrationV1) ([]byte, error) {
|
||||
|
||||
// Per spec, we want the fork version and genesis validator to be nil.
|
||||
// Which is genesis value and zero by default.
|
||||
@@ -72,7 +61,38 @@ func signValidatorRegistration(ctx context.Context, signer signingFunc, reg *eth
|
||||
Object: &validatorpb.SignRequest_Registration{Registration: reg},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, signExitErr)
|
||||
return nil, errors.Wrap(err, "could not sign validator registration")
|
||||
}
|
||||
return sig.Marshal(), nil
|
||||
}
|
||||
|
||||
// SignValidatorRegistrationRequest compares and returns either the cached validator registration request or signs a new one.
|
||||
func (v *validator) SignValidatorRegistrationRequest(ctx context.Context, signer iface.SigningFunc, newValidatorRegistration *ethpb.ValidatorRegistrationV1) (*ethpb.SignedValidatorRegistrationV1, error) {
|
||||
signedReg, ok := v.signedValidatorRegistrations[bytesutil.ToBytes48(newValidatorRegistration.Pubkey)]
|
||||
if ok && isValidatorRegistrationSame(signedReg.Message, newValidatorRegistration) {
|
||||
return signedReg, nil
|
||||
} else {
|
||||
sig, err := signValidatorRegistration(ctx, signer, newValidatorRegistration)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("failed to sign builder validator registration obj")
|
||||
return nil, err
|
||||
}
|
||||
newRequest := ðpb.SignedValidatorRegistrationV1{
|
||||
Message: newValidatorRegistration,
|
||||
Signature: sig,
|
||||
}
|
||||
v.signedValidatorRegistrations[bytesutil.ToBytes48(newValidatorRegistration.Pubkey)] = newRequest
|
||||
return newRequest, nil
|
||||
}
|
||||
}
|
||||
|
||||
func isValidatorRegistrationSame(cachedVR *ethpb.ValidatorRegistrationV1, newVR *ethpb.ValidatorRegistrationV1) bool {
|
||||
isSame := true
|
||||
if cachedVR.GasLimit != newVR.GasLimit {
|
||||
isSame = false
|
||||
}
|
||||
if hexutil.Encode(cachedVR.FeeRecipient) != hexutil.Encode(newVR.FeeRecipient) {
|
||||
isSame = false
|
||||
}
|
||||
return isSame
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/pkg/errors"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
@@ -18,7 +21,7 @@ func TestSubmitValidatorRegistration(t *testing.T) {
|
||||
defer finish()
|
||||
|
||||
ctx := context.Background()
|
||||
require.NoError(t, nil, SubmitValidatorRegistration(ctx, m.validatorClient, m.signfunc, []*ethpb.ValidatorRegistrationV1{}))
|
||||
require.NoError(t, nil, SubmitValidatorRegistration(ctx, m.validatorClient, []*ethpb.SignedValidatorRegistrationV1{}))
|
||||
|
||||
reg := ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: bytesutil.PadTo([]byte("fee"), 20),
|
||||
@@ -26,7 +29,6 @@ func TestSubmitValidatorRegistration(t *testing.T) {
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
}
|
||||
regs := []*ethpb.ValidatorRegistrationV1{reg}
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
SubmitValidatorRegistration(gomock.Any(), ðpb.SignedValidatorRegistrationsV1{
|
||||
@@ -36,7 +38,10 @@ func TestSubmitValidatorRegistration(t *testing.T) {
|
||||
},
|
||||
}).
|
||||
Return(nil, nil)
|
||||
require.NoError(t, nil, SubmitValidatorRegistration(ctx, m.validatorClient, m.signfunc, regs))
|
||||
require.NoError(t, nil, SubmitValidatorRegistration(ctx, m.validatorClient, []*ethpb.SignedValidatorRegistrationV1{
|
||||
{Message: reg,
|
||||
Signature: params.BeaconConfig().ZeroHash[:]},
|
||||
}))
|
||||
}
|
||||
|
||||
func TestSubmitValidatorRegistration_CantSign(t *testing.T) {
|
||||
@@ -50,7 +55,6 @@ func TestSubmitValidatorRegistration_CantSign(t *testing.T) {
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
}
|
||||
regs := []*ethpb.ValidatorRegistrationV1{reg}
|
||||
|
||||
m.validatorClient.EXPECT().
|
||||
SubmitValidatorRegistration(gomock.Any(), ðpb.SignedValidatorRegistrationsV1{
|
||||
@@ -60,7 +64,10 @@ func TestSubmitValidatorRegistration_CantSign(t *testing.T) {
|
||||
},
|
||||
}).
|
||||
Return(nil, errors.New("could not sign"))
|
||||
require.ErrorContains(t, "could not sign", SubmitValidatorRegistration(ctx, m.validatorClient, m.signfunc, regs))
|
||||
require.ErrorContains(t, "could not sign", SubmitValidatorRegistration(ctx, m.validatorClient, []*ethpb.SignedValidatorRegistrationV1{
|
||||
{Message: reg,
|
||||
Signature: params.BeaconConfig().ZeroHash[:]},
|
||||
}))
|
||||
}
|
||||
|
||||
func Test_signValidatorRegistration(t *testing.T) {
|
||||
@@ -78,3 +85,143 @@ func Test_signValidatorRegistration(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestValidator_SignValidatorRegistrationRequest(t *testing.T) {
|
||||
_, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
ctx := context.Background()
|
||||
byteval, err := hexutil.Decode("0x878705ba3f8bc32fcf7f4caa1a35e72af65cf766")
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
name string
|
||||
arg *ethpb.ValidatorRegistrationV1
|
||||
validatorSetter func(t *testing.T) *validator
|
||||
isCached bool
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: " Happy Path cached",
|
||||
arg: ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
GasLimit: 30000000,
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
},
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
v := validator{
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
genesisTime: 0,
|
||||
}
|
||||
v.signedValidatorRegistrations[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())] = ðpb.SignedValidatorRegistrationV1{
|
||||
Message: ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
GasLimit: 30000000,
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
},
|
||||
Signature: make([]byte, 0),
|
||||
}
|
||||
return &v
|
||||
},
|
||||
isCached: true,
|
||||
},
|
||||
{
|
||||
name: " Happy Path not cached gas updated",
|
||||
arg: ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
GasLimit: 30000000,
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
},
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
v := validator{
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
genesisTime: 0,
|
||||
}
|
||||
v.signedValidatorRegistrations[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())] = ðpb.SignedValidatorRegistrationV1{
|
||||
Message: ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
GasLimit: 35000000,
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
Timestamp: uint64(time.Now().Unix() - 1),
|
||||
},
|
||||
Signature: make([]byte, 0),
|
||||
}
|
||||
return &v
|
||||
},
|
||||
isCached: false,
|
||||
},
|
||||
{
|
||||
name: " Happy Path not cached feerecipient updated",
|
||||
arg: ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
FeeRecipient: byteval,
|
||||
GasLimit: 30000000,
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
},
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
v := validator{
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
genesisTime: 0,
|
||||
}
|
||||
v.signedValidatorRegistrations[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())] = ðpb.SignedValidatorRegistrationV1{
|
||||
Message: ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
GasLimit: 30000000,
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
Timestamp: uint64(time.Now().Unix() - 1),
|
||||
},
|
||||
Signature: make([]byte, 0),
|
||||
}
|
||||
return &v
|
||||
},
|
||||
isCached: false,
|
||||
},
|
||||
{
|
||||
name: " Happy Path not cached first Entry",
|
||||
arg: ðpb.ValidatorRegistrationV1{
|
||||
Pubkey: validatorKey.PublicKey().Marshal(),
|
||||
FeeRecipient: byteval,
|
||||
GasLimit: 30000000,
|
||||
Timestamp: uint64(time.Now().Unix()),
|
||||
},
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
v := validator{
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
genesisTime: 0,
|
||||
}
|
||||
return &v
|
||||
},
|
||||
isCached: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
v := tt.validatorSetter(t)
|
||||
|
||||
startingReq, ok := v.signedValidatorRegistrations[bytesutil.ToBytes48(tt.arg.Pubkey)]
|
||||
|
||||
got, err := v.SignValidatorRegistrationRequest(ctx, m.signfunc, tt.arg)
|
||||
require.NoError(t, err)
|
||||
if tt.isCached {
|
||||
require.DeepEqual(t, got, v.signedValidatorRegistrations[bytesutil.ToBytes48(tt.arg.Pubkey)])
|
||||
} else {
|
||||
if ok {
|
||||
require.NotEqual(t, got.Message.Timestamp, startingReq.Message.Timestamp)
|
||||
}
|
||||
require.Equal(t, got.Message.Timestamp, tt.arg.Timestamp)
|
||||
require.Equal(t, got.Message.GasLimit, tt.arg.GasLimit)
|
||||
require.Equal(t, hexutil.Encode(got.Message.FeeRecipient), hexutil.Encode(tt.arg.FeeRecipient))
|
||||
require.DeepEqual(t, got, v.signedValidatorRegistrations[bytesutil.ToBytes48(tt.arg.Pubkey)])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,7 @@ func (v *ValidatorService) Start() {
|
||||
startBalances: make(map[[fieldparams.BLSPubkeyLength]byte]uint64),
|
||||
prevBalance: make(map[[fieldparams.BLSPubkeyLength]byte]uint64),
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
attLogs: make(map[[32]byte]*attSubmitted),
|
||||
domainDataCache: cache,
|
||||
aggregatedSlotCommitteeIDCache: aggregatedSlotCommitteeIDCache,
|
||||
|
||||
@@ -261,3 +261,8 @@ func (_ *FakeValidator) PushProposerSettings(_ context.Context, _ keymanager.IKe
|
||||
func (_ *FakeValidator) SetPubKeyToValidatorIndexMap(_ context.Context, _ keymanager.IKeymanager) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SignValidatorRegistrationRequest for mocking
|
||||
func (_ *FakeValidator) SignValidatorRegistrationRequest(_ context.Context, _ iface.SigningFunc, _ *ethpb.ValidatorRegistrationV1) (*ethpb.SignedValidatorRegistrationV1, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ type validator struct {
|
||||
duties *ethpb.DutiesResponse
|
||||
prevBalance map[[fieldparams.BLSPubkeyLength]byte]uint64
|
||||
pubkeyToValidatorIndex map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex
|
||||
signedValidatorRegistrations map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1
|
||||
graffitiOrderedIndex uint64
|
||||
aggregatedSlotCommitteeIDCache *lru.Cache
|
||||
domainDataCache *ristretto.Cache
|
||||
@@ -953,7 +954,7 @@ func (v *validator) PushProposerSettings(ctx context.Context, km keymanager.IKey
|
||||
} else {
|
||||
log.Warn("In order to receive transaction fees from proposing blocks, " +
|
||||
"you must now specify a configuration known as a fee recipient config. " +
|
||||
"If it not provided, transaction fees will be burnt. Please see our documentation for more information on this requirement (https://docs.prylabs.network/docs/execution-node/fee-recipient).")
|
||||
"If it is not provided, transaction fees will be burnt. Please see our documentation for more information on this requirement (https://docs.prylabs.network/docs/execution-node/fee-recipient).")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -967,33 +968,44 @@ func (v *validator) PushProposerSettings(ctx context.Context, km keymanager.IKey
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
feeRecipients, registerValidatorRequests, err := v.buildProposerSettingsRequests(ctx, pubkeys)
|
||||
if len(pubkeys) == 0 {
|
||||
log.Info("No public keys have been imported. Skipping Push Proposer Settings")
|
||||
return nil
|
||||
}
|
||||
feeRecipients, signedRegisterValidatorRequests, err := v.buildProposerSettingsRequests(ctx, pubkeys, km.Sign)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(feeRecipients) == 0 {
|
||||
log.Warnf("no valid validator indices were found, prepare beacon proposer request fee recipients array is empty")
|
||||
log.Warnf("No valid validator indices were found, prepare beacon proposer request fee recipients array is empty")
|
||||
return nil
|
||||
}
|
||||
if len(feeRecipients) != len(pubkeys) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"activePubkeys": len(pubkeys) - len(feeRecipients),
|
||||
}).Warnln("will not prepare beacon proposer and update fee recipient until a validator index is assigned")
|
||||
}
|
||||
if _, err := v.validatorClient.PrepareBeaconProposer(ctx, ðpb.PrepareBeaconProposerRequest{
|
||||
Recipients: feeRecipients,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infoln("Prepared beacon proposer with fee recipient to validator index mapping")
|
||||
|
||||
if len(registerValidatorRequests) > 0 {
|
||||
if err := SubmitValidatorRegistration(ctx, v.validatorClient, km.Sign, registerValidatorRequests); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infoln("Submitted builder validator registration settings for custom builders")
|
||||
if len(signedRegisterValidatorRequests) != len(pubkeys) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"activePubkeys": len(pubkeys) - len(signedRegisterValidatorRequests),
|
||||
}).Warnln("will not be included in validator registration until a validator index is assigned")
|
||||
}
|
||||
if err := SubmitValidatorRegistration(ctx, v.validatorClient, signedRegisterValidatorRequests); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validator) buildProposerSettingsRequests(ctx context.Context, pubkeys [][fieldparams.BLSPubkeyLength]byte) ([]*ethpb.PrepareBeaconProposerRequest_FeeRecipientContainer, []*ethpb.ValidatorRegistrationV1, error) {
|
||||
func (v *validator) buildProposerSettingsRequests(ctx context.Context, pubkeys [][fieldparams.BLSPubkeyLength]byte, signer iface.SigningFunc) ([]*ethpb.PrepareBeaconProposerRequest_FeeRecipientContainer, []*ethpb.SignedValidatorRegistrationV1, error) {
|
||||
var validatorToFeeRecipients []*ethpb.PrepareBeaconProposerRequest_FeeRecipientContainer
|
||||
var registerValidatorRequests []*ethpb.ValidatorRegistrationV1
|
||||
var signedRegisterValidatorRequests []*ethpb.SignedValidatorRegistrationV1
|
||||
// need to check for pubkey to validator index mappings
|
||||
for i, key := range pubkeys {
|
||||
var enableValidatorRegistration bool
|
||||
@@ -1009,9 +1021,10 @@ func (v *validator) buildProposerSettingsRequests(ctx context.Context, pubkeys [
|
||||
}
|
||||
if !foundIndex {
|
||||
skipAppendToFeeRecipientArray = true
|
||||
} else {
|
||||
validatorIndex = ind
|
||||
v.pubkeyToValidatorIndex[key] = validatorIndex
|
||||
}
|
||||
validatorIndex = ind
|
||||
v.pubkeyToValidatorIndex[key] = validatorIndex
|
||||
}
|
||||
if v.ProposerSettings.DefaultConfig != nil {
|
||||
feeRecipient = v.ProposerSettings.DefaultConfig.FeeRecipient
|
||||
@@ -1039,22 +1052,30 @@ func (v *validator) buildProposerSettingsRequests(ctx context.Context, pubkeys [
|
||||
if hexutil.Encode(feeRecipient.Bytes()) == params.BeaconConfig().EthBurnAddressHex {
|
||||
log.Warnln("Fee recipient is set to the burn address. You will not be rewarded transaction fees on this setting. Please set a different fee recipient.")
|
||||
}
|
||||
|
||||
// Only include requests with assigned validator index
|
||||
if !skipAppendToFeeRecipientArray {
|
||||
validatorToFeeRecipients = append(validatorToFeeRecipients, ðpb.PrepareBeaconProposerRequest_FeeRecipientContainer{
|
||||
ValidatorIndex: validatorIndex,
|
||||
FeeRecipient: feeRecipient[:],
|
||||
})
|
||||
}
|
||||
if enableValidatorRegistration {
|
||||
registerValidatorRequests = append(registerValidatorRequests, ðpb.ValidatorRegistrationV1{
|
||||
if !skipAppendToFeeRecipientArray && enableValidatorRegistration {
|
||||
unsignedRequest := ðpb.ValidatorRegistrationV1{
|
||||
FeeRecipient: feeRecipient[:],
|
||||
GasLimit: gasLimit,
|
||||
Timestamp: uint64(time.Now().UTC().Unix()),
|
||||
Pubkey: pubkeys[i][:],
|
||||
})
|
||||
}
|
||||
request, err := v.SignValidatorRegistrationRequest(ctx, signer, unsignedRequest)
|
||||
if err != nil {
|
||||
//error is logged and skips appending
|
||||
continue
|
||||
}
|
||||
signedRegisterValidatorRequests = append(signedRegisterValidatorRequests, request)
|
||||
}
|
||||
}
|
||||
return validatorToFeeRecipients, registerValidatorRequests, nil
|
||||
return validatorToFeeRecipients, signedRegisterValidatorRequests, nil
|
||||
}
|
||||
|
||||
func (v *validator) cacheValidatorPubkeyHexToValidatorIndex(ctx context.Context, pubkey [fieldparams.BLSPubkeyLength]byte) (types.ValidatorIndex, bool, error) {
|
||||
|
||||
@@ -1460,17 +1460,19 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
feeRecipientMap map[types.ValidatorIndex]string
|
||||
mockExpectedRequests []ExpectedValidatorRegistration
|
||||
err string
|
||||
logMessages []string
|
||||
}{
|
||||
{
|
||||
name: " Happy Path proposer config not nil",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 2,
|
||||
Offset: 1,
|
||||
@@ -1545,11 +1547,12 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 2,
|
||||
Offset: 1,
|
||||
@@ -1620,11 +1623,12 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
@@ -1682,11 +1686,12 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
@@ -1740,10 +1745,11 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
@@ -1759,11 +1765,12 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
@@ -1804,10 +1811,11 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
@@ -1840,10 +1848,11 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
name: "Before Bellatrix returns nil",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
@@ -1859,11 +1868,12 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
name: "register validator batch failed",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
useWeb: false,
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
@@ -1913,16 +1923,89 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
},
|
||||
err: "could not submit signed registrations to beacon node",
|
||||
},
|
||||
{
|
||||
name: "Validator Index Not found with validator registration",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
node: nodeClient,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 2,
|
||||
Offset: 1,
|
||||
},
|
||||
genesisTime: 0,
|
||||
}
|
||||
// set bellatrix as current epoch
|
||||
params.BeaconConfig().BellatrixForkEpoch = 0
|
||||
err := v.WaitForKeymanagerInitialization(ctx)
|
||||
require.NoError(t, err)
|
||||
km, err := v.Keymanager()
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(ctx)
|
||||
require.NoError(t, err)
|
||||
v.ProposerSettings = &validatorserviceconfig.ProposerSettings{
|
||||
ProposeConfig: nil,
|
||||
DefaultConfig: &validatorserviceconfig.ProposerOption{
|
||||
FeeRecipient: common.HexToAddress(defaultFeeHex),
|
||||
ValidatorRegistration: &validatorserviceconfig.ValidatorRegistration{
|
||||
Enable: true,
|
||||
GasLimit: params.BeaconConfig().DefaultBuilderGasLimit,
|
||||
},
|
||||
},
|
||||
}
|
||||
client.EXPECT().ValidatorIndex(
|
||||
gomock.Any(), // ctx
|
||||
ðpb.ValidatorIndexRequest{PublicKey: keys[0][:]},
|
||||
).Return(ðpb.ValidatorIndexResponse{
|
||||
Index: 1,
|
||||
}, nil)
|
||||
|
||||
client.EXPECT().ValidatorIndex(
|
||||
gomock.Any(), // ctx
|
||||
ðpb.ValidatorIndexRequest{PublicKey: keys[1][:]},
|
||||
).Times(2).Return(nil, errors.New("Could not find validator index"))
|
||||
|
||||
client.EXPECT().SubmitValidatorRegistration(
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(&empty.Empty{}, nil)
|
||||
client.EXPECT().PrepareBeaconProposer(gomock.Any(), ðpb.PrepareBeaconProposerRequest{
|
||||
Recipients: []*ethpb.PrepareBeaconProposerRequest_FeeRecipientContainer{
|
||||
{FeeRecipient: common.HexToAddress(defaultFeeHex).Bytes(), ValidatorIndex: 1},
|
||||
},
|
||||
}).Return(nil, nil)
|
||||
return &v
|
||||
},
|
||||
feeRecipientMap: map[types.ValidatorIndex]string{
|
||||
1: defaultFeeHex,
|
||||
},
|
||||
mockExpectedRequests: []ExpectedValidatorRegistration{
|
||||
{
|
||||
FeeRecipient: byteValueAddress,
|
||||
GasLimit: params.BeaconConfig().DefaultBuilderGasLimit,
|
||||
},
|
||||
},
|
||||
logMessages: []string{
|
||||
"prepare beacon proposer and update fee recipient until a validator index is assigned",
|
||||
"not be included in validator registration until a validator index is assigned",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
v := tt.validatorSetter(t)
|
||||
km, err := v.Keymanager()
|
||||
require.NoError(t, err)
|
||||
pubkeys, err := km.FetchValidatingPublicKeys(ctx)
|
||||
require.NoError(t, err)
|
||||
if tt.feeRecipientMap != nil {
|
||||
feeRecipients, registerValidatorRequests, err := v.buildProposerSettingsRequests(ctx, pubkeys)
|
||||
feeRecipients, signedRegisterValidatorRequests, err := v.buildProposerSettingsRequests(ctx, pubkeys, km.Sign)
|
||||
require.NoError(t, err)
|
||||
for _, recipient := range feeRecipients {
|
||||
require.Equal(t, strings.ToLower(tt.feeRecipientMap[recipient.ValidatorIndex]), strings.ToLower(hexutil.Encode(recipient.FeeRecipient)))
|
||||
@@ -1934,15 +2017,22 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
}
|
||||
// check if Pubkeys are always unique
|
||||
var unique = make(map[string]bool)
|
||||
for _, request := range registerValidatorRequests {
|
||||
require.Equal(t, unique[common.BytesToAddress(request.Pubkey).Hex()], false)
|
||||
unique[common.BytesToAddress(request.Pubkey).Hex()] = true
|
||||
for _, request := range signedRegisterValidatorRequests {
|
||||
require.Equal(t, unique[common.BytesToAddress(request.Message.Pubkey).Hex()], false)
|
||||
unique[common.BytesToAddress(request.Message.Pubkey).Hex()] = true
|
||||
}
|
||||
require.Equal(t, len(tt.mockExpectedRequests), len(registerValidatorRequests))
|
||||
require.Equal(t, len(tt.mockExpectedRequests), len(signedRegisterValidatorRequests))
|
||||
require.Equal(t, len(signedRegisterValidatorRequests), len(v.signedValidatorRegistrations))
|
||||
}
|
||||
if err := v.PushProposerSettings(ctx, km); tt.err != "" {
|
||||
assert.ErrorContains(t, tt.err, err)
|
||||
}
|
||||
if len(tt.logMessages) > 0 {
|
||||
for _, message := range tt.logMessages {
|
||||
assert.LogsContain(t, hook, message)
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,10 +476,6 @@ func web3SignerConfig(cliCtx *cli.Context) (*remoteweb3signer.SetupConfig, error
|
||||
|
||||
func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSettings, error) {
|
||||
var fileConfig *validatorServiceConfig.ProposerSettingsPayload
|
||||
//TODO(10809): remove when fully deprecated
|
||||
if cliCtx.IsSet(flags.FeeRecipientConfigFileFlag.Name) && cliCtx.IsSet(flags.FeeRecipientConfigURLFlag.Name) {
|
||||
return nil, fmt.Errorf("cannot specify both --%s and --%s", flags.FeeRecipientConfigFileFlag.Name, flags.FeeRecipientConfigURLFlag.Name)
|
||||
}
|
||||
|
||||
if cliCtx.IsSet(flags.ProposerSettingsFlag.Name) && cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
|
||||
return nil, errors.New("cannot specify both " + flags.ProposerSettingsFlag.Name + " and " + flags.ProposerSettingsURLFlag.Name)
|
||||
@@ -506,14 +502,6 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
|
||||
}
|
||||
}
|
||||
|
||||
if cliCtx.IsSet(flags.FeeRecipientConfigFileFlag.Name) {
|
||||
return nil, errors.New(flags.FeeRecipientConfigFileFlag.Usage)
|
||||
}
|
||||
|
||||
if cliCtx.IsSet(flags.FeeRecipientConfigURLFlag.Name) {
|
||||
return nil, errors.New(flags.FeeRecipientConfigURLFlag.Usage)
|
||||
}
|
||||
|
||||
if cliCtx.IsSet(flags.ProposerSettingsFlag.Name) {
|
||||
if err := unmarshalFromFile(cliCtx.Context, cliCtx.String(flags.ProposerSettingsFlag.Name), &fileConfig); err != nil {
|
||||
return nil, err
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user