mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-11 06:18:05 -05:00
Compare commits
22 Commits
quicStream
...
run-hacks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d444a941d | ||
|
|
feb16ae4aa | ||
|
|
219301339c | ||
|
|
aec349f75a | ||
|
|
5f909caedf | ||
|
|
ba6dff3adb | ||
|
|
8cd05f098b | ||
|
|
425f5387fa | ||
|
|
f2ce115ade | ||
|
|
090a3e1ded | ||
|
|
c0acb7d352 | ||
|
|
0d6070e6fc | ||
|
|
bd00f851f0 | ||
|
|
1a0c07deec | ||
|
|
04f231a400 | ||
|
|
be1bfcce63 | ||
|
|
8cf5d79852 | ||
|
|
f7912e7c20 | ||
|
|
caa8be5dd1 | ||
|
|
0c15a30a34 | ||
|
|
7bce1c0714 | ||
|
|
d1084cbe48 |
16
WORKSPACE
16
WORKSPACE
@@ -342,22 +342,6 @@ filegroup(
|
||||
url = "https://github.com/eth-clients/eth2-networks/archive/934c948e69205dcf2deb87e4ae6cc140c335f94d.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "goerli_testnet",
|
||||
build_file_content = """
|
||||
filegroup(
|
||||
name = "configs",
|
||||
srcs = [
|
||||
"prater/config.yaml",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "43fc0f55ddff7b511713e2de07aa22846a67432df997296fb4fc09cd8ed1dcdb",
|
||||
strip_prefix = "goerli-6522ac6684693740cd4ddcc2a0662e03702aa4a1",
|
||||
url = "https://github.com/eth-clients/goerli/archive/6522ac6684693740cd4ddcc2a0662e03702aa4a1.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "holesky_testnet",
|
||||
build_file_content = """
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"constants.go",
|
||||
"headers.go",
|
||||
"jwt.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/api",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//crypto/rand:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["jwt_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = ["//testing/require:go_default_library"],
|
||||
)
|
||||
|
||||
@@ -4,4 +4,6 @@ const (
|
||||
WebUrlPrefix = "/v2/validator/"
|
||||
WebApiUrlPrefix = "/api/v2/validator/"
|
||||
KeymanagerApiPrefix = "/eth/v1"
|
||||
|
||||
AuthTokenFileName = "auth-token"
|
||||
)
|
||||
|
||||
32
api/jwt.go
Normal file
32
api/jwt.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/rand"
|
||||
)
|
||||
|
||||
// GenerateRandomHexString generates a random hex string that follows the standards for jwt token
|
||||
// used for beacon node -> execution client
|
||||
// used for web client -> validator client
|
||||
func GenerateRandomHexString() (string, error) {
|
||||
secret := make([]byte, 32)
|
||||
randGen := rand.NewGenerator()
|
||||
n, err := randGen.Read(secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if n != 32 {
|
||||
return "", errors.New("rand: unexpected length")
|
||||
}
|
||||
return hexutil.Encode(secret), nil
|
||||
}
|
||||
|
||||
// ValidateAuthToken validating auth token for web
|
||||
func ValidateAuthToken(token string) error {
|
||||
b, err := hexutil.Decode(token)
|
||||
// token should be hex-encoded and at least 256 bits
|
||||
if err != nil || len(b) < 32 {
|
||||
return errors.New("invalid auth token: token should be hex-encoded and at least 256 bits")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
13
api/jwt_test.go
Normal file
13
api/jwt_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
func TestGenerateRandomHexString(t *testing.T) {
|
||||
token, err := GenerateRandomHexString()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, ValidateAuthToken(token))
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
f "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
@@ -399,14 +398,6 @@ func (s *Service) InForkchoice(root [32]byte) bool {
|
||||
return s.cfg.ForkChoiceStore.HasNode(root)
|
||||
}
|
||||
|
||||
// IsViableForCheckpoint returns whether the given checkpoint is a checkpoint in any
|
||||
// chain known to forkchoice
|
||||
func (s *Service) IsViableForCheckpoint(cp *forkchoicetypes.Checkpoint) (bool, error) {
|
||||
s.cfg.ForkChoiceStore.RLock()
|
||||
defer s.cfg.ForkChoiceStore.RUnlock()
|
||||
return s.cfg.ForkChoiceStore.IsViableForCheckpoint(cp)
|
||||
}
|
||||
|
||||
// IsOptimisticForRoot takes the root as argument instead of the current head
|
||||
// and returns true if it is optimistic.
|
||||
func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool, error) {
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestService_headNextSyncCommitteeIndices(t *testing.T) {
|
||||
indices, err := c.headNextSyncCommitteeIndices(context.Background(), 0, primitives.Slot(slot))
|
||||
require.NoError(t, err)
|
||||
|
||||
// NextSyncCommittee should be be empty after `ProcessSyncCommitteeUpdates`. Validator should get indices.
|
||||
// NextSyncCommittee should be empty after `ProcessSyncCommitteeUpdates`. Validator should get indices.
|
||||
require.NotEqual(t, 0, len(indices))
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
|
||||
// Send finalized events and finalized deposits in the background
|
||||
if newFinalized {
|
||||
finalized := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
|
||||
go s.sendNewFinalizedEvent(blockCopy, postState)
|
||||
go s.sendNewFinalizedEvent(ctx, postState)
|
||||
depCtx, cancel := context.WithTimeout(context.Background(), depositDeadline)
|
||||
go func() {
|
||||
s.insertFinalizedDeposits(depCtx, finalized.Root)
|
||||
@@ -443,7 +443,7 @@ func (s *Service) updateFinalizationOnBlock(ctx context.Context, preState, postS
|
||||
|
||||
// sendNewFinalizedEvent sends a new finalization checkpoint event over the
|
||||
// event feed. It needs to be called on the background
|
||||
func (s *Service) sendNewFinalizedEvent(signed interfaces.ReadOnlySignedBeaconBlock, postState state.BeaconState) {
|
||||
func (s *Service) sendNewFinalizedEvent(ctx context.Context, postState state.BeaconState) {
|
||||
isValidPayload := false
|
||||
s.headLock.RLock()
|
||||
if s.head != nil {
|
||||
@@ -451,8 +451,17 @@ func (s *Service) sendNewFinalizedEvent(signed interfaces.ReadOnlySignedBeaconBl
|
||||
}
|
||||
s.headLock.RUnlock()
|
||||
|
||||
blk, err := s.cfg.BeaconDB.Block(ctx, bytesutil.ToBytes32(postState.FinalizedCheckpoint().Root))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not retrieve block for finalized checkpoint root. Finalized event will not be emitted")
|
||||
return
|
||||
}
|
||||
if blk == nil || blk.IsNil() || blk.Block() == nil || blk.Block().IsNil() {
|
||||
log.WithError(err).Error("Block retrieved for finalized checkpoint root is nil. Finalized event will not be emitted")
|
||||
return
|
||||
}
|
||||
stateRoot := blk.Block().StateRoot()
|
||||
// Send an event regarding the new finalized checkpoint over a common event feed.
|
||||
stateRoot := signed.Block().StateRoot()
|
||||
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.FinalizedCheckpoint,
|
||||
Data: ðpbv1.EventFinalizedCheckpoint{
|
||||
|
||||
@@ -8,12 +8,14 @@ import (
|
||||
|
||||
blockchainTesting "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
|
||||
statefeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/das"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
@@ -378,3 +380,38 @@ func TestHandleBlockBLSToExecutionChanges(t *testing.T) {
|
||||
require.Equal(t, false, pool.ValidatorExists(idx))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_sendNewFinalizedEvent(t *testing.T) {
|
||||
s, _ := minimalTestService(t)
|
||||
notifier := &blockchainTesting.MockStateNotifier{RecordEvents: true}
|
||||
s.cfg.StateNotifier = notifier
|
||||
finalizedSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
finalizedStRoot, err := finalizedSt.HashTreeRoot(s.ctx)
|
||||
require.NoError(t, err)
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.StateRoot = finalizedStRoot[:]
|
||||
sbb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
sbbRoot, err := sbb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.cfg.BeaconDB.SaveBlock(s.ctx, sbb))
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetFinalizedCheckpoint(ðpb.Checkpoint{
|
||||
Epoch: 123,
|
||||
Root: sbbRoot[:],
|
||||
}))
|
||||
|
||||
s.sendNewFinalizedEvent(s.ctx, st)
|
||||
|
||||
require.Equal(t, 1, len(notifier.ReceivedEvents()))
|
||||
e := notifier.ReceivedEvents()[0]
|
||||
assert.Equal(t, statefeed.FinalizedCheckpoint, int(e.Type))
|
||||
fc, ok := e.Data.(*ethpbv1.EventFinalizedCheckpoint)
|
||||
require.Equal(t, true, ok, "event has wrong data type")
|
||||
assert.Equal(t, primitives.Epoch(123), fc.Epoch)
|
||||
assert.DeepEqual(t, sbbRoot[:], fc.Block)
|
||||
assert.DeepEqual(t, finalizedStRoot[:], fc.State)
|
||||
assert.Equal(t, false, fc.ExecutionOptimistic)
|
||||
}
|
||||
|
||||
@@ -94,6 +94,15 @@ func (s *LazilyPersistentStore) IsDataAvailable(ctx context.Context, current pri
|
||||
entry := s.cache.ensure(key)
|
||||
defer s.cache.delete(key)
|
||||
root := b.Root()
|
||||
sumz, err := s.store.WaitForSummarizer(ctx)
|
||||
if err != nil {
|
||||
log.WithField("root", fmt.Sprintf("%#x", b.Root())).
|
||||
WithError(err).
|
||||
Debug("Failed to receive BlobStorageSummarizer within IsDataAvailable")
|
||||
} else {
|
||||
entry.setDiskSummary(sumz.Summary(root))
|
||||
}
|
||||
|
||||
// Verify we have all the expected sidecars, and fail fast if any are missing or inconsistent.
|
||||
// We don't try to salvage problematic batches because this indicates a misbehaving peer and we'd rather
|
||||
// ignore their response and decrease their peer score.
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
@@ -59,7 +60,12 @@ func (c *cache) delete(key cacheKey) {
|
||||
|
||||
// cacheEntry holds a fixed-length cache of BlobSidecars.
|
||||
type cacheEntry struct {
|
||||
scs [fieldparams.MaxBlobsPerBlock]*blocks.ROBlob
|
||||
scs [fieldparams.MaxBlobsPerBlock]*blocks.ROBlob
|
||||
diskSummary filesystem.BlobStorageSummary
|
||||
}
|
||||
|
||||
func (e *cacheEntry) setDiskSummary(sum filesystem.BlobStorageSummary) {
|
||||
e.diskSummary = sum
|
||||
}
|
||||
|
||||
// stash adds an item to the in-memory cache of BlobSidecars.
|
||||
@@ -81,9 +87,17 @@ func (e *cacheEntry) stash(sc *blocks.ROBlob) error {
|
||||
// the cache do not match those found in the block. If err is nil, then all expected
|
||||
// commitments were found in the cache and the sidecar slice return value can be used
|
||||
// to perform a DA check against the cached sidecars.
|
||||
// filter only returns blobs that need to be checked. Blobs already available on disk will be excluded.
|
||||
func (e *cacheEntry) filter(root [32]byte, kc safeCommitmentArray) ([]blocks.ROBlob, error) {
|
||||
scs := make([]blocks.ROBlob, kc.count())
|
||||
if e.diskSummary.AllAvailable(kc.count()) {
|
||||
return nil, nil
|
||||
}
|
||||
scs := make([]blocks.ROBlob, 0, kc.count())
|
||||
for i := uint64(0); i < fieldparams.MaxBlobsPerBlock; i++ {
|
||||
// We already have this blob, we don't need to write it or validate it.
|
||||
if e.diskSummary.HasIndex(i) {
|
||||
continue
|
||||
}
|
||||
if kc[i] == nil {
|
||||
if e.scs[i] != nil {
|
||||
return nil, errors.Wrapf(errCommitmentMismatch, "root=%#x, index=%#x, commitment=%#x, no block commitment", root, i, e.scs[i].KzgCommitment)
|
||||
@@ -97,7 +111,7 @@ func (e *cacheEntry) filter(root [32]byte, kc safeCommitmentArray) ([]blocks.ROB
|
||||
if !bytes.Equal(kc[i], e.scs[i].KzgCommitment) {
|
||||
return nil, errors.Wrapf(errCommitmentMismatch, "root=%#x, index=%#x, commitment=%#x, block commitment=%#x", root, i, e.scs[i].KzgCommitment, kc[i])
|
||||
}
|
||||
scs[i] = *e.scs[i]
|
||||
scs = append(scs, *e.scs[i])
|
||||
}
|
||||
|
||||
return scs, nil
|
||||
|
||||
@@ -3,9 +3,14 @@ package das
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
func TestCacheEnsureDelete(t *testing.T) {
|
||||
@@ -23,3 +28,145 @@ func TestCacheEnsureDelete(t *testing.T) {
|
||||
var nilEntry *cacheEntry
|
||||
require.Equal(t, nilEntry, c.entries[k])
|
||||
}
|
||||
|
||||
type filterTestCaseSetupFunc func(t *testing.T) (*cacheEntry, safeCommitmentArray, []blocks.ROBlob)
|
||||
|
||||
func filterTestCaseSetup(slot primitives.Slot, nBlobs int, onDisk []int, numExpected int) filterTestCaseSetupFunc {
|
||||
return func(t *testing.T) (*cacheEntry, safeCommitmentArray, []blocks.ROBlob) {
|
||||
blk, blobs := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, slot, nBlobs)
|
||||
commits, err := commitmentsToCheck(blk, blk.Block().Slot())
|
||||
require.NoError(t, err)
|
||||
entry := &cacheEntry{}
|
||||
if len(onDisk) > 0 {
|
||||
od := map[[32]byte][]int{blk.Root(): onDisk}
|
||||
sumz := filesystem.NewMockBlobStorageSummarizer(t, od)
|
||||
sum := sumz.Summary(blk.Root())
|
||||
entry.setDiskSummary(sum)
|
||||
}
|
||||
expected := make([]blocks.ROBlob, 0, nBlobs)
|
||||
for i := 0; i < commits.count(); i++ {
|
||||
if entry.diskSummary.HasIndex(uint64(i)) {
|
||||
continue
|
||||
}
|
||||
// If we aren't telling the cache a blob is on disk, add it to the expected list and stash.
|
||||
expected = append(expected, blobs[i])
|
||||
require.NoError(t, entry.stash(&blobs[i]))
|
||||
}
|
||||
require.Equal(t, numExpected, len(expected))
|
||||
return entry, commits, expected
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterDiskSummary(t *testing.T) {
|
||||
denebSlot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch)
|
||||
require.NoError(t, err)
|
||||
cases := []struct {
|
||||
name string
|
||||
setup filterTestCaseSetupFunc
|
||||
}{
|
||||
{
|
||||
name: "full blobs, all on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 6, []int{0, 1, 2, 3, 4, 5}, 0),
|
||||
},
|
||||
{
|
||||
name: "full blobs, first on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 6, []int{0}, 5),
|
||||
},
|
||||
{
|
||||
name: "full blobs, middle on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 6, []int{2}, 5),
|
||||
},
|
||||
{
|
||||
name: "full blobs, last on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 6, []int{5}, 5),
|
||||
},
|
||||
{
|
||||
name: "full blobs, none on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 6, []int{}, 6),
|
||||
},
|
||||
{
|
||||
name: "one commitment, on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 1, []int{0}, 0),
|
||||
},
|
||||
{
|
||||
name: "one commitment, not on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 1, []int{}, 1),
|
||||
},
|
||||
{
|
||||
name: "two commitments, first on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 2, []int{0}, 1),
|
||||
},
|
||||
{
|
||||
name: "two commitments, last on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 2, []int{1}, 1),
|
||||
},
|
||||
{
|
||||
name: "two commitments, none on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 2, []int{}, 2),
|
||||
},
|
||||
{
|
||||
name: "two commitments, all on disk",
|
||||
setup: filterTestCaseSetup(denebSlot, 2, []int{0, 1}, 0),
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
entry, commits, expected := c.setup(t)
|
||||
// first (root) argument doesn't matter, it is just for logs
|
||||
got, err := entry.filter([32]byte{}, commits)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(expected), len(got))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
denebSlot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch)
|
||||
require.NoError(t, err)
|
||||
cases := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) (*cacheEntry, safeCommitmentArray, []blocks.ROBlob)
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "commitments mismatch - extra sidecar",
|
||||
setup: func(t *testing.T) (*cacheEntry, safeCommitmentArray, []blocks.ROBlob) {
|
||||
entry, commits, expected := filterTestCaseSetup(denebSlot, 6, []int{0, 1}, 4)(t)
|
||||
commits[5] = nil
|
||||
return entry, commits, expected
|
||||
},
|
||||
err: errCommitmentMismatch,
|
||||
},
|
||||
{
|
||||
name: "sidecar missing",
|
||||
setup: func(t *testing.T) (*cacheEntry, safeCommitmentArray, []blocks.ROBlob) {
|
||||
entry, commits, expected := filterTestCaseSetup(denebSlot, 6, []int{0, 1}, 4)(t)
|
||||
entry.scs[5] = nil
|
||||
return entry, commits, expected
|
||||
},
|
||||
err: errMissingSidecar,
|
||||
},
|
||||
{
|
||||
name: "commitments mismatch - different bytes",
|
||||
setup: func(t *testing.T) (*cacheEntry, safeCommitmentArray, []blocks.ROBlob) {
|
||||
entry, commits, expected := filterTestCaseSetup(denebSlot, 6, []int{0, 1}, 4)(t)
|
||||
entry.scs[5].KzgCommitment = []byte("nope")
|
||||
return entry, commits, expected
|
||||
},
|
||||
err: errCommitmentMismatch,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
entry, commits, expected := c.setup(t)
|
||||
// first (root) argument doesn't matter, it is just for logs
|
||||
got, err := entry.filter([32]byte{}, commits)
|
||||
if c.err != nil {
|
||||
require.ErrorIs(t, err, c.err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(expected), len(got))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ go_library(
|
||||
srcs = [
|
||||
"blob.go",
|
||||
"cache.go",
|
||||
"ephemeral.go",
|
||||
"log.go",
|
||||
"metrics.go",
|
||||
"mock.go",
|
||||
"pruner.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem",
|
||||
|
||||
@@ -3,6 +3,7 @@ package filesystem
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
@@ -121,7 +122,7 @@ var ErrBlobStorageSummarizerUnavailable = errors.New("BlobStorage not initialize
|
||||
// BlobStorageSummarizer is not ready immediately on node startup because it needs to sample the blob filesystem to
|
||||
// determine which blobs are available.
|
||||
func (bs *BlobStorage) WaitForSummarizer(ctx context.Context) (BlobStorageSummarizer, error) {
|
||||
if bs.pruner == nil {
|
||||
if bs == nil || bs.pruner == nil {
|
||||
return nil, ErrBlobStorageSummarizerUnavailable
|
||||
}
|
||||
return bs.pruner.waitForCache(ctx)
|
||||
@@ -299,6 +300,15 @@ func (bs *BlobStorage) Clear() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithinRetentionPeriod checks if the requested epoch is within the blob retention period.
|
||||
func (bs *BlobStorage) WithinRetentionPeriod(requested, current primitives.Epoch) bool {
|
||||
if requested > math.MaxUint64-bs.retentionEpochs {
|
||||
// If there is an overflow, then the retention period was set to an extremely large number.
|
||||
return true
|
||||
}
|
||||
return requested+bs.retentionEpochs >= current
|
||||
}
|
||||
|
||||
type blobNamer struct {
|
||||
root [32]byte
|
||||
index uint64
|
||||
|
||||
@@ -2,6 +2,7 @@ package filesystem
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
@@ -24,8 +25,7 @@ func TestBlobStorage_SaveBlobData(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("no error for duplicate", func(t *testing.T) {
|
||||
fs, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
fs, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
existingSidecar := testSidecars[0]
|
||||
|
||||
blobPath := namerForSidecar(existingSidecar).path()
|
||||
@@ -129,8 +129,7 @@ func TestBlobStorage_SaveBlobData(t *testing.T) {
|
||||
// pollUntil polls a condition function until it returns true or a timeout is reached.
|
||||
|
||||
func TestBlobIndicesBounds(t *testing.T) {
|
||||
fs, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
fs, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
root := [32]byte{}
|
||||
|
||||
okIdx := uint64(fieldparams.MaxBlobsPerBlock - 1)
|
||||
@@ -161,8 +160,7 @@ func writeFakeSSZ(t *testing.T, fs afero.Fs, root [32]byte, idx uint64) {
|
||||
|
||||
func TestBlobStoragePrune(t *testing.T) {
|
||||
currentSlot := primitives.Slot(200000)
|
||||
fs, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
fs, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
|
||||
t.Run("PruneOne", func(t *testing.T) {
|
||||
_, sidecars := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 300, fieldparams.MaxBlobsPerBlock)
|
||||
@@ -218,8 +216,7 @@ func TestBlobStoragePrune(t *testing.T) {
|
||||
|
||||
func BenchmarkPruning(b *testing.B) {
|
||||
var t *testing.T
|
||||
_, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
_, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
|
||||
blockQty := 10000
|
||||
currentSlot := primitives.Slot(150000)
|
||||
@@ -248,3 +245,50 @@ func TestNewBlobStorage(t *testing.T) {
|
||||
_, err = NewBlobStorage(WithBasePath(path.Join(t.TempDir(), "good")))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestConfig_WithinRetentionPeriod(t *testing.T) {
|
||||
retention := primitives.Epoch(16)
|
||||
storage := &BlobStorage{retentionEpochs: retention}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
requested primitives.Epoch
|
||||
current primitives.Epoch
|
||||
within bool
|
||||
}{
|
||||
{
|
||||
name: "before",
|
||||
requested: 0,
|
||||
current: retention + 1,
|
||||
within: false,
|
||||
},
|
||||
{
|
||||
name: "same",
|
||||
requested: 0,
|
||||
current: 0,
|
||||
within: true,
|
||||
},
|
||||
{
|
||||
name: "boundary",
|
||||
requested: 0,
|
||||
current: retention,
|
||||
within: true,
|
||||
},
|
||||
{
|
||||
name: "one less",
|
||||
requested: retention - 1,
|
||||
current: retention,
|
||||
within: true,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
require.Equal(t, c.within, storage.WithinRetentionPeriod(c.requested, c.current))
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("overflow", func(t *testing.T) {
|
||||
storage := &BlobStorage{retentionEpochs: math.MaxUint64}
|
||||
require.Equal(t, true, storage.WithinRetentionPeriod(1, 1))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
// improving test performance and simplifying cleanup.
|
||||
func NewEphemeralBlobStorage(t testing.TB) *BlobStorage {
|
||||
fs := afero.NewMemMapFs()
|
||||
pruner, err := newBlobPruner(fs, params.BeaconConfig().MinEpochsForBlobsSidecarsRequest)
|
||||
pruner, err := newBlobPruner(fs, params.BeaconConfig().MinEpochsForBlobsSidecarsRequest, withWarmedCache())
|
||||
if err != nil {
|
||||
t.Fatal("test setup issue", err)
|
||||
}
|
||||
@@ -21,13 +21,13 @@ func NewEphemeralBlobStorage(t testing.TB) *BlobStorage {
|
||||
|
||||
// NewEphemeralBlobStorageWithFs can be used by tests that want access to the virtual filesystem
|
||||
// in order to interact with it outside the parameters of the BlobStorage api.
|
||||
func NewEphemeralBlobStorageWithFs(t testing.TB) (afero.Fs, *BlobStorage, error) {
|
||||
func NewEphemeralBlobStorageWithFs(t testing.TB) (afero.Fs, *BlobStorage) {
|
||||
fs := afero.NewMemMapFs()
|
||||
pruner, err := newBlobPruner(fs, params.BeaconConfig().MinEpochsForBlobsSidecarsRequest)
|
||||
pruner, err := newBlobPruner(fs, params.BeaconConfig().MinEpochsForBlobsSidecarsRequest, withWarmedCache())
|
||||
if err != nil {
|
||||
t.Fatal("test setup issue", err)
|
||||
}
|
||||
return fs, &BlobStorage{fs: fs, pruner: pruner}, nil
|
||||
return fs, &BlobStorage{fs: fs, pruner: pruner}
|
||||
}
|
||||
|
||||
type BlobMocker struct {
|
||||
@@ -61,3 +61,15 @@ func NewEphemeralBlobStorageWithMocker(_ testing.TB) (*BlobMocker, *BlobStorage)
|
||||
bs := &BlobStorage{fs: fs}
|
||||
return &BlobMocker{fs: fs, bs: bs}, bs
|
||||
}
|
||||
|
||||
func NewMockBlobStorageSummarizer(t *testing.T, set map[[32]byte][]int) BlobStorageSummarizer {
|
||||
c := newBlobStorageCache()
|
||||
for k, v := range set {
|
||||
for i := range v {
|
||||
if err := c.ensure(rootString(k), 0, uint64(v[i])); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
@@ -33,17 +33,32 @@ type blobPruner struct {
|
||||
prunedBefore atomic.Uint64
|
||||
windowSize primitives.Slot
|
||||
cache *blobStorageCache
|
||||
cacheWarmed chan struct{}
|
||||
cacheReady chan struct{}
|
||||
warmed bool
|
||||
fs afero.Fs
|
||||
}
|
||||
|
||||
func newBlobPruner(fs afero.Fs, retain primitives.Epoch) (*blobPruner, error) {
|
||||
type prunerOpt func(*blobPruner) error
|
||||
|
||||
func withWarmedCache() prunerOpt {
|
||||
return func(p *blobPruner) error {
|
||||
return p.warmCache()
|
||||
}
|
||||
}
|
||||
|
||||
func newBlobPruner(fs afero.Fs, retain primitives.Epoch, opts ...prunerOpt) (*blobPruner, error) {
|
||||
r, err := slots.EpochStart(retain + retentionBuffer)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not set retentionSlots")
|
||||
}
|
||||
cw := make(chan struct{})
|
||||
return &blobPruner{fs: fs, windowSize: r, cache: newBlobStorageCache(), cacheWarmed: cw}, nil
|
||||
p := &blobPruner{fs: fs, windowSize: r, cache: newBlobStorageCache(), cacheReady: cw}
|
||||
for _, o := range opts {
|
||||
if err := o(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// notify updates the pruner's view of root->blob mappings. This allows the pruner to build a cache
|
||||
@@ -57,6 +72,8 @@ func (p *blobPruner) notify(root [32]byte, latest primitives.Slot, idx uint64) e
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
if err := p.prune(primitives.Slot(pruned)); err != nil {
|
||||
log.WithError(err).Errorf("Failed to prune blobs from slot %d", latest)
|
||||
}
|
||||
@@ -74,16 +91,21 @@ func windowMin(latest, offset primitives.Slot) primitives.Slot {
|
||||
}
|
||||
|
||||
func (p *blobPruner) warmCache() error {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
if err := p.prune(0); err != nil {
|
||||
return err
|
||||
}
|
||||
close(p.cacheWarmed)
|
||||
if !p.warmed {
|
||||
p.warmed = true
|
||||
close(p.cacheReady)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *blobPruner) waitForCache(ctx context.Context) (*blobStorageCache, error) {
|
||||
select {
|
||||
case <-p.cacheWarmed:
|
||||
case <-p.cacheReady:
|
||||
return p.cache, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
@@ -94,8 +116,6 @@ func (p *blobPruner) waitForCache(ctx context.Context) (*blobStorageCache, error
|
||||
// It deletes blobs older than currentEpoch - (retentionEpochs+bufferEpochs).
|
||||
// This is so that we keep a slight buffer and blobs are deleted after n+2 epochs.
|
||||
func (p *blobPruner) prune(pruneBefore primitives.Slot) error {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
start := time.Now()
|
||||
totalPruned, totalErr := 0, 0
|
||||
// Customize logging/metrics behavior for the initial cache warmup when slot=0.
|
||||
|
||||
@@ -51,8 +51,7 @@ func TestTryPruneDir_CachedExpired(t *testing.T) {
|
||||
require.Equal(t, 0, pruned)
|
||||
})
|
||||
t.Run("blobs to delete", func(t *testing.T) {
|
||||
fs, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
fs, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
var slot primitives.Slot = 0
|
||||
_, sidecars := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, slot, 2)
|
||||
scs, err := verification.BlobSidecarSliceNoop(sidecars)
|
||||
@@ -83,8 +82,7 @@ func TestTryPruneDir_CachedExpired(t *testing.T) {
|
||||
|
||||
func TestTryPruneDir_SlotFromFile(t *testing.T) {
|
||||
t.Run("expired blobs deleted", func(t *testing.T) {
|
||||
fs, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
fs, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
var slot primitives.Slot = 0
|
||||
_, sidecars := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, slot, 2)
|
||||
scs, err := verification.BlobSidecarSliceNoop(sidecars)
|
||||
@@ -116,8 +114,7 @@ func TestTryPruneDir_SlotFromFile(t *testing.T) {
|
||||
require.Equal(t, 0, len(files))
|
||||
})
|
||||
t.Run("not expired, intact", func(t *testing.T) {
|
||||
fs, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
fs, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
// Set slot equal to the window size, so it should be retained.
|
||||
slot := bs.pruner.windowSize
|
||||
_, sidecars := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, slot, 2)
|
||||
@@ -184,8 +181,7 @@ func TestSlotFromFile(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(fmt.Sprintf("slot %d", c.slot), func(t *testing.T) {
|
||||
fs, bs, err := NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
fs, bs := NewEphemeralBlobStorageWithFs(t)
|
||||
_, sidecars := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, c.slot, 1)
|
||||
sc, err := verification.BlobSidecarNoop(sidecars[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -707,6 +707,7 @@ func (b *BeaconNode) registerP2P(cliCtx *cli.Context) error {
|
||||
PrivateKey: cliCtx.String(cmd.P2PPrivKey.Name),
|
||||
StaticPeerID: cliCtx.Bool(cmd.P2PStaticID.Name),
|
||||
MetaDataDir: cliCtx.String(cmd.P2PMetadata.Name),
|
||||
QUICPort: cliCtx.Uint(cmd.P2PQUICPort.Name),
|
||||
TCPPort: cliCtx.Uint(cmd.P2PTCPPort.Name),
|
||||
UDPPort: cliCtx.Uint(cmd.P2PUDPPort.Name),
|
||||
MaxPeers: cliCtx.Uint(cmd.P2PMaxPeers.Name),
|
||||
|
||||
@@ -217,9 +217,9 @@ func Test_hasNetworkFlag(t *testing.T) {
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "Prater testnet",
|
||||
networkName: features.PraterTestnet.Name,
|
||||
networkValue: "prater",
|
||||
name: "Holesky testnet",
|
||||
networkName: features.HoleskyTestnet.Name,
|
||||
networkValue: "holesky",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -90,6 +90,7 @@ go_library(
|
||||
"@com_github_libp2p_go_libp2p//core/peerstore:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/protocol:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/security/noise:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/transport/quic:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/transport/tcp:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_mplex//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_pubsub//:go_default_library",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/hash"
|
||||
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
|
||||
@@ -137,11 +138,11 @@ func (s *Service) internalBroadcastAttestation(ctx context.Context, subnet uint6
|
||||
// In the event our attestation is outdated and beyond the
|
||||
// acceptable threshold, we exit early and do not broadcast it.
|
||||
currSlot := slots.CurrentSlot(uint64(s.genesisTime.Unix()))
|
||||
if att.Data.Slot+params.BeaconConfig().SlotsPerEpoch < currSlot {
|
||||
if err := helpers.ValidateAttestationTime(att.Data.Slot, s.genesisTime, params.BeaconConfig().MaximumGossipClockDisparityDuration()); err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"attestationSlot": att.Data.Slot,
|
||||
"currentSlot": currSlot,
|
||||
}).Warning("Attestation is too old to broadcast, discarding it")
|
||||
}).WithError(err).Warning("Attestation is too old to broadcast, discarding it")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ type Config struct {
|
||||
PrivateKey string
|
||||
DataDir string
|
||||
MetaDataDir string
|
||||
QUICPort uint
|
||||
TCPPort uint
|
||||
UDPPort uint
|
||||
MaxPeers uint
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
ecdsaprysm "github.com/prysmaticlabs/prysm/v5/crypto/ecdsa"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
@@ -39,6 +40,11 @@ const (
|
||||
udp6
|
||||
)
|
||||
|
||||
type quicProtocol uint16
|
||||
|
||||
// quicProtocol is the "quic" key, which holds the QUIC port of the node.
|
||||
func (quicProtocol) ENRKey() string { return "quic" }
|
||||
|
||||
// RefreshENR uses an epoch to refresh the enr entry for our node
|
||||
// with the tracked committee ids for the epoch, allowing our node
|
||||
// to be dynamically discoverable by others given our tracked committee ids.
|
||||
@@ -100,14 +106,15 @@ func (s *Service) RefreshENR() {
|
||||
|
||||
// listen for new nodes watches for new nodes in the network and adds them to the peerstore.
|
||||
func (s *Service) listenForNewNodes() {
|
||||
iterator := s.dv5Listener.RandomNodes()
|
||||
iterator = enode.Filter(iterator, s.filterPeer)
|
||||
iterator := enode.Filter(s.dv5Listener.RandomNodes(), s.filterPeer)
|
||||
defer iterator.Close()
|
||||
|
||||
for {
|
||||
// Exit if service's context is canceled
|
||||
// Exit if service's context is canceled.
|
||||
if s.ctx.Err() != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if s.isPeerAtLimit(false /* inbound */) {
|
||||
// Pause the main loop for a period to stop looking
|
||||
// for new peers.
|
||||
@@ -115,16 +122,22 @@ func (s *Service) listenForNewNodes() {
|
||||
time.Sleep(pollingPeriod)
|
||||
continue
|
||||
}
|
||||
exists := iterator.Next()
|
||||
if !exists {
|
||||
|
||||
if exists := iterator.Next(); !exists {
|
||||
break
|
||||
}
|
||||
|
||||
node := iterator.Node()
|
||||
peerInfo, _, err := convertToAddrInfo(node)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not convert to peer info")
|
||||
continue
|
||||
}
|
||||
|
||||
if peerInfo == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Make sure that peer is not dialed too often, for each connection attempt there's a backoff period.
|
||||
s.Peers().RandomizeBackOff(peerInfo.ID)
|
||||
go func(info *peer.AddrInfo) {
|
||||
@@ -167,8 +180,7 @@ func (s *Service) createListener(
|
||||
|
||||
// Listen to all network interfaces
|
||||
// for both ip protocols.
|
||||
networkVersion := "udp"
|
||||
conn, err := net.ListenUDP(networkVersion, udpAddr)
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not listen to UDP")
|
||||
}
|
||||
@@ -178,6 +190,7 @@ func (s *Service) createListener(
|
||||
ipAddr,
|
||||
int(s.cfg.UDPPort),
|
||||
int(s.cfg.TCPPort),
|
||||
int(s.cfg.QUICPort),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create local node")
|
||||
@@ -209,7 +222,7 @@ func (s *Service) createListener(
|
||||
func (s *Service) createLocalNode(
|
||||
privKey *ecdsa.PrivateKey,
|
||||
ipAddr net.IP,
|
||||
udpPort, tcpPort int,
|
||||
udpPort, tcpPort, quicPort int,
|
||||
) (*enode.LocalNode, error) {
|
||||
db, err := enode.OpenDB("")
|
||||
if err != nil {
|
||||
@@ -218,11 +231,19 @@ func (s *Service) createLocalNode(
|
||||
localNode := enode.NewLocalNode(db, privKey)
|
||||
|
||||
ipEntry := enr.IP(ipAddr)
|
||||
udpEntry := enr.UDP(udpPort)
|
||||
tcpEntry := enr.TCP(tcpPort)
|
||||
localNode.Set(ipEntry)
|
||||
|
||||
udpEntry := enr.UDP(udpPort)
|
||||
localNode.Set(udpEntry)
|
||||
|
||||
tcpEntry := enr.TCP(tcpPort)
|
||||
localNode.Set(tcpEntry)
|
||||
|
||||
if features.Get().EnableQUIC {
|
||||
quicEntry := quicProtocol(quicPort)
|
||||
localNode.Set(quicEntry)
|
||||
}
|
||||
|
||||
localNode.SetFallbackIP(ipAddr)
|
||||
localNode.SetFallbackUDP(udpPort)
|
||||
|
||||
@@ -277,7 +298,7 @@ func (s *Service) startDiscoveryV5(
|
||||
// filterPeer validates each node that we retrieve from our dht. We
|
||||
// try to ascertain that the peer can be a valid protocol peer.
|
||||
// Validity Conditions:
|
||||
// 1. Peer has a valid IP and TCP port set in their enr.
|
||||
// 1. Peer has a valid IP and a (QUIC and/or TCP) port set in their enr.
|
||||
// 2. Peer hasn't been marked as 'bad'.
|
||||
// 3. Peer is not currently active or connected.
|
||||
// 4. Peer is ready to receive incoming connections.
|
||||
@@ -294,17 +315,13 @@ func (s *Service) filterPeer(node *enode.Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Ignore nodes with their TCP ports not set.
|
||||
if err := node.Record().Load(enr.WithEntry("tcp", new(enr.TCP))); err != nil {
|
||||
if !enr.IsNotFound(err) {
|
||||
log.WithError(err).Debug("Could not retrieve tcp port")
|
||||
}
|
||||
peerData, multiAddrs, err := convertToAddrInfo(node)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not convert to peer data")
|
||||
return false
|
||||
}
|
||||
|
||||
peerData, multiAddr, err := convertToAddrInfo(node)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not convert to peer data")
|
||||
if peerData == nil || len(multiAddrs) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -337,6 +354,9 @@ func (s *Service) filterPeer(node *enode.Node) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// If the peer has 2 multiaddrs, favor the QUIC address, which is in first position.
|
||||
multiAddr := multiAddrs[0]
|
||||
|
||||
// Add peer to peer handler.
|
||||
s.peers.Add(nodeENR, peerData.ID, multiAddr, network.DirUnknown)
|
||||
|
||||
@@ -380,11 +400,11 @@ func PeersFromStringAddrs(addrs []string) ([]ma.Multiaddr, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Could not get enode from string")
|
||||
}
|
||||
addr, err := convertToSingleMultiAddr(enodeAddr)
|
||||
nodeAddrs, err := retrieveMultiAddrsFromNode(enodeAddr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Could not get multiaddr")
|
||||
}
|
||||
allAddrs = append(allAddrs, addr)
|
||||
allAddrs = append(allAddrs, nodeAddrs...)
|
||||
}
|
||||
return allAddrs, nil
|
||||
}
|
||||
@@ -419,45 +439,139 @@ func parseGenericAddrs(addrs []string) (enodeString, multiAddrString []string) {
|
||||
}
|
||||
|
||||
func convertToMultiAddr(nodes []*enode.Node) []ma.Multiaddr {
|
||||
var multiAddrs []ma.Multiaddr
|
||||
// Expect each node to have a TCP and a QUIC address.
|
||||
multiAddrs := make([]ma.Multiaddr, 0, 2*len(nodes))
|
||||
|
||||
for _, node := range nodes {
|
||||
// ignore nodes with no ip address stored
|
||||
// Skip nodes with no ip address stored.
|
||||
if node.IP() == nil {
|
||||
continue
|
||||
}
|
||||
multiAddr, err := convertToSingleMultiAddr(node)
|
||||
|
||||
// Get up to two multiaddrs (TCP and QUIC) for each node.
|
||||
nodeMultiAddrs, err := retrieveMultiAddrsFromNode(node)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not convert to multiAddr")
|
||||
log.WithError(err).Errorf("Could not convert to multiAddr node %s", node)
|
||||
continue
|
||||
}
|
||||
multiAddrs = append(multiAddrs, multiAddr)
|
||||
|
||||
multiAddrs = append(multiAddrs, nodeMultiAddrs...)
|
||||
}
|
||||
|
||||
return multiAddrs
|
||||
}
|
||||
|
||||
func convertToAddrInfo(node *enode.Node) (*peer.AddrInfo, ma.Multiaddr, error) {
|
||||
multiAddr, err := convertToSingleMultiAddr(node)
|
||||
func convertToAddrInfo(node *enode.Node) (*peer.AddrInfo, []ma.Multiaddr, error) {
|
||||
multiAddrs, err := retrieveMultiAddrsFromNode(node)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
info, err := peer.AddrInfoFromP2pAddr(multiAddr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
if len(multiAddrs) == 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
return info, multiAddr, nil
|
||||
|
||||
infos, err := peer.AddrInfosFromP2pAddrs(multiAddrs...)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "could not convert to peer info: %v", multiAddrs)
|
||||
}
|
||||
|
||||
if len(infos) != 1 {
|
||||
return nil, nil, errors.Errorf("infos contains %v elements, expected exactly 1", len(infos))
|
||||
}
|
||||
|
||||
return &infos[0], multiAddrs, nil
|
||||
}
|
||||
|
||||
func convertToSingleMultiAddr(node *enode.Node) (ma.Multiaddr, error) {
|
||||
// retrieveMultiAddrsFromNode converts an enode.Node to a list of multiaddrs.
|
||||
// If the node has a both a QUIC and a TCP port set in their ENR, then
|
||||
// the multiaddr corresponding to the QUIC port is added first, followed
|
||||
// by the multiaddr corresponding to the TCP port.
|
||||
func retrieveMultiAddrsFromNode(node *enode.Node) ([]ma.Multiaddr, error) {
|
||||
multiaddrs := make([]ma.Multiaddr, 0, 2)
|
||||
|
||||
// Retrieve the node public key.
|
||||
pubkey := node.Pubkey()
|
||||
assertedKey, err := ecdsaprysm.ConvertToInterfacePubkey(pubkey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get pubkey")
|
||||
}
|
||||
|
||||
// Compute the node ID from the public key.
|
||||
id, err := peer.IDFromPublicKey(assertedKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get peer id")
|
||||
}
|
||||
return multiAddressBuilderWithID(node.IP().String(), "tcp", uint(node.TCP()), id)
|
||||
|
||||
if features.Get().EnableQUIC {
|
||||
// If the QUIC entry is present in the ENR, build the corresponding multiaddress.
|
||||
port, ok, err := getPort(node, quic)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get QUIC port")
|
||||
}
|
||||
|
||||
if ok {
|
||||
addr, err := multiAddressBuilderWithID(node.IP(), quic, port, id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not build QUIC address")
|
||||
}
|
||||
|
||||
multiaddrs = append(multiaddrs, addr)
|
||||
}
|
||||
}
|
||||
|
||||
// If the TCP entry is present in the ENR, build the corresponding multiaddress.
|
||||
port, ok, err := getPort(node, tcp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get TCP port")
|
||||
}
|
||||
|
||||
if ok {
|
||||
addr, err := multiAddressBuilderWithID(node.IP(), tcp, port, id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not build TCP address")
|
||||
}
|
||||
|
||||
multiaddrs = append(multiaddrs, addr)
|
||||
}
|
||||
|
||||
return multiaddrs, nil
|
||||
}
|
||||
|
||||
// getPort retrieves the port for a given node and protocol, as well as a boolean
|
||||
// indicating whether the port was found, and an error
|
||||
func getPort(node *enode.Node, protocol internetProtocol) (uint, bool, error) {
|
||||
var (
|
||||
port uint
|
||||
err error
|
||||
)
|
||||
|
||||
switch protocol {
|
||||
case tcp:
|
||||
var entry enr.TCP
|
||||
err = node.Load(&entry)
|
||||
port = uint(entry)
|
||||
case udp:
|
||||
var entry enr.UDP
|
||||
err = node.Load(&entry)
|
||||
port = uint(entry)
|
||||
case quic:
|
||||
var entry quicProtocol
|
||||
err = node.Load(&entry)
|
||||
port = uint(entry)
|
||||
default:
|
||||
return 0, false, errors.Errorf("invalid protocol: %v", protocol)
|
||||
}
|
||||
|
||||
if enr.IsNotFound(err) {
|
||||
return port, false, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, false, errors.Wrap(err, "could not get port")
|
||||
}
|
||||
|
||||
return port, true, nil
|
||||
}
|
||||
|
||||
func convertToUdpMultiAddr(node *enode.Node) ([]ma.Multiaddr, error) {
|
||||
@@ -475,14 +589,14 @@ func convertToUdpMultiAddr(node *enode.Node) ([]ma.Multiaddr, error) {
|
||||
var ip4 enr.IPv4
|
||||
var ip6 enr.IPv6
|
||||
if node.Load(&ip4) == nil {
|
||||
address, ipErr := multiAddressBuilderWithID(net.IP(ip4).String(), "udp", uint(node.UDP()), id)
|
||||
address, ipErr := multiAddressBuilderWithID(net.IP(ip4), udp, uint(node.UDP()), id)
|
||||
if ipErr != nil {
|
||||
return nil, errors.Wrap(ipErr, "could not build IPv4 address")
|
||||
}
|
||||
addresses = append(addresses, address)
|
||||
}
|
||||
if node.Load(&ip6) == nil {
|
||||
address, ipErr := multiAddressBuilderWithID(net.IP(ip6).String(), "udp", uint(node.UDP()), id)
|
||||
address, ipErr := multiAddressBuilderWithID(net.IP(ip6), udp, uint(node.UDP()), id)
|
||||
if ipErr != nil {
|
||||
return nil, errors.Wrap(ipErr, "could not build IPv6 address")
|
||||
}
|
||||
|
||||
@@ -166,8 +166,9 @@ func TestCreateLocalNode(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Define ports.
|
||||
const (
|
||||
udpPort = 2000
|
||||
tcpPort = 3000
|
||||
udpPort = 2000
|
||||
tcpPort = 3000
|
||||
quicPort = 3000
|
||||
)
|
||||
|
||||
// Create a private key.
|
||||
@@ -180,7 +181,7 @@ func TestCreateLocalNode(t *testing.T) {
|
||||
cfg: tt.cfg,
|
||||
}
|
||||
|
||||
localNode, err := service.createLocalNode(privKey, address, udpPort, tcpPort)
|
||||
localNode, err := service.createLocalNode(privKey, address, udpPort, tcpPort, quicPort)
|
||||
if tt.expectedError {
|
||||
require.NotNil(t, err)
|
||||
return
|
||||
@@ -237,7 +238,7 @@ func TestMultiAddrsConversion_InvalidIPAddr(t *testing.T) {
|
||||
genesisTime: time.Now(),
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
}
|
||||
node, err := s.createLocalNode(pkey, addr, 0, 0)
|
||||
node, err := s.createLocalNode(pkey, addr, 0, 0, 0)
|
||||
require.NoError(t, err)
|
||||
multiAddr := convertToMultiAddr([]*enode.Node{node.Node()})
|
||||
assert.Equal(t, 0, len(multiAddr), "Invalid ip address converted successfully")
|
||||
@@ -248,8 +249,9 @@ func TestMultiAddrConversion_OK(t *testing.T) {
|
||||
ipAddr, pkey := createAddrAndPrivKey(t)
|
||||
s := &Service{
|
||||
cfg: &Config{
|
||||
TCPPort: 0,
|
||||
UDPPort: 0,
|
||||
UDPPort: 2000,
|
||||
TCPPort: 3000,
|
||||
QUICPort: 3000,
|
||||
},
|
||||
genesisTime: time.Now(),
|
||||
genesisValidatorsRoot: bytesutil.PadTo([]byte{'A'}, 32),
|
||||
|
||||
@@ -28,7 +28,8 @@ import (
|
||||
)
|
||||
|
||||
func TestStartDiscv5_DifferentForkDigests(t *testing.T) {
|
||||
port := 2000
|
||||
const port = 2000
|
||||
|
||||
ipAddr, pkey := createAddrAndPrivKey(t)
|
||||
genesisTime := time.Now()
|
||||
genesisValidatorsRoot := make([]byte, fieldparams.RootLength)
|
||||
@@ -53,7 +54,7 @@ func TestStartDiscv5_DifferentForkDigests(t *testing.T) {
|
||||
|
||||
var listeners []*discover.UDPv5
|
||||
for i := 1; i <= 5; i++ {
|
||||
port = 3000 + i
|
||||
port := 3000 + i
|
||||
cfg.UDPPort = uint(port)
|
||||
ipAddr, pkey := createAddrAndPrivKey(t)
|
||||
|
||||
@@ -98,13 +99,14 @@ func TestStartDiscv5_DifferentForkDigests(t *testing.T) {
|
||||
s.genesisTime = genesisTime
|
||||
s.genesisValidatorsRoot = make([]byte, 32)
|
||||
s.dv5Listener = lastListener
|
||||
var addrs []ma.Multiaddr
|
||||
|
||||
for _, n := range nodes {
|
||||
if s.filterPeer(n) {
|
||||
addr, err := convertToSingleMultiAddr(n)
|
||||
addrs := make([]ma.Multiaddr, 0)
|
||||
|
||||
for _, node := range nodes {
|
||||
if s.filterPeer(node) {
|
||||
nodeAddrs, err := retrieveMultiAddrsFromNode(node)
|
||||
require.NoError(t, err)
|
||||
addrs = append(addrs, addr)
|
||||
addrs = append(addrs, nodeAddrs...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,10 +116,11 @@ func TestStartDiscv5_DifferentForkDigests(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStartDiscv5_SameForkDigests_DifferentNextForkData(t *testing.T) {
|
||||
const port = 2000
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
hook := logTest.NewGlobal()
|
||||
logrus.SetLevel(logrus.TraceLevel)
|
||||
port := 2000
|
||||
ipAddr, pkey := createAddrAndPrivKey(t)
|
||||
genesisTime := time.Now()
|
||||
genesisValidatorsRoot := make([]byte, 32)
|
||||
@@ -138,7 +141,7 @@ func TestStartDiscv5_SameForkDigests_DifferentNextForkData(t *testing.T) {
|
||||
|
||||
var listeners []*discover.UDPv5
|
||||
for i := 1; i <= 5; i++ {
|
||||
port = 3000 + i
|
||||
port := 3000 + i
|
||||
cfg.UDPPort = uint(port)
|
||||
ipAddr, pkey := createAddrAndPrivKey(t)
|
||||
|
||||
@@ -188,13 +191,13 @@ func TestStartDiscv5_SameForkDigests_DifferentNextForkData(t *testing.T) {
|
||||
s.genesisTime = genesisTime
|
||||
s.genesisValidatorsRoot = make([]byte, 32)
|
||||
s.dv5Listener = lastListener
|
||||
var addrs []ma.Multiaddr
|
||||
addrs := make([]ma.Multiaddr, 0, len(nodes))
|
||||
|
||||
for _, n := range nodes {
|
||||
if s.filterPeer(n) {
|
||||
addr, err := convertToSingleMultiAddr(n)
|
||||
for _, node := range nodes {
|
||||
if s.filterPeer(node) {
|
||||
nodeAddrs, err := retrieveMultiAddrsFromNode(node)
|
||||
require.NoError(t, err)
|
||||
addrs = append(addrs, addr)
|
||||
addrs = append(addrs, nodeAddrs...)
|
||||
}
|
||||
}
|
||||
if len(addrs) == 0 {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -12,32 +13,32 @@ import (
|
||||
var log = logrus.WithField("prefix", "p2p")
|
||||
|
||||
func logIPAddr(id peer.ID, addrs ...ma.Multiaddr) {
|
||||
var correctAddr ma.Multiaddr
|
||||
for _, addr := range addrs {
|
||||
if strings.Contains(addr.String(), "/ip4/") || strings.Contains(addr.String(), "/ip6/") {
|
||||
correctAddr = addr
|
||||
break
|
||||
if !(strings.Contains(addr.String(), "/ip4/") || strings.Contains(addr.String(), "/ip6/")) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if correctAddr != nil {
|
||||
|
||||
log.WithField(
|
||||
"multiAddr",
|
||||
correctAddr.String()+"/p2p/"+id.String(),
|
||||
addr.String()+"/p2p/"+id.String(),
|
||||
).Info("Node started p2p server")
|
||||
}
|
||||
}
|
||||
|
||||
func logExternalIPAddr(id peer.ID, addr string, port uint) {
|
||||
func logExternalIPAddr(id peer.ID, addr string, tcpPort, quicPort uint) {
|
||||
if addr != "" {
|
||||
multiAddr, err := MultiAddressBuilder(addr, port)
|
||||
multiAddrs, err := MultiAddressBuilder(net.ParseIP(addr), tcpPort, quicPort)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not create multiaddress")
|
||||
return
|
||||
}
|
||||
log.WithField(
|
||||
"multiAddr",
|
||||
multiAddr.String()+"/p2p/"+id.String(),
|
||||
).Info("Node started external p2p server")
|
||||
|
||||
for _, multiAddr := range multiAddrs {
|
||||
log.WithField(
|
||||
"multiAddr",
|
||||
multiAddr.String()+"/p2p/"+id.String(),
|
||||
).Info("Node started external p2p server")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,40 +11,68 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/p2p/security/noise"
|
||||
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||
libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
|
||||
libp2ptcp "github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||
gomplex "github.com/libp2p/go-mplex"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
ecdsaprysm "github.com/prysmaticlabs/prysm/v5/crypto/ecdsa"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
)
|
||||
|
||||
type internetProtocol string
|
||||
|
||||
const (
|
||||
udp = "udp"
|
||||
tcp = "tcp"
|
||||
quic = "quic"
|
||||
)
|
||||
|
||||
// MultiAddressBuilder takes in an ip address string and port to produce a go multiaddr format.
|
||||
func MultiAddressBuilder(ipAddr string, port uint) (ma.Multiaddr, error) {
|
||||
parsedIP := net.ParseIP(ipAddr)
|
||||
if parsedIP.To4() == nil && parsedIP.To16() == nil {
|
||||
return nil, errors.Errorf("invalid ip address provided: %s", ipAddr)
|
||||
func MultiAddressBuilder(ip net.IP, tcpPort, quicPort uint) ([]ma.Multiaddr, error) {
|
||||
ipType, err := extractIpType(ip)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to determine IP type")
|
||||
}
|
||||
if parsedIP.To4() != nil {
|
||||
return ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ipAddr, port))
|
||||
|
||||
// Example: /ip4/1.2.3.4./tcp/5678
|
||||
multiaddrStr := fmt.Sprintf("/%s/%s/tcp/%d", ipType, ip, tcpPort)
|
||||
multiAddrTCP, err := ma.NewMultiaddr(multiaddrStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot produce TCP multiaddr format from %s:%d", ip, tcpPort)
|
||||
}
|
||||
return ma.NewMultiaddr(fmt.Sprintf("/ip6/%s/tcp/%d", ipAddr, port))
|
||||
|
||||
multiaddrs := []ma.Multiaddr{multiAddrTCP}
|
||||
|
||||
if features.Get().EnableQUIC {
|
||||
// Example: /ip4/1.2.3.4/udp/5678/quic-v1
|
||||
multiAddrQUIC, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%s/udp/%d/quic-v1", ipType, ip, quicPort))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot produce QUIC multiaddr format from %s:%d", ip, tcpPort)
|
||||
}
|
||||
|
||||
multiaddrs = append(multiaddrs, multiAddrQUIC)
|
||||
}
|
||||
|
||||
return multiaddrs, nil
|
||||
}
|
||||
|
||||
// buildOptions for the libp2p host.
|
||||
func (s *Service) buildOptions(ip net.IP, priKey *ecdsa.PrivateKey) ([]libp2p.Option, error) {
|
||||
cfg := s.cfg
|
||||
listen, err := MultiAddressBuilder(ip.String(), cfg.TCPPort)
|
||||
multiaddrs, err := MultiAddressBuilder(ip, cfg.TCPPort, cfg.QUICPort)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot produce multiaddr format from %s:%d", ip.String(), cfg.TCPPort)
|
||||
return nil, errors.Wrapf(err, "cannot produce multiaddr format from %s:%d", ip, cfg.TCPPort)
|
||||
}
|
||||
if cfg.LocalIP != "" {
|
||||
if net.ParseIP(cfg.LocalIP) == nil {
|
||||
localIP := net.ParseIP(cfg.LocalIP)
|
||||
if localIP == nil {
|
||||
return nil, errors.Wrapf(err, "invalid local ip provided: %s:%d", cfg.LocalIP, cfg.TCPPort)
|
||||
}
|
||||
|
||||
listen, err = MultiAddressBuilder(cfg.LocalIP, cfg.TCPPort)
|
||||
multiaddrs, err = MultiAddressBuilder(localIP, cfg.TCPPort, cfg.QUICPort)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot produce multiaddr format from %s:%d", cfg.LocalIP, cfg.TCPPort)
|
||||
}
|
||||
@@ -62,36 +90,43 @@ func (s *Service) buildOptions(ip net.IP, priKey *ecdsa.PrivateKey) ([]libp2p.Op
|
||||
|
||||
options := []libp2p.Option{
|
||||
privKeyOption(priKey),
|
||||
libp2p.ListenAddrs(listen),
|
||||
libp2p.ListenAddrs(multiaddrs...),
|
||||
libp2p.UserAgent(version.BuildData()),
|
||||
libp2p.ConnectionGater(s),
|
||||
libp2p.Transport(tcp.NewTCPTransport),
|
||||
libp2p.Transport(libp2ptcp.NewTCPTransport),
|
||||
libp2p.DefaultMuxers,
|
||||
libp2p.Muxer("/mplex/6.7.0", mplex.DefaultTransport),
|
||||
libp2p.Security(noise.ID, noise.New),
|
||||
libp2p.Ping(false), // Disable Ping Service.
|
||||
}
|
||||
|
||||
if features.Get().EnableQUIC {
|
||||
options = append(options, libp2p.Transport(libp2pquic.NewTransport))
|
||||
}
|
||||
|
||||
if cfg.EnableUPnP {
|
||||
options = append(options, libp2p.NATPortMap()) // Allow to use UPnP
|
||||
}
|
||||
|
||||
if cfg.RelayNodeAddr != "" {
|
||||
options = append(options, libp2p.AddrsFactory(withRelayAddrs(cfg.RelayNodeAddr)))
|
||||
} else {
|
||||
// Disable relay if it has not been set.
|
||||
options = append(options, libp2p.DisableRelay())
|
||||
}
|
||||
|
||||
if cfg.HostAddress != "" {
|
||||
options = append(options, libp2p.AddrsFactory(func(addrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
external, err := MultiAddressBuilder(cfg.HostAddress, cfg.TCPPort)
|
||||
externalMultiaddrs, err := MultiAddressBuilder(net.ParseIP(cfg.HostAddress), cfg.TCPPort, cfg.QUICPort)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Unable to create external multiaddress")
|
||||
} else {
|
||||
addrs = append(addrs, external)
|
||||
addrs = append(addrs, externalMultiaddrs...)
|
||||
}
|
||||
return addrs
|
||||
}))
|
||||
}
|
||||
|
||||
if cfg.HostDNS != "" {
|
||||
options = append(options, libp2p.AddrsFactory(func(addrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
external, err := ma.NewMultiaddr(fmt.Sprintf("/dns4/%s/tcp/%d", cfg.HostDNS, cfg.TCPPort))
|
||||
@@ -107,21 +142,47 @@ func (s *Service) buildOptions(ip net.IP, priKey *ecdsa.PrivateKey) ([]libp2p.Op
|
||||
if features.Get().DisableResourceManager {
|
||||
options = append(options, libp2p.ResourceManager(&network.NullResourceManager{}))
|
||||
}
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func multiAddressBuilderWithID(ipAddr, protocol string, port uint, id peer.ID) (ma.Multiaddr, error) {
|
||||
parsedIP := net.ParseIP(ipAddr)
|
||||
if parsedIP.To4() == nil && parsedIP.To16() == nil {
|
||||
return nil, errors.Errorf("invalid ip address provided: %s", ipAddr)
|
||||
func extractIpType(ip net.IP) (string, error) {
|
||||
if ip.To4() != nil {
|
||||
return "ip4", nil
|
||||
}
|
||||
if id.String() == "" {
|
||||
return nil, errors.New("empty peer id given")
|
||||
|
||||
if ip.To16() != nil {
|
||||
return "ip6", nil
|
||||
}
|
||||
if parsedIP.To4() != nil {
|
||||
return ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/%s/%d/p2p/%s", ipAddr, protocol, port, id.String()))
|
||||
|
||||
return "", errors.Errorf("provided IP address is neither IPv4 nor IPv6: %s", ip)
|
||||
}
|
||||
|
||||
func multiAddressBuilderWithID(ip net.IP, protocol internetProtocol, port uint, id peer.ID) (ma.Multiaddr, error) {
|
||||
var multiaddrStr string
|
||||
|
||||
if id == "" {
|
||||
return nil, errors.Errorf("empty peer id given: %s", id)
|
||||
}
|
||||
return ma.NewMultiaddr(fmt.Sprintf("/ip6/%s/%s/%d/p2p/%s", ipAddr, protocol, port, id.String()))
|
||||
|
||||
ipType, err := extractIpType(ip)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to determine IP type")
|
||||
}
|
||||
|
||||
switch protocol {
|
||||
case udp, tcp:
|
||||
// Example with UDP: /ip4/1.2.3.4/udp/5678/p2p/16Uiu2HAkum7hhuMpWqFj3yNLcmQBGmThmqw2ohaCRThXQuKU9ohs
|
||||
// Example with TCP: /ip6/1.2.3.4/tcp/5678/p2p/16Uiu2HAkum7hhuMpWqFj3yNLcmQBGmThmqw2ohaCRThXQuKU9ohs
|
||||
multiaddrStr = fmt.Sprintf("/%s/%s/%s/%d/p2p/%s", ipType, ip, protocol, port, id)
|
||||
case quic:
|
||||
// Example: /ip4/1.2.3.4/udp/5678/quic-v1/p2p/16Uiu2HAkum7hhuMpWqFj3yNLcmQBGmThmqw2ohaCRThXQuKU9ohs
|
||||
multiaddrStr = fmt.Sprintf("/%s/%s/udp/%d/quic-v1/p2p/%s", ipType, ip, port, id)
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported protocol: %s", protocol)
|
||||
}
|
||||
|
||||
return ma.NewMultiaddr(multiaddrStr)
|
||||
}
|
||||
|
||||
// Adds a private key to the libp2p option if the option was provided.
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
@@ -88,30 +89,34 @@ func TestIPV6Support(t *testing.T) {
|
||||
lNode := enode.NewLocalNode(db, key)
|
||||
mockIPV6 := net.IP{0xff, 0x02, 0xAA, 0, 0x1F, 0, 0x2E, 0, 0, 0x36, 0x45, 0, 0, 0, 0, 0x02}
|
||||
lNode.Set(enr.IP(mockIPV6))
|
||||
ma, err := convertToSingleMultiAddr(lNode.Node())
|
||||
mas, err := retrieveMultiAddrsFromNode(lNode.Node())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipv6Exists := false
|
||||
for _, p := range ma.Protocols() {
|
||||
if p.Name == "ip4" {
|
||||
t.Error("Got ip4 address instead of ip6")
|
||||
|
||||
for _, ma := range mas {
|
||||
ipv6Exists := false
|
||||
for _, p := range ma.Protocols() {
|
||||
if p.Name == "ip4" {
|
||||
t.Error("Got ip4 address instead of ip6")
|
||||
}
|
||||
if p.Name == "ip6" {
|
||||
ipv6Exists = true
|
||||
}
|
||||
}
|
||||
if p.Name == "ip6" {
|
||||
ipv6Exists = true
|
||||
if !ipv6Exists {
|
||||
t.Error("Multiaddress did not have ipv6 protocol")
|
||||
}
|
||||
}
|
||||
if !ipv6Exists {
|
||||
t.Error("Multiaddress did not have ipv6 protocol")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultMultiplexers(t *testing.T) {
|
||||
var cfg libp2p.Config
|
||||
_ = cfg
|
||||
p2pCfg := &Config{
|
||||
TCPPort: 2000,
|
||||
UDPPort: 2000,
|
||||
TCPPort: 3000,
|
||||
QUICPort: 3000,
|
||||
StateNotifier: &mock.MockStateNotifier{},
|
||||
}
|
||||
svc := &Service{cfg: p2pCfg}
|
||||
@@ -127,5 +132,57 @@ func TestDefaultMultiplexers(t *testing.T) {
|
||||
|
||||
assert.Equal(t, protocol.ID("/yamux/1.0.0"), cfg.Muxers[0].ID)
|
||||
assert.Equal(t, protocol.ID("/mplex/6.7.0"), cfg.Muxers[1].ID)
|
||||
|
||||
}
|
||||
|
||||
func TestMultiAddressBuilderWithID(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
ip net.IP
|
||||
protocol internetProtocol
|
||||
port uint
|
||||
id string
|
||||
|
||||
expectedMultiaddrStr string
|
||||
}{
|
||||
{
|
||||
name: "UDP",
|
||||
ip: net.IPv4(192, 168, 0, 1),
|
||||
protocol: udp,
|
||||
port: 5678,
|
||||
id: "0025080212210204fb1ebb1aa467527d34306a4794a5171d6516405e720b909b7f816d63aef96a",
|
||||
|
||||
expectedMultiaddrStr: "/ip4/192.168.0.1/udp/5678/p2p/16Uiu2HAkum7hhuMpWqFj3yNLcmQBGmThmqw2ohaCRThXQuKU9ohs",
|
||||
},
|
||||
{
|
||||
name: "TCP",
|
||||
ip: net.IPv4(192, 168, 0, 1),
|
||||
protocol: tcp,
|
||||
port: 5678,
|
||||
id: "0025080212210204fb1ebb1aa467527d34306a4794a5171d6516405e720b909b7f816d63aef96a",
|
||||
|
||||
expectedMultiaddrStr: "/ip4/192.168.0.1/tcp/5678/p2p/16Uiu2HAkum7hhuMpWqFj3yNLcmQBGmThmqw2ohaCRThXQuKU9ohs",
|
||||
},
|
||||
{
|
||||
name: "QUIC",
|
||||
ip: net.IPv4(192, 168, 0, 1),
|
||||
protocol: quic,
|
||||
port: 5678,
|
||||
id: "0025080212210204fb1ebb1aa467527d34306a4794a5171d6516405e720b909b7f816d63aef96a",
|
||||
|
||||
expectedMultiaddrStr: "/ip4/192.168.0.1/udp/5678/quic-v1/p2p/16Uiu2HAkum7hhuMpWqFj3yNLcmQBGmThmqw2ohaCRThXQuKU9ohs",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
id, err := hex.DecodeString(tt.id)
|
||||
require.NoError(t, err)
|
||||
|
||||
actualMultiaddr, err := multiAddressBuilderWithID(tt.ip, tt.protocol, tt.port, peer.ID(id))
|
||||
require.NoError(t, err)
|
||||
|
||||
actualMultiaddrStr := actualMultiaddr.String()
|
||||
require.Equal(t, tt.expectedMultiaddrStr, actualMultiaddrStr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"context"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
@@ -76,6 +77,13 @@ const (
|
||||
MaxBackOffDuration = 5000
|
||||
)
|
||||
|
||||
type InternetProtocol string
|
||||
|
||||
const (
|
||||
TCP = "tcp"
|
||||
QUIC = "quic"
|
||||
)
|
||||
|
||||
// Status is the structure holding the peer status information.
|
||||
type Status struct {
|
||||
ctx context.Context
|
||||
@@ -449,6 +457,19 @@ func (p *Status) InboundConnected() []peer.ID {
|
||||
return peers
|
||||
}
|
||||
|
||||
// InboundConnectedWithProtocol returns the current batch of inbound peers that are connected with a given protocol.
|
||||
func (p *Status) InboundConnectedWithProtocol(protocol InternetProtocol) []peer.ID {
|
||||
p.store.RLock()
|
||||
defer p.store.RUnlock()
|
||||
peers := make([]peer.ID, 0)
|
||||
for pid, peerData := range p.store.Peers() {
|
||||
if peerData.ConnState == PeerConnected && peerData.Direction == network.DirInbound && strings.Contains(peerData.Address.String(), string(protocol)) {
|
||||
peers = append(peers, pid)
|
||||
}
|
||||
}
|
||||
return peers
|
||||
}
|
||||
|
||||
// Outbound returns the current batch of outbound peers.
|
||||
func (p *Status) Outbound() []peer.ID {
|
||||
p.store.RLock()
|
||||
@@ -475,7 +496,20 @@ func (p *Status) OutboundConnected() []peer.ID {
|
||||
return peers
|
||||
}
|
||||
|
||||
// Active returns the peers that are connecting or connected.
|
||||
// OutboundConnectedWithProtocol returns the current batch of outbound peers that are connected with a given protocol.
|
||||
func (p *Status) OutboundConnectedWithProtocol(protocol InternetProtocol) []peer.ID {
|
||||
p.store.RLock()
|
||||
defer p.store.RUnlock()
|
||||
peers := make([]peer.ID, 0)
|
||||
for pid, peerData := range p.store.Peers() {
|
||||
if peerData.ConnState == PeerConnected && peerData.Direction == network.DirOutbound && strings.Contains(peerData.Address.String(), string(protocol)) {
|
||||
peers = append(peers, pid)
|
||||
}
|
||||
}
|
||||
return peers
|
||||
}
|
||||
|
||||
// Active returns the peers that are active (connecting or connected).
|
||||
func (p *Status) Active() []peer.ID {
|
||||
p.store.RLock()
|
||||
defer p.store.RUnlock()
|
||||
@@ -514,7 +548,7 @@ func (p *Status) Disconnected() []peer.ID {
|
||||
return peers
|
||||
}
|
||||
|
||||
// Inactive returns the peers that are disconnecting or disconnected.
|
||||
// Inactive returns the peers that are inactive (disconnecting or disconnected).
|
||||
func (p *Status) Inactive() []peer.ID {
|
||||
p.store.RLock()
|
||||
defer p.store.RUnlock()
|
||||
|
||||
@@ -1111,6 +1111,87 @@ func TestInbound(t *testing.T) {
|
||||
assert.Equal(t, inbound.String(), result[0].String())
|
||||
}
|
||||
|
||||
func TestInboundConnected(t *testing.T) {
|
||||
p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||
PeerLimit: 30,
|
||||
ScorerParams: &scorers.Config{
|
||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||
Threshold: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
addr, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/33333")
|
||||
require.NoError(t, err)
|
||||
inbound := createPeer(t, p, addr, network.DirInbound, peers.PeerConnected)
|
||||
createPeer(t, p, addr, network.DirInbound, peers.PeerConnecting)
|
||||
|
||||
result := p.InboundConnected()
|
||||
require.Equal(t, 1, len(result))
|
||||
assert.Equal(t, inbound.String(), result[0].String())
|
||||
}
|
||||
|
||||
func TestInboundConnectedWithProtocol(t *testing.T) {
|
||||
p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||
PeerLimit: 30,
|
||||
ScorerParams: &scorers.Config{
|
||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||
Threshold: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
addrsTCP := []string{
|
||||
"/ip4/127.0.0.1/tcp/33333",
|
||||
"/ip4/127.0.0.2/tcp/44444",
|
||||
}
|
||||
|
||||
addrsQUIC := []string{
|
||||
"/ip4/192.168.1.3/udp/13000/quic-v1",
|
||||
"/ip4/192.168.1.4/udp/14000/quic-v1",
|
||||
"/ip4/192.168.1.5/udp/14000/quic-v1",
|
||||
}
|
||||
|
||||
expectedTCP := make(map[string]bool, len(addrsTCP))
|
||||
for _, addr := range addrsTCP {
|
||||
multiaddr, err := ma.NewMultiaddr(addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
peer := createPeer(t, p, multiaddr, network.DirInbound, peers.PeerConnected)
|
||||
expectedTCP[peer.String()] = true
|
||||
}
|
||||
|
||||
expectedQUIC := make(map[string]bool, len(addrsQUIC))
|
||||
for _, addr := range addrsQUIC {
|
||||
multiaddr, err := ma.NewMultiaddr(addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
peer := createPeer(t, p, multiaddr, network.DirInbound, peers.PeerConnected)
|
||||
expectedQUIC[peer.String()] = true
|
||||
}
|
||||
|
||||
// TCP
|
||||
// ---
|
||||
|
||||
actualTCP := p.InboundConnectedWithProtocol(peers.TCP)
|
||||
require.Equal(t, len(expectedTCP), len(actualTCP))
|
||||
|
||||
for _, actualPeer := range actualTCP {
|
||||
_, ok := expectedTCP[actualPeer.String()]
|
||||
require.Equal(t, true, ok)
|
||||
}
|
||||
|
||||
// QUIC
|
||||
// ----
|
||||
actualQUIC := p.InboundConnectedWithProtocol(peers.QUIC)
|
||||
require.Equal(t, len(expectedQUIC), len(actualQUIC))
|
||||
|
||||
for _, actualPeer := range actualQUIC {
|
||||
_, ok := expectedQUIC[actualPeer.String()]
|
||||
require.Equal(t, true, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutbound(t *testing.T) {
|
||||
p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||
PeerLimit: 30,
|
||||
@@ -1130,6 +1211,87 @@ func TestOutbound(t *testing.T) {
|
||||
assert.Equal(t, outbound.String(), result[0].String())
|
||||
}
|
||||
|
||||
func TestOutboundConnected(t *testing.T) {
|
||||
p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||
PeerLimit: 30,
|
||||
ScorerParams: &scorers.Config{
|
||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||
Threshold: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
addr, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/33333")
|
||||
require.NoError(t, err)
|
||||
inbound := createPeer(t, p, addr, network.DirOutbound, peers.PeerConnected)
|
||||
createPeer(t, p, addr, network.DirOutbound, peers.PeerConnecting)
|
||||
|
||||
result := p.OutboundConnected()
|
||||
require.Equal(t, 1, len(result))
|
||||
assert.Equal(t, inbound.String(), result[0].String())
|
||||
}
|
||||
|
||||
func TestOutboundConnectedWithProtocol(t *testing.T) {
|
||||
p := peers.NewStatus(context.Background(), &peers.StatusConfig{
|
||||
PeerLimit: 30,
|
||||
ScorerParams: &scorers.Config{
|
||||
BadResponsesScorerConfig: &scorers.BadResponsesScorerConfig{
|
||||
Threshold: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
addrsTCP := []string{
|
||||
"/ip4/127.0.0.1/tcp/33333",
|
||||
"/ip4/127.0.0.2/tcp/44444",
|
||||
}
|
||||
|
||||
addrsQUIC := []string{
|
||||
"/ip4/192.168.1.3/udp/13000/quic-v1",
|
||||
"/ip4/192.168.1.4/udp/14000/quic-v1",
|
||||
"/ip4/192.168.1.5/udp/14000/quic-v1",
|
||||
}
|
||||
|
||||
expectedTCP := make(map[string]bool, len(addrsTCP))
|
||||
for _, addr := range addrsTCP {
|
||||
multiaddr, err := ma.NewMultiaddr(addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
peer := createPeer(t, p, multiaddr, network.DirOutbound, peers.PeerConnected)
|
||||
expectedTCP[peer.String()] = true
|
||||
}
|
||||
|
||||
expectedQUIC := make(map[string]bool, len(addrsQUIC))
|
||||
for _, addr := range addrsQUIC {
|
||||
multiaddr, err := ma.NewMultiaddr(addr)
|
||||
require.NoError(t, err)
|
||||
|
||||
peer := createPeer(t, p, multiaddr, network.DirOutbound, peers.PeerConnected)
|
||||
expectedQUIC[peer.String()] = true
|
||||
}
|
||||
|
||||
// TCP
|
||||
// ---
|
||||
|
||||
actualTCP := p.OutboundConnectedWithProtocol(peers.TCP)
|
||||
require.Equal(t, len(expectedTCP), len(actualTCP))
|
||||
|
||||
for _, actualPeer := range actualTCP {
|
||||
_, ok := expectedTCP[actualPeer.String()]
|
||||
require.Equal(t, true, ok)
|
||||
}
|
||||
|
||||
// QUIC
|
||||
// ----
|
||||
actualQUIC := p.OutboundConnectedWithProtocol(peers.QUIC)
|
||||
require.Equal(t, len(expectedQUIC), len(actualQUIC))
|
||||
|
||||
for _, actualPeer := range actualQUIC {
|
||||
_, ok := expectedQUIC[actualPeer.String()]
|
||||
require.Equal(t, true, ok)
|
||||
}
|
||||
}
|
||||
|
||||
// addPeer is a helper to add a peer with a given connection state)
|
||||
func addPeer(t *testing.T, p *peers.Status, state peerdata.PeerConnectionState) peer.ID {
|
||||
// Set up some peers with different states
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/peers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/peers/scorers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
leakybucket "github.com/prysmaticlabs/prysm/v5/container/leaky-bucket"
|
||||
prysmnetwork "github.com/prysmaticlabs/prysm/v5/network"
|
||||
@@ -124,31 +125,34 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to build p2p options")
|
||||
}
|
||||
|
||||
// Sets mplex timeouts
|
||||
configureMplex()
|
||||
h, err := libp2p.New(opts...)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create p2p host")
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "failed to create p2p host")
|
||||
}
|
||||
|
||||
s.host = h
|
||||
|
||||
// Gossipsub registration is done before we add in any new peers
|
||||
// due to libp2p's gossipsub implementation not taking into
|
||||
// account previously added peers when creating the gossipsub
|
||||
// object.
|
||||
psOpts := s.pubsubOptions()
|
||||
|
||||
// Set the pubsub global parameters that we require.
|
||||
setPubSubParameters()
|
||||
|
||||
// Reinitialize them in the event we are running a custom config.
|
||||
attestationSubnetCount = params.BeaconConfig().AttestationSubnetCount
|
||||
syncCommsSubnetCount = params.BeaconConfig().SyncCommitteeSubnetCount
|
||||
|
||||
gs, err := pubsub.NewGossipSub(s.ctx, s.host, psOpts...)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to start pubsub")
|
||||
return nil, err
|
||||
return nil, errors.Wrapf(err, "failed to create p2p pubsub")
|
||||
}
|
||||
|
||||
s.pubsub = gs
|
||||
|
||||
s.peers = peers.NewStatus(ctx, &peers.StatusConfig{
|
||||
@@ -213,7 +217,7 @@ func (s *Service) Start() {
|
||||
if len(s.cfg.StaticPeers) > 0 {
|
||||
addrs, err := PeersFromStringAddrs(s.cfg.StaticPeers)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not connect to static peer")
|
||||
log.WithError(err).Error("could not convert ENR to multiaddr")
|
||||
}
|
||||
// Set trusted peers for those that are provided as static addresses.
|
||||
pids := peerIdsFromMultiAddrs(addrs)
|
||||
@@ -232,11 +236,24 @@ func (s *Service) Start() {
|
||||
async.RunEvery(s.ctx, time.Duration(params.BeaconConfig().RespTimeout)*time.Second, s.updateMetrics)
|
||||
async.RunEvery(s.ctx, refreshRate, s.RefreshENR)
|
||||
async.RunEvery(s.ctx, 1*time.Minute, func() {
|
||||
log.WithFields(logrus.Fields{
|
||||
"inbound": len(s.peers.InboundConnected()),
|
||||
"outbound": len(s.peers.OutboundConnected()),
|
||||
"activePeers": len(s.peers.Active()),
|
||||
}).Info("Peer summary")
|
||||
inboundQUICCount := len(s.peers.InboundConnectedWithProtocol(peers.QUIC))
|
||||
inboundTCPCount := len(s.peers.InboundConnectedWithProtocol(peers.TCP))
|
||||
outboundQUICCount := len(s.peers.OutboundConnectedWithProtocol(peers.QUIC))
|
||||
outboundTCPCount := len(s.peers.OutboundConnectedWithProtocol(peers.TCP))
|
||||
total := inboundQUICCount + inboundTCPCount + outboundQUICCount + outboundTCPCount
|
||||
|
||||
fields := logrus.Fields{
|
||||
"inboundTCP": inboundTCPCount,
|
||||
"outboundTCP": outboundTCPCount,
|
||||
"total": total,
|
||||
}
|
||||
|
||||
if features.Get().EnableQUIC {
|
||||
fields["inboundQUIC"] = inboundQUICCount
|
||||
fields["outboundQUIC"] = outboundQUICCount
|
||||
}
|
||||
|
||||
log.WithFields(fields).Info("Connected peers")
|
||||
})
|
||||
|
||||
multiAddrs := s.host.Network().ListenAddresses()
|
||||
@@ -244,9 +261,10 @@ func (s *Service) Start() {
|
||||
|
||||
p2pHostAddress := s.cfg.HostAddress
|
||||
p2pTCPPort := s.cfg.TCPPort
|
||||
p2pQUICPort := s.cfg.QUICPort
|
||||
|
||||
if p2pHostAddress != "" {
|
||||
logExternalIPAddr(s.host.ID(), p2pHostAddress, p2pTCPPort)
|
||||
logExternalIPAddr(s.host.ID(), p2pHostAddress, p2pTCPPort, p2pQUICPort)
|
||||
verifyConnectivity(p2pHostAddress, p2pTCPPort, "tcp")
|
||||
}
|
||||
|
||||
|
||||
@@ -102,8 +102,9 @@ func TestService_Start_OnlyStartsOnce(t *testing.T) {
|
||||
|
||||
cs := startup.NewClockSynchronizer()
|
||||
cfg := &Config{
|
||||
TCPPort: 2000,
|
||||
UDPPort: 2000,
|
||||
TCPPort: 3000,
|
||||
QUICPort: 3000,
|
||||
ClockWaiter: cs,
|
||||
}
|
||||
s, err := NewService(context.Background(), cfg)
|
||||
@@ -147,8 +148,9 @@ func TestService_Start_NoDiscoverFlag(t *testing.T) {
|
||||
|
||||
cs := startup.NewClockSynchronizer()
|
||||
cfg := &Config{
|
||||
TCPPort: 2000,
|
||||
UDPPort: 2000,
|
||||
TCPPort: 3000,
|
||||
QUICPort: 3000,
|
||||
StateNotifier: &mock.MockStateNotifier{},
|
||||
NoDiscovery: true, // <-- no s.dv5Listener is created
|
||||
ClockWaiter: cs,
|
||||
|
||||
@@ -93,6 +93,11 @@ func (s *Service) FindPeersWithSubnet(ctx context.Context, topic string,
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if info == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
if err := s.connectWithPeer(ctx, *info); err != nil {
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestStartDiscV5_FindPeersWithSubnet(t *testing.T) {
|
||||
genesisTime := time.Now()
|
||||
|
||||
bootNodeService := &Service{
|
||||
cfg: &Config{TCPPort: 2000, UDPPort: 3000},
|
||||
cfg: &Config{UDPPort: 2000, TCPPort: 3000, QUICPort: 3000},
|
||||
genesisTime: genesisTime,
|
||||
genesisValidatorsRoot: genesisValidatorsRoot,
|
||||
}
|
||||
@@ -89,8 +89,9 @@ func TestStartDiscV5_FindPeersWithSubnet(t *testing.T) {
|
||||
service, err := NewService(ctx, &Config{
|
||||
Discv5BootStrapAddrs: []string{bootNodeENR},
|
||||
MaxPeers: 30,
|
||||
TCPPort: uint(2000 + i),
|
||||
UDPPort: uint(3000 + i),
|
||||
UDPPort: uint(2000 + i),
|
||||
TCPPort: uint(3000 + i),
|
||||
QUICPort: uint(3000 + i),
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
@@ -133,8 +134,9 @@ func TestStartDiscV5_FindPeersWithSubnet(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Discv5BootStrapAddrs: []string{bootNodeENR},
|
||||
MaxPeers: 30,
|
||||
TCPPort: 2010,
|
||||
UDPPort: 3010,
|
||||
UDPPort: 2010,
|
||||
TCPPort: 3010,
|
||||
QUICPort: 3010,
|
||||
}
|
||||
|
||||
service, err := NewService(ctx, cfg)
|
||||
|
||||
@@ -50,7 +50,7 @@ func ensurePeerConnections(ctx context.Context, h host.Host, peers *peers.Status
|
||||
c := h.Network().ConnsToPeer(p.ID)
|
||||
if len(c) == 0 {
|
||||
if err := connectWithTimeout(ctx, h, p); err != nil {
|
||||
log.WithField("peer", p.ID).WithField("addrs", p.Addrs).WithError(err).Errorf("Failed to reconnect to peer")
|
||||
log.WithField("peer", p.ID).WithField("addrs", p.Addrs).WithError(err).Errorf("failed to reconnect to peer")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ go_library(
|
||||
"//beacon-chain/rpc/eth/helpers:go_default_library",
|
||||
"//beacon-chain/rpc/eth/shared:go_default_library",
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
@@ -121,6 +122,7 @@ go_test(
|
||||
"@com_github_gorilla_mux//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@com_github_stretchr_testify//mock:go_default_library",
|
||||
"@org_uber_go_mock//gomock:go_default_library",
|
||||
],
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/prysm/v1alpha1/validator"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -42,7 +44,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
errNilBlock = errors.New("nil block")
|
||||
errNilBlock = errors.New("nil block")
|
||||
errEquivocatedBlock = errors.New("block is equivocated")
|
||||
)
|
||||
|
||||
type handled bool
|
||||
@@ -1254,6 +1257,16 @@ func (s *Server) publishBlockSSZ(ctx context.Context, w http.ResponseWriter, r *
|
||||
},
|
||||
}
|
||||
if err = s.validateBroadcast(ctx, r, genericBlock); err != nil {
|
||||
if errors.Is(err, errEquivocatedBlock) {
|
||||
b, err := blocks.NewSignedBeaconBlock(genericBlock)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := s.broadcastSeenBlockSidecars(ctx, b, genericBlock.GetDeneb().Blobs, genericBlock.GetDeneb().KzgProofs); err != nil {
|
||||
log.WithError(err).Error("Failed to broadcast blob sidecars")
|
||||
}
|
||||
}
|
||||
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@@ -1383,6 +1396,16 @@ func (s *Server) publishBlock(ctx context.Context, w http.ResponseWriter, r *htt
|
||||
consensusBlock, err = denebBlockContents.ToGeneric()
|
||||
if err == nil {
|
||||
if err = s.validateBroadcast(ctx, r, consensusBlock); err != nil {
|
||||
if errors.Is(err, errEquivocatedBlock) {
|
||||
b, err := blocks.NewSignedBeaconBlock(consensusBlock)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := s.broadcastSeenBlockSidecars(ctx, b, consensusBlock.GetDeneb().Blobs, consensusBlock.GetDeneb().KzgProofs); err != nil {
|
||||
log.WithError(err).Error("Failed to broadcast blob sidecars")
|
||||
}
|
||||
}
|
||||
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@@ -1547,7 +1570,7 @@ func (s *Server) validateConsensus(ctx context.Context, blk interfaces.ReadOnlyS
|
||||
|
||||
func (s *Server) validateEquivocation(blk interfaces.ReadOnlyBeaconBlock) error {
|
||||
if s.ForkchoiceFetcher.HighestReceivedBlockSlot() == blk.Slot() {
|
||||
return fmt.Errorf("block for slot %d already exists in fork choice", blk.Slot())
|
||||
return errors.Wrapf(errEquivocatedBlock, "block for slot %d already exists in fork choice", blk.Slot())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -2072,3 +2095,37 @@ func (s *Server) GetDepositSnapshot(w http.ResponseWriter, r *http.Request) {
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Broadcast blob sidecars even if the block of the same slot has been imported.
|
||||
// To ensure safety, we will only broadcast blob sidecars if the header references the same block that was previously seen.
|
||||
// Otherwise, a proposer could get slashed through a different blob sidecar header reference.
|
||||
func (s *Server) broadcastSeenBlockSidecars(
|
||||
ctx context.Context,
|
||||
b interfaces.SignedBeaconBlock,
|
||||
blobs [][]byte,
|
||||
kzgProofs [][]byte) error {
|
||||
scs, err := validator.BuildBlobSidecars(b, blobs, kzgProofs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, sc := range scs {
|
||||
r, err := sc.SignedBlockHeader.Header.HashTreeRoot()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to hash block header for blob sidecar")
|
||||
continue
|
||||
}
|
||||
if !s.FinalizationFetcher.InForkchoice(r) {
|
||||
log.WithField("root", fmt.Sprintf("%#x", r)).Debug("Block header not in forkchoice, skipping blob sidecar broadcast")
|
||||
continue
|
||||
}
|
||||
if err := s.Broadcaster.BroadcastBlob(ctx, sc.Index, sc); err != nil {
|
||||
log.WithError(err).Error("Failed to broadcast blob sidecar for index ", sc.Index)
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"index": sc.Index,
|
||||
"slot": sc.SignedBlockHeader.Header.Slot,
|
||||
"kzgCommitment": fmt.Sprintf("%#x", sc.KzgCommitment),
|
||||
}).Info("Broadcasted blob sidecar for already seen block")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
mockp2p "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/testing"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
@@ -2472,7 +2474,9 @@ func TestValidateEquivocation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
blk.SetSlot(st.Slot())
|
||||
|
||||
assert.ErrorContains(t, "already exists", server.validateEquivocation(blk.Block()))
|
||||
err = server.validateEquivocation(blk.Block())
|
||||
assert.ErrorContains(t, "already exists", err)
|
||||
require.ErrorIs(t, err, errEquivocatedBlock)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3630,3 +3634,27 @@ func TestGetDepositSnapshot(t *testing.T) {
|
||||
assert.Equal(t, finalized, len(resp.Finalized))
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_broadcastBlobSidecars(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
blockToPropose := util.NewBeaconBlockContentsDeneb()
|
||||
blockToPropose.Blobs = [][]byte{{0x01}, {0x02}, {0x03}}
|
||||
blockToPropose.KzgProofs = [][]byte{{0x01}, {0x02}, {0x03}}
|
||||
blockToPropose.Block.Block.Body.BlobKzgCommitments = [][]byte{bytesutil.PadTo([]byte("kc"), 48), bytesutil.PadTo([]byte("kc1"), 48), bytesutil.PadTo([]byte("kc2"), 48)}
|
||||
d := ð.GenericSignedBeaconBlock_Deneb{Deneb: blockToPropose}
|
||||
b := ð.GenericSignedBeaconBlock{Block: d}
|
||||
|
||||
server := &Server{
|
||||
Broadcaster: &mockp2p.MockBroadcaster{},
|
||||
FinalizationFetcher: &chainMock.ChainService{NotFinalized: true},
|
||||
}
|
||||
|
||||
blk, err := blocks.NewSignedBeaconBlock(b.Block)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, server.broadcastSeenBlockSidecars(context.Background(), blk, b.GetDeneb().Blobs, b.GetDeneb().KzgProofs))
|
||||
require.LogsDoNotContain(t, hook, "Broadcasted blob sidecar for already seen block")
|
||||
|
||||
server.FinalizationFetcher = &chainMock.ChainService{NotFinalized: false}
|
||||
require.NoError(t, server.broadcastSeenBlockSidecars(context.Background(), blk, b.GetDeneb().Blobs, b.GetDeneb().KzgProofs))
|
||||
require.LogsContain(t, hook, "Broadcasted blob sidecar for already seen block")
|
||||
}
|
||||
|
||||
@@ -369,16 +369,7 @@ func decodeIds(w http.ResponseWriter, st state.BeaconState, rawIds []string, ign
|
||||
func valsFromIds(w http.ResponseWriter, st state.BeaconState, ids []primitives.ValidatorIndex) ([]state.ReadOnlyValidator, bool) {
|
||||
var vals []state.ReadOnlyValidator
|
||||
if len(ids) == 0 {
|
||||
allVals := st.Validators()
|
||||
vals = make([]state.ReadOnlyValidator, len(allVals))
|
||||
for i, val := range allVals {
|
||||
readOnlyVal, err := statenative.NewValidator(val)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not convert validator: "+err.Error(), http.StatusInternalServerError)
|
||||
return nil, false
|
||||
}
|
||||
vals[i] = readOnlyVal
|
||||
}
|
||||
vals = st.ValidatorsReadOnly()
|
||||
} else {
|
||||
vals = make([]state.ReadOnlyValidator, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
|
||||
@@ -108,7 +108,7 @@ func (*Server) GetVersion(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// GetHealth returns node health status in http status codes. Useful for load balancers.
|
||||
func (s *Server) GetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := trace.StartSpan(r.Context(), "node.GetHealth")
|
||||
ctx, span := trace.StartSpan(r.Context(), "node.GetHealth")
|
||||
defer span.End()
|
||||
|
||||
rawSyncingStatus, syncingStatus, ok := shared.UintFromQuery(w, r, "syncing_status", false)
|
||||
@@ -119,10 +119,14 @@ func (s *Server) GetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if s.SyncChecker.Synced() {
|
||||
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(ctx)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not check optimistic status: "+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
if s.SyncChecker.Synced() && !optimistic {
|
||||
return
|
||||
}
|
||||
if s.SyncChecker.Syncing() || s.SyncChecker.Initialized() {
|
||||
if s.SyncChecker.Syncing() || optimistic {
|
||||
if rawSyncingStatus != "" {
|
||||
w.WriteHeader(intSyncingStatus)
|
||||
} else {
|
||||
@@ -130,5 +134,6 @@ func (s *Server) GetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
}
|
||||
|
||||
@@ -91,8 +91,10 @@ func TestGetVersion(t *testing.T) {
|
||||
|
||||
func TestGetHealth(t *testing.T) {
|
||||
checker := &syncmock.Sync{}
|
||||
optimisticFetcher := &mock.ChainService{Optimistic: false}
|
||||
s := &Server{
|
||||
SyncChecker: checker,
|
||||
SyncChecker: checker,
|
||||
OptimisticModeFetcher: optimisticFetcher,
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/node/health", nil)
|
||||
@@ -101,25 +103,30 @@ func TestGetHealth(t *testing.T) {
|
||||
s.GetHealth(writer, request)
|
||||
assert.Equal(t, http.StatusServiceUnavailable, writer.Code)
|
||||
|
||||
checker.IsInitialized = true
|
||||
request = httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/node/health", nil)
|
||||
writer = httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.GetHealth(writer, request)
|
||||
assert.Equal(t, http.StatusPartialContent, writer.Code)
|
||||
|
||||
checker.IsSyncing = true
|
||||
checker.IsSynced = false
|
||||
request = httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://example.com/eth/v1/node/health?syncing_status=%d", http.StatusPaymentRequired), nil)
|
||||
writer = httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.GetHealth(writer, request)
|
||||
assert.Equal(t, http.StatusPaymentRequired, writer.Code)
|
||||
|
||||
checker.IsSyncing = false
|
||||
checker.IsSynced = true
|
||||
request = httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/node/health", nil)
|
||||
writer = httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.GetHealth(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
checker.IsSyncing = false
|
||||
checker.IsSynced = true
|
||||
optimisticFetcher.Optimistic = true
|
||||
request = httptest.NewRequest(http.MethodGet, "http://example.com/eth/v1/node/health", nil)
|
||||
writer = httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
s.GetHealth(writer, request)
|
||||
assert.Equal(t, http.StatusPartialContent, writer.Code)
|
||||
}
|
||||
|
||||
func TestGetIdentity(t *testing.T) {
|
||||
|
||||
@@ -223,7 +223,7 @@ func (p *BeaconDbBlocker) Blobs(ctx context.Context, id string, indices []uint64
|
||||
return nil, &core.RpcError{Err: errors.Wrap(err, "failed to retrieve block from db"), Reason: core.Internal}
|
||||
}
|
||||
// if block is not in the retention window return 200 w/ empty list
|
||||
if !params.WithinDAPeriod(slots.ToEpoch(b.Block().Slot()), slots.ToEpoch(p.GenesisTimeFetcher.CurrentSlot())) {
|
||||
if !p.BlobStorage.WithinRetentionPeriod(slots.ToEpoch(b.Block().Slot()), slots.ToEpoch(p.GenesisTimeFetcher.CurrentSlot())) {
|
||||
return make([]*blocks.VerifiedROBlob, 0), nil
|
||||
}
|
||||
commitments, err := b.Block().Body().BlobKzgCommitments()
|
||||
|
||||
@@ -164,8 +164,7 @@ func TestGetBlob(t *testing.T) {
|
||||
db := testDB.SetupDB(t)
|
||||
denebBlock, blobs := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, 123, 4)
|
||||
require.NoError(t, db.SaveBlock(context.Background(), denebBlock))
|
||||
_, bs, err := filesystem.NewEphemeralBlobStorageWithFs(t)
|
||||
require.NoError(t, err)
|
||||
_, bs := filesystem.NewEphemeralBlobStorageWithFs(t)
|
||||
testSidecars, err := verification.BlobSidecarSliceNoop(blobs)
|
||||
require.NoError(t, err)
|
||||
for i := range testSidecars {
|
||||
|
||||
@@ -341,7 +341,7 @@ func (vs *Server) handleUnblindedBlock(block interfaces.SignedBeaconBlock, req *
|
||||
if dbBlockContents == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return buildBlobSidecars(block, dbBlockContents.Blobs, dbBlockContents.KzgProofs)
|
||||
return BuildBlobSidecars(block, dbBlockContents.Blobs, dbBlockContents.KzgProofs)
|
||||
}
|
||||
|
||||
// broadcastReceiveBlock broadcasts a block and handles its reception.
|
||||
|
||||
@@ -56,8 +56,8 @@ func (c *blobsBundleCache) prune(minSlot primitives.Slot) {
|
||||
}
|
||||
}
|
||||
|
||||
// buildBlobSidecars given a block, builds the blob sidecars for the block.
|
||||
func buildBlobSidecars(blk interfaces.SignedBeaconBlock, blobs [][]byte, kzgProofs [][]byte) ([]*ethpb.BlobSidecar, error) {
|
||||
// BuildBlobSidecars given a block, builds the blob sidecars for the block.
|
||||
func BuildBlobSidecars(blk interfaces.SignedBeaconBlock, blobs [][]byte, kzgProofs [][]byte) ([]*ethpb.BlobSidecar, error) {
|
||||
if blk.Version() < version.Deneb {
|
||||
return nil, nil // No blobs before deneb.
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestServer_buildBlobSidecars(t *testing.T) {
|
||||
require.NoError(t, blk.SetBlobKzgCommitments(kzgCommitments))
|
||||
proof, err := hexutil.Decode("0xb4021b0de10f743893d4f71e1bf830c019e832958efd6795baf2f83b8699a9eccc5dc99015d8d4d8ec370d0cc333c06a")
|
||||
require.NoError(t, err)
|
||||
scs, err := buildBlobSidecars(blk, [][]byte{
|
||||
scs, err := BuildBlobSidecars(blk, [][]byte{
|
||||
make([]byte, fieldparams.BlobLength), make([]byte, fieldparams.BlobLength),
|
||||
}, [][]byte{
|
||||
proof, proof,
|
||||
|
||||
@@ -135,7 +135,7 @@ With 1_048_576 validators, we need 4096 * 2MB = 8GB
|
||||
Storing both MIN and MAX spans for 1_048_576 validators takes 16GB.
|
||||
|
||||
Each chunk is stored snappy-compressed in the database.
|
||||
If all validators attest ideally, a MIN SPAN chunk will contain only `2`s, and and MAX SPAN chunk will contain only `0`s.
|
||||
If all validators attest ideally, a MIN SPAN chunk will contain only `2`s, and MAX SPAN chunk will contain only `0`s.
|
||||
This will compress very well, and will let us store a lot of data in a small amount of space.
|
||||
*/
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ type ReadOnlyValidator interface {
|
||||
// ReadOnlyValidators defines a struct which only has read access to validators methods.
|
||||
type ReadOnlyValidators interface {
|
||||
Validators() []*ethpb.Validator
|
||||
ValidatorsReadOnly() []ReadOnlyValidator
|
||||
ValidatorAtIndex(idx primitives.ValidatorIndex) (*ethpb.Validator, error)
|
||||
ValidatorAtIndexReadOnly(idx primitives.ValidatorIndex) (ReadOnlyValidator, error)
|
||||
ValidatorIndexByPubkey(key [fieldparams.BLSPubkeyLength]byte) (primitives.ValidatorIndex, bool)
|
||||
|
||||
@@ -21,6 +21,14 @@ func (b *BeaconState) Validators() []*ethpb.Validator {
|
||||
return b.validatorsVal()
|
||||
}
|
||||
|
||||
// ValidatorsReadOnly participating in consensus on the beacon chain.
|
||||
func (b *BeaconState) ValidatorsReadOnly() []state.ReadOnlyValidator {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.validatorsReadOnlyVal()
|
||||
}
|
||||
|
||||
func (b *BeaconState) validatorsVal() []*ethpb.Validator {
|
||||
var v []*ethpb.Validator
|
||||
if features.Get().EnableExperimentalState {
|
||||
@@ -46,6 +54,35 @@ func (b *BeaconState) validatorsVal() []*ethpb.Validator {
|
||||
return res
|
||||
}
|
||||
|
||||
func (b *BeaconState) validatorsReadOnlyVal() []state.ReadOnlyValidator {
|
||||
var v []*ethpb.Validator
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.validatorsMultiValue == nil {
|
||||
return nil
|
||||
}
|
||||
v = b.validatorsMultiValue.Value(b)
|
||||
} else {
|
||||
if b.validators == nil {
|
||||
return nil
|
||||
}
|
||||
v = b.validators
|
||||
}
|
||||
|
||||
res := make([]state.ReadOnlyValidator, len(v))
|
||||
var err error
|
||||
for i := 0; i < len(res); i++ {
|
||||
val := v[i]
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
res[i], err = NewValidator(val)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// references of validators participating in consensus on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState. This does not
|
||||
// copy fully and instead just copies the reference.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package backfill
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
@@ -55,6 +56,8 @@ const (
|
||||
batchEndSequence
|
||||
)
|
||||
|
||||
var retryDelay = time.Second
|
||||
|
||||
type batchId string
|
||||
|
||||
type batch struct {
|
||||
@@ -62,6 +65,7 @@ type batch struct {
|
||||
scheduled time.Time
|
||||
seq int // sequence identifier, ie how many times has the sequence() method served this batch
|
||||
retries int
|
||||
retryAfter time.Time
|
||||
begin primitives.Slot
|
||||
end primitives.Slot // half-open interval, [begin, end), ie >= start, < end.
|
||||
results verifiedROBlocks
|
||||
@@ -74,7 +78,7 @@ type batch struct {
|
||||
}
|
||||
|
||||
func (b batch) logFields() logrus.Fields {
|
||||
return map[string]interface{}{
|
||||
f := map[string]interface{}{
|
||||
"batchId": b.id(),
|
||||
"state": b.state.String(),
|
||||
"scheduled": b.scheduled.String(),
|
||||
@@ -86,6 +90,10 @@ func (b batch) logFields() logrus.Fields {
|
||||
"blockPid": b.blockPid,
|
||||
"blobPid": b.blobPid,
|
||||
}
|
||||
if b.retries > 0 {
|
||||
f["retryAfter"] = b.retryAfter.String()
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func (b batch) replaces(r batch) bool {
|
||||
@@ -153,7 +161,8 @@ func (b batch) withState(s batchState) batch {
|
||||
switch b.state {
|
||||
case batchErrRetryable:
|
||||
b.retries += 1
|
||||
log.WithFields(b.logFields()).Info("Sequencing batch for retry")
|
||||
b.retryAfter = time.Now().Add(retryDelay)
|
||||
log.WithFields(b.logFields()).Info("Sequencing batch for retry after delay")
|
||||
case batchInit, batchNil:
|
||||
b.firstScheduled = b.scheduled
|
||||
}
|
||||
@@ -190,8 +199,32 @@ func (b batch) availabilityStore() das.AvailabilityStore {
|
||||
return b.bs.store
|
||||
}
|
||||
|
||||
var batchBlockUntil = func(ctx context.Context, untilRetry time.Duration, b batch) error {
|
||||
log.WithFields(b.logFields()).WithField("untilRetry", untilRetry.String()).
|
||||
Debug("Sleeping for retry backoff delay")
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-time.After(untilRetry):
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (b batch) waitUntilReady(ctx context.Context) error {
|
||||
// Wait to retry a failed batch to avoid hammering peers
|
||||
// if we've hit a state where batches will consistently fail.
|
||||
// Avoids spamming requests and logs.
|
||||
if b.retries > 0 {
|
||||
untilRetry := time.Until(b.retryAfter)
|
||||
if untilRetry > time.Millisecond {
|
||||
return batchBlockUntil(ctx, untilRetry, b)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sortBatchDesc(bb []batch) {
|
||||
sort.Slice(bb, func(i, j int) bool {
|
||||
return bb[j].end < bb[i].end
|
||||
return bb[i].end > bb[j].end
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package backfill
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
@@ -19,3 +22,22 @@ func TestSortBatchDesc(t *testing.T) {
|
||||
require.Equal(t, orderOut[i], batches[i].end)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitUntilReady(t *testing.T) {
|
||||
b := batch{}.withState(batchErrRetryable)
|
||||
require.Equal(t, time.Time{}, b.retryAfter)
|
||||
var got time.Duration
|
||||
wur := batchBlockUntil
|
||||
var errDerp = errors.New("derp")
|
||||
batchBlockUntil = func(_ context.Context, ur time.Duration, _ batch) error {
|
||||
got = ur
|
||||
return errDerp
|
||||
}
|
||||
// retries counter and timestamp are set when we mark the batch for sequencing, if it is in the retry state
|
||||
b = b.withState(batchSequenced)
|
||||
require.ErrorIs(t, b.waitUntilReady(context.Background()), errDerp)
|
||||
require.Equal(t, true, retryDelay-time.Until(b.retryAfter) < time.Millisecond)
|
||||
require.Equal(t, true, got < retryDelay && got > retryDelay-time.Millisecond)
|
||||
require.Equal(t, 1, b.retries)
|
||||
batchBlockUntil = wur
|
||||
}
|
||||
|
||||
@@ -143,6 +143,11 @@ func (p *p2pBatchWorkerPool) batchRouter(pa PeerAssigner) {
|
||||
return
|
||||
}
|
||||
for _, pid := range assigned {
|
||||
if err := todo[0].waitUntilReady(p.ctx); err != nil {
|
||||
log.WithError(p.ctx.Err()).Info("p2pBatchWorkerPool context canceled, shutting down")
|
||||
p.shutdown(p.ctx.Err())
|
||||
return
|
||||
}
|
||||
busy[pid] = true
|
||||
todo[0].busy = pid
|
||||
p.toWorkers <- todo[0].withPeer(pid)
|
||||
|
||||
@@ -33,7 +33,6 @@ go_library(
|
||||
"//beacon-chain/verification:go_default_library",
|
||||
"//cmd/beacon-chain/flags:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
@@ -83,10 +82,10 @@ go_test(
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/startup:go_default_library",
|
||||
"//beacon-chain/sync:go_default_library",
|
||||
"//beacon-chain/sync/verify:go_default_library",
|
||||
"//beacon-chain/verification:go_default_library",
|
||||
"//cmd/beacon-chain/flags:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
|
||||
p2pTypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/startup"
|
||||
@@ -18,7 +19,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/sync/verify"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/flags"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
blocks2 "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/rand"
|
||||
"github.com/prysmaticlabs/prysm/v5/math"
|
||||
p2ppb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -76,6 +77,7 @@ type blocksFetcherConfig struct {
|
||||
db db.ReadOnlyDatabase
|
||||
peerFilterCapacityWeight float64
|
||||
mode syncMode
|
||||
bs filesystem.BlobStorageSummarizer
|
||||
}
|
||||
|
||||
// blocksFetcher is a service to fetch chain data from peers.
|
||||
@@ -91,6 +93,7 @@ type blocksFetcher struct {
|
||||
ctxMap prysmsync.ContextByteVersions
|
||||
p2p p2p.P2P
|
||||
db db.ReadOnlyDatabase
|
||||
bs filesystem.BlobStorageSummarizer
|
||||
blocksPerPeriod uint64
|
||||
rateLimiter *leakybucket.Collector
|
||||
peerLocks map[peer.ID]*peerLock
|
||||
@@ -149,6 +152,7 @@ func newBlocksFetcher(ctx context.Context, cfg *blocksFetcherConfig) *blocksFetc
|
||||
ctxMap: cfg.ctxMap,
|
||||
p2p: cfg.p2p,
|
||||
db: cfg.db,
|
||||
bs: cfg.bs,
|
||||
blocksPerPeriod: uint64(blocksPerPeriod),
|
||||
rateLimiter: rateLimiter,
|
||||
peerLocks: make(map[peer.ID]*peerLock),
|
||||
@@ -236,7 +240,7 @@ func (f *blocksFetcher) loop() {
|
||||
|
||||
// Main loop.
|
||||
for {
|
||||
// Make sure there is are available peers before processing requests.
|
||||
// Make sure there are available peers before processing requests.
|
||||
if _, err := f.waitForMinimumPeers(f.ctx); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
@@ -372,22 +376,17 @@ func sortedBlockWithVerifiedBlobSlice(blocks []interfaces.ReadOnlySignedBeaconBl
|
||||
return rb, nil
|
||||
}
|
||||
|
||||
func blobRequest(bwb []blocks2.BlockWithROBlobs, blobWindowStart primitives.Slot) *p2ppb.BlobSidecarsByRangeRequest {
|
||||
if len(bwb) == 0 {
|
||||
return nil
|
||||
}
|
||||
lowest := lowestSlotNeedsBlob(blobWindowStart, bwb)
|
||||
if lowest == nil {
|
||||
return nil
|
||||
}
|
||||
highest := bwb[len(bwb)-1].Block.Block().Slot()
|
||||
return &p2ppb.BlobSidecarsByRangeRequest{
|
||||
StartSlot: *lowest,
|
||||
Count: uint64(highest.SubSlot(*lowest)) + 1,
|
||||
}
|
||||
type commitmentCount struct {
|
||||
slot primitives.Slot
|
||||
root [32]byte
|
||||
count int
|
||||
}
|
||||
|
||||
func lowestSlotNeedsBlob(retentionStart primitives.Slot, bwb []blocks2.BlockWithROBlobs) *primitives.Slot {
|
||||
type commitmentCountList []commitmentCount
|
||||
|
||||
// countCommitments makes a list of all blocks that have commitments that need to be satisfied.
|
||||
// This gives us a representation to finish building the request that is lightweight and readable for testing.
|
||||
func countCommitments(bwb []blocks2.BlockWithROBlobs, retentionStart primitives.Slot) commitmentCountList {
|
||||
if len(bwb) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -397,8 +396,13 @@ func lowestSlotNeedsBlob(retentionStart primitives.Slot, bwb []blocks2.BlockWith
|
||||
if bwb[len(bwb)-1].Block.Block().Slot() < retentionStart {
|
||||
return nil
|
||||
}
|
||||
for _, b := range bwb {
|
||||
fc := make([]commitmentCount, 0, len(bwb))
|
||||
for i := range bwb {
|
||||
b := bwb[i]
|
||||
slot := b.Block.Block().Slot()
|
||||
if b.Block.Version() < version.Deneb {
|
||||
continue
|
||||
}
|
||||
if slot < retentionStart {
|
||||
continue
|
||||
}
|
||||
@@ -406,67 +410,116 @@ func lowestSlotNeedsBlob(retentionStart primitives.Slot, bwb []blocks2.BlockWith
|
||||
if err != nil || len(commits) == 0 {
|
||||
continue
|
||||
}
|
||||
return &slot
|
||||
fc = append(fc, commitmentCount{slot: slot, root: b.Block.Root(), count: len(commits)})
|
||||
}
|
||||
return fc
|
||||
}
|
||||
|
||||
// func slotRangeForCommitmentCounts(cc []commitmentCount, bs filesystem.BlobStorageSummarizer) *blobRange {
|
||||
func (cc commitmentCountList) blobRange(bs filesystem.BlobStorageSummarizer) *blobRange {
|
||||
if len(cc) == 0 {
|
||||
return nil
|
||||
}
|
||||
// If we don't have a blob summarizer, can't check local blobs, request blobs over complete range.
|
||||
if bs == nil {
|
||||
return &blobRange{low: cc[0].slot, high: cc[len(cc)-1].slot}
|
||||
}
|
||||
for i := range cc {
|
||||
hci := cc[i]
|
||||
// This list is always ordered by increasing slot, per req/resp validation rules.
|
||||
// Skip through slots until we find one with missing blobs.
|
||||
if bs.Summary(hci.root).AllAvailable(hci.count) {
|
||||
continue
|
||||
}
|
||||
// The slow of the first missing blob is the lower bound.
|
||||
// If we don't find an upper bound, we'll have a 1 slot request (same low/high).
|
||||
needed := &blobRange{low: hci.slot, high: hci.slot}
|
||||
// Iterate backward through the list to find the highest missing slot above the lower bound.
|
||||
// Return the complete range as soon as we find it; if lower bound is already the last element,
|
||||
// or if we never find an upper bound, we'll fall through to the bounds being equal after this loop.
|
||||
for z := len(cc) - 1; z > i; z-- {
|
||||
hcz := cc[z]
|
||||
if bs.Summary(hcz.root).AllAvailable(hcz.count) {
|
||||
continue
|
||||
}
|
||||
needed.high = hcz.slot
|
||||
return needed
|
||||
}
|
||||
return needed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sortBlobs(blobs []blocks.ROBlob) []blocks.ROBlob {
|
||||
sort.Slice(blobs, func(i, j int) bool {
|
||||
if blobs[i].Slot() == blobs[j].Slot() {
|
||||
return blobs[i].Index < blobs[j].Index
|
||||
}
|
||||
return blobs[i].Slot() < blobs[j].Slot()
|
||||
})
|
||||
type blobRange struct {
|
||||
low primitives.Slot
|
||||
high primitives.Slot
|
||||
}
|
||||
|
||||
return blobs
|
||||
func (r *blobRange) Request() *p2ppb.BlobSidecarsByRangeRequest {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return &p2ppb.BlobSidecarsByRangeRequest{
|
||||
StartSlot: r.low,
|
||||
Count: uint64(r.high.SubSlot(r.low)) + 1,
|
||||
}
|
||||
}
|
||||
|
||||
var errBlobVerification = errors.New("peer unable to serve aligned BlobSidecarsByRange and BeaconBlockSidecarsByRange responses")
|
||||
var errMissingBlobsForBlockCommitments = errors.Wrap(errBlobVerification, "blobs unavailable for processing block with kzg commitments")
|
||||
|
||||
func verifyAndPopulateBlobs(bwb []blocks2.BlockWithROBlobs, blobs []blocks.ROBlob, blobWindowStart primitives.Slot) ([]blocks2.BlockWithROBlobs, error) {
|
||||
// Assumes bwb has already been sorted by sortedBlockWithVerifiedBlobSlice.
|
||||
blobs = sortBlobs(blobs)
|
||||
blobi := 0
|
||||
// Loop over all blocks, and each time a commitment is observed, advance the index into the blob slice.
|
||||
// The assumption is that the blob slice contains a value for every commitment in the blocks it is based on,
|
||||
// correctly ordered by slot and blob index.
|
||||
for i, bb := range bwb {
|
||||
block := bb.Block.Block()
|
||||
if block.Slot() < blobWindowStart {
|
||||
func verifyAndPopulateBlobs(bwb []blocks2.BlockWithROBlobs, blobs []blocks.ROBlob, req *p2ppb.BlobSidecarsByRangeRequest, bss filesystem.BlobStorageSummarizer) ([]blocks2.BlockWithROBlobs, error) {
|
||||
blobsByRoot := make(map[[32]byte][]blocks.ROBlob)
|
||||
for i := range blobs {
|
||||
if blobs[i].Slot() < req.StartSlot {
|
||||
continue
|
||||
}
|
||||
commits, err := block.Body().BlobKzgCommitments()
|
||||
br := blobs[i].BlockRoot()
|
||||
blobsByRoot[br] = append(blobsByRoot[br], blobs[i])
|
||||
}
|
||||
for i := range bwb {
|
||||
bwi, err := populateBlock(bwb[i], blobsByRoot[bwb[i].Block.Root()], req, bss)
|
||||
if err != nil {
|
||||
if errors.Is(err, consensus_types.ErrUnsupportedField) {
|
||||
log.
|
||||
WithField("blockSlot", block.Slot()).
|
||||
WithField("retentionStart", blobWindowStart).
|
||||
Warn("block with slot within blob retention period has version which does not support commitments")
|
||||
if errors.Is(err, errDidntPopulate) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
return bwb, err
|
||||
}
|
||||
bb.Blobs = make([]blocks.ROBlob, len(commits))
|
||||
for ci := range commits {
|
||||
// There are more expected commitments in this block, but we've run out of blobs from the response
|
||||
// (out-of-bound error guard).
|
||||
if blobi == len(blobs) {
|
||||
return nil, missingCommitError(bb.Block.Root(), bb.Block.Block().Slot(), commits[ci:])
|
||||
}
|
||||
bl := blobs[blobi]
|
||||
if err := verify.BlobAlignsWithBlock(bl, bb.Block); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bb.Blobs[ci] = bl
|
||||
blobi += 1
|
||||
}
|
||||
bwb[i] = bb
|
||||
bwb[i] = bwi
|
||||
}
|
||||
return bwb, nil
|
||||
}
|
||||
|
||||
var errDidntPopulate = errors.New("skipping population of block")
|
||||
|
||||
func populateBlock(bw blocks2.BlockWithROBlobs, blobs []blocks.ROBlob, req *p2ppb.BlobSidecarsByRangeRequest, bss filesystem.BlobStorageSummarizer) (blocks2.BlockWithROBlobs, error) {
|
||||
blk := bw.Block
|
||||
if blk.Version() < version.Deneb || blk.Block().Slot() < req.StartSlot {
|
||||
return bw, errDidntPopulate
|
||||
}
|
||||
commits, err := blk.Block().Body().BlobKzgCommitments()
|
||||
if err != nil {
|
||||
return bw, errDidntPopulate
|
||||
}
|
||||
if len(commits) == 0 {
|
||||
return bw, errDidntPopulate
|
||||
}
|
||||
// Drop blobs on the floor if we already have them.
|
||||
if bss != nil && bss.Summary(blk.Root()).AllAvailable(len(commits)) {
|
||||
return bw, errDidntPopulate
|
||||
}
|
||||
if len(commits) != len(blobs) {
|
||||
return bw, missingCommitError(blk.Root(), blk.Block().Slot(), commits)
|
||||
}
|
||||
for ci := range commits {
|
||||
if err := verify.BlobAlignsWithBlock(blobs[ci], blk); err != nil {
|
||||
return bw, err
|
||||
}
|
||||
}
|
||||
bw.Blobs = blobs
|
||||
return bw, nil
|
||||
}
|
||||
|
||||
func missingCommitError(root [32]byte, slot primitives.Slot, missing [][]byte) error {
|
||||
missStr := make([]string, 0, len(missing))
|
||||
for k := range missing {
|
||||
@@ -488,7 +541,7 @@ func (f *blocksFetcher) fetchBlobsFromPeer(ctx context.Context, bwb []blocks2.Bl
|
||||
return nil, err
|
||||
}
|
||||
// Construct request message based on observed interval of blocks in need of blobs.
|
||||
req := blobRequest(bwb, blobWindowStart)
|
||||
req := countCommitments(bwb, blobWindowStart).blobRange(f.bs).Request()
|
||||
if req == nil {
|
||||
return bwb, nil
|
||||
}
|
||||
@@ -508,7 +561,7 @@ func (f *blocksFetcher) fetchBlobsFromPeer(ctx context.Context, bwb []blocks2.Bl
|
||||
continue
|
||||
}
|
||||
f.p2p.Peers().Scorers().BlockProviderScorer().Touch(p)
|
||||
robs, err := verifyAndPopulateBlobs(bwb, blobs, blobWindowStart)
|
||||
robs, err := verifyAndPopulateBlobs(bwb, blobs, req, f.bs)
|
||||
if err != nil {
|
||||
log.WithField("peer", p).WithError(err).Debug("Invalid BeaconBlobsByRange response")
|
||||
continue
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -14,13 +13,14 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||
dbtest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
p2pm "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
|
||||
p2pt "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/startup"
|
||||
beaconsync "github.com/prysmaticlabs/prysm/v5/beacon-chain/sync"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/sync/verify"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/flags"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
@@ -960,28 +960,7 @@ func TestTimeToWait(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortBlobs(t *testing.T) {
|
||||
_, blobs := util.ExtendBlocksPlusBlobs(t, []blocks.ROBlock{}, 10)
|
||||
shuffled := make([]blocks.ROBlob, len(blobs))
|
||||
for i := range blobs {
|
||||
shuffled[i] = blobs[i]
|
||||
}
|
||||
rand.Shuffle(len(shuffled), func(i, j int) {
|
||||
shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
|
||||
})
|
||||
sorted := sortBlobs(shuffled)
|
||||
require.Equal(t, len(sorted), len(shuffled))
|
||||
for i := range blobs {
|
||||
expect := blobs[i]
|
||||
actual := sorted[i]
|
||||
require.Equal(t, expect.Slot(), actual.Slot())
|
||||
require.Equal(t, expect.Index, actual.Index)
|
||||
require.Equal(t, bytesutil.ToBytes48(expect.KzgCommitment), bytesutil.ToBytes48(actual.KzgCommitment))
|
||||
require.Equal(t, expect.BlockRoot(), actual.BlockRoot())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLowestSlotNeedsBlob(t *testing.T) {
|
||||
func TestBlobRangeForBlocks(t *testing.T) {
|
||||
blks, _ := util.ExtendBlocksPlusBlobs(t, []blocks.ROBlock{}, 10)
|
||||
sbbs := make([]interfaces.ReadOnlySignedBeaconBlock, len(blks))
|
||||
for i := range blks {
|
||||
@@ -990,12 +969,12 @@ func TestLowestSlotNeedsBlob(t *testing.T) {
|
||||
retentionStart := primitives.Slot(5)
|
||||
bwb, err := sortedBlockWithVerifiedBlobSlice(sbbs)
|
||||
require.NoError(t, err)
|
||||
lowest := lowestSlotNeedsBlob(retentionStart, bwb)
|
||||
require.Equal(t, retentionStart, *lowest)
|
||||
bounds := countCommitments(bwb, retentionStart).blobRange(nil)
|
||||
require.Equal(t, retentionStart, bounds.low)
|
||||
higher := primitives.Slot(len(blks) + 1)
|
||||
lowest = lowestSlotNeedsBlob(higher, bwb)
|
||||
var nilSlot *primitives.Slot
|
||||
require.Equal(t, nilSlot, lowest)
|
||||
bounds = countCommitments(bwb, higher).blobRange(nil)
|
||||
var nilBounds *blobRange
|
||||
require.Equal(t, nilBounds, bounds)
|
||||
|
||||
blks, _ = util.ExtendBlocksPlusBlobs(t, []blocks.ROBlock{}, 10)
|
||||
sbbs = make([]interfaces.ReadOnlySignedBeaconBlock, len(blks))
|
||||
@@ -1008,14 +987,14 @@ func TestLowestSlotNeedsBlob(t *testing.T) {
|
||||
next := bwb[6].Block.Block().Slot()
|
||||
skip := bwb[5].Block.Block()
|
||||
bwb[5].Block, _ = util.GenerateTestDenebBlockWithSidecar(t, skip.ParentRoot(), skip.Slot(), 0)
|
||||
lowest = lowestSlotNeedsBlob(retentionStart, bwb)
|
||||
require.Equal(t, next, *lowest)
|
||||
bounds = countCommitments(bwb, retentionStart).blobRange(nil)
|
||||
require.Equal(t, next, bounds.low)
|
||||
}
|
||||
|
||||
func TestBlobRequest(t *testing.T) {
|
||||
var nilReq *ethpb.BlobSidecarsByRangeRequest
|
||||
// no blocks
|
||||
req := blobRequest([]blocks.BlockWithROBlobs{}, 0)
|
||||
req := countCommitments([]blocks.BlockWithROBlobs{}, 0).blobRange(nil).Request()
|
||||
require.Equal(t, nilReq, req)
|
||||
blks, _ := util.ExtendBlocksPlusBlobs(t, []blocks.ROBlock{}, 10)
|
||||
sbbs := make([]interfaces.ReadOnlySignedBeaconBlock, len(blks))
|
||||
@@ -1027,26 +1006,180 @@ func TestBlobRequest(t *testing.T) {
|
||||
maxBlkSlot := primitives.Slot(len(blks) - 1)
|
||||
|
||||
tooHigh := primitives.Slot(len(blks) + 1)
|
||||
req = blobRequest(bwb, tooHigh)
|
||||
req = countCommitments(bwb, tooHigh).blobRange(nil).Request()
|
||||
require.Equal(t, nilReq, req)
|
||||
|
||||
req = blobRequest(bwb, maxBlkSlot)
|
||||
req = countCommitments(bwb, maxBlkSlot).blobRange(nil).Request()
|
||||
require.Equal(t, uint64(1), req.Count)
|
||||
require.Equal(t, maxBlkSlot, req.StartSlot)
|
||||
|
||||
halfway := primitives.Slot(5)
|
||||
req = blobRequest(bwb, halfway)
|
||||
req = countCommitments(bwb, halfway).blobRange(nil).Request()
|
||||
require.Equal(t, halfway, req.StartSlot)
|
||||
// adding 1 to include the halfway slot itself
|
||||
require.Equal(t, uint64(1+maxBlkSlot-halfway), req.Count)
|
||||
|
||||
before := bwb[0].Block.Block().Slot()
|
||||
allAfter := bwb[1:]
|
||||
req = blobRequest(allAfter, before)
|
||||
req = countCommitments(allAfter, before).blobRange(nil).Request()
|
||||
require.Equal(t, allAfter[0].Block.Block().Slot(), req.StartSlot)
|
||||
require.Equal(t, len(allAfter), int(req.Count))
|
||||
}
|
||||
|
||||
func TestCountCommitments(t *testing.T) {
|
||||
// no blocks
|
||||
// blocks before retention start filtered
|
||||
// blocks without commitments filtered
|
||||
// pre-deneb filtered
|
||||
// variety of commitment counts are accurate, from 1 to max
|
||||
type testcase struct {
|
||||
name string
|
||||
bwb func(t *testing.T, c testcase) []blocks.BlockWithROBlobs
|
||||
numBlocks int
|
||||
retStart primitives.Slot
|
||||
resCount int
|
||||
}
|
||||
cases := []testcase{
|
||||
{
|
||||
name: "nil blocks is safe",
|
||||
bwb: func(t *testing.T, c testcase) []blocks.BlockWithROBlobs {
|
||||
return nil
|
||||
},
|
||||
retStart: 0,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
bwb := c.bwb(t, c)
|
||||
cc := countCommitments(bwb, c.retStart)
|
||||
require.Equal(t, c.resCount, len(cc))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitmentCountList(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
cc commitmentCountList
|
||||
bss func(*testing.T) filesystem.BlobStorageSummarizer
|
||||
expected *blobRange
|
||||
request *ethpb.BlobSidecarsByRangeRequest
|
||||
}{
|
||||
{
|
||||
name: "nil commitmentCount is safe",
|
||||
cc: nil,
|
||||
expected: nil,
|
||||
request: nil,
|
||||
},
|
||||
{
|
||||
name: "nil bss, single slot",
|
||||
cc: []commitmentCount{
|
||||
{slot: 11235, count: 1},
|
||||
},
|
||||
expected: &blobRange{low: 11235, high: 11235},
|
||||
request: ðpb.BlobSidecarsByRangeRequest{StartSlot: 11235, Count: 1},
|
||||
},
|
||||
{
|
||||
name: "nil bss, sparse slots",
|
||||
cc: []commitmentCount{
|
||||
{slot: 11235, count: 1},
|
||||
{slot: 11240, count: fieldparams.MaxBlobsPerBlock},
|
||||
{slot: 11250, count: 3},
|
||||
},
|
||||
expected: &blobRange{low: 11235, high: 11250},
|
||||
request: ðpb.BlobSidecarsByRangeRequest{StartSlot: 11235, Count: 16},
|
||||
},
|
||||
{
|
||||
name: "AllAvailable in middle, some avail low, none high",
|
||||
bss: func(t *testing.T) filesystem.BlobStorageSummarizer {
|
||||
onDisk := map[[32]byte][]int{
|
||||
bytesutil.ToBytes32([]byte("0")): {0, 1},
|
||||
bytesutil.ToBytes32([]byte("1")): {0, 1, 2, 3, 4, 5},
|
||||
}
|
||||
return filesystem.NewMockBlobStorageSummarizer(t, onDisk)
|
||||
},
|
||||
cc: []commitmentCount{
|
||||
{slot: 0, count: 3, root: bytesutil.ToBytes32([]byte("0"))},
|
||||
{slot: 5, count: fieldparams.MaxBlobsPerBlock, root: bytesutil.ToBytes32([]byte("1"))},
|
||||
{slot: 15, count: 3},
|
||||
},
|
||||
expected: &blobRange{low: 0, high: 15},
|
||||
request: ðpb.BlobSidecarsByRangeRequest{StartSlot: 0, Count: 16},
|
||||
},
|
||||
{
|
||||
name: "AllAvailable at high and low",
|
||||
bss: func(t *testing.T) filesystem.BlobStorageSummarizer {
|
||||
onDisk := map[[32]byte][]int{
|
||||
bytesutil.ToBytes32([]byte("0")): {0, 1},
|
||||
bytesutil.ToBytes32([]byte("2")): {0, 1, 2, 3, 4, 5},
|
||||
}
|
||||
return filesystem.NewMockBlobStorageSummarizer(t, onDisk)
|
||||
},
|
||||
cc: []commitmentCount{
|
||||
{slot: 0, count: 2, root: bytesutil.ToBytes32([]byte("0"))},
|
||||
{slot: 5, count: 3},
|
||||
{slot: 15, count: fieldparams.MaxBlobsPerBlock, root: bytesutil.ToBytes32([]byte("2"))},
|
||||
},
|
||||
expected: &blobRange{low: 5, high: 5},
|
||||
request: ðpb.BlobSidecarsByRangeRequest{StartSlot: 5, Count: 1},
|
||||
},
|
||||
{
|
||||
name: "AllAvailable at high and low, adjacent range in middle",
|
||||
bss: func(t *testing.T) filesystem.BlobStorageSummarizer {
|
||||
onDisk := map[[32]byte][]int{
|
||||
bytesutil.ToBytes32([]byte("0")): {0, 1},
|
||||
bytesutil.ToBytes32([]byte("2")): {0, 1, 2, 3, 4, 5},
|
||||
}
|
||||
return filesystem.NewMockBlobStorageSummarizer(t, onDisk)
|
||||
},
|
||||
cc: []commitmentCount{
|
||||
{slot: 0, count: 2, root: bytesutil.ToBytes32([]byte("0"))},
|
||||
{slot: 5, count: 3},
|
||||
{slot: 6, count: 3},
|
||||
{slot: 15, count: fieldparams.MaxBlobsPerBlock, root: bytesutil.ToBytes32([]byte("2"))},
|
||||
},
|
||||
expected: &blobRange{low: 5, high: 6},
|
||||
request: ðpb.BlobSidecarsByRangeRequest{StartSlot: 5, Count: 2},
|
||||
},
|
||||
{
|
||||
name: "AllAvailable at high and low, range in middle",
|
||||
bss: func(t *testing.T) filesystem.BlobStorageSummarizer {
|
||||
onDisk := map[[32]byte][]int{
|
||||
bytesutil.ToBytes32([]byte("0")): {0, 1},
|
||||
bytesutil.ToBytes32([]byte("1")): {0, 1},
|
||||
bytesutil.ToBytes32([]byte("2")): {0, 1, 2, 3, 4, 5},
|
||||
}
|
||||
return filesystem.NewMockBlobStorageSummarizer(t, onDisk)
|
||||
},
|
||||
cc: []commitmentCount{
|
||||
{slot: 0, count: 2, root: bytesutil.ToBytes32([]byte("0"))},
|
||||
{slot: 5, count: 3, root: bytesutil.ToBytes32([]byte("1"))},
|
||||
{slot: 10, count: 3},
|
||||
{slot: 15, count: fieldparams.MaxBlobsPerBlock, root: bytesutil.ToBytes32([]byte("2"))},
|
||||
},
|
||||
expected: &blobRange{low: 5, high: 10},
|
||||
request: ðpb.BlobSidecarsByRangeRequest{StartSlot: 5, Count: 6},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
var bss filesystem.BlobStorageSummarizer
|
||||
if c.bss != nil {
|
||||
bss = c.bss(t)
|
||||
}
|
||||
br := c.cc.blobRange(bss)
|
||||
require.DeepEqual(t, c.expected, br)
|
||||
if c.request == nil {
|
||||
require.IsNil(t, br.Request())
|
||||
} else {
|
||||
req := br.Request()
|
||||
require.DeepEqual(t, req.StartSlot, c.request.StartSlot)
|
||||
require.DeepEqual(t, req.Count, c.request.Count)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testSequenceBlockWithBlob(t *testing.T, nblocks int) ([]blocks.BlockWithROBlobs, []blocks.ROBlob) {
|
||||
blks, blobs := util.ExtendBlocksPlusBlobs(t, []blocks.ROBlock{}, nblocks)
|
||||
sbbs := make([]interfaces.ReadOnlySignedBeaconBlock, len(blks))
|
||||
@@ -1058,91 +1191,75 @@ func testSequenceBlockWithBlob(t *testing.T, nblocks int) ([]blocks.BlockWithROB
|
||||
return bwb, blobs
|
||||
}
|
||||
|
||||
func testReqFromResp(bwb []blocks.BlockWithROBlobs) *ethpb.BlobSidecarsByRangeRequest {
|
||||
return ðpb.BlobSidecarsByRangeRequest{
|
||||
StartSlot: bwb[0].Block.Block().Slot(),
|
||||
Count: uint64(bwb[len(bwb)-1].Block.Block().Slot()-bwb[0].Block.Block().Slot()) + 1,
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyAndPopulateBlobs(t *testing.T) {
|
||||
bwb, blobs := testSequenceBlockWithBlob(t, 10)
|
||||
lastBlobIdx := len(blobs) - 1
|
||||
// Blocks are all before the retention window, blobs argument is ignored.
|
||||
windowAfter := bwb[len(bwb)-1].Block.Block().Slot() + 1
|
||||
_, err := verifyAndPopulateBlobs(bwb, nil, windowAfter)
|
||||
require.NoError(t, err)
|
||||
t.Run("happy path", func(t *testing.T) {
|
||||
bwb, blobs := testSequenceBlockWithBlob(t, 10)
|
||||
|
||||
firstBlockSlot := bwb[0].Block.Block().Slot()
|
||||
// slice off blobs for the last block so we hit the out of bounds / blob exhaustion check.
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs[0:len(blobs)-6], firstBlockSlot)
|
||||
require.ErrorIs(t, err, errMissingBlobsForBlockCommitments)
|
||||
|
||||
bwb, blobs = testSequenceBlockWithBlob(t, 10)
|
||||
// Misalign the slots of the blobs for the first block to simulate them being missing from the response.
|
||||
offByOne := blobs[0].Slot()
|
||||
for i := range blobs {
|
||||
if blobs[i].Slot() == offByOne {
|
||||
blobs[i].SignedBlockHeader.Header.Slot = offByOne + 1
|
||||
expectedCommits := make(map[[48]byte]bool)
|
||||
for _, bl := range blobs {
|
||||
expectedCommits[bytesutil.ToBytes48(bl.KzgCommitment)] = true
|
||||
}
|
||||
}
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs, firstBlockSlot)
|
||||
require.ErrorIs(t, err, verify.ErrBlobBlockMisaligned)
|
||||
require.Equal(t, len(blobs), len(expectedCommits))
|
||||
|
||||
bwb, blobs = testSequenceBlockWithBlob(t, 10)
|
||||
blobs[lastBlobIdx], err = blocks.NewROBlobWithRoot(blobs[lastBlobIdx].BlobSidecar, blobs[0].BlockRoot())
|
||||
require.NoError(t, err)
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs, firstBlockSlot)
|
||||
require.ErrorIs(t, err, verify.ErrBlobBlockMisaligned)
|
||||
|
||||
bwb, blobs = testSequenceBlockWithBlob(t, 10)
|
||||
blobs[lastBlobIdx].Index = 100
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs, firstBlockSlot)
|
||||
require.ErrorIs(t, err, verify.ErrIncorrectBlobIndex)
|
||||
|
||||
bwb, blobs = testSequenceBlockWithBlob(t, 10)
|
||||
blobs[lastBlobIdx].SignedBlockHeader.Header.ProposerIndex = 100
|
||||
blobs[lastBlobIdx], err = blocks.NewROBlob(blobs[lastBlobIdx].BlobSidecar)
|
||||
require.NoError(t, err)
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs, firstBlockSlot)
|
||||
require.ErrorIs(t, err, verify.ErrBlobBlockMisaligned)
|
||||
|
||||
bwb, blobs = testSequenceBlockWithBlob(t, 10)
|
||||
blobs[lastBlobIdx].SignedBlockHeader.Header.ParentRoot = blobs[0].SignedBlockHeader.Header.ParentRoot
|
||||
blobs[lastBlobIdx], err = blocks.NewROBlob(blobs[lastBlobIdx].BlobSidecar)
|
||||
require.NoError(t, err)
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs, firstBlockSlot)
|
||||
require.ErrorIs(t, err, verify.ErrBlobBlockMisaligned)
|
||||
|
||||
var emptyKzg [48]byte
|
||||
bwb, blobs = testSequenceBlockWithBlob(t, 10)
|
||||
blobs[lastBlobIdx].KzgCommitment = emptyKzg[:]
|
||||
blobs[lastBlobIdx], err = blocks.NewROBlob(blobs[lastBlobIdx].BlobSidecar)
|
||||
require.NoError(t, err)
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs, firstBlockSlot)
|
||||
require.ErrorIs(t, err, verify.ErrMismatchedBlobCommitments)
|
||||
|
||||
// happy path
|
||||
bwb, blobs = testSequenceBlockWithBlob(t, 10)
|
||||
|
||||
expectedCommits := make(map[[48]byte]bool)
|
||||
for _, bl := range blobs {
|
||||
expectedCommits[bytesutil.ToBytes48(bl.KzgCommitment)] = true
|
||||
}
|
||||
// The assertions using this map expect all commitments to be unique, so make sure that stays true.
|
||||
require.Equal(t, len(blobs), len(expectedCommits))
|
||||
|
||||
bwb, err = verifyAndPopulateBlobs(bwb, blobs, firstBlockSlot)
|
||||
require.NoError(t, err)
|
||||
for _, bw := range bwb {
|
||||
commits, err := bw.Block.Block().Body().BlobKzgCommitments()
|
||||
bwb, err := verifyAndPopulateBlobs(bwb, blobs, testReqFromResp(bwb), nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(commits), len(bw.Blobs))
|
||||
for i := range commits {
|
||||
bc := bytesutil.ToBytes48(commits[i])
|
||||
require.Equal(t, bc, bytesutil.ToBytes48(bw.Blobs[i].KzgCommitment))
|
||||
// Since we delete entries we've seen, duplicates will cause an error here.
|
||||
_, ok := expectedCommits[bc]
|
||||
// Make sure this was an expected delete, then delete it from the map so we can make sure we saw all of them.
|
||||
require.Equal(t, true, ok)
|
||||
delete(expectedCommits, bc)
|
||||
for _, bw := range bwb {
|
||||
commits, err := bw.Block.Block().Body().BlobKzgCommitments()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(commits), len(bw.Blobs))
|
||||
for i := range commits {
|
||||
bc := bytesutil.ToBytes48(commits[i])
|
||||
require.Equal(t, bc, bytesutil.ToBytes48(bw.Blobs[i].KzgCommitment))
|
||||
// Since we delete entries we've seen, duplicates will cause an error here.
|
||||
_, ok := expectedCommits[bc]
|
||||
// Make sure this was an expected delete, then delete it from the map so we can make sure we saw all of them.
|
||||
require.Equal(t, true, ok)
|
||||
delete(expectedCommits, bc)
|
||||
}
|
||||
}
|
||||
}
|
||||
// We delete each entry we've seen, so if we see all expected commits, the map should be empty at the end.
|
||||
require.Equal(t, 0, len(expectedCommits))
|
||||
// We delete each entry we've seen, so if we see all expected commits, the map should be empty at the end.
|
||||
require.Equal(t, 0, len(expectedCommits))
|
||||
})
|
||||
t.Run("missing blobs", func(t *testing.T) {
|
||||
bwb, blobs := testSequenceBlockWithBlob(t, 10)
|
||||
_, err := verifyAndPopulateBlobs(bwb, blobs[1:], testReqFromResp(bwb), nil)
|
||||
require.ErrorIs(t, err, errMissingBlobsForBlockCommitments)
|
||||
})
|
||||
t.Run("no blobs for last block", func(t *testing.T) {
|
||||
bwb, blobs := testSequenceBlockWithBlob(t, 10)
|
||||
lastIdx := len(bwb) - 1
|
||||
lastBlk := bwb[lastIdx].Block
|
||||
cmts, err := lastBlk.Block().Body().BlobKzgCommitments()
|
||||
require.NoError(t, err)
|
||||
blobs = blobs[0 : len(blobs)-len(cmts)]
|
||||
lastBlk, _ = util.GenerateTestDenebBlockWithSidecar(t, lastBlk.Block().ParentRoot(), lastBlk.Block().Slot(), 0)
|
||||
bwb[lastIdx].Block = lastBlk
|
||||
_, err = verifyAndPopulateBlobs(bwb, blobs, testReqFromResp(bwb), nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
t.Run("blobs not copied if all locally available", func(t *testing.T) {
|
||||
bwb, blobs := testSequenceBlockWithBlob(t, 10)
|
||||
// r1 only has some blobs locally available, so we'll still copy them all.
|
||||
// r7 has all blobs locally available, so we shouldn't copy them.
|
||||
i1, i7 := 1, 7
|
||||
r1, r7 := bwb[i1].Block.Root(), bwb[i7].Block.Root()
|
||||
onDisk := map[[32]byte][]int{
|
||||
r1: {0, 1},
|
||||
r7: {0, 1, 2, 3, 4, 5},
|
||||
}
|
||||
bss := filesystem.NewMockBlobStorageSummarizer(t, onDisk)
|
||||
bwb, err := verifyAndPopulateBlobs(bwb, blobs, testReqFromResp(bwb), bss)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 6, len(bwb[i1].Blobs))
|
||||
require.Equal(t, 0, len(bwb[i7].Blobs))
|
||||
})
|
||||
}
|
||||
|
||||
func TestBatchLimit(t *testing.T) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/startup"
|
||||
beaconsync "github.com/prysmaticlabs/prysm/v5/beacon-chain/sync"
|
||||
@@ -69,6 +70,7 @@ type blocksQueueConfig struct {
|
||||
p2p p2p.P2P
|
||||
db db.ReadOnlyDatabase
|
||||
mode syncMode
|
||||
bs filesystem.BlobStorageSummarizer
|
||||
}
|
||||
|
||||
// blocksQueue is a priority queue that serves as a intermediary between block fetchers (producers)
|
||||
@@ -101,12 +103,16 @@ func newBlocksQueue(ctx context.Context, cfg *blocksQueueConfig) *blocksQueue {
|
||||
|
||||
blocksFetcher := cfg.blocksFetcher
|
||||
if blocksFetcher == nil {
|
||||
if cfg.bs == nil {
|
||||
log.Warn("rpc fetcher starting without blob availability cache, duplicate blobs may be requested.")
|
||||
}
|
||||
blocksFetcher = newBlocksFetcher(ctx, &blocksFetcherConfig{
|
||||
ctxMap: cfg.ctxMap,
|
||||
chain: cfg.chain,
|
||||
p2p: cfg.p2p,
|
||||
db: cfg.db,
|
||||
clock: cfg.clock,
|
||||
bs: cfg.bs,
|
||||
})
|
||||
}
|
||||
highestExpectedSlot := cfg.highestExpectedSlot
|
||||
@@ -139,7 +145,7 @@ func newBlocksQueue(ctx context.Context, cfg *blocksQueueConfig) *blocksQueue {
|
||||
queue.smm.addEventHandler(eventDataReceived, stateScheduled, queue.onDataReceivedEvent(ctx))
|
||||
queue.smm.addEventHandler(eventTick, stateDataParsed, queue.onReadyToSendEvent(ctx))
|
||||
queue.smm.addEventHandler(eventTick, stateSkipped, queue.onProcessSkippedEvent(ctx))
|
||||
queue.smm.addEventHandler(eventTick, stateSent, queue.onCheckStaleEvent(ctx))
|
||||
queue.smm.addEventHandler(eventTick, stateSent, onCheckStaleEvent(ctx))
|
||||
|
||||
return queue
|
||||
}
|
||||
@@ -451,7 +457,7 @@ func (q *blocksQueue) onProcessSkippedEvent(ctx context.Context) eventHandlerFn
|
||||
|
||||
// onCheckStaleEvent is an event that allows to mark stale epochs,
|
||||
// so that they can be re-processed.
|
||||
func (_ *blocksQueue) onCheckStaleEvent(ctx context.Context) eventHandlerFn {
|
||||
func onCheckStaleEvent(ctx context.Context) eventHandlerFn {
|
||||
return func(m *stateMachine, in interface{}) (stateID, error) {
|
||||
if ctx.Err() != nil {
|
||||
return m.state, ctx.Err()
|
||||
|
||||
@@ -971,24 +971,12 @@ func TestBlocksQueue_onProcessSkippedEvent(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlocksQueue_onCheckStaleEvent(t *testing.T) {
|
||||
blockBatchLimit := flags.Get().BlockBatchLimit
|
||||
mc, p2p, _ := initializeTestServices(t, []primitives.Slot{}, []*peerData{})
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
fetcher := newBlocksFetcher(ctx, &blocksFetcherConfig{
|
||||
chain: mc,
|
||||
p2p: p2p,
|
||||
})
|
||||
|
||||
t.Run("expired context", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
queue := newBlocksQueue(ctx, &blocksQueueConfig{
|
||||
blocksFetcher: fetcher,
|
||||
chain: mc,
|
||||
highestExpectedSlot: primitives.Slot(blockBatchLimit),
|
||||
})
|
||||
handlerFn := queue.onCheckStaleEvent(ctx)
|
||||
handlerFn := onCheckStaleEvent(ctx)
|
||||
cancel()
|
||||
updatedState, err := handlerFn(&stateMachine{
|
||||
state: stateSkipped,
|
||||
@@ -998,16 +986,10 @@ func TestBlocksQueue_onCheckStaleEvent(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("invalid input state", func(t *testing.T) {
|
||||
queue := newBlocksQueue(ctx, &blocksQueueConfig{
|
||||
blocksFetcher: fetcher,
|
||||
chain: mc,
|
||||
highestExpectedSlot: primitives.Slot(blockBatchLimit),
|
||||
})
|
||||
|
||||
invalidStates := []stateID{stateNew, stateScheduled, stateDataParsed, stateSkipped}
|
||||
for _, state := range invalidStates {
|
||||
t.Run(state.String(), func(t *testing.T) {
|
||||
handlerFn := queue.onCheckStaleEvent(ctx)
|
||||
handlerFn := onCheckStaleEvent(ctx)
|
||||
updatedState, err := handlerFn(&stateMachine{
|
||||
state: state,
|
||||
}, nil)
|
||||
@@ -1018,12 +1000,7 @@ func TestBlocksQueue_onCheckStaleEvent(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("process non stale machine", func(t *testing.T) {
|
||||
queue := newBlocksQueue(ctx, &blocksQueueConfig{
|
||||
blocksFetcher: fetcher,
|
||||
chain: mc,
|
||||
highestExpectedSlot: primitives.Slot(blockBatchLimit),
|
||||
})
|
||||
handlerFn := queue.onCheckStaleEvent(ctx)
|
||||
handlerFn := onCheckStaleEvent(ctx)
|
||||
updatedState, err := handlerFn(&stateMachine{
|
||||
state: stateSent,
|
||||
updated: prysmTime.Now().Add(-staleEpochTimeout / 2),
|
||||
@@ -1034,12 +1011,7 @@ func TestBlocksQueue_onCheckStaleEvent(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("process stale machine", func(t *testing.T) {
|
||||
queue := newBlocksQueue(ctx, &blocksQueueConfig{
|
||||
blocksFetcher: fetcher,
|
||||
chain: mc,
|
||||
highestExpectedSlot: primitives.Slot(blockBatchLimit),
|
||||
})
|
||||
handlerFn := queue.onCheckStaleEvent(ctx)
|
||||
handlerFn := onCheckStaleEvent(ctx)
|
||||
updatedState, err := handlerFn(&stateMachine{
|
||||
state: stateSent,
|
||||
updated: prysmTime.Now().Add(-staleEpochTimeout),
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/das"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/sync"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/verification"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
@@ -62,7 +63,39 @@ func (s *Service) roundRobinSync(genesis time.Time) error {
|
||||
return s.syncToNonFinalizedEpoch(ctx, genesis)
|
||||
}
|
||||
|
||||
// syncToFinalizedEpoch sync from head to best known finalized epoch.
|
||||
func (s *Service) startBlocksQueue(ctx context.Context, highestSlot primitives.Slot, mode syncMode) (*blocksQueue, error) {
|
||||
vr := s.clock.GenesisValidatorsRoot()
|
||||
ctxMap, err := sync.ContextByteVersionsForValRoot(vr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to initialize context version map using genesis validator root = %#x", vr)
|
||||
}
|
||||
|
||||
summarizer, err := s.cfg.BlobStorage.WaitForSummarizer(ctx)
|
||||
if err != nil {
|
||||
// The summarizer is an optional optimization, we can continue without, only stop if there is a different error.
|
||||
if !errors.Is(err, filesystem.ErrBlobStorageSummarizerUnavailable) {
|
||||
return nil, err
|
||||
}
|
||||
summarizer = nil // This should already be nil, but we'll set it just to be safe.
|
||||
}
|
||||
cfg := &blocksQueueConfig{
|
||||
p2p: s.cfg.P2P,
|
||||
db: s.cfg.DB,
|
||||
chain: s.cfg.Chain,
|
||||
clock: s.clock,
|
||||
ctxMap: ctxMap,
|
||||
highestExpectedSlot: highestSlot,
|
||||
mode: mode,
|
||||
bs: summarizer,
|
||||
}
|
||||
queue := newBlocksQueue(ctx, cfg)
|
||||
if err := queue.start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return queue, nil
|
||||
}
|
||||
|
||||
// syncToFinalizedEpoch sync from head to the best known finalized epoch.
|
||||
func (s *Service) syncToFinalizedEpoch(ctx context.Context, genesis time.Time) error {
|
||||
highestFinalizedSlot, err := slots.EpochStart(s.highestFinalizedEpoch())
|
||||
if err != nil {
|
||||
@@ -74,28 +107,12 @@ func (s *Service) syncToFinalizedEpoch(ctx context.Context, genesis time.Time) e
|
||||
return nil
|
||||
}
|
||||
|
||||
vr := s.clock.GenesisValidatorsRoot()
|
||||
ctxMap, err := sync.ContextByteVersionsForValRoot(vr)
|
||||
queue, err := s.startBlocksQueue(ctx, highestFinalizedSlot, modeStopOnFinalizedEpoch)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to initialize context version map using genesis validator root = %#x", vr)
|
||||
}
|
||||
queue := newBlocksQueue(ctx, &blocksQueueConfig{
|
||||
p2p: s.cfg.P2P,
|
||||
db: s.cfg.DB,
|
||||
chain: s.cfg.Chain,
|
||||
clock: s.clock,
|
||||
ctxMap: ctxMap,
|
||||
highestExpectedSlot: highestFinalizedSlot,
|
||||
mode: modeStopOnFinalizedEpoch,
|
||||
})
|
||||
if err := queue.start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for data := range queue.fetchedData {
|
||||
// If blobs are available. Verify blobs and blocks are consistence.
|
||||
// We can't import a block if there's no associated blob within DA bound.
|
||||
// The blob has to pass aggregated proof check.
|
||||
s.processFetchedData(ctx, genesis, s.cfg.Chain.HeadSlot(), data)
|
||||
}
|
||||
|
||||
@@ -113,21 +130,8 @@ func (s *Service) syncToFinalizedEpoch(ctx context.Context, genesis time.Time) e
|
||||
// syncToNonFinalizedEpoch sync from head to best known non-finalized epoch supported by majority
|
||||
// of peers (no less than MinimumSyncPeers*2 peers).
|
||||
func (s *Service) syncToNonFinalizedEpoch(ctx context.Context, genesis time.Time) error {
|
||||
vr := s.clock.GenesisValidatorsRoot()
|
||||
ctxMap, err := sync.ContextByteVersionsForValRoot(vr)
|
||||
queue, err := s.startBlocksQueue(ctx, slots.Since(genesis), modeNonConstrained)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to initialize context version map using genesis validator root = %#x", vr)
|
||||
}
|
||||
queue := newBlocksQueue(ctx, &blocksQueueConfig{
|
||||
p2p: s.cfg.P2P,
|
||||
db: s.cfg.DB,
|
||||
chain: s.cfg.Chain,
|
||||
clock: s.clock,
|
||||
ctxMap: ctxMap,
|
||||
highestExpectedSlot: slots.Since(genesis),
|
||||
mode: modeNonConstrained,
|
||||
})
|
||||
if err := queue.start(); err != nil {
|
||||
return err
|
||||
}
|
||||
for data := range queue.fetchedData {
|
||||
|
||||
@@ -142,7 +142,13 @@ func (s *Service) registerRPC(baseTopic string, handle rpcHandler) {
|
||||
// it successfully writes a response. We don't blindly call
|
||||
// Close here because we may have only written a partial
|
||||
// response.
|
||||
// About the special case for quic-v1, please see:
|
||||
// https://github.com/quic-go/quic-go/issues/3291
|
||||
defer func() {
|
||||
if strings.Contains(stream.Conn().RemoteMultiaddr().String(), "quic-v1") {
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
_err := stream.Reset()
|
||||
_ = _err
|
||||
}()
|
||||
|
||||
@@ -482,7 +482,10 @@ func TestSendRequest_SendBeaconBlocksByRootRequest(t *testing.T) {
|
||||
func TestBlobValidatorFromRootReq(t *testing.T) {
|
||||
rootA := bytesutil.PadTo([]byte("valid"), 32)
|
||||
rootB := bytesutil.PadTo([]byte("invalid"), 32)
|
||||
header := ðpb.SignedBeaconBlockHeader{}
|
||||
header := ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{Slot: 0},
|
||||
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
}
|
||||
blobSidecarA0 := util.GenerateTestDenebBlobSidecar(t, bytesutil.ToBytes32(rootA), header, 0, []byte{}, make([][]byte, 0))
|
||||
blobSidecarA1 := util.GenerateTestDenebBlobSidecar(t, bytesutil.ToBytes32(rootA), header, 1, []byte{}, make([][]byte, 0))
|
||||
blobSidecarB0 := util.GenerateTestDenebBlobSidecar(t, bytesutil.ToBytes32(rootB), header, 0, []byte{}, make([][]byte, 0))
|
||||
@@ -590,7 +593,8 @@ func TestBlobValidatorFromRangeReq(t *testing.T) {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
vf := blobValidatorFromRangeReq(c.req)
|
||||
header := ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{Slot: c.responseSlot},
|
||||
Header: ðpb.BeaconBlockHeader{Slot: c.responseSlot},
|
||||
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
}
|
||||
sc := util.GenerateTestDenebBlobSidecar(t, [32]byte{}, header, 0, []byte{}, make([][]byte, 0))
|
||||
err := vf(sc)
|
||||
|
||||
@@ -46,10 +46,12 @@ func (batch *BlobBatchVerifier) VerifiedROBlobs(ctx context.Context, blk blocks.
|
||||
if len(scs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
blkSig := blk.Signature()
|
||||
// We assume the proposer is validated wrt the block in batch block processing before performing the DA check.
|
||||
// So at this stage we just need to make sure the value being signed and signature bytes match the block.
|
||||
for i := range scs {
|
||||
if blk.Signature() != bytesutil.ToBytes96(scs[i].SignedBlockHeader.Signature) {
|
||||
blobSig := bytesutil.ToBytes96(scs[i].SignedBlockHeader.Signature)
|
||||
if blkSig != blobSig {
|
||||
return nil, ErrBatchSignatureMismatch
|
||||
}
|
||||
// Extra defensive check to make sure the roots match. This should be unnecessary in practice since the root from
|
||||
|
||||
@@ -6,10 +6,9 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/cmd/beacon-chain/jwt",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api:go_default_library",
|
||||
"//cmd:go_default_library",
|
||||
"//crypto/rand:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/v5/api"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/rand"
|
||||
"github.com/prysmaticlabs/prysm/v5/io/file"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -52,7 +50,7 @@ func generateAuthSecretInFile(c *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
secret, err := generateRandomHexString()
|
||||
secret, err := api.GenerateRandomHexString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -62,15 +60,3 @@ func generateAuthSecretInFile(c *cli.Context) error {
|
||||
logrus.Infof("Successfully wrote JSON-RPC authentication secret to file %s", fileName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateRandomHexString() (string, error) {
|
||||
secret := make([]byte, 32)
|
||||
randGen := rand.NewGenerator()
|
||||
n, err := randGen.Read(secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if n <= 0 {
|
||||
return "", errors.New("rand: unexpected length")
|
||||
}
|
||||
return hexutil.Encode(secret), nil
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ var appFlags = []cli.Flag{
|
||||
cmd.StaticPeers,
|
||||
cmd.RelayNode,
|
||||
cmd.P2PUDPPort,
|
||||
cmd.P2PQUICPort,
|
||||
cmd.P2PTCPPort,
|
||||
cmd.P2PIP,
|
||||
cmd.P2PHost,
|
||||
|
||||
@@ -55,6 +55,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
cmd.BootstrapNode,
|
||||
cmd.RelayNode,
|
||||
cmd.P2PUDPPort,
|
||||
cmd.P2PQUICPort,
|
||||
cmd.P2PTCPPort,
|
||||
cmd.DataDirFlag,
|
||||
cmd.VerbosityFlag,
|
||||
|
||||
21
cmd/flags.go
21
cmd/flags.go
@@ -4,6 +4,7 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
@@ -112,13 +113,19 @@ var (
|
||||
// P2PUDPPort defines the port to be used by discv5.
|
||||
P2PUDPPort = &cli.IntFlag{
|
||||
Name: "p2p-udp-port",
|
||||
Usage: "The port used by discv5.",
|
||||
Usage: "The UDP port used by the discovery service discv5.",
|
||||
Value: 12000,
|
||||
}
|
||||
// P2PTCPPort defines the port to be used by libp2p.
|
||||
// P2PQUICPort defines the QUIC port to be used by libp2p.
|
||||
P2PQUICPort = &cli.IntFlag{
|
||||
Name: "p2p-quic-port",
|
||||
Usage: "The QUIC port used by libp2p.",
|
||||
Value: 13000,
|
||||
}
|
||||
// P2PTCPPort defines the TCP port to be used by libp2p.
|
||||
P2PTCPPort = &cli.IntFlag{
|
||||
Name: "p2p-tcp-port",
|
||||
Usage: "The port used by libp2p.",
|
||||
Usage: "The TCP port used by libp2p.",
|
||||
Value: 13000,
|
||||
}
|
||||
// P2PIP defines the local IP to be used by libp2p.
|
||||
@@ -323,10 +330,10 @@ func ValidateNoArgs(ctx *cli.Context) error {
|
||||
|
||||
// verifies that the provided command is in the command list.
|
||||
func checkCommandList(commands []*cli.Command, name string) *cli.Command {
|
||||
for _, c := range commands {
|
||||
if c.Name == name {
|
||||
return c
|
||||
}
|
||||
if i := slices.IndexFunc(commands, func(c *cli.Command) bool {
|
||||
return c.Name == name
|
||||
}); i >= 0 {
|
||||
return commands[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ go_library(
|
||||
"@com_github_libp2p_go_libp2p//core/peer:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//core/protocol:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/security/noise:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/transport/quic:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//p2p/transport/tcp:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/p2p/security/noise"
|
||||
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||
libp2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
|
||||
libp2ptcp "github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||
"github.com/pkg/errors"
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
@@ -43,7 +44,7 @@ type client struct {
|
||||
nodeClient pb.NodeClient
|
||||
}
|
||||
|
||||
func newClient(beaconEndpoints []string, clientPort uint) (*client, error) {
|
||||
func newClient(beaconEndpoints []string, tcpPort, quicPort uint) (*client, error) {
|
||||
ipAdd := ipAddr()
|
||||
priv, err := privKey()
|
||||
if err != nil {
|
||||
@@ -53,15 +54,16 @@ func newClient(beaconEndpoints []string, clientPort uint) (*client, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not set up p2p metadata")
|
||||
}
|
||||
listen, err := p2p.MultiAddressBuilder(ipAdd.String(), clientPort)
|
||||
multiaddrs, err := p2p.MultiAddressBuilder(ipAdd, tcpPort, quicPort)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not set up listening multiaddr")
|
||||
}
|
||||
options := []libp2p.Option{
|
||||
privKeyOption(priv),
|
||||
libp2p.ListenAddrs(listen),
|
||||
libp2p.ListenAddrs(multiaddrs...),
|
||||
libp2p.UserAgent(version.BuildData()),
|
||||
libp2p.Transport(tcp.NewTCPTransport),
|
||||
libp2p.Transport(libp2pquic.NewTransport),
|
||||
libp2p.Transport(libp2ptcp.NewTCPTransport),
|
||||
}
|
||||
options = append(options, libp2p.Security(noise.ID, noise.New))
|
||||
options = append(options, libp2p.Ping(false))
|
||||
|
||||
@@ -22,11 +22,12 @@ import (
|
||||
)
|
||||
|
||||
var requestBlobsFlags = struct {
|
||||
Peers string
|
||||
ClientPort uint
|
||||
APIEndpoints string
|
||||
StartSlot uint64
|
||||
Count uint64
|
||||
Peers string
|
||||
ClientPortTCP uint
|
||||
ClientPortQUIC uint
|
||||
APIEndpoints string
|
||||
StartSlot uint64
|
||||
Count uint64
|
||||
}{}
|
||||
|
||||
var requestBlobsCmd = &cli.Command{
|
||||
@@ -47,9 +48,16 @@ var requestBlobsCmd = &cli.Command{
|
||||
Value: "",
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "client-port",
|
||||
Usage: "port to use for the client as a libp2p host",
|
||||
Destination: &requestBlobsFlags.ClientPort,
|
||||
Name: "client-port-tcp",
|
||||
Aliases: []string{"client-port"},
|
||||
Usage: "TCP port to use for the client as a libp2p host",
|
||||
Destination: &requestBlobsFlags.ClientPortTCP,
|
||||
Value: 13001,
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "client-port-quic",
|
||||
Usage: "QUIC port to use for the client as a libp2p host",
|
||||
Destination: &requestBlobsFlags.ClientPortQUIC,
|
||||
Value: 13001,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
@@ -60,13 +68,13 @@ var requestBlobsCmd = &cli.Command{
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "start-slot",
|
||||
Usage: "start slot for blocks by range request. If unset, will use start_slot(current_epoch-1)",
|
||||
Usage: "start slot for blobs by range request. If unset, will use start_slot(current_epoch-1)",
|
||||
Destination: &requestBlobsFlags.StartSlot,
|
||||
Value: 0,
|
||||
},
|
||||
&cli.Uint64Flag{
|
||||
Name: "count",
|
||||
Usage: "number of blocks to request, (default 32)",
|
||||
Usage: "number of blobs to request, (default 32)",
|
||||
Destination: &requestBlobsFlags.Count,
|
||||
Value: 32,
|
||||
},
|
||||
@@ -90,7 +98,7 @@ func cliActionRequestBlobs(cliCtx *cli.Context) error {
|
||||
allAPIEndpoints = strings.Split(requestBlobsFlags.APIEndpoints, ",")
|
||||
}
|
||||
var err error
|
||||
c, err := newClient(allAPIEndpoints, requestBlobsFlags.ClientPort)
|
||||
c, err := newClient(allAPIEndpoints, requestBlobsFlags.ClientPortTCP, requestBlobsFlags.ClientPortQUIC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -23,12 +23,14 @@ import (
|
||||
)
|
||||
|
||||
var requestBlocksFlags = struct {
|
||||
Peers string
|
||||
ClientPort uint
|
||||
APIEndpoints string
|
||||
StartSlot uint64
|
||||
Count uint64
|
||||
Step uint64
|
||||
Network string
|
||||
Peers string
|
||||
ClientPortTCP uint
|
||||
ClientPortQUIC uint
|
||||
APIEndpoints string
|
||||
StartSlot uint64
|
||||
Count uint64
|
||||
Step uint64
|
||||
}{}
|
||||
|
||||
var requestBlocksCmd = &cli.Command{
|
||||
@@ -42,6 +44,12 @@ var requestBlocksCmd = &cli.Command{
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
cmd.ChainConfigFileFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "network",
|
||||
Usage: "network to run on (mainnet, sepolia, holesky)",
|
||||
Destination: &requestBlocksFlags.Network,
|
||||
Value: "mainnet",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "peer-multiaddrs",
|
||||
Usage: "comma-separated, peer multiaddr(s) to connect to for p2p requests",
|
||||
@@ -49,9 +57,16 @@ var requestBlocksCmd = &cli.Command{
|
||||
Value: "",
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "client-port",
|
||||
Usage: "port to use for the client as a libp2p host",
|
||||
Destination: &requestBlocksFlags.ClientPort,
|
||||
Name: "client-port-tcp",
|
||||
Aliases: []string{"client-port"},
|
||||
Usage: "TCP port to use for the client as a libp2p host",
|
||||
Destination: &requestBlocksFlags.ClientPortTCP,
|
||||
Value: 13001,
|
||||
},
|
||||
&cli.UintFlag{
|
||||
Name: "client-port-quic",
|
||||
Usage: "QUIC port to use for the client as a libp2p host",
|
||||
Destination: &requestBlocksFlags.ClientPortQUIC,
|
||||
Value: 13001,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
@@ -82,6 +97,21 @@ var requestBlocksCmd = &cli.Command{
|
||||
}
|
||||
|
||||
func cliActionRequestBlocks(cliCtx *cli.Context) error {
|
||||
switch requestBlocksFlags.Network {
|
||||
case params.SepoliaName:
|
||||
if err := params.SetActive(params.SepoliaConfig()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case params.HoleskyName:
|
||||
if err := params.SetActive(params.HoleskyConfig()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
case params.MainnetName:
|
||||
// Do nothing
|
||||
default:
|
||||
log.Fatalf("Unknown network provided: %s", requestBlocksFlags.Network)
|
||||
}
|
||||
|
||||
if cliCtx.IsSet(cmd.ChainConfigFileFlag.Name) {
|
||||
chainConfigFileName := cliCtx.String(cmd.ChainConfigFileFlag.Name)
|
||||
if err := params.LoadChainConfigFile(chainConfigFileName, nil); err != nil {
|
||||
@@ -98,7 +128,7 @@ func cliActionRequestBlocks(cliCtx *cli.Context) error {
|
||||
allAPIEndpoints = strings.Split(requestBlocksFlags.APIEndpoints, ",")
|
||||
}
|
||||
var err error
|
||||
c, err := newClient(allAPIEndpoints, requestBlocksFlags.ClientPort)
|
||||
c, err := newClient(allAPIEndpoints, requestBlocksFlags.ClientPortTCP, requestBlocksFlags.ClientPortQUIC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ var (
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config-name",
|
||||
Usage: "Config kind to be used for generating the genesis state. Default: mainnet. Options include mainnet, interop, minimal, prater, sepolia. --chain-config-file will override this flag.",
|
||||
Usage: "Config kind to be used for generating the genesis state. Default: mainnet. Options include mainnet, interop, minimal, sepolia, holesky. --chain-config-file will override this flag.",
|
||||
Destination: &generateGenesisStateFlags.ConfigName,
|
||||
Value: params.MainnetName,
|
||||
},
|
||||
|
||||
@@ -167,7 +167,6 @@ var Commands = []*cli.Command{
|
||||
flags.ForceExitFlag,
|
||||
flags.VoluntaryExitJSONOutputPath,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
|
||||
@@ -27,7 +27,6 @@ var Commands = &cli.Command{
|
||||
flags.WalletPasswordFileFlag,
|
||||
flags.DeletePublicKeysFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
@@ -63,7 +62,6 @@ var Commands = &cli.Command{
|
||||
flags.GrpcRetriesFlag,
|
||||
flags.GrpcRetryDelayFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
@@ -97,7 +95,6 @@ var Commands = &cli.Command{
|
||||
flags.BackupPublicKeysFlag,
|
||||
flags.BackupPasswordFile,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
@@ -128,7 +125,6 @@ var Commands = &cli.Command{
|
||||
flags.AccountPasswordFileFlag,
|
||||
flags.ImportPrivateKeyFileFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
@@ -171,7 +167,6 @@ var Commands = &cli.Command{
|
||||
flags.ForceExitFlag,
|
||||
flags.VoluntaryExitJSONOutputPath,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
|
||||
@@ -15,6 +15,7 @@ go_library(
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//api:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/io/file"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -133,6 +134,15 @@ var (
|
||||
Usage: "Port used to listening and respond metrics for Prometheus.",
|
||||
Value: 8081,
|
||||
}
|
||||
|
||||
// AuthTokenPathFlag defines the path to the auth token used to secure the validator api.
|
||||
AuthTokenPathFlag = &cli.StringFlag{
|
||||
Name: "keymanager-token-file",
|
||||
Usage: "Path to auth token file used for validator apis.",
|
||||
Value: filepath.Join(filepath.Join(DefaultValidatorDir(), WalletDefaultDirName), api.AuthTokenFileName),
|
||||
Aliases: []string{"validator-api-bearer-file"},
|
||||
}
|
||||
|
||||
// WalletDirFlag defines the path to a wallet directory for Prysm accounts.
|
||||
WalletDirFlag = &cli.StringFlag{
|
||||
Name: "wallet-dir",
|
||||
|
||||
@@ -75,6 +75,7 @@ var appFlags = []cli.Flag{
|
||||
flags.EnableWebFlag,
|
||||
flags.GraffitiFileFlag,
|
||||
flags.EnableDistributed,
|
||||
flags.AuthTokenPathFlag,
|
||||
// Consensys' Web3Signer flags
|
||||
flags.Web3SignerURLFlag,
|
||||
flags.Web3SignerPublicValidatorKeysFlag,
|
||||
|
||||
@@ -22,7 +22,6 @@ var Commands = &cli.Command{
|
||||
cmd.DataDirFlag,
|
||||
flags.SlashingProtectionExportDirFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
features.EnableMinimalSlashingProtection,
|
||||
@@ -51,7 +50,6 @@ var Commands = &cli.Command{
|
||||
cmd.DataDirFlag,
|
||||
flags.SlashingProtectionJSONFileFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
features.EnableMinimalSlashingProtection,
|
||||
|
||||
@@ -123,6 +123,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.BuilderGasLimitFlag,
|
||||
flags.ValidatorsRegistrationBatchSizeFlag,
|
||||
flags.EnableDistributed,
|
||||
flags.AuthTokenPathFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -31,7 +31,6 @@ var Commands = &cli.Command{
|
||||
flags.Mnemonic25thWordFileFlag,
|
||||
flags.SkipMnemonic25thWordCheckFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
@@ -63,7 +62,6 @@ var Commands = &cli.Command{
|
||||
flags.Mnemonic25thWordFileFlag,
|
||||
flags.SkipMnemonic25thWordCheckFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
features.HoleskyTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
|
||||
@@ -9,6 +9,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/cmd/validator/web",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api:go_default_library",
|
||||
"//cmd:go_default_library",
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
|
||||
@@ -2,7 +2,9 @@ package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
@@ -24,6 +26,7 @@ var Commands = &cli.Command{
|
||||
flags.WalletDirFlag,
|
||||
flags.GRPCGatewayHost,
|
||||
flags.GRPCGatewayPort,
|
||||
flags.AuthTokenPathFlag,
|
||||
cmd.AcceptTosFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
@@ -43,7 +46,12 @@ var Commands = &cli.Command{
|
||||
gatewayHost := cliCtx.String(flags.GRPCGatewayHost.Name)
|
||||
gatewayPort := cliCtx.Int(flags.GRPCGatewayPort.Name)
|
||||
validatorWebAddr := fmt.Sprintf("%s:%d", gatewayHost, gatewayPort)
|
||||
if err := rpc.CreateAuthToken(walletDirPath, validatorWebAddr); err != nil {
|
||||
authTokenPath := filepath.Join(walletDirPath, api.AuthTokenFileName)
|
||||
tempAuthTokenPath := cliCtx.String(flags.AuthTokenPathFlag.Name)
|
||||
if tempAuthTokenPath != "" {
|
||||
authTokenPath = tempAuthTokenPath
|
||||
}
|
||||
if err := rpc.CreateAuthToken(authTokenPath, validatorWebAddr); err != nil {
|
||||
log.WithError(err).Fatal("Could not create web auth token")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -42,6 +42,7 @@ type Flags struct {
|
||||
WriteSSZStateTransitions bool // WriteSSZStateTransitions to tmp directory.
|
||||
EnablePeerScorer bool // EnablePeerScorer enables experimental peer scoring in p2p.
|
||||
EnableLightClient bool // EnableLightClient enables light client APIs.
|
||||
EnableQUIC bool // EnableQUIC specifies whether to enable QUIC transport for libp2p.
|
||||
WriteWalletPasswordOnWebOnboarding bool // WriteWalletPasswordOnWebOnboarding writes the password to disk after Prysm web signup.
|
||||
EnableDoppelGanger bool // EnableDoppelGanger enables doppelganger protection on startup for the validator.
|
||||
EnableHistoricalSpaceRepresentation bool // EnableHistoricalSpaceRepresentation enables the saving of registry validators in separate buckets to save space
|
||||
@@ -123,14 +124,7 @@ func InitWithReset(c *Flags) func() {
|
||||
|
||||
// configureTestnet sets the config according to specified testnet flag
|
||||
func configureTestnet(ctx *cli.Context) error {
|
||||
if ctx.Bool(PraterTestnet.Name) {
|
||||
log.Info("Running on the Prater Testnet")
|
||||
if err := params.SetActive(params.PraterConfig().Copy()); err != nil {
|
||||
return err
|
||||
}
|
||||
applyPraterFeatureFlags(ctx)
|
||||
params.UsePraterNetworkConfig()
|
||||
} else if ctx.Bool(SepoliaTestnet.Name) {
|
||||
if ctx.Bool(SepoliaTestnet.Name) {
|
||||
log.Info("Running on the Sepolia Beacon Chain Testnet")
|
||||
if err := params.SetActive(params.SepoliaConfig().Copy()); err != nil {
|
||||
return err
|
||||
@@ -157,10 +151,6 @@ func configureTestnet(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Insert feature flags within the function to be enabled for Prater testnet.
|
||||
func applyPraterFeatureFlags(ctx *cli.Context) {
|
||||
}
|
||||
|
||||
// Insert feature flags within the function to be enabled for Sepolia testnet.
|
||||
func applySepoliaFeatureFlags(ctx *cli.Context) {
|
||||
}
|
||||
@@ -265,6 +255,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
logEnabled(BlobSaveFsync)
|
||||
cfg.BlobSaveFsync = true
|
||||
}
|
||||
if ctx.IsSet(EnableQUIC.Name) {
|
||||
logEnabled(EnableQUIC)
|
||||
cfg.EnableQUIC = true
|
||||
}
|
||||
|
||||
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}
|
||||
Init(cfg)
|
||||
|
||||
@@ -8,12 +8,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// PraterTestnet flag for the multiclient Ethereum consensus testnet.
|
||||
PraterTestnet = &cli.BoolFlag{
|
||||
Name: "prater",
|
||||
Usage: "Runs Prysm configured for the Prater / Goerli test network.",
|
||||
Aliases: []string{"goerli"},
|
||||
}
|
||||
// SepoliaTestnet flag for the multiclient Ethereum consensus testnet.
|
||||
SepoliaTestnet = &cli.BoolFlag{
|
||||
Name: "sepolia",
|
||||
@@ -109,8 +103,8 @@ var (
|
||||
}
|
||||
enableDoppelGangerProtection = &cli.BoolFlag{
|
||||
Name: "enable-doppelganger",
|
||||
Usage: `Enables the validator to perform a doppelganger check.
|
||||
This is not "a foolproof method to find duplicate instances in the network.
|
||||
Usage: `Enables the validator to perform a doppelganger check.
|
||||
This is not a foolproof method to find duplicate instances in the network.
|
||||
Your validator will still be vulnerable if it is being run in unsafe configurations.`,
|
||||
}
|
||||
disableStakinContractCheck = &cli.BoolFlag{
|
||||
@@ -171,19 +165,24 @@ var (
|
||||
Name: "blob-save-fsync",
|
||||
Usage: "Forces new blob files to be fysnc'd before continuing, ensuring durable blob writes.",
|
||||
}
|
||||
// EnableQUIC enables connection using the QUIC protocol for peers which support it.
|
||||
EnableQUIC = &cli.BoolFlag{
|
||||
Name: "enable-quic",
|
||||
Usage: "Enables connection using the QUIC protocol for peers which support it.",
|
||||
}
|
||||
)
|
||||
|
||||
// devModeFlags holds list of flags that are set when development mode is on.
|
||||
var devModeFlags = []cli.Flag{
|
||||
enableExperimentalState,
|
||||
backfill.EnableExperimentalBackfill,
|
||||
EnableQUIC,
|
||||
}
|
||||
|
||||
// ValidatorFlags contains a list of all the feature flags that apply to the validator client.
|
||||
var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
|
||||
writeWalletPasswordOnWebOnboarding,
|
||||
HoleskyTestnet,
|
||||
PraterTestnet,
|
||||
SepoliaTestnet,
|
||||
Mainnet,
|
||||
dynamicKeyReloadDebounceInterval,
|
||||
@@ -208,7 +207,6 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
||||
saveInvalidBlobTempFlag,
|
||||
disableGRPCConnectionLogging,
|
||||
HoleskyTestnet,
|
||||
PraterTestnet,
|
||||
SepoliaTestnet,
|
||||
Mainnet,
|
||||
disablePeerScorer,
|
||||
@@ -229,6 +227,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
||||
DisableRegistrationCache,
|
||||
EnableLightClient,
|
||||
BlobSaveFsync,
|
||||
EnableQUIC,
|
||||
}...)...)
|
||||
|
||||
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.
|
||||
@@ -239,7 +238,6 @@ var E2EBeaconChainFlags = []string{
|
||||
// NetworkFlags contains a list of network flags.
|
||||
var NetworkFlags = []cli.Flag{
|
||||
Mainnet,
|
||||
PraterTestnet,
|
||||
SepoliaTestnet,
|
||||
HoleskyTestnet,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ go_library(
|
||||
"network_config.go",
|
||||
"testnet_e2e_config.go",
|
||||
"testnet_holesky_config.go",
|
||||
"testnet_prater_config.go",
|
||||
"testnet_sepolia_config.go",
|
||||
"testutils.go",
|
||||
"testutils_develop.go", # keep
|
||||
@@ -50,7 +49,6 @@ go_test(
|
||||
"mainnet_config_test.go",
|
||||
"testnet_config_test.go",
|
||||
"testnet_holesky_config_test.go",
|
||||
"testnet_prater_config_test.go",
|
||||
],
|
||||
data = glob(["*.yaml"]) + [
|
||||
"testdata/e2e_config.yaml",
|
||||
@@ -58,14 +56,12 @@ go_test(
|
||||
"@consensus_spec_tests_mainnet//:test_data",
|
||||
"@consensus_spec_tests_minimal//:test_data",
|
||||
"@eth2_networks//:configs",
|
||||
"@goerli_testnet//:configs",
|
||||
"@holesky_testnet//:configs",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
gotags = ["develop"],
|
||||
tags = ["CI_race_detection"],
|
||||
deps = [
|
||||
"//build/bazel:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
|
||||
@@ -3,7 +3,6 @@ package params
|
||||
func init() {
|
||||
defaults := []*BeaconChainConfig{
|
||||
MainnetConfig(),
|
||||
PraterConfig(),
|
||||
MinimalSpecConfig(),
|
||||
E2ETestConfig(),
|
||||
E2EMainnetTestConfig(),
|
||||
|
||||
2
config/params/testdata/e2e_config.yaml
vendored
2
config/params/testdata/e2e_config.yaml
vendored
@@ -82,7 +82,7 @@ PROPOSER_SCORE_BOOST: 40
|
||||
|
||||
# Deposit contract
|
||||
# ---------------------------------------------------------------
|
||||
# Ethereum Goerli testnet
|
||||
# Testnet
|
||||
DEPOSIT_CHAIN_ID: 1337 # Override for e2e tests
|
||||
DEPOSIT_NETWORK_ID: 1337 # Override for e2e tests
|
||||
# Configured on a per testnet basis
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
eth1Params "github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// UsePraterNetworkConfig uses the Prater specific
|
||||
// network config.
|
||||
func UsePraterNetworkConfig() {
|
||||
cfg := BeaconNetworkConfig().Copy()
|
||||
cfg.ContractDeploymentBlock = 4367322
|
||||
cfg.BootstrapNodes = []string{
|
||||
// Prysm's bootnode
|
||||
"enr:-Ku4QFmUkNp0g9bsLX2PfVeIyT-9WO-PZlrqZBNtEyofOOfLMScDjaTzGxIb1Ns9Wo5Pm_8nlq-SZwcQfTH2cgO-s88Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDkvpOTAAAQIP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQLV_jMOIxKbjHFKgrkFvwDvpexo6Nd58TK5k7ss4Vt0IoN1ZHCCG1g",
|
||||
// Lighthouse's bootnode by Afri
|
||||
"enr:-LK4QH1xnjotgXwg25IDPjrqRGFnH1ScgNHA3dv1Z8xHCp4uP3N3Jjl_aYv_WIxQRdwZvSukzbwspXZ7JjpldyeVDzMCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpB53wQoAAAQIP__________gmlkgnY0gmlwhIe1te-Jc2VjcDI1NmsxoQOkcGXqbCJYbcClZ3z5f6NWhX_1YPFRYRRWQpJjwSHpVIN0Y3CCIyiDdWRwgiMo",
|
||||
// Lighthouse's bootnode by Sigp
|
||||
"enr:-Ly4QFPk-cTMxZ3jWTafiNblEZkQIXGF2aVzCIGW0uHp6KaEAvBMoctE8S7YU0qZtuS7By0AA4YMfKoN9ls_GJRccVpFh2F0dG5ldHOI__________-EZXRoMpCC9KcrAgAQIIS2AQAAAAAAgmlkgnY0gmlwhKh3joWJc2VjcDI1NmsxoQKrxz8M1IHwJqRIpDqdVW_U1PeixMW5SfnBD-8idYIQrIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA",
|
||||
"enr:-L64QJmwSDtaHVgGiqIxJWUtxWg6uLCipsms6j-8BdsOJfTWAs7CLF9HJnVqFE728O-JYUDCxzKvRdeMqBSauHVCMdaCAVWHYXR0bmV0c4j__________4RldGgykIL0pysCABAghLYBAAAAAACCaWSCdjSCaXCEQWxOdolzZWNwMjU2azGhA7Qmod9fK86WidPOzLsn5_8QyzL7ZcJ1Reca7RnD54vuiHN5bmNuZXRzD4N0Y3CCIyiDdWRwgiMo",
|
||||
// Teku's bootnode By Afri
|
||||
"enr:-KG4QCIzJZTY_fs_2vqWEatJL9RrtnPwDCv-jRBuO5FQ2qBrfJubWOWazri6s9HsyZdu-fRUfEzkebhf1nvO42_FVzwDhGV0aDKQed8EKAAAECD__________4JpZIJ2NIJpcISHtbYziXNlY3AyNTZrMaED4m9AqVs6F32rSCGsjtYcsyfQE2K8nDiGmocUY_iq-TSDdGNwgiMog3VkcIIjKA",
|
||||
}
|
||||
OverrideBeaconNetworkConfig(cfg)
|
||||
}
|
||||
|
||||
// PraterConfig defines the config for the
|
||||
// Prater testnet.
|
||||
func PraterConfig() *BeaconChainConfig {
|
||||
cfg := MainnetConfig().Copy()
|
||||
cfg.MinGenesisTime = 1614588812
|
||||
cfg.GenesisDelay = 1919188
|
||||
cfg.ConfigName = PraterName
|
||||
cfg.GenesisForkVersion = []byte{0x00, 0x00, 0x10, 0x20}
|
||||
cfg.SecondsPerETH1Block = 14
|
||||
cfg.DepositChainID = eth1Params.GoerliChainConfig.ChainID.Uint64()
|
||||
cfg.DepositNetworkID = eth1Params.GoerliChainConfig.ChainID.Uint64()
|
||||
cfg.AltairForkEpoch = 36660
|
||||
cfg.AltairForkVersion = []byte{0x1, 0x0, 0x10, 0x20}
|
||||
cfg.BellatrixForkEpoch = 112260
|
||||
cfg.BellatrixForkVersion = []byte{0x2, 0x0, 0x10, 0x20}
|
||||
cfg.CapellaForkEpoch = 162304
|
||||
cfg.CapellaForkVersion = []byte{0x3, 0x0, 0x10, 0x20}
|
||||
cfg.DenebForkEpoch = 231680 // 2024-01-17 06:32:00 (UTC)
|
||||
cfg.DenebForkVersion = []byte{0x4, 0x0, 0x10, 0x20}
|
||||
cfg.TerminalTotalDifficulty = "10790000"
|
||||
cfg.DepositContractAddress = "0xff50ed3d0ec03aC01D4C79aAd74928BFF48a7b2b"
|
||||
cfg.InitializeForkSchedule()
|
||||
return cfg
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package params_test
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/build/bazel"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
func TestPraterConfigMatchesUpstreamYaml(t *testing.T) {
|
||||
presetFPs := presetsFilePath(t, "mainnet")
|
||||
mn, err := params.ByName(params.MainnetName)
|
||||
require.NoError(t, err)
|
||||
cfg := mn.Copy()
|
||||
for _, fp := range presetFPs {
|
||||
cfg, err = params.UnmarshalConfigFile(fp, cfg)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
fPath, err := bazel.Runfile("external/goerli_testnet")
|
||||
require.NoError(t, err)
|
||||
configFP := path.Join(fPath, "prater", "config.yaml")
|
||||
pcfg, err := params.UnmarshalConfigFile(configFP, nil)
|
||||
require.NoError(t, err)
|
||||
fields := fieldsFromYamls(t, append(presetFPs, configFP))
|
||||
assertYamlFieldsMatch(t, "prater", fields, pcfg, params.PraterConfig())
|
||||
}
|
||||
@@ -8,8 +8,6 @@ const (
|
||||
MainnetName = "mainnet"
|
||||
MainnetTestName = "mainnet-test"
|
||||
MinimalName = "minimal"
|
||||
PraterName = "prater"
|
||||
GoerliName = "goerli"
|
||||
SepoliaName = "sepolia"
|
||||
HoleskyName = "holesky"
|
||||
)
|
||||
|
||||
@@ -244,7 +244,8 @@ func Test_VerifyKZGInclusionProof(t *testing.T) {
|
||||
StateRoot: make([]byte, 32),
|
||||
}
|
||||
signedHeader := ðpb.SignedBeaconBlockHeader{
|
||||
Header: header,
|
||||
Header: header,
|
||||
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
}
|
||||
sidecar := ðpb.BlobSidecar{
|
||||
Index: uint64(index),
|
||||
|
||||
@@ -1,35 +1,42 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
var errNilBlockHeader = errors.New("received nil beacon block header")
|
||||
|
||||
// ROBlob represents a read-only blob sidecar with its block root.
|
||||
type ROBlob struct {
|
||||
*ethpb.BlobSidecar
|
||||
root [32]byte
|
||||
}
|
||||
|
||||
func roblobNilCheck(b *ethpb.BlobSidecar) error {
|
||||
if b == nil {
|
||||
return errNilBlob
|
||||
}
|
||||
if b.SignedBlockHeader == nil || b.SignedBlockHeader.Header == nil {
|
||||
return errNilBlockHeader
|
||||
}
|
||||
if len(b.SignedBlockHeader.Signature) == 0 {
|
||||
return errMissingBlockSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewROBlobWithRoot creates a new ROBlob with a given root.
|
||||
func NewROBlobWithRoot(b *ethpb.BlobSidecar, root [32]byte) (ROBlob, error) {
|
||||
if b == nil {
|
||||
return ROBlob{}, errNilBlock
|
||||
if err := roblobNilCheck(b); err != nil {
|
||||
return ROBlob{}, err
|
||||
}
|
||||
return ROBlob{BlobSidecar: b, root: root}, nil
|
||||
}
|
||||
|
||||
// NewROBlob creates a new ROBlob by computing the HashTreeRoot of the header.
|
||||
func NewROBlob(b *ethpb.BlobSidecar) (ROBlob, error) {
|
||||
if b == nil {
|
||||
return ROBlob{}, errNilBlock
|
||||
}
|
||||
if b.SignedBlockHeader == nil || b.SignedBlockHeader.Header == nil {
|
||||
return ROBlob{}, errNilBlockHeader
|
||||
if err := roblobNilCheck(b); err != nil {
|
||||
return ROBlob{}, err
|
||||
}
|
||||
root, err := b.SignedBlockHeader.Header.HashTreeRoot()
|
||||
if err != nil {
|
||||
|
||||
@@ -5,50 +5,94 @@ import (
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
func TestNewROBlobWithRoot(t *testing.T) {
|
||||
sidecar := ðpb.BlobSidecar{}
|
||||
root := [32]byte{}
|
||||
|
||||
blob, err := NewROBlobWithRoot(sidecar, root)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, root, blob.BlockRoot())
|
||||
|
||||
blob, err = NewROBlobWithRoot(nil, root)
|
||||
assert.Equal(t, errNilBlock, err)
|
||||
}
|
||||
|
||||
// TestNewROBlob tests the NewROBlob function.
|
||||
func TestNewROBlob(t *testing.T) {
|
||||
h := ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ParentRoot: make([]byte, fieldparams.RootLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
BodyRoot: make([]byte, fieldparams.RootLength),
|
||||
func TestROBlobNilChecks(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
bfunc func(t *testing.T) *ethpb.BlobSidecar
|
||||
err error
|
||||
root []byte
|
||||
}{
|
||||
{
|
||||
name: "nil signed blob",
|
||||
bfunc: func(t *testing.T) *ethpb.BlobSidecar {
|
||||
return nil
|
||||
},
|
||||
err: errNilBlob,
|
||||
root: bytesutil.PadTo([]byte("sup"), 32),
|
||||
},
|
||||
{
|
||||
name: "nil signed block header",
|
||||
bfunc: func(t *testing.T) *ethpb.BlobSidecar {
|
||||
return ðpb.BlobSidecar{
|
||||
SignedBlockHeader: nil,
|
||||
}
|
||||
},
|
||||
err: errNilBlockHeader,
|
||||
root: bytesutil.PadTo([]byte("sup"), 32),
|
||||
},
|
||||
{
|
||||
name: "nil inner header",
|
||||
bfunc: func(t *testing.T) *ethpb.BlobSidecar {
|
||||
return ðpb.BlobSidecar{
|
||||
SignedBlockHeader: ðpb.SignedBeaconBlockHeader{
|
||||
Header: nil,
|
||||
},
|
||||
}
|
||||
},
|
||||
err: errNilBlockHeader,
|
||||
root: bytesutil.PadTo([]byte("sup"), 32),
|
||||
},
|
||||
{
|
||||
name: "nil signature",
|
||||
bfunc: func(t *testing.T) *ethpb.BlobSidecar {
|
||||
return ðpb.BlobSidecar{
|
||||
SignedBlockHeader: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
ParentRoot: make([]byte, fieldparams.RootLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
BodyRoot: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
Signature: nil,
|
||||
},
|
||||
}
|
||||
},
|
||||
err: errMissingBlockSignature,
|
||||
root: bytesutil.PadTo([]byte("sup"), 32),
|
||||
},
|
||||
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
}
|
||||
sidecar := ðpb.BlobSidecar{
|
||||
SignedBlockHeader: h,
|
||||
for _, c := range cases {
|
||||
t.Run(c.name+" NewROBlob", func(t *testing.T) {
|
||||
b := c.bfunc(t)
|
||||
bl, err := NewROBlob(b)
|
||||
if c.err != nil {
|
||||
require.ErrorIs(t, err, c.err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
hr, err := b.SignedBlockHeader.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, hr, bl.BlockRoot())
|
||||
}
|
||||
})
|
||||
if len(c.root) == 0 {
|
||||
continue
|
||||
}
|
||||
t.Run(c.name+" NewROBlobWithRoot", func(t *testing.T) {
|
||||
b := c.bfunc(t)
|
||||
// We want the same validation when specifying a root.
|
||||
bl, err := NewROBlobWithRoot(b, bytesutil.ToBytes32(c.root))
|
||||
if c.err != nil {
|
||||
require.ErrorIs(t, err, c.err)
|
||||
} else {
|
||||
assert.Equal(t, bytesutil.ToBytes32(c.root), bl.BlockRoot())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
blob, err := NewROBlob(sidecar)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, blob)
|
||||
|
||||
_, err = NewROBlob(nil)
|
||||
assert.Equal(t, errNilBlock, err)
|
||||
|
||||
sidecar.SignedBlockHeader = nil
|
||||
_, err = NewROBlob(sidecar)
|
||||
assert.Equal(t, errNilBlockHeader, err)
|
||||
|
||||
sidecar.SignedBlockHeader = ðpb.SignedBeaconBlockHeader{}
|
||||
_, err = NewROBlob(sidecar)
|
||||
assert.Equal(t, errNilBlockHeader, err)
|
||||
}
|
||||
|
||||
func TestBlockRoot(t *testing.T) {
|
||||
|
||||
@@ -4,9 +4,11 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
@@ -88,3 +90,103 @@ func testROBlock(t *testing.T, slot primitives.Slot, root [32]byte) ROBlock {
|
||||
root: root,
|
||||
}
|
||||
}
|
||||
|
||||
func TestROBlockNilChecks(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
bfunc func(t *testing.T) interfaces.SignedBeaconBlock
|
||||
err error
|
||||
root []byte
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
bfunc: func(t *testing.T) interfaces.SignedBeaconBlock {
|
||||
b, err := NewSignedBeaconBlock(hydrateSignedBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path - with root",
|
||||
bfunc: func(t *testing.T) interfaces.SignedBeaconBlock {
|
||||
b, err := NewSignedBeaconBlock(hydrateSignedBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
},
|
||||
root: bytesutil.PadTo([]byte("sup"), 32),
|
||||
},
|
||||
{
|
||||
name: "nil signed block",
|
||||
bfunc: func(t *testing.T) interfaces.SignedBeaconBlock {
|
||||
return nil
|
||||
},
|
||||
err: ErrNilSignedBeaconBlock,
|
||||
},
|
||||
{
|
||||
name: "nil signed block - with root",
|
||||
bfunc: func(t *testing.T) interfaces.SignedBeaconBlock {
|
||||
return nil
|
||||
},
|
||||
err: ErrNilSignedBeaconBlock,
|
||||
root: bytesutil.PadTo([]byte("sup"), 32),
|
||||
},
|
||||
{
|
||||
name: "nil inner block",
|
||||
bfunc: func(t *testing.T) interfaces.SignedBeaconBlock {
|
||||
return &SignedBeaconBlock{
|
||||
version: version.Deneb,
|
||||
block: nil,
|
||||
signature: bytesutil.ToBytes96(nil),
|
||||
}
|
||||
},
|
||||
err: ErrNilSignedBeaconBlock,
|
||||
},
|
||||
{
|
||||
name: "nil inner block",
|
||||
bfunc: func(t *testing.T) interfaces.SignedBeaconBlock {
|
||||
return &SignedBeaconBlock{
|
||||
version: version.Deneb,
|
||||
block: nil,
|
||||
signature: bytesutil.ToBytes96(nil),
|
||||
}
|
||||
},
|
||||
err: ErrNilSignedBeaconBlock,
|
||||
},
|
||||
{
|
||||
name: "nil block body",
|
||||
bfunc: func(t *testing.T) interfaces.SignedBeaconBlock {
|
||||
bb := &BeaconBlock{
|
||||
version: version.Deneb,
|
||||
slot: 0,
|
||||
proposerIndex: 0,
|
||||
parentRoot: bytesutil.ToBytes32(nil),
|
||||
stateRoot: bytesutil.ToBytes32(nil),
|
||||
body: nil,
|
||||
}
|
||||
return &SignedBeaconBlock{
|
||||
version: version.Deneb,
|
||||
block: bb,
|
||||
signature: bytesutil.ToBytes96(nil),
|
||||
}
|
||||
},
|
||||
err: ErrNilSignedBeaconBlock,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
b := c.bfunc(t)
|
||||
var err error
|
||||
if len(c.root) == 0 {
|
||||
_, err = NewROBlock(b)
|
||||
} else {
|
||||
_, err = NewROBlockWithRoot(b, bytesutil.ToBytes32(c.root))
|
||||
}
|
||||
if c.err != nil {
|
||||
require.ErrorIs(t, err, c.err)
|
||||
return
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,13 @@ const (
|
||||
var (
|
||||
// ErrUnsupportedVersion for beacon block methods.
|
||||
ErrUnsupportedVersion = errors.New("unsupported beacon block version")
|
||||
errNilBlob = errors.New("received nil blob sidecar")
|
||||
errNilBlock = errors.New("received nil beacon block")
|
||||
errNilBlockBody = errors.New("received nil beacon block body")
|
||||
errIncorrectBlockVersion = errors.New(incorrectBlockVersion)
|
||||
errIncorrectBodyVersion = errors.New(incorrectBodyVersion)
|
||||
errNilBlockHeader = errors.New("received nil beacon block header")
|
||||
errMissingBlockSignature = errors.New("received nil beacon block signature")
|
||||
)
|
||||
|
||||
// BeaconBlockBody is the main beacon block body structure. It can represent any block type.
|
||||
|
||||
@@ -91,6 +91,7 @@ package mvslice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -578,10 +579,8 @@ func (s *Slice[V]) updateAppendedItem(obj Identifiable, index uint64, val V) err
|
||||
}
|
||||
|
||||
func containsId(ids []uint64, wanted uint64) (int, bool) {
|
||||
for i, id := range ids {
|
||||
if id == wanted {
|
||||
return i, true
|
||||
}
|
||||
if i := slices.Index(ids, wanted); i >= 0 {
|
||||
return i, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ var urltests = []struct {
|
||||
maskedUrl string
|
||||
}{
|
||||
{"https://a:b@xyz.net", "https://***@xyz.net"},
|
||||
{"https://eth-goerli.alchemyapi.io/v2/tOZG5mjl3.zl_nZdZTNIBUzsDq62R_dkOtY",
|
||||
"https://eth-goerli.alchemyapi.io/***"},
|
||||
{"https://eth-holesky.alchemyapi.io/v2/tOZG5mjl3.zl_nZdZTNIBUzsDq62R_dkOtY",
|
||||
"https://eth-holesky.alchemyapi.io/***"},
|
||||
{"https://google.com/search?q=golang", "https://google.com/***"},
|
||||
{"https://user@example.com/foo%2fbar", "https://***@example.com/***"},
|
||||
{"http://john@example.com/#x/y%2Fz", "http://***@example.com/#***"},
|
||||
|
||||
1354
proto/engine/v1/epbs.pb.go
generated
Executable file
1354
proto/engine/v1/epbs.pb.go
generated
Executable file
File diff suppressed because it is too large
Load Diff
938
proto/eth/v1/beacon_state.pb.go
generated
Executable file
938
proto/eth/v1/beacon_state.pb.go
generated
Executable file
@@ -0,0 +1,938 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v4.25.1
|
||||
// source: proto/eth/v1/beacon_state.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
github_com_prysmaticlabs_go_bitfield "github.com/prysmaticlabs/go-bitfield"
|
||||
github_com_prysmaticlabs_prysm_v5_consensus_types_primitives "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
_ "github.com/prysmaticlabs/prysm/v5/proto/eth/ext"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
_ "google.golang.org/protobuf/types/descriptorpb"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type BeaconState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
GenesisTime uint64 `protobuf:"varint,1001,opt,name=genesis_time,json=genesisTime,proto3" json:"genesis_time,omitempty"`
|
||||
GenesisValidatorsRoot []byte `protobuf:"bytes,1002,opt,name=genesis_validators_root,json=genesisValidatorsRoot,proto3" json:"genesis_validators_root,omitempty" ssz-size:"32"`
|
||||
Slot github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot `protobuf:"varint,1003,opt,name=slot,proto3" json:"slot,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"`
|
||||
Fork *Fork `protobuf:"bytes,1004,opt,name=fork,proto3" json:"fork,omitempty"`
|
||||
LatestBlockHeader *BeaconBlockHeader `protobuf:"bytes,2001,opt,name=latest_block_header,json=latestBlockHeader,proto3" json:"latest_block_header,omitempty"`
|
||||
BlockRoots [][]byte `protobuf:"bytes,2002,rep,name=block_roots,json=blockRoots,proto3" json:"block_roots,omitempty" ssz-size:"8192,32"`
|
||||
StateRoots [][]byte `protobuf:"bytes,2003,rep,name=state_roots,json=stateRoots,proto3" json:"state_roots,omitempty" ssz-size:"8192,32"`
|
||||
HistoricalRoots [][]byte `protobuf:"bytes,2004,rep,name=historical_roots,json=historicalRoots,proto3" json:"historical_roots,omitempty" ssz-max:"16777216" ssz-size:"?,32"`
|
||||
Eth1Data *Eth1Data `protobuf:"bytes,3001,opt,name=eth1_data,json=eth1Data,proto3" json:"eth1_data,omitempty"`
|
||||
Eth1DataVotes []*Eth1Data `protobuf:"bytes,3002,rep,name=eth1_data_votes,json=eth1DataVotes,proto3" json:"eth1_data_votes,omitempty" ssz-max:"2048"`
|
||||
Eth1DepositIndex uint64 `protobuf:"varint,3003,opt,name=eth1_deposit_index,json=eth1DepositIndex,proto3" json:"eth1_deposit_index,omitempty"`
|
||||
Validators []*Validator `protobuf:"bytes,4001,rep,name=validators,proto3" json:"validators,omitempty" ssz-max:"1099511627776"`
|
||||
Balances []uint64 `protobuf:"varint,4002,rep,packed,name=balances,proto3" json:"balances,omitempty" ssz-max:"1099511627776"`
|
||||
RandaoMixes [][]byte `protobuf:"bytes,5001,rep,name=randao_mixes,json=randaoMixes,proto3" json:"randao_mixes,omitempty" ssz-size:"65536,32"`
|
||||
Slashings []uint64 `protobuf:"varint,6001,rep,packed,name=slashings,proto3" json:"slashings,omitempty" ssz-size:"8192"`
|
||||
PreviousEpochAttestations []*PendingAttestation `protobuf:"bytes,7001,rep,name=previous_epoch_attestations,json=previousEpochAttestations,proto3" json:"previous_epoch_attestations,omitempty" ssz-max:"4096"`
|
||||
CurrentEpochAttestations []*PendingAttestation `protobuf:"bytes,7002,rep,name=current_epoch_attestations,json=currentEpochAttestations,proto3" json:"current_epoch_attestations,omitempty" ssz-max:"4096"`
|
||||
JustificationBits github_com_prysmaticlabs_go_bitfield.Bitvector4 `protobuf:"bytes,8001,opt,name=justification_bits,json=justificationBits,proto3" json:"justification_bits,omitempty" cast-type:"github.com/prysmaticlabs/go-bitfield.Bitvector4" ssz-size:"1"`
|
||||
PreviousJustifiedCheckpoint *Checkpoint `protobuf:"bytes,8002,opt,name=previous_justified_checkpoint,json=previousJustifiedCheckpoint,proto3" json:"previous_justified_checkpoint,omitempty"`
|
||||
CurrentJustifiedCheckpoint *Checkpoint `protobuf:"bytes,8003,opt,name=current_justified_checkpoint,json=currentJustifiedCheckpoint,proto3" json:"current_justified_checkpoint,omitempty"`
|
||||
FinalizedCheckpoint *Checkpoint `protobuf:"bytes,8004,opt,name=finalized_checkpoint,json=finalizedCheckpoint,proto3" json:"finalized_checkpoint,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BeaconState) Reset() {
|
||||
*x = BeaconState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *BeaconState) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BeaconState) ProtoMessage() {}
|
||||
|
||||
func (x *BeaconState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BeaconState.ProtoReflect.Descriptor instead.
|
||||
func (*BeaconState) Descriptor() ([]byte, []int) {
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetGenesisTime() uint64 {
|
||||
if x != nil {
|
||||
return x.GenesisTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetGenesisValidatorsRoot() []byte {
|
||||
if x != nil {
|
||||
return x.GenesisValidatorsRoot
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetSlot() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot {
|
||||
if x != nil {
|
||||
return x.Slot
|
||||
}
|
||||
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(0)
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetFork() *Fork {
|
||||
if x != nil {
|
||||
return x.Fork
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetLatestBlockHeader() *BeaconBlockHeader {
|
||||
if x != nil {
|
||||
return x.LatestBlockHeader
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetBlockRoots() [][]byte {
|
||||
if x != nil {
|
||||
return x.BlockRoots
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetStateRoots() [][]byte {
|
||||
if x != nil {
|
||||
return x.StateRoots
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetHistoricalRoots() [][]byte {
|
||||
if x != nil {
|
||||
return x.HistoricalRoots
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetEth1Data() *Eth1Data {
|
||||
if x != nil {
|
||||
return x.Eth1Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetEth1DataVotes() []*Eth1Data {
|
||||
if x != nil {
|
||||
return x.Eth1DataVotes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetEth1DepositIndex() uint64 {
|
||||
if x != nil {
|
||||
return x.Eth1DepositIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetValidators() []*Validator {
|
||||
if x != nil {
|
||||
return x.Validators
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetBalances() []uint64 {
|
||||
if x != nil {
|
||||
return x.Balances
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetRandaoMixes() [][]byte {
|
||||
if x != nil {
|
||||
return x.RandaoMixes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetSlashings() []uint64 {
|
||||
if x != nil {
|
||||
return x.Slashings
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetPreviousEpochAttestations() []*PendingAttestation {
|
||||
if x != nil {
|
||||
return x.PreviousEpochAttestations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetCurrentEpochAttestations() []*PendingAttestation {
|
||||
if x != nil {
|
||||
return x.CurrentEpochAttestations
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetJustificationBits() github_com_prysmaticlabs_go_bitfield.Bitvector4 {
|
||||
if x != nil {
|
||||
return x.JustificationBits
|
||||
}
|
||||
return github_com_prysmaticlabs_go_bitfield.Bitvector4(nil)
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetPreviousJustifiedCheckpoint() *Checkpoint {
|
||||
if x != nil {
|
||||
return x.PreviousJustifiedCheckpoint
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetCurrentJustifiedCheckpoint() *Checkpoint {
|
||||
if x != nil {
|
||||
return x.CurrentJustifiedCheckpoint
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BeaconState) GetFinalizedCheckpoint() *Checkpoint {
|
||||
if x != nil {
|
||||
return x.FinalizedCheckpoint
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PendingAttestation struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AggregationBits github_com_prysmaticlabs_go_bitfield.Bitlist `protobuf:"bytes,1,opt,name=aggregation_bits,json=aggregationBits,proto3" json:"aggregation_bits,omitempty" cast-type:"github.com/prysmaticlabs/go-bitfield.Bitlist" ssz-max:"2048"`
|
||||
Data *AttestationData `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
|
||||
InclusionDelay github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot `protobuf:"varint,3,opt,name=inclusion_delay,json=inclusionDelay,proto3" json:"inclusion_delay,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"`
|
||||
ProposerIndex github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex `protobuf:"varint,4,opt,name=proposer_index,json=proposerIndex,proto3" json:"proposer_index,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.ValidatorIndex"`
|
||||
}
|
||||
|
||||
func (x *PendingAttestation) Reset() {
|
||||
*x = PendingAttestation{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PendingAttestation) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PendingAttestation) ProtoMessage() {}
|
||||
|
||||
func (x *PendingAttestation) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PendingAttestation.ProtoReflect.Descriptor instead.
|
||||
func (*PendingAttestation) Descriptor() ([]byte, []int) {
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *PendingAttestation) GetAggregationBits() github_com_prysmaticlabs_go_bitfield.Bitlist {
|
||||
if x != nil {
|
||||
return x.AggregationBits
|
||||
}
|
||||
return github_com_prysmaticlabs_go_bitfield.Bitlist(nil)
|
||||
}
|
||||
|
||||
func (x *PendingAttestation) GetData() *AttestationData {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PendingAttestation) GetInclusionDelay() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot {
|
||||
if x != nil {
|
||||
return x.InclusionDelay
|
||||
}
|
||||
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(0)
|
||||
}
|
||||
|
||||
func (x *PendingAttestation) GetProposerIndex() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex {
|
||||
if x != nil {
|
||||
return x.ProposerIndex
|
||||
}
|
||||
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex(0)
|
||||
}
|
||||
|
||||
type Committee struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Index github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.CommitteeIndex `protobuf:"varint,1,opt,name=index,proto3" json:"index,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.CommitteeIndex"`
|
||||
Slot github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"`
|
||||
Validators []github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex `protobuf:"varint,3,rep,packed,name=validators,proto3" json:"validators,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.ValidatorIndex"`
|
||||
}
|
||||
|
||||
func (x *Committee) Reset() {
|
||||
*x = Committee{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Committee) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Committee) ProtoMessage() {}
|
||||
|
||||
func (x *Committee) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Committee.ProtoReflect.Descriptor instead.
|
||||
func (*Committee) Descriptor() ([]byte, []int) {
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Committee) GetIndex() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.CommitteeIndex {
|
||||
if x != nil {
|
||||
return x.Index
|
||||
}
|
||||
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.CommitteeIndex(0)
|
||||
}
|
||||
|
||||
func (x *Committee) GetSlot() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot {
|
||||
if x != nil {
|
||||
return x.Slot
|
||||
}
|
||||
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(0)
|
||||
}
|
||||
|
||||
func (x *Committee) GetValidators() []github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex {
|
||||
if x != nil {
|
||||
return x.Validators
|
||||
}
|
||||
return []github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.ValidatorIndex(nil)
|
||||
}
|
||||
|
||||
type Fork struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
PreviousVersion []byte `protobuf:"bytes,1,opt,name=previous_version,json=previousVersion,proto3" json:"previous_version,omitempty" ssz-size:"4"`
|
||||
CurrentVersion []byte `protobuf:"bytes,2,opt,name=current_version,json=currentVersion,proto3" json:"current_version,omitempty" ssz-size:"4"`
|
||||
Epoch github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Epoch `protobuf:"varint,3,opt,name=epoch,proto3" json:"epoch,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Epoch"`
|
||||
}
|
||||
|
||||
func (x *Fork) Reset() {
|
||||
*x = Fork{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Fork) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Fork) ProtoMessage() {}
|
||||
|
||||
func (x *Fork) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Fork.ProtoReflect.Descriptor instead.
|
||||
func (*Fork) Descriptor() ([]byte, []int) {
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Fork) GetPreviousVersion() []byte {
|
||||
if x != nil {
|
||||
return x.PreviousVersion
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Fork) GetCurrentVersion() []byte {
|
||||
if x != nil {
|
||||
return x.CurrentVersion
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Fork) GetEpoch() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Epoch {
|
||||
if x != nil {
|
||||
return x.Epoch
|
||||
}
|
||||
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Epoch(0)
|
||||
}
|
||||
|
||||
type ForkChoiceHeadsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Data []*ForkChoiceHead `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ForkChoiceHeadsResponse) Reset() {
|
||||
*x = ForkChoiceHeadsResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ForkChoiceHeadsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ForkChoiceHeadsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ForkChoiceHeadsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ForkChoiceHeadsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ForkChoiceHeadsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ForkChoiceHeadsResponse) GetData() []*ForkChoiceHead {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ForkChoiceHead struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Root []byte `protobuf:"bytes,1,opt,name=root,proto3" json:"root,omitempty" ssz-size:"32"`
|
||||
Slot github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot `protobuf:"varint,2,opt,name=slot,proto3" json:"slot,omitempty" cast-type:"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives.Slot"`
|
||||
}
|
||||
|
||||
func (x *ForkChoiceHead) Reset() {
|
||||
*x = ForkChoiceHead{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ForkChoiceHead) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ForkChoiceHead) ProtoMessage() {}
|
||||
|
||||
func (x *ForkChoiceHead) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ForkChoiceHead.ProtoReflect.Descriptor instead.
|
||||
func (*ForkChoiceHead) Descriptor() ([]byte, []int) {
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *ForkChoiceHead) GetRoot() []byte {
|
||||
if x != nil {
|
||||
return x.Root
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ForkChoiceHead) GetSlot() github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot {
|
||||
if x != nil {
|
||||
return x.Slot
|
||||
}
|
||||
return github_com_prysmaticlabs_prysm_v5_consensus_types_primitives.Slot(0)
|
||||
}
|
||||
|
||||
type BeaconStateResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Data *BeaconState `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BeaconStateResponse) Reset() {
|
||||
*x = BeaconStateResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *BeaconStateResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BeaconStateResponse) ProtoMessage() {}
|
||||
|
||||
func (x *BeaconStateResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_eth_v1_beacon_state_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BeaconStateResponse.ProtoReflect.Descriptor instead.
|
||||
func (*BeaconStateResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *BeaconStateResponse) GetData() *BeaconState {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_proto_eth_v1_beacon_state_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_proto_eth_v1_beacon_state_proto_rawDesc = []byte{
|
||||
0x0a, 0x1f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x2f, 0x62,
|
||||
0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x0f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e,
|
||||
0x76, 0x31, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f,
|
||||
0x65, 0x78, 0x74, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x1a, 0x1e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x2f,
|
||||
0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x1a, 0x1f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31, 0x2f,
|
||||
0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x1a, 0x1c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31,
|
||||
0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x22, 0xdb, 0x0b, 0x0a, 0x0b, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65,
|
||||
0x12, 0x22, 0x0a, 0x0c, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x18, 0xe9, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x17, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f,
|
||||
0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18,
|
||||
0xea, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x15,
|
||||
0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72,
|
||||
0x73, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x5a, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0xeb, 0x07,
|
||||
0x20, 0x01, 0x28, 0x04, 0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61,
|
||||
0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f,
|
||||
0x74, 0x12, 0x2a, 0x0a, 0x04, 0x66, 0x6f, 0x72, 0x6b, 0x18, 0xec, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x15, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x46, 0x6f, 0x72, 0x6b, 0x52, 0x04, 0x66, 0x6f, 0x72, 0x6b, 0x12, 0x53, 0x0a,
|
||||
0x13, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65,
|
||||
0x61, 0x64, 0x65, 0x72, 0x18, 0xd1, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x65, 0x74,
|
||||
0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x65,
|
||||
0x61, 0x63, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52,
|
||||
0x11, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x61, 0x64,
|
||||
0x65, 0x72, 0x12, 0x2d, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x72, 0x6f, 0x6f, 0x74,
|
||||
0x73, 0x18, 0xd2, 0x0f, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x0b, 0x8a, 0xb5, 0x18, 0x07, 0x38, 0x31,
|
||||
0x39, 0x32, 0x2c, 0x33, 0x32, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x6f, 0x6f, 0x74,
|
||||
0x73, 0x12, 0x2d, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x73,
|
||||
0x18, 0xd3, 0x0f, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x0b, 0x8a, 0xb5, 0x18, 0x07, 0x38, 0x31, 0x39,
|
||||
0x32, 0x2c, 0x33, 0x32, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x73,
|
||||
0x12, 0x40, 0x0a, 0x10, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x72,
|
||||
0x6f, 0x6f, 0x74, 0x73, 0x18, 0xd4, 0x0f, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x14, 0x8a, 0xb5, 0x18,
|
||||
0x04, 0x3f, 0x2c, 0x33, 0x32, 0x92, 0xb5, 0x18, 0x08, 0x31, 0x36, 0x37, 0x37, 0x37, 0x32, 0x31,
|
||||
0x36, 0x52, 0x0f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x52, 0x6f, 0x6f,
|
||||
0x74, 0x73, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x74, 0x68, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18,
|
||||
0xb9, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75,
|
||||
0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x74, 0x68, 0x31, 0x44, 0x61, 0x74,
|
||||
0x61, 0x52, 0x08, 0x65, 0x74, 0x68, 0x31, 0x44, 0x61, 0x74, 0x61, 0x12, 0x4c, 0x0a, 0x0f, 0x65,
|
||||
0x74, 0x68, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x18, 0xba,
|
||||
0x17, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d,
|
||||
0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x74, 0x68, 0x31, 0x44, 0x61, 0x74, 0x61,
|
||||
0x42, 0x08, 0x92, 0xb5, 0x18, 0x04, 0x32, 0x30, 0x34, 0x38, 0x52, 0x0d, 0x65, 0x74, 0x68, 0x31,
|
||||
0x44, 0x61, 0x74, 0x61, 0x56, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x65, 0x74, 0x68,
|
||||
0x31, 0x5f, 0x64, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18,
|
||||
0xbb, 0x17, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x65, 0x74, 0x68, 0x31, 0x44, 0x65, 0x70, 0x6f,
|
||||
0x73, 0x69, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69,
|
||||
0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0xa1, 0x1f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||
0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x42, 0x11, 0x92, 0xb5, 0x18, 0x0d, 0x31,
|
||||
0x30, 0x39, 0x39, 0x35, 0x31, 0x31, 0x36, 0x32, 0x37, 0x37, 0x37, 0x36, 0x52, 0x0a, 0x76, 0x61,
|
||||
0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x2e, 0x0a, 0x08, 0x62, 0x61, 0x6c, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x73, 0x18, 0xa2, 0x1f, 0x20, 0x03, 0x28, 0x04, 0x42, 0x11, 0x92, 0xb5, 0x18,
|
||||
0x0d, 0x31, 0x30, 0x39, 0x39, 0x35, 0x31, 0x31, 0x36, 0x32, 0x37, 0x37, 0x37, 0x36, 0x52, 0x08,
|
||||
0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x0c, 0x72, 0x61, 0x6e, 0x64,
|
||||
0x61, 0x6f, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x73, 0x18, 0x89, 0x27, 0x20, 0x03, 0x28, 0x0c, 0x42,
|
||||
0x0c, 0x8a, 0xb5, 0x18, 0x08, 0x36, 0x35, 0x35, 0x33, 0x36, 0x2c, 0x33, 0x32, 0x52, 0x0b, 0x72,
|
||||
0x61, 0x6e, 0x64, 0x61, 0x6f, 0x4d, 0x69, 0x78, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x09, 0x73, 0x6c,
|
||||
0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x18, 0xf1, 0x2e, 0x20, 0x03, 0x28, 0x04, 0x42, 0x08,
|
||||
0x8a, 0xb5, 0x18, 0x04, 0x38, 0x31, 0x39, 0x32, 0x52, 0x09, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x12, 0x6e, 0x0a, 0x1b, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f,
|
||||
0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x18, 0xd9, 0x36, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x65, 0x74, 0x68, 0x65,
|
||||
0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x6e, 0x64,
|
||||
0x69, 0x6e, 0x67, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08,
|
||||
0x92, 0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x19, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f,
|
||||
0x75, 0x73, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x12, 0x6c, 0x0a, 0x1a, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x65,
|
||||
0x70, 0x6f, 0x63, 0x68, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x18, 0xda, 0x36, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72,
|
||||
0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69,
|
||||
0x6e, 0x67, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0x92,
|
||||
0xb5, 0x18, 0x04, 0x34, 0x30, 0x39, 0x36, 0x52, 0x18, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74,
|
||||
0x45, 0x70, 0x6f, 0x63, 0x68, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x12, 0x68, 0x0a, 0x12, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0xc1, 0x3e, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x38,
|
||||
0x82, 0xb5, 0x18, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70,
|
||||
0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x67, 0x6f, 0x2d,
|
||||
0x62, 0x69, 0x74, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x2e, 0x42, 0x69, 0x74, 0x76, 0x65, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x34, 0x8a, 0xb5, 0x18, 0x01, 0x31, 0x52, 0x11, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66,
|
||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, 0x74, 0x73, 0x12, 0x60, 0x0a, 0x1d, 0x70,
|
||||
0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x69, 0x65,
|
||||
0x64, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0xc2, 0x3e, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74,
|
||||
0x52, 0x1b, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x4a, 0x75, 0x73, 0x74, 0x69, 0x66,
|
||||
0x69, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x5e, 0x0a,
|
||||
0x1c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x66, 0x69,
|
||||
0x65, 0x64, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0xc3, 0x3e,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e,
|
||||
0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e,
|
||||
0x74, 0x52, 0x1a, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4a, 0x75, 0x73, 0x74, 0x69, 0x66,
|
||||
0x69, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x4f, 0x0a,
|
||||
0x14, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b,
|
||||
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0xc4, 0x3e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65,
|
||||
0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x43,
|
||||
0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x13, 0x66, 0x69, 0x6e, 0x61, 0x6c,
|
||||
0x69, 0x7a, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x97,
|
||||
0x03, 0x0a, 0x12, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x63, 0x0a, 0x10, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42,
|
||||
0x38, 0x82, 0xb5, 0x18, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x67, 0x6f,
|
||||
0x2d, 0x62, 0x69, 0x74, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x2e, 0x42, 0x69, 0x74, 0x6c, 0x69, 0x73,
|
||||
0x74, 0x92, 0xb5, 0x18, 0x04, 0x32, 0x30, 0x34, 0x38, 0x52, 0x0f, 0x61, 0x67, 0x67, 0x72, 0x65,
|
||||
0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x69, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x64, 0x61,
|
||||
0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72,
|
||||
0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73,
|
||||
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
|
||||
0x12, 0x6e, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65,
|
||||
0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x45, 0x82, 0xb5, 0x18, 0x41, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61,
|
||||
0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35,
|
||||
0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73,
|
||||
0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74,
|
||||
0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x61, 0x79,
|
||||
0x12, 0x76, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64,
|
||||
0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4f, 0x82, 0xb5, 0x18, 0x4b, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74,
|
||||
0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f,
|
||||
0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f,
|
||||
0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64,
|
||||
0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x70, 0x6f,
|
||||
0x73, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xbe, 0x02, 0x0a, 0x09, 0x43, 0x6f, 0x6d,
|
||||
0x6d, 0x69, 0x74, 0x74, 0x65, 0x65, 0x12, 0x65, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x4f, 0x82, 0xb5, 0x18, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c,
|
||||
0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69,
|
||||
0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65,
|
||||
0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x59, 0x0a,
|
||||
0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x45, 0x82, 0xb5, 0x18,
|
||||
0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73,
|
||||
0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f,
|
||||
0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70,
|
||||
0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x53, 0x6c,
|
||||
0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x12, 0x6f, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69,
|
||||
0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x04, 0x42, 0x4f, 0x82, 0xb5,
|
||||
0x18, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79,
|
||||
0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
|
||||
0x2f, 0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x56,
|
||||
0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0a, 0x76,
|
||||
0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x04, 0x46, 0x6f,
|
||||
0x72, 0x6b, 0x12, 0x30, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x05, 0x8a, 0xb5,
|
||||
0x18, 0x01, 0x34, 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x56, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x0f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x05, 0x8a,
|
||||
0xb5, 0x18, 0x01, 0x34, 0x52, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x04, 0x42, 0x46, 0x82, 0xb5, 0x18, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62,
|
||||
0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x6e, 0x73, 0x75, 0x73, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69,
|
||||
0x74, 0x69, 0x76, 0x65, 0x73, 0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x52, 0x05, 0x65, 0x70, 0x6f,
|
||||
0x63, 0x68, 0x22, 0x4e, 0x0a, 0x17, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65,
|
||||
0x48, 0x65, 0x61, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a,
|
||||
0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x65, 0x74,
|
||||
0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6f,
|
||||
0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x64, 0x61,
|
||||
0x74, 0x61, 0x22, 0x87, 0x01, 0x0a, 0x0e, 0x46, 0x6f, 0x72, 0x6b, 0x43, 0x68, 0x6f, 0x69, 0x63,
|
||||
0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x04, 0x72, 0x6f, 0x6f,
|
||||
0x74, 0x12, 0x59, 0x0a, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42,
|
||||
0x45, 0x82, 0xb5, 0x18, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||
0x70, 0x72, 0x79, 0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72,
|
||||
0x79, 0x73, 0x6d, 0x2f, 0x76, 0x35, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x73, 0x75, 0x73,
|
||||
0x2d, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x69, 0x74, 0x69, 0x76, 0x65,
|
||||
0x73, 0x2e, 0x53, 0x6c, 0x6f, 0x74, 0x52, 0x04, 0x73, 0x6c, 0x6f, 0x74, 0x22, 0x47, 0x0a, 0x13,
|
||||
0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1c, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,
|
||||
0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x7d, 0x0a, 0x13, 0x6f, 0x72, 0x67, 0x2e, 0x65, 0x74, 0x68,
|
||||
0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x65, 0x74, 0x68, 0x2e, 0x76, 0x31, 0x42, 0x10, 0x42, 0x65,
|
||||
0x61, 0x63, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
|
||||
0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x79,
|
||||
0x73, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x70, 0x72, 0x79, 0x73, 0x6d,
|
||||
0x2f, 0x76, 0x35, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x74, 0x68, 0x2f, 0x76, 0x31,
|
||||
0xaa, 0x02, 0x0f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2e, 0x45, 0x74, 0x68, 0x2e,
|
||||
0x56, 0x31, 0xca, 0x02, 0x0f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5c, 0x45, 0x74,
|
||||
0x68, 0x5c, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_proto_eth_v1_beacon_state_proto_rawDescOnce sync.Once
|
||||
file_proto_eth_v1_beacon_state_proto_rawDescData = file_proto_eth_v1_beacon_state_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_proto_eth_v1_beacon_state_proto_rawDescGZIP() []byte {
|
||||
file_proto_eth_v1_beacon_state_proto_rawDescOnce.Do(func() {
|
||||
file_proto_eth_v1_beacon_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_eth_v1_beacon_state_proto_rawDescData)
|
||||
})
|
||||
return file_proto_eth_v1_beacon_state_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proto_eth_v1_beacon_state_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_proto_eth_v1_beacon_state_proto_goTypes = []interface{}{
|
||||
(*BeaconState)(nil), // 0: ethereum.eth.v1.BeaconState
|
||||
(*PendingAttestation)(nil), // 1: ethereum.eth.v1.PendingAttestation
|
||||
(*Committee)(nil), // 2: ethereum.eth.v1.Committee
|
||||
(*Fork)(nil), // 3: ethereum.eth.v1.Fork
|
||||
(*ForkChoiceHeadsResponse)(nil), // 4: ethereum.eth.v1.ForkChoiceHeadsResponse
|
||||
(*ForkChoiceHead)(nil), // 5: ethereum.eth.v1.ForkChoiceHead
|
||||
(*BeaconStateResponse)(nil), // 6: ethereum.eth.v1.BeaconStateResponse
|
||||
(*BeaconBlockHeader)(nil), // 7: ethereum.eth.v1.BeaconBlockHeader
|
||||
(*Eth1Data)(nil), // 8: ethereum.eth.v1.Eth1Data
|
||||
(*Validator)(nil), // 9: ethereum.eth.v1.Validator
|
||||
(*Checkpoint)(nil), // 10: ethereum.eth.v1.Checkpoint
|
||||
(*AttestationData)(nil), // 11: ethereum.eth.v1.AttestationData
|
||||
}
|
||||
var file_proto_eth_v1_beacon_state_proto_depIdxs = []int32{
|
||||
3, // 0: ethereum.eth.v1.BeaconState.fork:type_name -> ethereum.eth.v1.Fork
|
||||
7, // 1: ethereum.eth.v1.BeaconState.latest_block_header:type_name -> ethereum.eth.v1.BeaconBlockHeader
|
||||
8, // 2: ethereum.eth.v1.BeaconState.eth1_data:type_name -> ethereum.eth.v1.Eth1Data
|
||||
8, // 3: ethereum.eth.v1.BeaconState.eth1_data_votes:type_name -> ethereum.eth.v1.Eth1Data
|
||||
9, // 4: ethereum.eth.v1.BeaconState.validators:type_name -> ethereum.eth.v1.Validator
|
||||
1, // 5: ethereum.eth.v1.BeaconState.previous_epoch_attestations:type_name -> ethereum.eth.v1.PendingAttestation
|
||||
1, // 6: ethereum.eth.v1.BeaconState.current_epoch_attestations:type_name -> ethereum.eth.v1.PendingAttestation
|
||||
10, // 7: ethereum.eth.v1.BeaconState.previous_justified_checkpoint:type_name -> ethereum.eth.v1.Checkpoint
|
||||
10, // 8: ethereum.eth.v1.BeaconState.current_justified_checkpoint:type_name -> ethereum.eth.v1.Checkpoint
|
||||
10, // 9: ethereum.eth.v1.BeaconState.finalized_checkpoint:type_name -> ethereum.eth.v1.Checkpoint
|
||||
11, // 10: ethereum.eth.v1.PendingAttestation.data:type_name -> ethereum.eth.v1.AttestationData
|
||||
5, // 11: ethereum.eth.v1.ForkChoiceHeadsResponse.data:type_name -> ethereum.eth.v1.ForkChoiceHead
|
||||
0, // 12: ethereum.eth.v1.BeaconStateResponse.data:type_name -> ethereum.eth.v1.BeaconState
|
||||
13, // [13:13] is the sub-list for method output_type
|
||||
13, // [13:13] is the sub-list for method input_type
|
||||
13, // [13:13] is the sub-list for extension type_name
|
||||
13, // [13:13] is the sub-list for extension extendee
|
||||
0, // [0:13] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proto_eth_v1_beacon_state_proto_init() }
|
||||
func file_proto_eth_v1_beacon_state_proto_init() {
|
||||
if File_proto_eth_v1_beacon_state_proto != nil {
|
||||
return
|
||||
}
|
||||
file_proto_eth_v1_attestation_proto_init()
|
||||
file_proto_eth_v1_beacon_block_proto_init()
|
||||
file_proto_eth_v1_validator_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_proto_eth_v1_beacon_state_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*BeaconState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_eth_v1_beacon_state_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PendingAttestation); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_eth_v1_beacon_state_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Committee); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_eth_v1_beacon_state_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Fork); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_eth_v1_beacon_state_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ForkChoiceHeadsResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_eth_v1_beacon_state_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ForkChoiceHead); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_proto_eth_v1_beacon_state_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*BeaconStateResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proto_eth_v1_beacon_state_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 7,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_proto_eth_v1_beacon_state_proto_goTypes,
|
||||
DependencyIndexes: file_proto_eth_v1_beacon_state_proto_depIdxs,
|
||||
MessageInfos: file_proto_eth_v1_beacon_state_proto_msgTypes,
|
||||
}.Build()
|
||||
File_proto_eth_v1_beacon_state_proto = out.File
|
||||
file_proto_eth_v1_beacon_state_proto_rawDesc = nil
|
||||
file_proto_eth_v1_beacon_state_proto_goTypes = nil
|
||||
file_proto_eth_v1_beacon_state_proto_depIdxs = nil
|
||||
}
|
||||
4
proto/eth/v1/beacon_state.pb.gw.go
Executable file
4
proto/eth/v1/beacon_state.pb.gw.go
Executable file
@@ -0,0 +1,4 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package ignore
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user