Compare commits

..

1 Commits

Author SHA1 Message Date
nisdas
c1270b6b81 try it out 2023-05-11 21:04:48 +08:00
95 changed files with 350 additions and 1940 deletions

View File

@@ -43,12 +43,4 @@ build --flaky_test_attempts=5
# Better caching
build:nostamp --nostamp
# Build metadata
build --build_metadata=ROLE=CI
build --build_metadata=REPO_URL=https://github.com/prysmaticlabs/prysm.git
build --workspace_status_command=./hack/workspace_status_ci.sh
# Buildbuddy
build --bes_results_url=https://app.buildbuddy.io/invocation/
build --bes_backend=grpcs://remote.buildbuddy.io
build:nostamp --workspace_status_command=./hack/workspace_status_ci.sh

View File

@@ -26,14 +26,14 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Go 1.20
- name: Set up Go 1.19
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: 1.19
- name: Run Gosec Security Scanner
run: | # https://github.com/securego/gosec/issues/469
export PATH=$PATH:$(go env GOPATH)/bin
go install github.com/securego/gosec/v2/cmd/gosec@v2.15.0
go install github.com/securego/gosec/v2/cmd/gosec@v2.12.0
gosec -exclude=G307 -exclude-dir=crypto/bls/herumi ./...
lint:
@@ -43,16 +43,16 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Go 1.20
- name: Set up Go 1.19
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: 1.19
id: go
- name: Golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.52.2
version: v1.50.1
args: --config=.golangci.yml --out-${NO_FUTURE}format colored-line-number
build:
@@ -62,7 +62,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: '1.20'
go-version: 1.19
id: go
- name: Check out code into the Go module directory

View File

@@ -4,14 +4,14 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/prysmaticlabs/prysm)](https://goreportcard.com/report/github.com/prysmaticlabs/prysm)
[![Consensus_Spec_Version 1.3.0](https://img.shields.io/badge/Consensus%20Spec%20Version-v1.3.0-blue.svg)](https://github.com/ethereum/consensus-specs/tree/v1.3.0)
[![Execution_API_Version 1.0.0-beta.2](https://img.shields.io/badge/Execution%20API%20Version-v1.0.0.beta.2-blue.svg)](https://github.com/ethereum/execution-apis/tree/v1.0.0-beta.2/src/engine)
[![Discord](https://user-images.githubusercontent.com/7288322/34471967-1df7808a-efbb-11e7-9088-ed0b04151291.png)](https://discord.gg/prysmaticlabs)
[![Discord](https://user-images.githubusercontent.com/7288322/34471967-1df7808a-efbb-11e7-9088-ed0b04151291.png)](https://discord.gg/CTYGPUJ)
[![GitPOAP Badge](https://public-api.gitpoap.io/v1/repo/prysmaticlabs/prysm/badge)](https://www.gitpoap.io/gh/prysmaticlabs/prysm)
This is the core repository for Prysm, a [Golang](https://golang.org/) implementation of the [Ethereum Consensus](https://ethereum.org/en/eth2/) specification, developed by [Prysmatic Labs](https://prysmaticlabs.com). See the [Changelog](https://github.com/prysmaticlabs/prysm/releases) for details of the latest releases and upcoming breaking changes.
### Getting Started
A detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the [official documentation portal](https://docs.prylabs.network). If you still have questions, feel free to stop by our [Discord](https://discord.gg/prysmaticlabs).
A detailed set of installation and usage instructions as well as breakdowns of each individual component are available in the [official documentation portal](https://docs.prylabs.network). If you still have questions, feel free to stop by our [Discord](https://discord.gg/CTYGPUJ).
### Staking on Mainnet

View File

@@ -346,74 +346,6 @@ func (p *ExecutionPayload) ToProto() (*v1.ExecutionPayload, error) {
}, nil
}
// FromProto converts a proto execution payload type to our builder
// compatible payload type.
func FromProto(payload *v1.ExecutionPayload) (ExecutionPayload, error) {
bFee, err := sszBytesToUint256(payload.BaseFeePerGas)
if err != nil {
return ExecutionPayload{}, err
}
txs := make([]hexutil.Bytes, len(payload.Transactions))
for i := range payload.Transactions {
txs[i] = payload.Transactions[i]
}
return ExecutionPayload{
ParentHash: payload.ParentHash,
FeeRecipient: payload.FeeRecipient,
StateRoot: payload.StateRoot,
ReceiptsRoot: payload.ReceiptsRoot,
LogsBloom: payload.LogsBloom,
PrevRandao: payload.PrevRandao,
BlockNumber: Uint64String(payload.BlockNumber),
GasLimit: Uint64String(payload.GasLimit),
GasUsed: Uint64String(payload.GasUsed),
Timestamp: Uint64String(payload.Timestamp),
ExtraData: payload.ExtraData,
BaseFeePerGas: bFee,
BlockHash: payload.BlockHash,
Transactions: txs,
}, nil
}
// FromProtoCapella converts a proto execution payload type for capella to our
// builder compatible payload type.
func FromProtoCapella(payload *v1.ExecutionPayloadCapella) (ExecutionPayloadCapella, error) {
bFee, err := sszBytesToUint256(payload.BaseFeePerGas)
if err != nil {
return ExecutionPayloadCapella{}, err
}
txs := make([]hexutil.Bytes, len(payload.Transactions))
for i := range payload.Transactions {
txs[i] = payload.Transactions[i]
}
withdrawals := make([]Withdrawal, len(payload.Withdrawals))
for i, w := range payload.Withdrawals {
withdrawals[i] = Withdrawal{
Index: Uint256{Int: big.NewInt(0).SetUint64(w.Index)},
ValidatorIndex: Uint256{Int: big.NewInt(0).SetUint64(uint64(w.ValidatorIndex))},
Address: w.Address,
Amount: Uint256{Int: big.NewInt(0).SetUint64(w.Amount)},
}
}
return ExecutionPayloadCapella{
ParentHash: payload.ParentHash,
FeeRecipient: payload.FeeRecipient,
StateRoot: payload.StateRoot,
ReceiptsRoot: payload.ReceiptsRoot,
LogsBloom: payload.LogsBloom,
PrevRandao: payload.PrevRandao,
BlockNumber: Uint64String(payload.BlockNumber),
GasLimit: Uint64String(payload.GasLimit),
GasUsed: Uint64String(payload.GasUsed),
Timestamp: Uint64String(payload.Timestamp),
ExtraData: payload.ExtraData,
BaseFeePerGas: bFee,
BlockHash: payload.BlockHash,
Transactions: txs,
Withdrawals: withdrawals,
}, nil
}
type ExecHeaderResponseCapella struct {
Data struct {
Signature hexutil.Bytes `json:"signature"`

View File

@@ -8,7 +8,6 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
doublylinkedtree "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/doubly-linked-tree"
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -381,14 +380,6 @@ func (s *Service) InForkchoice(root [32]byte) bool {
return s.cfg.ForkChoiceStore.HasNode(root)
}
// IsViableForkCheckpoint 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) {

View File

@@ -25,11 +25,8 @@ var (
errWSBlockNotFound = errors.New("weak subjectivity root not found in db")
// errWSBlockNotFoundInEpoch is returned when a block is not found in the WS cache or DB within epoch.
errWSBlockNotFoundInEpoch = errors.New("weak subjectivity root not found in db within epoch")
// ErrNotDescendantOfFinalized is returned when a block is not a descendant of the finalized checkpoint
// errNotDescendantOfFinalized is returned when a block is not a descendant of the finalized checkpoint
ErrNotDescendantOfFinalized = invalidBlock{error: errors.New("not descendant of finalized checkpoint")}
// ErrNotCheckpoint is returned when a given checkpoint is not a
// checkpoint in any chain known to forkchoice
ErrNotCheckpoint = errors.New("not a checkpoint in forkchoice")
)
// An invalid block is the block that fails state transition based on the core protocol rules.

View File

@@ -53,7 +53,7 @@ func (s *Service) HeadSyncContributionProofDomain(ctx context.Context, slot prim
// HeadSyncCommitteeIndices returns the sync committee index position using the head state. Input `slot` is taken in consideration
// where validator's duty for `slot - 1` is used for block inclusion in `slot`. That means when a validator is at epoch boundary
// across EPOCHS_PER_SYNC_COMMITTEE_PERIOD then the validator will be considered using next period sync committee.
// across EPOCHS_PER_SYNC_COMMITTEE_PERIOD then the valiator will be considered using next period sync committee.
//
// Spec definition:
// Being assigned to a sync committee for a given slot means that the validator produces and broadcasts signatures for slot - 1 for inclusion in slot.

View File

@@ -8,7 +8,6 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/async"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
forkchoicetypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
@@ -19,17 +18,7 @@ import (
)
// getAttPreState retrieves the att pre state by either from the cache or the DB.
func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (state.ReadOnlyBeaconState, error) {
// If the attestation is recent and canonical we can use the head state to compute the shuffling.
headEpoch := slots.ToEpoch(s.HeadSlot())
if c.Epoch == headEpoch {
targetSlot, err := s.cfg.ForkChoiceStore.Slot([32]byte(c.Root))
if err == nil && slots.ToEpoch(targetSlot)+1 >= headEpoch {
if s.cfg.ForkChoiceStore.IsCanonical([32]byte(c.Root)) {
return s.HeadStateReadOnly(ctx)
}
}
}
func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (state.BeaconState, error) {
// Use a multilock to allow scoped holding of a mutex by a checkpoint root + epoch
// allowing us to behave smarter in terms of how this function is used concurrently.
epochKey := strconv.FormatUint(uint64(c.Epoch), 10 /* base 10 */)
@@ -43,36 +32,7 @@ func (s *Service) getAttPreState(ctx context.Context, c *ethpb.Checkpoint) (stat
if cachedState != nil && !cachedState.IsNil() {
return cachedState, nil
}
// Try the next slot cache for the early epoch calls, this should mostly have been covered already
// but is cheap
slot, err := slots.EpochStart(c.Epoch)
if err != nil {
return nil, errors.Wrap(err, "could not compute epoch start")
}
cachedState = transition.NextSlotState(c.Root, slot)
if cachedState != nil && !cachedState.IsNil() {
if cachedState.Slot() != slot {
cachedState, err = transition.ProcessSlots(ctx, cachedState, slot)
if err != nil {
return nil, errors.Wrap(err, "could not process slots")
}
}
if err := s.checkpointStateCache.AddCheckpointState(c, cachedState); err != nil {
return nil, errors.Wrap(err, "could not save checkpoint state to cache")
}
return cachedState, nil
}
// Do not process attestations for old non viable checkpoints otherwise
ok, err := s.cfg.ForkChoiceStore.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: [32]byte(c.Root), Epoch: c.Epoch})
if err != nil {
return nil, errors.Wrap(err, "could not check checkpoint condition in forkchoice")
}
if !ok {
return nil, errors.Wrap(ErrNotCheckpoint, fmt.Sprintf("epoch %d root %#x", c.Epoch, c.Root))
}
// Fallback to state regeneration.
baseState, err := s.cfg.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(c.Root))
if err != nil {
return nil, errors.Wrapf(err, "could not get pre state for epoch %d", c.Epoch)

View File

@@ -27,20 +27,11 @@ func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
blkWithoutState := util.NewBeaconBlock()
blkWithoutState.Block.Slot = 0
util.SaveBlock(t, ctx, beaconDB, blkWithoutState)
cp := &ethpb.Checkpoint{}
st, blkRoot, err := prepareForkchoiceState(ctx, 0, [32]byte{}, [32]byte{}, params.BeaconConfig().ZeroHash, cp, cp)
BlkWithOutStateRoot, err := blkWithoutState.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
blkWithStateBadAtt := util.NewBeaconBlock()
blkWithStateBadAtt.Block.Slot = 1
r, err := blkWithStateBadAtt.Block.HashTreeRoot()
require.NoError(t, err)
cp = &ethpb.Checkpoint{Root: r[:]}
st, blkRoot, err = prepareForkchoiceState(ctx, blkWithStateBadAtt.Block.Slot, r, [32]byte{}, params.BeaconConfig().ZeroHash, cp, cp)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
util.SaveBlock(t, ctx, beaconDB, blkWithStateBadAtt)
BlkWithStateBadAttRoot, err := blkWithStateBadAtt.Block.HashTreeRoot()
require.NoError(t, err)
@@ -51,7 +42,7 @@ func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, BlkWithStateBadAttRoot))
blkWithValidState := util.NewBeaconBlock()
blkWithValidState.Block.Slot = 32
blkWithValidState.Block.Slot = 2
util.SaveBlock(t, ctx, beaconDB, blkWithValidState)
blkWithValidStateRoot, err := blkWithValidState.Block.HashTreeRoot()
@@ -66,10 +57,6 @@ func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
require.NoError(t, err)
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, blkWithValidStateRoot))
service.head = &head{
state: st,
}
tests := []struct {
name string
a *ethpb.Attestation
@@ -80,6 +67,11 @@ func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
a: util.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: params.BeaconConfig().SlotsPerEpoch, Target: &ethpb.Checkpoint{Root: make([]byte, 32)}}}),
wantedErr: "slot 32 does not match target epoch 0",
},
{
name: "no pre state for attestations's target block",
a: util.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Target: &ethpb.Checkpoint{Root: BlkWithOutStateRoot[:]}}}),
wantedErr: "could not get pre state for epoch 0",
},
{
name: "process attestation doesn't match current epoch",
a: util.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 100 * params.BeaconConfig().SlotsPerEpoch, Target: &ethpb.Checkpoint{Epoch: 100,
@@ -168,9 +160,6 @@ func TestStore_SaveCheckpointState(t *testing.T) {
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'A'})))
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &ethpb.StateSummary{Root: bytesutil.PadTo([]byte{'A'}, fieldparams.RootLength)}))
st, root, err := prepareForkchoiceState(ctx, 1, [32]byte(cp1.Root), [32]byte{}, [32]byte{'R'}, cp1, cp1)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, root))
s1, err := service.getAttPreState(ctx, cp1)
require.NoError(t, err)
assert.Equal(t, 1*params.BeaconConfig().SlotsPerEpoch, s1.Slot(), "Unexpected state slot")
@@ -178,17 +167,8 @@ func TestStore_SaveCheckpointState(t *testing.T) {
cp2 := &ethpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'B'}, fieldparams.RootLength)}
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'B'})))
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &ethpb.StateSummary{Root: bytesutil.PadTo([]byte{'B'}, fieldparams.RootLength)}))
s2, err := service.getAttPreState(ctx, cp2)
require.ErrorContains(t, "epoch 2 root 0x4200000000000000000000000000000000000000000000000000000000000000: not a checkpoint in forkchoice", err)
st, root, err = prepareForkchoiceState(ctx, 33, [32]byte(cp2.Root), [32]byte(cp1.Root), [32]byte{'R'}, cp2, cp2)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, root))
s2, err = service.getAttPreState(ctx, cp2)
require.NoError(t, err)
assert.Equal(t, 2*params.BeaconConfig().SlotsPerEpoch, s2.Slot(), "Unexpected state slot")
s1, err = service.getAttPreState(ctx, cp1)
@@ -207,10 +187,6 @@ func TestStore_SaveCheckpointState(t *testing.T) {
cp3 := &ethpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'C'}, fieldparams.RootLength)}
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, s, bytesutil.ToBytes32([]byte{'C'})))
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &ethpb.StateSummary{Root: bytesutil.PadTo([]byte{'C'}, fieldparams.RootLength)}))
st, root, err = prepareForkchoiceState(ctx, 31, [32]byte(cp3.Root), [32]byte(cp2.Root), [32]byte{'P'}, cp2, cp2)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, root))
s3, err := service.getAttPreState(ctx, cp3)
require.NoError(t, err)
assert.Equal(t, s.Slot(), s3.Slot(), "Unexpected state slot")
@@ -219,18 +195,11 @@ func TestStore_SaveCheckpointState(t *testing.T) {
func TestStore_UpdateCheckpointState(t *testing.T) {
service, tr := minimalTestService(t)
ctx := tr.ctx
baseState, _ := util.DeterministicGenesisState(t, 1)
epoch := primitives.Epoch(1)
blk := util.NewBeaconBlock()
r1, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
checkpoint := &ethpb.Checkpoint{Epoch: epoch, Root: r1[:]}
baseState, _ := util.DeterministicGenesisState(t, 1)
checkpoint := &ethpb.Checkpoint{Epoch: epoch, Root: bytesutil.PadTo([]byte("hi"), fieldparams.RootLength)}
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(checkpoint.Root)))
st, blkRoot, err := prepareForkchoiceState(ctx, blk.Block.Slot, r1, [32]byte{}, params.BeaconConfig().ZeroHash, checkpoint, checkpoint)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, r1))
returned, err := service.getAttPreState(ctx, checkpoint)
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().SlotsPerEpoch.Mul(uint64(checkpoint.Epoch)), returned.Slot(), "Incorrectly returned base state")
@@ -240,16 +209,8 @@ func TestStore_UpdateCheckpointState(t *testing.T) {
assert.Equal(t, returned.Slot(), cached.Slot(), "State should have been cached")
epoch = 2
blk = util.NewBeaconBlock()
blk.Block.Slot = 64
r2, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
newCheckpoint := &ethpb.Checkpoint{Epoch: epoch, Root: r2[:]}
newCheckpoint := &ethpb.Checkpoint{Epoch: epoch, Root: bytesutil.PadTo([]byte("bye"), fieldparams.RootLength)}
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(newCheckpoint.Root)))
st, blkRoot, err = prepareForkchoiceState(ctx, blk.Block.Slot, r2, r1, params.BeaconConfig().ZeroHash, newCheckpoint, newCheckpoint)
require.NoError(t, err)
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, st, r2))
returned, err = service.getAttPreState(ctx, newCheckpoint)
require.NoError(t, err)
s, err := slots.EpochStart(newCheckpoint.Epoch)
@@ -328,22 +289,3 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
assert.NoError(t, service.verifyBeaconBlock(ctx, d), "Did not receive the wanted error")
}
func TestGetAttPreState_HeadState(t *testing.T) {
service, tr := minimalTestService(t)
ctx := tr.ctx
baseState, _ := util.DeterministicGenesisState(t, 1)
epoch := primitives.Epoch(1)
blk := util.NewBeaconBlock()
r1, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
checkpoint := &ethpb.Checkpoint{Epoch: epoch, Root: r1[:]}
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, baseState, bytesutil.ToBytes32(checkpoint.Root)))
require.NoError(t, transition.UpdateNextSlotCache(ctx, checkpoint.Root, baseState))
_, err = service.getAttPreState(ctx, checkpoint)
require.NoError(t, err)
st, err := service.checkpointStateCache.StateByCheckpoint(checkpoint)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().SlotsPerEpoch, st.Slot())
}

View File

@@ -1875,9 +1875,9 @@ func TestOnBlock_HandleBlockAttestations(t *testing.T) {
r3 := bytesutil.ToBytes32(a3.Data.BeaconBlockRoot)
require.Equal(t, false, service.cfg.ForkChoiceStore.HasNode(r3))
require.NoError(t, service.handleBlockAttestations(ctx, wsb.Block(), st)) // fine to use the same committee as st
require.NoError(t, service.handleBlockAttestations(ctx, wsb.Block(), st)) // fine to use the same committe as st
require.Equal(t, 0, service.cfg.AttPool.ForkchoiceAttestationCount())
require.NoError(t, service.handleBlockAttestations(ctx, wsb3.Block(), st3)) // fine to use the same committee as st
require.NoError(t, service.handleBlockAttestations(ctx, wsb3.Block(), st3)) // fine to use the same committe as st
require.Equal(t, 1, len(service.cfg.AttPool.BlockAttestations()))
}

View File

@@ -26,7 +26,7 @@ const reorgLateBlockCountAttestations = 2 * time.Second
// AttestationStateFetcher allows for retrieving a beacon state corresponding to the block
// root of an attestation's target checkpoint.
type AttestationStateFetcher interface {
AttestationTargetState(ctx context.Context, target *ethpb.Checkpoint) (state.ReadOnlyBeaconState, error)
AttestationTargetState(ctx context.Context, target *ethpb.Checkpoint) (state.BeaconState, error)
}
// AttestationReceiver interface defines the methods of chain service receive and processing new attestations.
@@ -37,7 +37,7 @@ type AttestationReceiver interface {
}
// AttestationTargetState returns the pre state of attestation.
func (s *Service) AttestationTargetState(ctx context.Context, target *ethpb.Checkpoint) (state.ReadOnlyBeaconState, error) {
func (s *Service) AttestationTargetState(ctx context.Context, target *ethpb.Checkpoint) (state.BeaconState, error) {
ss, err := slots.EpochStart(target.Epoch)
if err != nil {
return nil, err
@@ -45,9 +45,6 @@ func (s *Service) AttestationTargetState(ctx context.Context, target *ethpb.Chec
if err := slots.ValidateClock(ss, uint64(s.genesisTime.Unix())); err != nil {
return nil, err
}
// We acquire the lock here instead than on gettAttPreState because that function gets called from UpdateHead that holds a write lock
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
return s.getAttPreState(ctx, target)
}

View File

@@ -320,7 +320,7 @@ func (_ *ChainService) ReceiveAttestation(_ context.Context, _ *ethpb.Attestatio
}
// AttestationTargetState mocks AttestationTargetState method in chain service.
func (s *ChainService) AttestationTargetState(_ context.Context, _ *ethpb.Checkpoint) (state.ReadOnlyBeaconState, error) {
func (s *ChainService) AttestationTargetState(_ context.Context, _ *ethpb.Checkpoint) (state.BeaconState, error) {
return s.State, nil
}

View File

@@ -804,7 +804,7 @@ func TestFinalizedDeposits_ReturnsTrieCorrectly(t *testing.T) {
require.NoError(t, dc.InsertFinalizedDeposits(context.Background(), 3))
require.NoError(t, dc.InsertFinalizedDeposits(context.Background(), 4))
// Mimic finalized deposit trie fetch.
// Mimick finalized deposit trie fetch.
fd := dc.FinalizedDeposits(context.Background())
deps := dc.NonFinalizedDeposits(context.Background(), fd.MerkleTrieIndex, big.NewInt(14))
insertIndex := fd.MerkleTrieIndex + 1

View File

@@ -183,11 +183,11 @@ func ValidateAttestationTime(attSlot primitives.Slot, genesisTime time.Time, clo
currentSlot,
)
if attTime.Before(lowerBounds) {
attReceivedTooLateCount.Inc()
attReceivedTooEarlyCount.Inc()
return attError
}
if attTime.After(upperBounds) {
attReceivedTooEarlyCount.Inc()
attReceivedTooLateCount.Inc()
return attError
}
return nil

View File

@@ -150,7 +150,7 @@ func TestSlashValidator_OK(t *testing.T) {
maxBalance := params.BeaconConfig().MaxEffectiveBalance
slashedBalance := state.Slashings()[state.Slot().Mod(uint64(params.BeaconConfig().EpochsPerSlashingsVector))]
assert.Equal(t, maxBalance, slashedBalance, "Slashed balance isn't the expected amount")
assert.Equal(t, maxBalance, slashedBalance, "Slashed balance isnt the expected amount")
whistleblowerReward := slashedBalance / params.BeaconConfig().WhistleBlowerRewardQuotient
bal, err := state.BalanceAtIndex(proposer)

View File

@@ -543,7 +543,7 @@ func TestStore_Blocks_Retrieve_SlotRangeWithStep(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 150, len(retrieved))
for _, b := range retrieved {
assert.Equal(t, primitives.Slot(0), (b.Block().Slot()-100)%step, "Unexpected block slot %d", b.Block().Slot())
assert.Equal(t, primitives.Slot(0), (b.Block().Slot()-100)%step, "Unexpect block slot %d", b.Block().Slot())
}
})
}

View File

@@ -14,6 +14,7 @@ go_library(
"metrics.go",
"options.go",
"prometheus.go",
"provider.go",
"rpc_connection.go",
"service.go",
],
@@ -89,6 +90,7 @@ go_test(
"init_test.go",
"log_processing_test.go",
"prometheus_test.go",
"provider_test.go",
"service_test.go",
],
data = glob(["testdata/**"]),
@@ -120,6 +122,7 @@ go_test(
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/clientstats:go_default_library",
"//network/authorization:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",

View File

@@ -7,7 +7,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
"github.com/prysmaticlabs/prysm/v4/network"
"github.com/prysmaticlabs/prysm/v4/network/authorization"
)
@@ -16,7 +15,7 @@ type Option func(s *Service) error
// WithHttpEndpoint parse http endpoint for the powchain service to use.
func WithHttpEndpoint(endpointString string) Option {
return func(s *Service) error {
s.cfg.currHttpEndpoint = network.HttpEndpoint(endpointString)
s.cfg.currHttpEndpoint = HttpEndpoint(endpointString)
return nil
}
}
@@ -28,7 +27,7 @@ func WithHttpEndpointAndJWTSecret(endpointString string, secret []byte) Option {
return nil
}
// Overwrite authorization type for all endpoints to be of a bearer type.
hEndpoint := network.HttpEndpoint(endpointString)
hEndpoint := HttpEndpoint(endpointString)
hEndpoint.Auth.Method = authorization.Bearer
hEndpoint.Auth.Value = string(secret)

View File

@@ -15,7 +15,7 @@ import (
func TestCleanup(t *testing.T) {
ctx := context.Background()
pc, err := NewPowchainCollector(ctx)
assert.NoError(t, err, "Unexpected error calling NewPowchainCollector")
assert.NoError(t, err, "Uxpected error caling NewPowchainCollector")
unregistered := pc.unregister()
assert.Equal(t, true, unregistered, "PowchainCollector.unregister did not return true (via prometheus.DefaultRegistry)")
// PowchainCollector is a prometheus.Collector, so we should be able to register it again
@@ -39,7 +39,7 @@ func TestCleanup(t *testing.T) {
func TestCancelation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
pc, err := NewPowchainCollector(ctx)
assert.NoError(t, err, "Unexpected error calling NewPowchainCollector")
assert.NoError(t, err, "Uxpected error caling NewPowchainCollector")
ticker := time.NewTicker(10 * time.Second)
cancel()
select {

View File

@@ -0,0 +1,49 @@
package execution
import (
"encoding/base64"
"strings"
"github.com/prysmaticlabs/prysm/v4/network"
"github.com/prysmaticlabs/prysm/v4/network/authorization"
)
// HttpEndpoint extracts an httputils.Endpoint from the provider parameter.
func HttpEndpoint(eth1Provider string) network.Endpoint {
endpoint := network.Endpoint{
Url: "",
Auth: network.AuthorizationData{
Method: authorization.None,
Value: "",
}}
authValues := strings.Split(eth1Provider, ",")
endpoint.Url = strings.TrimSpace(authValues[0])
if len(authValues) > 2 {
log.Errorf(
"ETH1 endpoint string can contain one comma for specifying the authorization header to access the provider."+
" String contains too many commas: %d. Skipping authorization.", len(authValues)-1)
} else if len(authValues) == 2 {
switch network.Method(strings.TrimSpace(authValues[1])) {
case authorization.Basic:
basicAuthValues := strings.Split(strings.TrimSpace(authValues[1]), " ")
if len(basicAuthValues) != 2 {
log.Errorf("Basic Authentication has incorrect format. Skipping authorization.")
} else {
endpoint.Auth.Method = authorization.Basic
endpoint.Auth.Value = base64.StdEncoding.EncodeToString([]byte(basicAuthValues[1]))
}
case authorization.Bearer:
bearerAuthValues := strings.Split(strings.TrimSpace(authValues[1]), " ")
if len(bearerAuthValues) != 2 {
log.Errorf("Bearer Authentication has incorrect format. Skipping authorization.")
} else {
endpoint.Auth.Method = authorization.Bearer
endpoint.Auth.Value = bearerAuthValues[1]
}
case authorization.None:
log.Errorf("Authorization has incorrect format or authorization type is not supported.")
}
}
return endpoint
}

View File

@@ -0,0 +1,74 @@
package execution
import (
"testing"
"github.com/prysmaticlabs/prysm/v4/network/authorization"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
logTest "github.com/sirupsen/logrus/hooks/test"
)
func TestHttpEndpoint(t *testing.T) {
hook := logTest.NewGlobal()
url := "http://test"
t.Run("URL", func(t *testing.T) {
endpoint := HttpEndpoint(url)
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
})
t.Run("URL with separator", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
})
t.Run("URL with whitespace", func(t *testing.T) {
endpoint := HttpEndpoint(" " + url + " ,")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
})
t.Run("Basic auth", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",Basic username:password")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Basic, endpoint.Auth.Method)
assert.Equal(t, "dXNlcm5hbWU6cGFzc3dvcmQ=", endpoint.Auth.Value)
})
t.Run("Basic auth with whitespace", func(t *testing.T) {
endpoint := HttpEndpoint(url + ", Basic username:password ")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Basic, endpoint.Auth.Method)
assert.Equal(t, "dXNlcm5hbWU6cGFzc3dvcmQ=", endpoint.Auth.Value)
})
t.Run("Basic auth with incorrect format", func(t *testing.T) {
hook.Reset()
endpoint := HttpEndpoint(url + ",Basic username:password foo")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
assert.LogsContain(t, hook, "Skipping authorization")
})
t.Run("Bearer auth", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",Bearer token")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Bearer, endpoint.Auth.Method)
assert.Equal(t, "token", endpoint.Auth.Value)
})
t.Run("Bearer auth with whitespace", func(t *testing.T) {
endpoint := HttpEndpoint(url + ", Bearer token ")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Bearer, endpoint.Auth.Method)
assert.Equal(t, "token", endpoint.Auth.Value)
})
t.Run("Bearer auth with incorrect format", func(t *testing.T) {
hook.Reset()
endpoint := HttpEndpoint(url + ",Bearer token foo")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
assert.LogsContain(t, hook, "Skipping authorization")
})
t.Run("Too many separators", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",Bearer token,foo")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
assert.LogsContain(t, hook, "Skipping authorization")
})
}

View File

@@ -3,6 +3,7 @@ package execution
import (
"context"
"fmt"
"net/url"
"strings"
"time"
@@ -106,10 +107,26 @@ func (s *Service) retryExecutionClientConnection(ctx context.Context, err error)
// Initializes an RPC connection with authentication headers.
func (s *Service) newRPCClientWithAuth(ctx context.Context, endpoint network.Endpoint) (*gethRPC.Client, error) {
client, err := network.NewExecutionRPCClient(ctx, endpoint)
// Need to handle ipc and http
var client *gethRPC.Client
u, err := url.Parse(endpoint.Url)
if err != nil {
return nil, err
}
switch u.Scheme {
case "http", "https":
client, err = gethRPC.DialOptions(ctx, endpoint.Url, gethRPC.WithHTTPClient(endpoint.HttpClient()))
if err != nil {
return nil, err
}
case "", "ipc":
client, err = gethRPC.DialIPC(ctx, endpoint.Url)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme)
}
if endpoint.Auth.Method != authorization.None {
header, err := endpoint.Auth.ToHeaderValue()
if err != nil {

View File

@@ -228,39 +228,6 @@ func (f *ForkChoice) AncestorRoot(ctx context.Context, root [32]byte, slot primi
return n.root, nil
}
// IsViableForCheckpoint returns whether the root passed is a checkpoint root for any
// known chain in forkchoice.
func (f *ForkChoice) IsViableForCheckpoint(cp *forkchoicetypes.Checkpoint) (bool, error) {
node, ok := f.store.nodeByRoot[cp.Root]
if !ok || node == nil {
return false, nil
}
epochStart, err := slots.EpochStart(cp.Epoch)
if err != nil {
return false, err
}
if node.slot > epochStart {
return false, nil
}
if len(node.children) == 0 {
return true, nil
}
if node.slot == epochStart {
return true, nil
}
nodeEpoch := slots.ToEpoch(node.slot)
if nodeEpoch >= cp.Epoch {
return false, nil
}
for _, child := range node.children {
if child.slot > epochStart {
return true, nil
}
}
return false, nil
}
// updateBalances updates the balances that directly voted for each block taking into account the
// validators' latest votes.
func (f *ForkChoice) updateBalances() error {
@@ -627,12 +594,3 @@ func (f *ForkChoice) updateJustifiedBalances(ctx context.Context, root [32]byte)
f.store.committeeWeight /= uint64(params.BeaconConfig().SlotsPerEpoch)
return nil
}
// Slot returns the slot of the given root if it's known to forkchoice
func (f *ForkChoice) Slot(root [32]byte) (primitives.Slot, error) {
n, ok := f.store.nodeByRoot[root]
if !ok || n == nil {
return 0, ErrNilNode
}
return n.slot, nil
}

View File

@@ -754,110 +754,3 @@ func TestForkChoice_UnrealizedJustifiedPayloadBlockHash(t *testing.T) {
got := f.UnrealizedJustifiedPayloadBlockHash()
require.Equal(t, [32]byte{'A'}, got)
}
func TestForkChoiceIsViableForCheckpoint(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
st, root, err := prepareForkchoiceState(ctx, 0, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 0, 0)
require.NoError(t, err)
// No Node
viable, err := f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: root})
require.NoError(t, err)
require.Equal(t, false, viable)
// No Children
require.NoError(t, f.InsertNode(ctx, st, root))
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: root, Epoch: 0})
require.NoError(t, err)
require.Equal(t, true, viable)
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: root, Epoch: 1})
require.NoError(t, err)
require.Equal(t, true, viable)
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: root, Epoch: 2})
require.NoError(t, err)
require.Equal(t, true, viable)
st, broot, err := prepareForkchoiceState(ctx, 1, [32]byte{'b'}, root, [32]byte{'B'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, broot))
// Epoch start
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: root})
require.NoError(t, err)
require.Equal(t, true, viable)
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: root, Epoch: 1})
require.NoError(t, err)
require.Equal(t, false, viable)
// No Children but impossible checkpoint
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: broot})
require.NoError(t, err)
require.Equal(t, false, viable)
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: broot, Epoch: 1})
require.NoError(t, err)
require.Equal(t, true, viable)
st, croot, err := prepareForkchoiceState(ctx, 2, [32]byte{'c'}, broot, [32]byte{'C'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, croot))
// Children in same epoch
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: broot})
require.NoError(t, err)
require.Equal(t, false, viable)
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: broot, Epoch: 1})
require.NoError(t, err)
require.Equal(t, false, viable)
st, droot, err := prepareForkchoiceState(ctx, params.BeaconConfig().SlotsPerEpoch, [32]byte{'d'}, broot, [32]byte{'D'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, droot))
// Children in next epoch but boundary
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: broot})
require.NoError(t, err)
require.Equal(t, false, viable)
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: broot, Epoch: 1})
require.NoError(t, err)
require.Equal(t, false, viable)
// Boundary block
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: droot, Epoch: 1})
require.NoError(t, err)
require.Equal(t, true, viable)
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: droot, Epoch: 0})
require.NoError(t, err)
require.Equal(t, false, viable)
// Children in next epoch
st, eroot, err := prepareForkchoiceState(ctx, params.BeaconConfig().SlotsPerEpoch+1, [32]byte{'e'}, broot, [32]byte{'E'}, 0, 0)
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, eroot))
viable, err = f.IsViableForCheckpoint(&forkchoicetypes.Checkpoint{Root: broot, Epoch: 1})
require.NoError(t, err)
require.Equal(t, true, viable)
}
func TestForkChoiceSlot(t *testing.T) {
f := setup(0, 0)
ctx := context.Background()
st, root, err := prepareForkchoiceState(ctx, 3, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 0, 0)
require.NoError(t, err)
// No Node
_, err = f.Slot(root)
require.ErrorIs(t, ErrNilNode, err)
require.NoError(t, f.InsertNode(ctx, st, root))
slot, err := f.Slot(root)
require.NoError(t, err)
require.Equal(t, primitives.Slot(3), slot)
}

View File

@@ -53,7 +53,6 @@ type Getter interface {
CommonAncestor(ctx context.Context, root1 [32]byte, root2 [32]byte) ([32]byte, primitives.Slot, error)
IsCanonical(root [32]byte) bool
FinalizedCheckpoint() *forkchoicetypes.Checkpoint
IsViableForCheckpoint(*forkchoicetypes.Checkpoint) (bool, error)
FinalizedPayloadBlockHash() [32]byte
JustifiedCheckpoint() *forkchoicetypes.Checkpoint
PreviousJustifiedCheckpoint() *forkchoicetypes.Checkpoint
@@ -67,7 +66,6 @@ type Getter interface {
Tips() ([][32]byte, []primitives.Slot)
IsOptimistic(root [32]byte) (bool, error)
ShouldOverrideFCU() bool
Slot([32]byte) (primitives.Slot, error)
}
// Setter allows to set forkchoice information

View File

@@ -742,7 +742,6 @@ func (b *BeaconNode) registerSlasherService() error {
SlashingPoolInserter: b.slashingsPool,
SyncChecker: syncService,
HeadStateFetcher: chainService,
ClockWaiter: b.clockWaiter,
})
if err != nil {
return err

View File

@@ -202,7 +202,7 @@ func TestGossipTopicMapping_scanfcheck_GossipTopicFormattingSanityCheck(t *testi
if string(c) == "%" {
next := string(topic[i+1])
if next != "d" && next != "x" {
t.Errorf("Topic %s has formatting incompatible with scanfcheck. Only %%d and %%x are supported", topic)
t.Errorf("Topic %s has formatting incompatiable with scanfcheck. Only %%d and %%x are supported", topic)
}
}
}

View File

@@ -49,7 +49,6 @@ func (s *Service) FindPeersWithSubnet(ctx context.Context, topic string,
topic += s.Encoding().ProtocolSuffix()
iterator := s.dv5Listener.RandomNodes()
defer iterator.Close()
switch {
case strings.Contains(topic, GossipAttestationMessage):
iterator = filterNodes(ctx, iterator, s.filterPeerForAttSubnet(index))

View File

@@ -22,7 +22,7 @@ func (ds *Server) GetPeer(_ context.Context, peerReq *ethpb.PeerRequest) (*ethpb
return ds.getPeer(pid)
}
// ListPeers returns all peers known to the host node, regardless of if they are connected/
// ListPeers returns all peers known to the host node, irregardless of if they are connected/
// disconnected.
func (ds *Server) ListPeers(_ context.Context, _ *empty.Empty) (*ethpb.DebugPeerResponses, error) {
var responses []*ethpb.DebugPeerResponse

View File

@@ -127,6 +127,7 @@ func (vs *Server) setExecutionData(ctx context.Context, blk interfaces.SignedBea
}
}
}
executionData, err := vs.getExecutionPayload(ctx, slot, idx, blk.Block().ParentRoot(), headState)
if err != nil {
return errors.Wrap(err, "failed to get execution payload")

View File

@@ -409,7 +409,7 @@ func (m *MaxSpanChunksSlice) Update(
// a min span chunk for use in chunk updates. To compute this value, we look at the difference between
// H = historyLength and the current epoch. Then, we check if the source epoch > difference. If so,
// then the start epoch is source epoch - 1. Otherwise, we return to the caller a boolean signifying
// the input arguments are invalid for the chunk and the start epoch does not exist.
// the input argumets are invalid for the chunk and the start epoch does not exist.
func (m *MinSpanChunksSlice) StartEpoch(
sourceEpoch, currentEpoch primitives.Epoch,
) (epoch primitives.Epoch, exists bool) {

View File

@@ -20,7 +20,7 @@ var (
type FieldTrie struct {
*sync.RWMutex
reference *stateutil.Reference
fieldLayers [][]*[32]byte
fieldLayers [][]byte
field types.FieldIndex
dataType types.DataType
length uint64
@@ -162,9 +162,9 @@ func (f *FieldTrie) CopyTrie() *FieldTrie {
numOfElems: f.numOfElems,
}
}
dstFieldTrie := make([][]*[32]byte, len(f.fieldLayers))
dstFieldTrie := make([][]byte, len(f.fieldLayers))
for i, layer := range f.fieldLayers {
dstFieldTrie[i] = make([]*[32]byte, len(layer))
dstFieldTrie[i] = make([]byte, len(layer))
copy(dstFieldTrie[i], layer)
}
return &FieldTrie{
@@ -252,6 +252,6 @@ func (f *FieldTrie) Empty() bool {
// InsertFieldLayer manually inserts a field layer. This method
// bypasses the normal method of field computation, it is only
// meant to be used in tests.
func (f *FieldTrie) InsertFieldLayer(layer [][]*[32]byte) {
func (f *FieldTrie) InsertFieldLayer(layer [][]byte) {
f.fieldLayers = layer
}

View File

@@ -348,13 +348,13 @@ func TestBeaconState_HashTreeRoot(t *testing.T) {
assert.NoError(t, err)
root, err := testState.HashTreeRoot(context.Background())
if err == nil && tt.error != "" {
t.Errorf("Expected error, expected %v, received %v", tt.error, err)
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
}
pbState, err := statenative.ProtobufBeaconStatePhase0(testState.ToProtoUnsafe())
require.NoError(t, err)
genericHTR, err := pbState.HashTreeRoot()
if err == nil && tt.error != "" {
t.Errorf("Expected error, expected %v, received %v", tt.error, err)
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
}
assert.DeepNotEqual(t, []byte{}, root[:], "Received empty hash tree root")
assert.DeepEqual(t, genericHTR[:], root[:], "Expected hash tree root to match generic")
@@ -435,13 +435,13 @@ func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) {
assert.NoError(t, err)
root, err := testState.HashTreeRoot(context.Background())
if err == nil && tt.error != "" {
t.Errorf("Expected error, expected %v, received %v", tt.error, err)
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
}
pbState, err := statenative.ProtobufBeaconStatePhase0(testState.ToProtoUnsafe())
require.NoError(t, err)
genericHTR, err := pbState.HashTreeRoot()
if err == nil && tt.error != "" {
t.Errorf("Expected error, expected %v, received %v", tt.error, err)
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
}
assert.DeepNotEqual(t, []byte{}, root[:], "Received empty hash tree root")
assert.DeepEqual(t, genericHTR[:], root[:], "Expected hash tree root to match generic")

View File

@@ -56,7 +56,7 @@ func optimizedValidatorRoots(validators []*ethpb.Validator) ([][32]byte, error)
if len(validators) == 0 {
return [][32]byte{}, nil
}
roots := make([][32]byte, 0, len(validators)*validatorFieldRoots)
roots := make([]byte, 0, len(validators)*validatorFieldRoots)
for i := 0; i < len(validators); i++ {
fRoots, err := ValidatorFieldRoots(validators[i])
if err != nil {

View File

@@ -43,53 +43,52 @@ func ReturnTrieLayer(elements [][32]byte, length uint64) ([][]*[32]byte, error)
// ReturnTrieLayerVariable returns the representation of a merkle trie when
// provided with the elements of a variable sized trie and the corresponding depth of
// it.
func ReturnTrieLayerVariable(elements [][32]byte, length uint64) [][]*[32]byte {
func ReturnTrieLayerVariable(elements [][32]byte, length uint64) [][]byte {
depth := ssz.Depth(length)
layers := make([][]*[32]byte, depth+1)
layers := make([][]byte, depth+1)
// Return zerohash at depth
if len(elements) == 0 {
zerohash := trie.ZeroHashes[depth]
layers[len(layers)-1] = []*[32]byte{&zerohash}
layers[len(layers)-1] = zerohash[:]
return layers
}
transformedLeaves := make([]*[32]byte, len(elements))
transformedLeaves := make([]byte, len(elements)*32)
for i := range elements {
arr := elements[i]
transformedLeaves[i] = &arr
copy(transformedLeaves[i*32:(i+1)*32], elements[i][:])
}
layers[0] = transformedLeaves
buffer := bytes.NewBuffer([]byte{})
buffer.Grow(64)
for i := uint8(0); i < depth; i++ {
layerLen := len(layers[i])
oddNodeLength := layerLen%2 == 1
numOfChunks := len(layers[i]) / 32
oddNodeLength := numOfChunks%2 == 1
if oddNodeLength {
zerohash := trie.ZeroHashes[i]
elements = append(elements, zerohash)
layerLen++
numOfChunks++
}
layers[i+1] = make([]*[32]byte, layerLen/2)
newElems := make([][32]byte, layerLen/2)
layers[i+1] = make([]byte, (numOfChunks/2)*32)
newElems := make([][32]byte, numOfChunks/2)
htr.VectorizedSha256(elements, newElems)
elements = newElems
for j := range elements {
layers[i+1][j] = &elements[j]
copy(layers[i+1][j*32:(j+1)*32], elements[j][:])
}
}
return layers
}
// RecomputeFromLayer recomputes specific branches of a fixed sized trie depending on the provided changed indexes.
func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][]*[32]byte) ([32]byte, [][]*[32]byte, error) {
func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][]byte) ([32]byte, [][]byte, error) {
hasher := hash.CustomSHA256Hasher()
for i, idx := range changedIdx {
layer[0][idx] = &changedLeaves[i]
copy(layer[0][idx*32:(idx+1)*32], changedLeaves[i][:])
}
if len(changedIdx) == 0 {
return *layer[0][0], layer, nil
return *(*[32]byte)(layer[0][:32]), layer, nil
}
leaves := layer[0]
@@ -102,7 +101,7 @@ func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][
changedIdx = append(changedIdx, maxChangedIndex+1)
}
root := *layer[0][0]
root := *(*[32]byte)(layer[0][:32])
for _, idx := range changedIdx {
ii, err := math.Int(idx)
@@ -118,12 +117,12 @@ func RecomputeFromLayer(changedLeaves [][32]byte, changedIdx []uint64, layer [][
}
// RecomputeFromLayerVariable recomputes specific branches of a variable sized trie depending on the provided changed indexes.
func RecomputeFromLayerVariable(changedLeaves [][32]byte, changedIdx []uint64, layer [][]*[32]byte) ([32]byte, [][]*[32]byte, error) {
func RecomputeFromLayerVariable(changedLeaves [][32]byte, changedIdx []uint64, layer [][]byte) ([32]byte, [][]byte, error) {
hasher := hash.CustomSHA256Hasher()
if len(changedIdx) == 0 {
return *layer[0][0], layer, nil
return *(*[32]byte)(layer[0][:32]), layer, nil
}
root := *layer[len(layer)-1][0]
root := *(*[32]byte)(layer[len(layer)-1][:32])
for i, idx := range changedIdx {
ii, err := math.Int(idx)
@@ -140,9 +139,9 @@ func RecomputeFromLayerVariable(changedLeaves [][32]byte, changedIdx []uint64, l
// this method assumes that the provided trie already has all its elements included
// in the base depth.
func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
hasher func([]byte) [32]byte) ([32]byte, [][]*[32]byte, error) {
root := *chunks[idx]
func recomputeRootFromLayer(idx int, layers [][]byte, chunks []byte,
hasher func([]byte) [32]byte) ([32]byte, [][]byte, error) {
root := *(*[32]byte)(chunks[idx*32 : (idx+1)*32])
layers[0] = chunks
// The merkle tree structure looks as follows:
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
@@ -157,7 +156,7 @@ func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
var neighbor [32]byte
if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) {
neighbor = *layers[i][neighborIdx]
neighbor = *(*[32]byte)(layers[i][neighborIdx*32 : (neighborIdx+1)*32])
}
if isLeft {
copy(combinedChunks[:32], root[:])
@@ -174,15 +173,15 @@ func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
// Update the cached layers at the parent index.
rootVal := root
if len(layers[i+1]) == 0 {
layers[i+1] = append(layers[i+1], &rootVal)
layers[i+1] = append(layers[i+1], rootVal[:]...)
} else {
layers[i+1][parentIdx] = &rootVal
copy(layers[i+1][parentIdx*32:(parentIdx+1)*32], rootVal[:])
}
currentIndex = parentIdx
}
// If there is only a single leaf, we return it (the identity element).
if len(layers[0]) == 1 {
return *layers[0][0], layers, nil
return *(*[32]byte)(layers[0][:32]), layers, nil
}
return root, layers, nil
}
@@ -190,13 +189,13 @@ func recomputeRootFromLayer(idx int, layers [][]*[32]byte, chunks []*[32]byte,
// this method assumes that the base branch does not consist of all leaves of the
// trie. Instead missing leaves are assumed to be zerohashes, following the structure
// of a sparse merkle trie.
func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]*[32]byte,
hasher func([]byte) [32]byte) ([32]byte, [][]*[32]byte, error) {
func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]byte,
hasher func([]byte) [32]byte) ([32]byte, [][]byte, error) {
for idx >= len(layers[0]) {
zerohash := trie.ZeroHashes[0]
layers[0] = append(layers[0], &zerohash)
layers[0] = append(layers[0], zerohash[:]...)
}
layers[0][idx] = &item
copy(layers[0][idx*32:(idx+1):32], item[:])
currentIndex := idx
root := item
@@ -211,7 +210,7 @@ func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]*[32]byte
if neighborIdx >= len(layers[i]) {
neighbor = trie.ZeroHashes[i]
} else {
neighbor = *layers[i][neighborIdx]
neighbor = *(*[32]byte)(layers[i][(neighborIdx * 32) : (neighborIdx+1)*32])
}
if isLeft {
copy(combinedChunks[:32], root[:])
@@ -227,17 +226,17 @@ func recomputeRootFromLayerVariable(idx int, item [32]byte, layers [][]*[32]byte
parentIdx := currentIndex / 2
if len(layers[i+1]) == 0 || parentIdx >= len(layers[i+1]) {
newItem := root
layers[i+1] = append(layers[i+1], &newItem)
layers[i+1] = append(layers[i+1], newItem[:]...)
} else {
newItem := root
layers[i+1][parentIdx] = &newItem
copy(layers[i+1][parentIdx*32:(parentIdx+1)*32], newItem[:])
}
currentIndex = parentIdx
}
return root, layers, nil
}
// AddInMixin describes a method from which a length mixin is added to the
// AddInMixin describes a method from which a lenth mixin is added to the
// provided root.
func AddInMixin(root [32]byte, length uint64) ([32]byte, error) {
rootBuf := new(bytes.Buffer)

View File

@@ -13,6 +13,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/operation"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
@@ -151,6 +152,20 @@ func (s *Service) validateAggregatedAtt(ctx context.Context, signed *ethpb.Signe
return pubsub.ValidationIgnore, err
}
attSlot := signed.Message.Aggregate.Data.Slot
// Only advance state if different epoch as the committee can only change on an epoch transition.
if slots.ToEpoch(attSlot) > slots.ToEpoch(bs.Slot()) {
startSlot, err := slots.EpochStart(slots.ToEpoch(attSlot))
if err != nil {
return pubsub.ValidationIgnore, err
}
bs, err = transition.ProcessSlots(ctx, bs, startSlot)
if err != nil {
tracing.AnnotateError(span, err)
return pubsub.ValidationIgnore, err
}
}
// Verify validator index is within the beacon committee.
if err := validateIndexInCommittee(ctx, bs, signed.Message.Aggregate, signed.Message.AggregatorIndex); err != nil {
wrappedErr := errors.Wrapf(err, "Could not validate index in committee")

View File

@@ -329,7 +329,7 @@ func (s *Service) setSyncContributionBits(c *ethpb.SyncCommitteeContribution) er
}
bitsList, ok := v.([][]byte)
if !ok {
return errors.New("could not convert cached value to []bitfield.Bitvector")
return errors.New("could not covert cached value to []bitfield.Bitvector")
}
has, err := bitListOverlaps(bitsList, c.AggregationBits)
if err != nil {
@@ -354,7 +354,7 @@ func (s *Service) hasSeenSyncContributionBits(c *ethpb.SyncCommitteeContribution
}
bitsList, ok := v.([][]byte)
if !ok {
return false, errors.New("could not convert cached value to []bitfield.Bitvector128")
return false, errors.New("could not covert cached value to []bitfield.Bitvector128")
}
return bitListOverlaps(bitsList, c.AggregationBits.Bytes())
}

View File

@@ -72,7 +72,7 @@ func (m MetadataV0) MetadataObjV0() *pb.MetaDataV0 {
return m.md
}
// MetadataObjV1 returns the inner metadata object in its type
// MetadataObjV1 returns the inner metatdata object in its type
// specified form. If it doesn't exist then we return nothing.
func (_ MetadataV0) MetadataObjV1() *pb.MetaDataV1 {
return nil
@@ -147,7 +147,7 @@ func (_ MetadataV1) MetadataObjV0() *pb.MetaDataV0 {
return nil
}
// MetadataObjV1 returns the inner metadata object in its type
// MetadataObjV1 returns the inner metatdata object in its type
// specified form. If it doesn't exist then we return nothing.
func (m MetadataV1) MetadataObjV1() *pb.MetaDataV1 {
return m.md

View File

@@ -14,7 +14,7 @@ var _ heap.Interface = &queue{}
// some tests rely on the ordering of items from this method
func testCases() (tc []*Item) {
// create a slice of items with priority / times offset by these seconds
// create a slice of items with priority / times offest by these seconds
for i, m := range []time.Duration{
5,
183600, // 51 hours

View File

@@ -78,7 +78,7 @@ func TestValidatorRegister_OK(t *testing.T) {
merkleTreeIndex[i] = binary.LittleEndian.Uint64(idx)
}
assert.Equal(t, uint64(0), merkleTreeIndex[0], "Deposit event total deposit count mismatched")
assert.Equal(t, uint64(1), merkleTreeIndex[1], "Deposit event total deposit count mismatched")
assert.Equal(t, uint64(2), merkleTreeIndex[2], "Deposit event total deposit count mismatched")
assert.Equal(t, uint64(0), merkleTreeIndex[0], "Deposit event total desposit count miss matched")
assert.Equal(t, uint64(1), merkleTreeIndex[1], "Deposit event total desposit count miss matched")
assert.Equal(t, uint64(2), merkleTreeIndex[2], "Deposit event total desposit count miss matched")
}

View File

@@ -4,16 +4,16 @@ package blst
import (
"fmt"
"sync"
"github.com/pkg/errors"
lruwrpr "github.com/prysmaticlabs/prysm/v4/cache/lru"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/crypto/bls/common"
)
var pubkeyLock sync.RWMutex
var pubkeyMap = make(map[[48]byte]*PublicKey)
var maxKeys = 1_000_000
var pubkeyCache = lruwrpr.New(maxKeys)
// PublicKey used in the BLS signature scheme.
type PublicKey struct {
@@ -26,13 +26,9 @@ func PublicKeyFromBytes(pubKey []byte) (common.PublicKey, error) {
return nil, fmt.Errorf("public key must be %d bytes", params.BeaconConfig().BLSPubkeyLength)
}
newKey := (*[fieldparams.BLSPubkeyLength]byte)(pubKey)
pubkeyLock.RLock()
if cv, ok := pubkeyMap[*newKey]; ok {
pubkeyLock.RUnlock()
return cv.Copy(), nil
if cv, ok := pubkeyCache.Get(*newKey); ok {
return cv.(*PublicKey).Copy(), nil
}
pubkeyLock.RUnlock()
// Subgroup check NOT done when decompressing pubkey.
p := new(blstPublicKey).Uncompress(pubKey)
if p == nil {
@@ -45,16 +41,8 @@ func PublicKeyFromBytes(pubKey []byte) (common.PublicKey, error) {
}
pubKeyObj := &PublicKey{p: p}
copiedKey := pubKeyObj.Copy()
assertedKey, ok := (copiedKey).(*PublicKey)
// Should be impossible to happen, this is checked
// to satisfy lint tools.
if !ok {
return pubKeyObj, nil
}
cacheKey := *newKey
pubkeyLock.Lock()
pubkeyMap[cacheKey] = assertedKey
pubkeyLock.Unlock()
pubkeyCache.Add(cacheKey, copiedKey)
return pubKeyObj, nil
}

View File

@@ -5,7 +5,6 @@ package blst_test
import (
"bytes"
"errors"
"sync"
"testing"
"github.com/prysmaticlabs/prysm/v4/crypto/bls/blst"
@@ -99,51 +98,26 @@ func TestPublicKeysEmpty(t *testing.T) {
require.ErrorContains(t, "nil or empty public keys", err)
}
func TestPublicKeyMap(t *testing.T) {
priv, err := blst.RandKey()
require.NoError(t, err)
pubkeyA := priv.PublicKey().Marshal()
priv2, err := blst.RandKey()
require.NoError(t, err)
pubkeyB := priv2.PublicKey().Marshal()
km := blst.KeyMap()
_, ok := km[[48]byte(pubkeyA)]
require.Equal(t, false, ok, "pubkey a exists")
_, ok = km[[48]byte(pubkeyB)]
require.Equal(t, false, ok, "pubkey b exists")
wg := new(sync.WaitGroup)
wg.Add(1)
go func() {
_, err := blst.PublicKeyFromBytes(pubkeyA)
require.NoError(t, err)
wg.Done()
}()
wg.Add(1)
go func() {
_, err := blst.PublicKeyFromBytes(pubkeyB)
require.NoError(t, err)
wg.Done()
}()
wg.Wait()
km = blst.KeyMap()
_, ok = km[[48]byte(pubkeyA)]
require.Equal(t, true, ok, "pubkey a does not exist")
_, ok = km[[48]byte(pubkeyB)]
require.Equal(t, true, ok, "pubkey b does not exist")
}
func BenchmarkPublicKeyFromBytes(b *testing.B) {
priv, err := blst.RandKey()
require.NoError(b, err)
pubkey := priv.PublicKey()
pubkeyBytes := pubkey.Marshal()
for i := 0; i < b.N; i++ {
_, err := blst.PublicKeyFromBytes(pubkeyBytes)
require.NoError(b, err)
}
b.Run("cache on", func(b *testing.B) {
blst.EnableCaches()
for i := 0; i < b.N; i++ {
_, err := blst.PublicKeyFromBytes(pubkeyBytes)
require.NoError(b, err)
}
})
b.Run("cache off", func(b *testing.B) {
blst.DisableCaches()
for i := 0; i < b.N; i++ {
_, err := blst.PublicKeyFromBytes(pubkeyBytes)
require.NoError(b, err)
}
})
}

View File

@@ -1,8 +1,13 @@
package blst
// Note: These functions are for tests to access private globals, such as pubkeyMap.
// Note: These functions are for tests to access private globals, such as pubkeyCache.
// KeyMap returns the pubkey cache.
func KeyMap() map[[48]byte]*PublicKey {
return pubkeyMap
// DisableCaches sets the cache sizes to 0.
func DisableCaches() {
pubkeyCache.Resize(0)
}
// EnableCaches sets the cache sizes to the default values.
func EnableCaches() {
pubkeyCache.Resize(maxKeys)
}

View File

@@ -9,7 +9,14 @@ import (
// hardware configuration, using this routine can lead to a significant
// performance improvement compared to the default method of hashing
// lists.
func VectorizedSha256(inputList [][32]byte, outputList [][32]byte) {
func VectorizedSha256(inputList []byte, outputList []byte) {
err := gohashtree.HashByteSlice(outputList, inputList)
if err != nil {
panic(err)
}
}
func VectorizedSha256Chunks(inputList [][32]byte, outputList [][32]byte) {
err := gohashtree.Hash(outputList, inputList)
if err != nil {
panic(err)

View File

@@ -3303,8 +3303,8 @@ def prysm_deps():
go_repository(
name = "com_github_prysmaticlabs_gohashtree",
importpath = "github.com/prysmaticlabs/gohashtree",
sum = "h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY=",
version = "v0.0.3-alpha",
sum = "h1:po9GKr5APkGj8blcsaPYj/EBlZbvCmoKE/oGLZE+PNI=",
version = "v0.0.3-alpha.0.20230510131438-bf992328364a",
)
go_repository(

View File

@@ -131,7 +131,7 @@ func (cf *VersionedUnmarshaler) UnmarshalBeaconState(marshaled []byte) (s state.
}
var beaconBlockSlot = fieldSpec{
// ssz variable length offset (not to be confused with the fieldSpec offset) is a uint32
// ssz variable length offset (not to be confused with the fieldSpec offest) is a uint32
// variable length. Offsets come before fixed length data, so that's 4 bytes at the beginning
// then signature is 96 bytes, 4+96 = 100
offset: 100,

View File

@@ -214,7 +214,7 @@ func MerkleizeVector(elements [][32]byte, length uint64) [32]byte {
elements = append(elements, zerohash)
}
outputLen := len(elements) / 2
htr.VectorizedSha256(elements, elements)
htr.VectorizedSha256Chunks(elements, elements)
elements = elements[:outputLen]
}
return elements[0]

2
go.mod
View File

@@ -248,7 +248,7 @@ require (
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/validator/v10 v10.11.1
github.com/peterh/liner v1.2.0 // indirect
github.com/prysmaticlabs/gohashtree v0.0.3-alpha
github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230510131438-bf992328364a
golang.org/x/sys v0.7.0 // indirect
google.golang.org/api v0.34.0 // indirect
google.golang.org/appengine v1.6.7 // indirect

4
go.sum
View File

@@ -1066,8 +1066,12 @@ github.com/prysmaticlabs/fastssz v0.0.0-20220628121656-93dfe28febab/go.mod h1:MA
github.com/prysmaticlabs/go-bitfield v0.0.0-20210108222456-8e92c3709aa0/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4tdWQK9ZpYygoV7+vS6QkDvQVySboMVEIxBJmXw=
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4=
github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw=
github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
github.com/prysmaticlabs/gohashtree v0.0.3-alpha h1:1EVinCWdb3Lorq7xn8DYQHf48nCcdAM3Vb18KsFlRWY=
github.com/prysmaticlabs/gohashtree v0.0.3-alpha/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230510131438-bf992328364a h1:po9GKr5APkGj8blcsaPYj/EBlZbvCmoKE/oGLZE+PNI=
github.com/prysmaticlabs/gohashtree v0.0.3-alpha.0.20230510131438-bf992328364a/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk=
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20230315201114-09284ba20446 h1:4wctORg/1TkgLgXejv9yOSAm3cDBJxoTzl/RNuZmX28=
github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20230315201114-09284ba20446/go.mod h1:IOyTYjcIO0rkmnGBfJTL0NJ11exy/Tc2QEuv7hCXp24=
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c h1:9PHRCuO/VN0s9k+RmLykho7AjDxblNYI5bYKed16NPU=

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Continuous Integration script to check that BUILD.bazel files are as expected
# Continous Integration script to check that BUILD.bazel files are as expected
# when generated from gazelle.
# Duplicate redirect 5 to stdout so that it can be captured, but still printed

View File

@@ -155,7 +155,7 @@ cat << EOF
-c Move discovered coverage reports to the trash
-z FILE Upload specified file directly to Codecov and bypass all report generation.
This is intended to be used only with a pre-formatted Codecov report and is not
This is inteded to be used only with a pre-formatted Codecov report and is not
expected to work under any other circumstances.
-Z Exit with 1 if not successful. Default will Exit with 0

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -e
# Prints the latest git version tag, like "v2.12.8"
git tag -l 'v*' --sort=creatordate |
perl -nle 'if (/^v\d+\.\d+\.\d+$/) { print $_ }' |
tail -n1

View File

@@ -70,7 +70,7 @@ if git diff-index --quiet HEAD --; then
echo "nothing to push, exiting early"
exit 0
else
echo "changes detected, committing and pushing to ethereumapis"
echo "changes detected, commiting and pushing to ethereumapis"
fi
# Push to the mirror repository

View File

@@ -1,24 +1,9 @@
#!/bin/bash
repo_url=$(git config --get remote.origin.url)
echo "REPO_URL $repo_url"
# Note: The STABLE_ prefix will force a relink when the value changes when using rules_go x_defs.
commit_sha=$(git rev-parse HEAD)
echo "COMMIT_SHA $commit_sha"
echo "GIT_BRANCH $git_branch"
git_tree_status=$(git diff-index --quiet HEAD -- && echo 'Clean' || echo 'Modified')
echo "GIT_TREE_STATUS $git_tree_status"
# Note: the "STABLE_" suffix causes these to be part of the "stable" workspace
# status, which may trigger rebuilds of certain targets if these values change
# and you're building with the "--stamp" flag.
latest_version_tag=$(./hack/latest_version_tag.sh)
echo "STABLE_VERSION_TAG $latest_version_tag"
echo "STABLE_COMMIT_SHA $commit_sha"
echo "STABLE_GIT_TAG $latest_version_tag"
echo DOCKER_TAG "$(git rev-parse --abbrev-ref HEAD)-$(git rev-parse --short=6 HEAD)"
echo DATE "$(date --rfc-3339=seconds --utc)"
echo DATE_UNIX "$(date --utc +%s)"
echo STABLE_GIT_COMMIT "continuous-integration"
echo DATE "now"
echo DATE_UNIX "0"
echo DOCKER_TAG "ci-foo"
echo STABLE_GIT_TAG "c1000deadbeef"

View File

@@ -12,7 +12,7 @@ type Scraper interface {
// An Updater can take the io.Reader created by Scraper and
// send it to a data sink for consumption. An Updater is used
// for instance to send the scraped data for a beacon-node to
// for instance ot send the scraped data for a beacon-node to
// a remote client-stats endpoint.
type Updater interface {
Update(io.Reader) error

View File

@@ -12,7 +12,6 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//network/authorization:go_default_library",
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
"@com_github_golang_jwt_jwt_v4//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
@@ -33,6 +32,5 @@ go_test(
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_golang_jwt_jwt_v4//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)

View File

@@ -1,17 +1,11 @@
package network
import (
"context"
"encoding/base64"
"errors"
"fmt"
"net/http"
"net/url"
"strings"
gethRPC "github.com/ethereum/go-ethereum/rpc"
"github.com/prysmaticlabs/prysm/v4/network/authorization"
log "github.com/sirupsen/logrus"
)
// Endpoint is an endpoint with authorization data.
@@ -59,46 +53,6 @@ func (d *AuthorizationData) ToHeaderValue() (string, error) {
return "", errors.New("could not create HTTP header for unknown authorization method")
}
// HttpEndpoint extracts an httputils.Endpoint from the provider parameter.
func HttpEndpoint(eth1Provider string) Endpoint {
endpoint := Endpoint{
Url: "",
Auth: AuthorizationData{
Method: authorization.None,
Value: "",
}}
authValues := strings.Split(eth1Provider, ",")
endpoint.Url = strings.TrimSpace(authValues[0])
if len(authValues) > 2 {
log.Errorf(
"ETH1 endpoint string can contain one comma for specifying the authorization header to access the provider."+
" String contains too many commas: %d. Skipping authorization.", len(authValues)-1)
} else if len(authValues) == 2 {
switch Method(strings.TrimSpace(authValues[1])) {
case authorization.Basic:
basicAuthValues := strings.Split(strings.TrimSpace(authValues[1]), " ")
if len(basicAuthValues) != 2 {
log.Errorf("Basic Authentication has incorrect format. Skipping authorization.")
} else {
endpoint.Auth.Method = authorization.Basic
endpoint.Auth.Value = base64.StdEncoding.EncodeToString([]byte(basicAuthValues[1]))
}
case authorization.Bearer:
bearerAuthValues := strings.Split(strings.TrimSpace(authValues[1]), " ")
if len(bearerAuthValues) != 2 {
log.Errorf("Bearer Authentication has incorrect format. Skipping authorization.")
} else {
endpoint.Auth.Method = authorization.Bearer
endpoint.Auth.Value = bearerAuthValues[1]
}
case authorization.None:
log.Errorf("Authorization has incorrect format or authorization type is not supported.")
}
}
return endpoint
}
// Method returns the authorizationmethod.AuthorizationMethod corresponding with the parameter value.
func Method(auth string) authorization.AuthorizationMethod {
if strings.HasPrefix(strings.ToLower(auth), "basic") {
@@ -122,27 +76,3 @@ func NewHttpClientWithSecret(secret string) *http.Client {
Transport: authTransport,
}
}
func NewExecutionRPCClient(ctx context.Context, endpoint Endpoint) (*gethRPC.Client, error) {
// Need to handle ipc and http
var client *gethRPC.Client
u, err := url.Parse(endpoint.Url)
if err != nil {
return nil, err
}
switch u.Scheme {
case "http", "https":
client, err = gethRPC.DialOptions(ctx, endpoint.Url, gethRPC.WithHTTPClient(endpoint.HttpClient()))
if err != nil {
return nil, err
}
case "", "ipc":
client, err = gethRPC.DialIPC(ctx, endpoint.Url)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme)
}
return client, nil
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/network/authorization"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
logTest "github.com/sirupsen/logrus/hooks/test"
)
func TestToHeaderValue(t *testing.T) {
@@ -141,68 +140,3 @@ func TestAuthorizationDataEquals(t *testing.T) {
assert.Equal(t, false, d.Equals(other))
})
}
func TestHttpEndpoint(t *testing.T) {
hook := logTest.NewGlobal()
url := "http://test"
t.Run("URL", func(t *testing.T) {
endpoint := HttpEndpoint(url)
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
})
t.Run("URL with separator", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
})
t.Run("URL with whitespace", func(t *testing.T) {
endpoint := HttpEndpoint(" " + url + " ,")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
})
t.Run("Basic auth", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",Basic username:password")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Basic, endpoint.Auth.Method)
assert.Equal(t, "dXNlcm5hbWU6cGFzc3dvcmQ=", endpoint.Auth.Value)
})
t.Run("Basic auth with whitespace", func(t *testing.T) {
endpoint := HttpEndpoint(url + ", Basic username:password ")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Basic, endpoint.Auth.Method)
assert.Equal(t, "dXNlcm5hbWU6cGFzc3dvcmQ=", endpoint.Auth.Value)
})
t.Run("Basic auth with incorrect format", func(t *testing.T) {
hook.Reset()
endpoint := HttpEndpoint(url + ",Basic username:password foo")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
assert.LogsContain(t, hook, "Skipping authorization")
})
t.Run("Bearer auth", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",Bearer token")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Bearer, endpoint.Auth.Method)
assert.Equal(t, "token", endpoint.Auth.Value)
})
t.Run("Bearer auth with whitespace", func(t *testing.T) {
endpoint := HttpEndpoint(url + ", Bearer token ")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.Bearer, endpoint.Auth.Method)
assert.Equal(t, "token", endpoint.Auth.Value)
})
t.Run("Bearer auth with incorrect format", func(t *testing.T) {
hook.Reset()
endpoint := HttpEndpoint(url + ",Bearer token foo")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
assert.LogsContain(t, hook, "Skipping authorization")
})
t.Run("Too many separators", func(t *testing.T) {
endpoint := HttpEndpoint(url + ",Bearer token,foo")
assert.Equal(t, url, endpoint.Url)
assert.Equal(t, authorization.None, endpoint.Auth.Method)
assert.LogsContain(t, hook, "Skipping authorization")
})
}

View File

@@ -16,7 +16,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/time/slots"
)
// IsForkNextEpoch checks if an allotted fork is in the following epoch.
// IsForkNextEpoch checks if an alloted fork is in the following epoch.
func IsForkNextEpoch(genesisTime time.Time, genesisValidatorsRoot []byte) (bool, error) {
if genesisTime.IsZero() {
return false, errors.New("genesis time is not set")

View File

@@ -740,7 +740,7 @@ message ListValidatorAssignmentsRequest {
}
// 48 byte validator public keys to filter assignments for the given epoch.
repeated bytes public_keys = 3 [(ethereum.eth.ext.ssz_size) = "?,48"];
// Validator indices to filter assignments for the given epoch.
// Validator indicies to filter assignments for the given epoch.
repeated uint64 indices = 4 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives.ValidatorIndex"];
// The maximum number of ValidatorAssignments to return in the response.

View File

@@ -10,7 +10,7 @@ At the core of Ethereum Serenity lies the "Beacon Chain", a proof-of-stake based
|---------|---------|---------|-------------|
| eth | BeaconChain | v1alpha1 | This service is used to retrieve critical data relevant to the Ethereum Beacon Chain, including the most recent head block, current pending deposits, the chain state and more. |
| eth | Node | v1alpha1 | The Node service returns information about the Ethereum node itself, including versioning and general information as well as network sync status and a list of services currently implemented on the node.
| eth | Validator | v1alpha1 | This API provides the information a validator needs to retrieve throughout its lifecycle, including received assignments from the network, its current index in the state, as well the rewards and penalties that have been applied to it.
| eth | Validator | v1alpha1 | This API provides the information a validator needs to retrieve throughout its lifecycle, including recieved assignments from the network, its current index in the state, as well the rewards and penalties that have been applied to it.
### JSON Mapping

View File

@@ -354,11 +354,7 @@ func startPProf(address string) {
http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize))
log.WithField("addr", fmt.Sprintf("http://%s/debug/pprof", address)).Info("Starting pprof server")
go func() {
srv := &http.Server{
Addr: address,
ReadHeaderTimeout: 3 * time.Second,
}
if err := srv.ListenAndServe(); err != nil {
if err := http.ListenAndServe(address, nil); err != nil {
log.Error("Failure in running pprof server", "err", err)
}
}()

View File

@@ -4,7 +4,6 @@ load("@prysm//tools/go:def.bzl", "go_test")
# gazelle:exclude mainnet_e2e_test.go
# gazelle:exclude mainnet_scenario_e2e_test.go
# gazelle:exclude minimal_scenario_e2e_test.go
# gazelle:exclude minimal_builder_e2e_test.go
# Presubmit tests represent the group of endtoend tests that are run on pull
# requests and must be passing before a pull request can merge.
@@ -26,7 +25,6 @@ test_suite(
"manual",
],
tests = [
":go_builder_test",
":go_mainnet_test",
],
)
@@ -119,39 +117,6 @@ go_test(
deps = common_deps,
)
# gazelle:ignore
go_test(
name = "go_builder_test",
size = "large",
testonly = True,
srcs = [
"component_handler_test.go",
"endtoend_setup_test.go",
"endtoend_test.go",
"minimal_builder_e2e_test.go",
],
args = ["-test.v"],
data = [
"//:prysm_sh",
"//cmd/beacon-chain",
"//cmd/validator",
"//config/params:custom_configs",
"//tools/bootnode",
"@com_github_ethereum_go_ethereum//cmd/geth",
"@web3signer",
],
eth_network = "minimal",
flaky = True,
shard_count = 2,
tags = [
"e2e",
"manual",
"minimal",
"requires-network",
],
deps = common_deps,
)
go_test(
name = "go_mainnet_test",
size = "large",

View File

@@ -28,7 +28,6 @@ type componentHandler struct {
web3Signer e2etypes.ComponentRunner
bootnode e2etypes.ComponentRunner
eth1Miner e2etypes.ComponentRunner
builders e2etypes.MultipleComponentRunners
eth1Proxy e2etypes.MultipleComponentRunners
eth1Nodes e2etypes.MultipleComponentRunners
beaconNodes e2etypes.MultipleComponentRunners
@@ -138,47 +137,23 @@ func (c *componentHandler) setup() {
if config.TestCheckpointSync {
appendDebugEndpoints(config)
}
var builders *components.BuilderSet
var proxies *eth1.ProxySet
if config.UseBuilder {
// Builder
builders = components.NewBuilderSet()
g.Go(func() error {
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{eth1Nodes}); err != nil {
return errors.Wrap(err, "builders require execution nodes to run")
}
if err := builders.Start(ctx); err != nil {
return errors.Wrap(err, "failed to start builders")
}
return nil
})
c.builders = builders
} else {
// Proxies
proxies = eth1.NewProxySet()
g.Go(func() error {
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{eth1Nodes}); err != nil {
return errors.Wrap(err, "proxies require execution nodes to run")
}
if err := proxies.Start(ctx); err != nil {
return errors.Wrap(err, "failed to start proxies")
}
return nil
})
c.eth1Proxy = proxies
}
// Proxies
proxies := eth1.NewProxySet()
g.Go(func() error {
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{eth1Nodes}); err != nil {
return errors.Wrap(err, "proxies require execution nodes to run")
}
if err := proxies.Start(ctx); err != nil {
return errors.Wrap(err, "failed to start proxies")
}
return nil
})
c.eth1Proxy = proxies
// Beacon nodes.
beaconNodes := components.NewBeaconNodes(config)
g.Go(func() error {
wantedComponents := []e2etypes.ComponentRunner{eth1Nodes, bootNode}
if config.UseBuilder {
wantedComponents = append(wantedComponents, builders)
} else {
wantedComponents = append(wantedComponents, proxies)
}
if err := helpers.ComponentsStarted(ctx, wantedComponents); err != nil {
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{eth1Nodes, proxies, bootNode}); err != nil {
return errors.Wrap(err, "beacon nodes require proxies, execution and boot node to run")
}
beaconNodes.SetENR(bootNode.ENR())
@@ -240,12 +215,7 @@ func (c *componentHandler) setup() {
func (c *componentHandler) required() []e2etypes.ComponentRunner {
multiClientActive := e2e.TestParams.LighthouseBeaconNodeCount > 0
requiredComponents := []e2etypes.ComponentRunner{
c.tracingSink, c.eth1Nodes, c.bootnode, c.beaconNodes, c.validatorNodes,
}
if c.cfg.UseBuilder {
requiredComponents = append(requiredComponents, c.builders)
} else {
requiredComponents = append(requiredComponents, c.eth1Proxy)
c.tracingSink, c.eth1Nodes, c.bootnode, c.beaconNodes, c.validatorNodes, c.eth1Proxy,
}
if multiClientActive {
requiredComponents = append(requiredComponents, []e2etypes.ComponentRunner{c.keygen, c.lighthouseBeaconNodes, c.lighthouseValidatorNodes}...)

View File

@@ -6,7 +6,6 @@ go_library(
srcs = [
"beacon_node.go",
"boot_node.go",
"builder.go",
"lighthouse_beacon.go",
"lighthouse_validator.go",
"log.go",
@@ -36,7 +35,6 @@ go_library(
"//testing/endtoend/helpers:go_default_library",
"//testing/endtoend/params:go_default_library",
"//testing/endtoend/types:go_default_library",
"//testing/middleware/builder:go_default_library",
"//validator/keymanager:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",

View File

@@ -282,9 +282,6 @@ func (node *BeaconNode) Start(ctx context.Context) error {
if !config.TestFeature || index%2 == 0 {
args = append(args, features.E2EBeaconChainFlags...)
}
if config.UseBuilder {
args = append(args, fmt.Sprintf("--%s=%s:%d", flags.MevRelayEndpoint.Name, "http://127.0.0.1", e2e.TestParams.Ports.Eth1ProxyPort+index))
}
args = append(args, config.BeaconFlags...)
cmd := exec.CommandContext(ctx, binaryPath, args...) // #nosec G204 -- Safe

View File

@@ -1,213 +0,0 @@
package components
import (
"context"
"encoding/hex"
"fmt"
"os"
"path"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/io/file"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
e2e "github.com/prysmaticlabs/prysm/v4/testing/endtoend/params"
e2etypes "github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/v4/testing/middleware/builder"
"github.com/sirupsen/logrus"
)
// BuilderSet represents a set of builders for the validators running via a relay.
type BuilderSet struct {
e2etypes.ComponentRunner
started chan struct{}
builders []e2etypes.ComponentRunner
}
// NewBuilderSet creates and returns a set of builders.
func NewBuilderSet() *BuilderSet {
return &BuilderSet{
started: make(chan struct{}, 1),
}
}
// Start starts all the builders in set.
func (s *BuilderSet) Start(ctx context.Context) error {
totalNodeCount := e2e.TestParams.BeaconNodeCount + e2e.TestParams.LighthouseBeaconNodeCount
nodes := make([]e2etypes.ComponentRunner, totalNodeCount)
for i := 0; i < totalNodeCount; i++ {
nodes[i] = NewBuilder(i)
}
s.builders = nodes
// Wait for all nodes to finish their job (blocking).
// Once nodes are ready passed in handler function will be called.
return helpers.WaitOnNodes(ctx, nodes, func() {
// All nodes started, close channel, so that all services waiting on a set, can proceed.
close(s.started)
})
}
// Started checks whether builder set is started and all builders are ready to be queried.
func (s *BuilderSet) Started() <-chan struct{} {
return s.started
}
// Pause pauses the component and its underlying process.
func (s *BuilderSet) Pause() error {
for _, n := range s.builders {
if err := n.Pause(); err != nil {
return err
}
}
return nil
}
// Resume resumes the component and its underlying process.
func (s *BuilderSet) Resume() error {
for _, n := range s.builders {
if err := n.Resume(); err != nil {
return err
}
}
return nil
}
// Stop stops the component and its underlying process.
func (s *BuilderSet) Stop() error {
for _, n := range s.builders {
if err := n.Stop(); err != nil {
return err
}
}
return nil
}
// PauseAtIndex pauses the component and its underlying process at the desired index.
func (s *BuilderSet) PauseAtIndex(i int) error {
if i >= len(s.builders) {
return errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.builders))
}
return s.builders[i].Pause()
}
// ResumeAtIndex resumes the component and its underlying process at the desired index.
func (s *BuilderSet) ResumeAtIndex(i int) error {
if i >= len(s.builders) {
return errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.builders))
}
return s.builders[i].Resume()
}
// StopAtIndex stops the component and its underlying process at the desired index.
func (s *BuilderSet) StopAtIndex(i int) error {
if i >= len(s.builders) {
return errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.builders))
}
return s.builders[i].Stop()
}
// ComponentAtIndex returns the component at the provided index.
func (s *BuilderSet) ComponentAtIndex(i int) (e2etypes.ComponentRunner, error) {
if i >= len(s.builders) {
return nil, errors.Errorf("provided index exceeds slice size: %d >= %d", i, len(s.builders))
}
return s.builders[i], nil
}
// Builder represents a block builder.
type Builder struct {
e2etypes.ComponentRunner
started chan struct{}
index int
builder *builder.Builder
cancel func()
}
// NewBuilder creates and returns a builder.
func NewBuilder(index int) *Builder {
return &Builder{
started: make(chan struct{}, 1),
index: index,
}
}
// Start runs a builder.
func (node *Builder) Start(ctx context.Context) error {
f, err := os.Create(path.Join(e2e.TestParams.LogPath, "builder_"+strconv.Itoa(node.index)+".log"))
if err != nil {
return err
}
jwtPath := path.Join(e2e.TestParams.TestPath, "eth1data/"+strconv.Itoa(node.index)+"/")
if node.index == 0 {
jwtPath = path.Join(e2e.TestParams.TestPath, "eth1data/miner/")
}
jwtPath = path.Join(jwtPath, "geth/jwtsecret")
secret, err := parseJWTSecretFromFile(jwtPath)
if err != nil {
return err
}
opts := []builder.Option{
builder.WithDestinationAddress(fmt.Sprintf("http://127.0.0.1:%d", e2e.TestParams.Ports.Eth1AuthRPCPort+node.index)),
builder.WithPort(e2e.TestParams.Ports.Eth1ProxyPort + node.index),
builder.WithLogger(logrus.New()),
builder.WithLogFile(f),
builder.WithJwtSecret(string(secret)),
}
bd, err := builder.New(opts...)
if err != nil {
return err
}
log.Infof("Starting builder %d with port: %d and file %s", node.index, e2e.TestParams.Ports.Eth1ProxyPort+node.index, f.Name())
// Set cancel into context.
ctx, cancel := context.WithCancel(ctx)
node.cancel = cancel
node.builder = bd
// Mark node as ready.
close(node.started)
return bd.Start(ctx)
}
// Started checks whether the builder is started and ready to be queried.
func (node *Builder) Started() <-chan struct{} {
return node.started
}
// Pause pauses the component and its underlying process.
func (node *Builder) Pause() error {
// no-op
return nil
}
// Resume resumes the component and its underlying process.
func (node *Builder) Resume() error {
// no-op
return nil
}
// Stop kills the component and its underlying process.
func (node *Builder) Stop() error {
node.cancel()
return nil
}
func parseJWTSecretFromFile(jwtSecretFile string) ([]byte, error) {
enc, err := file.ReadFileAsBytes(jwtSecretFile)
if err != nil {
return nil, err
}
strData := strings.TrimSpace(string(enc))
if strData == "" {
return nil, fmt.Errorf("provided JWT secret in file %s cannot be empty", jwtSecretFile)
}
secret, err := hex.DecodeString(strings.TrimPrefix(strData, "0x"))
if err != nil {
return nil, err
}
if len(secret) < 32 {
return nil, errors.New("provided JWT secret should be a hex string of at least 32 bytes")
}
return secret, nil
}

View File

@@ -46,11 +46,7 @@ func WaitForBlocks(web3 *ethclient.Client, key *keystore.Key, blocksToWait uint6
finishBlock := block.NumberU64() + blocksToWait
for block.NumberU64() <= finishBlock {
gasPrice, err := web3.SuggestGasPrice(context.Background())
if err != nil {
return err
}
spamTX := types.NewTransaction(nonce, key.Address, big.NewInt(0), params.SpamTxGasLimit, gasPrice, []byte{})
spamTX := types.NewTransaction(nonce, key.Address, big.NewInt(0), params.SpamTxGasLimit, big.NewInt(1e6), []byte{})
signed, err := types.SignTx(spamTX, types.NewEIP155Signer(chainID), key.PrivateKey)
if err != nil {
return err

View File

@@ -70,7 +70,7 @@ func (t *TransactionGenerator) Start(ctx context.Context) error {
}
f := filler.NewFiller(rnd)
// Broadcast Transactions every 3 blocks
txPeriod := time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
txPeriod := 3 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second
ticker := time.NewTicker(txPeriod)
gasPrice := big.NewInt(1e11)
for {
@@ -99,22 +99,16 @@ func SendTransaction(client *rpc.Client, key *ecdsa.PrivateKey, f *filler.Filler
if err != nil {
return err
}
nonce, err := backend.PendingNonceAt(context.Background(), sender)
nonce, err := backend.NonceAt(context.Background(), sender, big.NewInt(-1))
if err != nil {
return err
}
expectedPrice, err := backend.SuggestGasPrice(context.Background())
if err != nil {
return err
}
if expectedPrice.Cmp(gasPrice) > 0 {
gasPrice = expectedPrice
}
g, _ := errgroup.WithContext(context.Background())
for i := uint64(0); i < N; i++ {
index := i
g.Go(func() error {
tx, err := txfuzz.RandomValidTx(client, f, sender, nonce+index, expectedPrice, nil, al)
tx, err := txfuzz.RandomValidTx(client, f, sender, nonce+index, gasPrice, nil, al)
if err != nil {
// In the event the transaction constructed is not valid, we continue with the routine
// rather than complete stop it.

View File

@@ -264,9 +264,6 @@ func (v *ValidatorNode) Start(ctx context.Context) error {
fmt.Sprintf("--%s=%d", flags.InteropStartIndex.Name, offset),
)
}
if v.config.UseBuilder {
args = append(args, fmt.Sprintf("--%s", flags.EnableBuilderFlag.Name))
}
args = append(args, config.ValidatorFlags...)
if v.config.UsePrysmShValidator {

View File

@@ -86,9 +86,6 @@ func e2eMinimal(t *testing.T, v int, cfgo ...types.E2EConfigOpt) *testRunner {
for _, o := range cfgo {
o(testConfig)
}
if testConfig.UseBuilder {
testConfig.Evaluators = append(testConfig.Evaluators, ev.BuilderIsActive)
}
return newTestRunner(t, testConfig)
}
@@ -168,9 +165,6 @@ func e2eMainnet(t *testing.T, usePrysmSh, useMultiClient bool, cfg *params.Beaco
if testConfig.UseValidatorCrossClient {
testConfig.Evaluators = append(testConfig.Evaluators, beaconapi_evaluators.BeaconAPIMultiClientVerifyIntegrity)
}
if testConfig.UseBuilder {
testConfig.Evaluators = append(testConfig.Evaluators, ev.BuilderIsActive)
}
return newTestRunner(t, testConfig)
}

View File

@@ -243,7 +243,7 @@ func (r *testRunner) waitForMatchingHead(ctx context.Context, timeout time.Durat
for {
select {
case <-dctx.Done():
// deadline ensures that the test eventually exits when beacon node fails to sync in a reasonable timeframe
// deadline ensures that the test eventually exits when beacon node fails to sync in a resonable timeframe
elapsed := time.Since(start)
return fmt.Errorf("deadline exceeded after %s waiting for known good block to appear in checkpoint-synced node", elapsed)
default:

View File

@@ -6,7 +6,6 @@ go_library(
srcs = [
"api_gateway_v1alpha1.go",
"api_middleware.go",
"builder.go",
"data.go",
"execution_engine.go",
"fee_recipient.go",

View File

@@ -1,103 +0,0 @@
package evaluators
import (
"context"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/helpers"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/policies"
e2etypes "github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
"github.com/prysmaticlabs/prysm/v4/time/slots"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
)
// BuilderIsActive checks that the builder is indeed producing the respective payloads
var BuilderIsActive = e2etypes.Evaluator{
Name: "builder_is_active_at_epoch_%d",
Policy: policies.OnwardsNthEpoch(helpers.BellatrixE2EForkEpoch),
Evaluation: builderActive,
}
func builderActive(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewNodeClient(conn)
beaconClient := ethpb.NewBeaconChainClient(conn)
genesis, err := client.GetGenesis(context.Background(), &emptypb.Empty{})
if err != nil {
return errors.Wrap(err, "failed to get genesis data")
}
currSlot := slots.CurrentSlot(uint64(genesis.GenesisTime.AsTime().Unix()))
currEpoch := slots.ToEpoch(currSlot)
lowestBound := primitives.Epoch(0)
if currEpoch >= 1 {
lowestBound = currEpoch - 1
}
if lowestBound < helpers.BellatrixE2EForkEpoch {
lowestBound = helpers.BellatrixE2EForkEpoch
}
blockCtrs, err := beaconClient.ListBeaconBlocks(context.Background(), &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: lowestBound}})
if err != nil {
return errors.Wrap(err, "failed to get beacon blocks")
}
for _, ctr := range blockCtrs.BlockContainers {
b, err := syncCompatibleBlockFromCtr(ctr)
if err != nil {
return errors.Wrapf(err, "block type doesn't exist for block at epoch %d", lowestBound)
}
if b.IsNil() {
return errors.New("nil block provided")
}
forkStartSlot, err := slots.EpochStart(helpers.BellatrixE2EForkEpoch)
if err != nil {
return err
}
if forkStartSlot == b.Block().Slot() || forkStartSlot+1 == b.Block().Slot() {
// Skip fork slot and the next one, as we don't send FCUs yet.
continue
}
execPayload, err := b.Block().Body().Execution()
if err != nil {
return err
}
if string(execPayload.ExtraData()) != "prysm-builder" {
return errors.Errorf("block with slot %d was not built by the builder. It has an extra data of %s", b.Block().Slot(), string(execPayload.ExtraData()))
}
}
if lowestBound == currEpoch {
return nil
}
blockCtrs, err = beaconClient.ListBeaconBlocks(context.Background(), &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: currEpoch}})
if err != nil {
return errors.Wrap(err, "failed to get validator participation")
}
for _, ctr := range blockCtrs.BlockContainers {
b, err := syncCompatibleBlockFromCtr(ctr)
if err != nil {
return errors.Wrapf(err, "block type doesn't exist for block at epoch %d", lowestBound)
}
if b.IsNil() {
return errors.New("nil block provided")
}
forkStartSlot, err := slots.EpochStart(helpers.BellatrixE2EForkEpoch)
if err != nil {
return err
}
if forkStartSlot == b.Block().Slot() || forkStartSlot+1 == b.Block().Slot() {
// Skip fork slot and the next one, as we don't send FCUs yet.
continue
}
execPayload, err := b.Block().Body().Execution()
if err != nil {
return err
}
if string(execPayload.ExtraData()) != "prysm-builder" {
return errors.Errorf("block with slot %d was not built by the builder. It has an extra data of %s", b.Block().Slot(), string(execPayload.ExtraData()))
}
}
return nil
}

View File

@@ -69,7 +69,7 @@ func validatorsAreActive(ec *types.EvaluationContext, conns ...*grpc.ClientConn)
expectedCount := params.BeaconConfig().MinGenesisActiveValidatorCount
receivedCount := uint64(len(validators.ValidatorList))
if expectedCount != receivedCount {
return fmt.Errorf("expected validator count to be %d, received %d", expectedCount, receivedCount)
return fmt.Errorf("expected validator count to be %d, recevied %d", expectedCount, receivedCount)
}
effBalanceLowCount := 0

View File

@@ -1,13 +0,0 @@
package endtoend
import (
"testing"
"github.com/prysmaticlabs/prysm/v4/runtime/version"
"github.com/prysmaticlabs/prysm/v4/testing/endtoend/types"
)
func TestEndToEnd_MinimalConfig_WithBuilder(t *testing.T) {
r := e2eMinimal(t, version.Phase0, types.WithCheckpointSync(), types.WithBuilder())
r.run()
}

View File

@@ -44,12 +44,6 @@ func WithValidatorRESTApi() E2EConfigOpt {
}
}
func WithBuilder() E2EConfigOpt {
return func(cfg *E2EConfig) {
cfg.UseBuilder = true
}
}
// E2EConfig defines the struct for all configurations needed for E2E testing.
type E2EConfig struct {
TestCheckpointSync bool
@@ -62,7 +56,6 @@ type E2EConfig struct {
UseFixedPeerIDs bool
UseValidatorCrossClient bool
UseBeaconRestApi bool
UseBuilder bool
EpochsToRun uint64
Seed int64
TracingSinkEndpoint string

View File

@@ -1,35 +0,0 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"builder.go",
"options.go",
],
importpath = "github.com/prysmaticlabs/prysm/v4/testing/middleware/builder",
visibility = ["//visibility:public"],
deps = [
"//api/client/builder:go_default_library",
"//beacon-chain/core/signing:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//network:go_default_library",
"//network/authorization:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_ethereum_go_ethereum//beacon/engine:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
"@com_github_ethereum_go_ethereum//trie:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
)

View File

@@ -1,659 +0,0 @@
package builder
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"math/big"
"net"
"net/http"
"strconv"
"strings"
"time"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
gethTypes "github.com/ethereum/go-ethereum/core/types"
gethRPC "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
gMux "github.com/gorilla/mux"
builderAPI "github.com/prysmaticlabs/prysm/v4/api/client/builder"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v4/math"
"github.com/prysmaticlabs/prysm/v4/network"
"github.com/prysmaticlabs/prysm/v4/network/authorization"
v1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/sirupsen/logrus"
)
const (
statusPath = "/eth/v1/builder/status"
registerPath = "/eth/v1/builder/validators"
headerPath = "/eth/v1/builder/header/{slot:[0-9]+}/{parent_hash:0x[a-fA-F0-9]+}/{pubkey:0x[a-fA-F0-9]+}"
blindedPath = "/eth/v1/builder/blinded_blocks"
// ForkchoiceUpdatedMethod v1 request string for JSON-RPC.
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
// ForkchoiceUpdatedMethodV2 v2 request string for JSON-RPC.
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
// GetPayloadMethod v1 request string for JSON-RPC.
GetPayloadMethod = "engine_getPayloadV1"
// GetPayloadMethodV2 v2 request string for JSON-RPC.
GetPayloadMethodV2 = "engine_getPayloadV2"
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
)
var (
defaultBuilderHost = "127.0.0.1"
defaultBuilderPort = 8551
)
type jsonRPCObject struct {
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params []interface{} `json:"params"`
ID uint64 `json:"id"`
Result interface{} `json:"result"`
}
type ForkchoiceUpdatedResponse struct {
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params []interface{} `json:"params"`
ID uint64 `json:"id"`
Result struct {
Status *v1.PayloadStatus `json:"payloadStatus"`
PayloadId *v1.PayloadIDBytes `json:"payloadId"`
} `json:"result"`
}
type ExecPayloadResponse struct {
Version string `json:"version"`
Data *v1.ExecutionPayload `json:"data"`
}
type ExecHeaderResponseCapella struct {
Version string `json:"version"`
Data struct {
Signature hexutil.Bytes `json:"signature"`
Message *builderAPI.BuilderBidCapella `json:"message"`
} `json:"data"`
}
type Builder struct {
cfg *config
address string
execClient *gethRPC.Client
currId *v1.PayloadIDBytes
currPayload interfaces.ExecutionData
mux *gMux.Router
validatorMap map[string]*eth.ValidatorRegistrationV1
srv *http.Server
}
// New creates a proxy server forwarding requests from a consensus client to an execution client.
func New(opts ...Option) (*Builder, error) {
p := &Builder{
cfg: &config{
builderPort: defaultBuilderPort,
builderHost: defaultBuilderHost,
logger: logrus.New(),
},
}
for _, o := range opts {
if err := o(p); err != nil {
return nil, err
}
}
if p.cfg.destinationUrl == nil {
return nil, errors.New("must provide a destination address for request proxying")
}
endpoint := network.HttpEndpoint(p.cfg.destinationUrl.String())
endpoint.Auth.Method = authorization.Bearer
endpoint.Auth.Value = p.cfg.secret
execClient, err := network.NewExecutionRPCClient(context.Background(), endpoint)
if err != nil {
return nil, err
}
mux := http.NewServeMux()
mux.Handle("/", p)
router := gMux.NewRouter()
router.HandleFunc(statusPath, func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusOK)
})
router.HandleFunc(registerPath, p.registerValidators)
router.HandleFunc(headerPath, p.handleHeaderRequest)
router.HandleFunc(blindedPath, p.handleBlindedBlock)
addr := fmt.Sprintf("%s:%d", p.cfg.builderHost, p.cfg.builderPort)
srv := &http.Server{
Handler: mux,
Addr: addr,
ReadHeaderTimeout: time.Second,
}
p.address = addr
p.srv = srv
p.execClient = execClient
p.validatorMap = map[string]*eth.ValidatorRegistrationV1{}
p.mux = router
return p, nil
}
// Address for the proxy server.
func (p *Builder) Address() string {
return p.address
}
// Start a proxy server.
func (p *Builder) Start(ctx context.Context) error {
p.srv.BaseContext = func(listener net.Listener) context.Context {
return ctx
}
p.cfg.logger.WithFields(logrus.Fields{
"executionAddress": p.cfg.destinationUrl.String(),
}).Infof("Builder now listening on address %s", p.address)
go func() {
if err := p.srv.ListenAndServe(); err != nil {
p.cfg.logger.Error(err)
}
}()
for {
<-ctx.Done()
return p.srv.Shutdown(context.Background())
}
}
// ServeHTTP requests from a consensus client to an execution client, modifying in-flight requests
// and/or responses as desired. It also processes any backed-up requests.
func (p *Builder) ServeHTTP(w http.ResponseWriter, r *http.Request) {
p.cfg.logger.Infof("Received %s request from beacon with url: %s", r.Method, r.URL.Path)
if p.isBuilderCall(r) {
p.mux.ServeHTTP(w, r)
return
}
requestBytes, err := parseRequestBytes(r)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not parse request")
return
}
execRes, err := p.sendHttpRequest(r, requestBytes)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not forward request")
return
}
p.cfg.logger.Infof("Received response for %s request with method %s from %s", r.Method, r.Method, p.cfg.destinationUrl.String())
defer func() {
if err = execRes.Body.Close(); err != nil {
p.cfg.logger.WithError(err).Error("Could not do close proxy responseGen body")
}
}()
buf := bytes.NewBuffer([]byte{})
if _, err = io.Copy(buf, execRes.Body); err != nil {
p.cfg.logger.WithError(err).Error("Could not copy proxy request body")
return
}
byteResp := bytesutil.SafeCopyBytes(buf.Bytes())
p.handleEngineCalls(requestBytes, byteResp)
// Pipe the proxy responseGen to the original caller.
if _, err = io.Copy(w, buf); err != nil {
p.cfg.logger.WithError(err).Error("Could not copy proxy request body")
return
}
}
func (p *Builder) handleEngineCalls(req, resp []byte) {
if !isEngineAPICall(req) {
return
}
rpcObj, err := unmarshalRPCObject(req)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not unmarshal rpc object")
return
}
p.cfg.logger.Infof("Received engine call %s", rpcObj.Method)
switch rpcObj.Method {
case ForkchoiceUpdatedMethod, ForkchoiceUpdatedMethodV2:
result := &ForkchoiceUpdatedResponse{}
err = json.Unmarshal(resp, result)
if err != nil {
p.cfg.logger.Errorf("Could not unmarshal fcu: %v", err)
return
}
p.currId = result.Result.PayloadId
p.cfg.logger.Infof("Received payload id of %#x", result.Result.PayloadId)
}
}
func (p *Builder) isBuilderCall(req *http.Request) bool {
return strings.Contains(req.URL.Path, "/eth/v1/builder/")
}
func (p *Builder) registerValidators(w http.ResponseWriter, req *http.Request) {
registrations := []builderAPI.SignedValidatorRegistration{}
if err := json.NewDecoder(req.Body).Decode(&registrations); err != nil {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
for _, r := range registrations {
msg := r.Message
p.validatorMap[string(r.Message.Pubkey)] = msg
}
// TODO: Verify Signatures from validators
w.WriteHeader(http.StatusOK)
}
func (p *Builder) handleHeaderRequest(w http.ResponseWriter, req *http.Request) {
urlParams := gMux.Vars(req)
pHash := urlParams["parent_hash"]
if pHash == "" {
http.Error(w, "no valid parent hash", http.StatusBadRequest)
return
}
reqSlot := urlParams["slot"]
if reqSlot == "" {
http.Error(w, "no valid slot provided", http.StatusBadRequest)
return
}
slot, err := strconv.Atoi(reqSlot)
if err != nil {
http.Error(w, "invalid slot provided", http.StatusBadRequest)
return
}
ax := types.Slot(slot)
currEpoch := types.Epoch(ax / params.BeaconConfig().SlotsPerEpoch)
if currEpoch >= params.BeaconConfig().CapellaForkEpoch {
p.handleHeadeRequestCapella(w)
return
}
b, err := p.retrievePendingBlock()
if err != nil {
p.cfg.logger.WithError(err).Error("Could not retrieve pending block")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
secKey, err := bls.RandKey()
if err != nil {
p.cfg.logger.WithError(err).Error("Could not retrieve secret key")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
wObj, err := blocks.WrappedExecutionPayload(b)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not wrap execution payload")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
hdr, err := blocks.PayloadToHeader(wObj)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not make payload into header")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
gEth := big.NewInt(int64(params.BeaconConfig().GweiPerEth))
weiEth := gEth.Mul(gEth, gEth)
val := builderAPI.Uint256{Int: weiEth}
wrappedHdr := &builderAPI.ExecutionPayloadHeader{ExecutionPayloadHeader: hdr}
bid := &builderAPI.BuilderBid{
Header: wrappedHdr,
Value: val,
Pubkey: secKey.PublicKey().Marshal(),
}
sszBid := &eth.BuilderBid{
Header: hdr,
Value: val.SSZBytes(),
Pubkey: secKey.PublicKey().Marshal(),
}
d, err := signing.ComputeDomain(params.BeaconConfig().DomainApplicationBuilder,
nil, /* fork version */
nil /* genesis val root */)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not compute the domain")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
rt, err := signing.ComputeSigningRoot(sszBid, d)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not compute the signing root")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
sig := secKey.Sign(rt[:])
hdrResp := &builderAPI.ExecHeaderResponse{
Version: "bellatrix",
Data: struct {
Signature hexutil.Bytes `json:"signature"`
Message *builderAPI.BuilderBid `json:"message"`
}{
Signature: sig.Marshal(),
Message: bid,
},
}
err = json.NewEncoder(w).Encode(hdrResp)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not encode response")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
p.currPayload = wObj
w.WriteHeader(http.StatusOK)
}
func (p *Builder) handleHeadeRequestCapella(w http.ResponseWriter) {
b, err := p.retrievePendingBlockCapella()
if err != nil {
p.cfg.logger.WithError(err).Error("Could not retrieve pending block")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
secKey, err := bls.RandKey()
if err != nil {
p.cfg.logger.WithError(err).Error("Could not retrieve secret key")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
v := big.NewInt(0).SetBytes(bytesutil.ReverseByteOrder(b.Value))
v = v.Mul(v, big.NewInt(2))
// Is used as the helper modifies the big.Int
weiVal := big.NewInt(0).SetBytes(bytesutil.ReverseByteOrder(b.Value))
weiVal = weiVal.Mul(weiVal, big.NewInt(2))
wObj, err := blocks.WrappedExecutionPayloadCapella(b.Payload, math.WeiToGwei(weiVal))
if err != nil {
p.cfg.logger.WithError(err).Error("Could not wrap execution payload")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
hdr, err := blocks.PayloadToHeaderCapella(wObj)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not make payload into header")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
val := builderAPI.Uint256{Int: v}
wrappedHdr := &builderAPI.ExecutionPayloadHeaderCapella{ExecutionPayloadHeaderCapella: hdr}
bid := &builderAPI.BuilderBidCapella{
Header: wrappedHdr,
Value: val,
Pubkey: secKey.PublicKey().Marshal(),
}
sszBid := &eth.BuilderBidCapella{
Header: hdr,
Value: val.SSZBytes(),
Pubkey: secKey.PublicKey().Marshal(),
}
d, err := signing.ComputeDomain(params.BeaconConfig().DomainApplicationBuilder,
nil, /* fork version */
nil /* genesis val root */)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not compute the domain")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
rt, err := signing.ComputeSigningRoot(sszBid, d)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not compute the signing root")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
sig := secKey.Sign(rt[:])
hdrResp := &ExecHeaderResponseCapella{
Version: "capella",
Data: struct {
Signature hexutil.Bytes `json:"signature"`
Message *builderAPI.BuilderBidCapella `json:"message"`
}{
Signature: sig.Marshal(),
Message: bid,
},
}
err = json.NewEncoder(w).Encode(hdrResp)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not encode response")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
p.currPayload = wObj
w.WriteHeader(http.StatusOK)
}
func (p *Builder) handleBlindedBlock(w http.ResponseWriter, req *http.Request) {
sb := &builderAPI.SignedBlindedBeaconBlockBellatrix{
SignedBlindedBeaconBlockBellatrix: &eth.SignedBlindedBeaconBlockBellatrix{},
}
err := json.NewDecoder(req.Body).Decode(sb)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not decode blinded block")
// TODO: Allow the method to unmarshal blinded blocks correctly
}
if p.currPayload == nil {
p.cfg.logger.Error("No payload is cached")
http.Error(w, "payload not found", http.StatusInternalServerError)
return
}
if payload, err := p.currPayload.PbCapella(); err == nil {
convertedPayload, err := builderAPI.FromProtoCapella(payload)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not convert the payload")
http.Error(w, "payload not found", http.StatusInternalServerError)
return
}
execResp := &builderAPI.ExecPayloadResponseCapella{
Version: "capella",
Data: convertedPayload,
}
err = json.NewEncoder(w).Encode(execResp)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not encode full payload response")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
return
}
bellPayload, err := p.currPayload.PbBellatrix()
if err != nil {
p.cfg.logger.WithError(err).Error("Could not retrieve the payload")
http.Error(w, "payload not found", http.StatusInternalServerError)
return
}
convertedPayload, err := builderAPI.FromProto(bellPayload)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not convert the payload")
http.Error(w, "payload not found", http.StatusInternalServerError)
return
}
execResp := &builderAPI.ExecPayloadResponse{
Version: "bellatrix",
Data: convertedPayload,
}
err = json.NewEncoder(w).Encode(execResp)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not encode full payload response")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
func (p *Builder) retrievePendingBlock() (*v1.ExecutionPayload, error) {
result := &engine.ExecutableData{}
if p.currId == nil {
return nil, errors.New("no payload id is cached")
}
err := p.execClient.CallContext(context.Background(), result, GetPayloadMethod, *p.currId)
if err != nil {
return nil, err
}
payloadEnv, err := modifyExecutionPayload(*result, big.NewInt(0))
if err != nil {
return nil, err
}
marshalledOutput, err := payloadEnv.ExecutionPayload.MarshalJSON()
if err != nil {
return nil, err
}
bellatrixPayload := &v1.ExecutionPayload{}
if err = json.Unmarshal(marshalledOutput, bellatrixPayload); err != nil {
return nil, err
}
return bellatrixPayload, nil
}
func (p *Builder) retrievePendingBlockCapella() (*v1.ExecutionPayloadCapellaWithValue, error) {
result := &engine.ExecutionPayloadEnvelope{}
if p.currId == nil {
return nil, errors.New("no payload id is cached")
}
err := p.execClient.CallContext(context.Background(), result, GetPayloadMethodV2, *p.currId)
if err != nil {
return nil, err
}
payloadEnv, err := modifyExecutionPayload(*result.ExecutionPayload, result.BlockValue)
if err != nil {
return nil, err
}
marshalledOutput, err := payloadEnv.MarshalJSON()
if err != nil {
return nil, err
}
capellaPayload := &v1.ExecutionPayloadCapellaWithValue{}
if err = json.Unmarshal(marshalledOutput, capellaPayload); err != nil {
return nil, err
}
return capellaPayload, nil
}
func (p *Builder) sendHttpRequest(req *http.Request, requestBytes []byte) (*http.Response, error) {
proxyReq, err := http.NewRequest(req.Method, p.cfg.destinationUrl.String(), req.Body)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not create new request")
return nil, err
}
// Set the modified request as the proxy request body.
proxyReq.Body = ioutil.NopCloser(bytes.NewBuffer(requestBytes))
// Required proxy headers for forwarding JSON-RPC requests to the execution client.
proxyReq.Header.Set("Host", req.Host)
proxyReq.Header.Set("X-Forwarded-For", req.RemoteAddr)
proxyReq.Header.Set("Content-Type", "application/json")
client := &http.Client{}
if p.cfg.secret != "" {
client = network.NewHttpClientWithSecret(p.cfg.secret)
}
proxyRes, err := client.Do(proxyReq)
if err != nil {
p.cfg.logger.WithError(err).Error("Could not forward request to destination server")
return nil, err
}
return proxyRes, nil
}
// Peek into the bytes of an HTTP request's body.
func parseRequestBytes(req *http.Request) ([]byte, error) {
requestBytes, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, err
}
if err = req.Body.Close(); err != nil {
return nil, err
}
req.Body = ioutil.NopCloser(bytes.NewBuffer(requestBytes))
return requestBytes, nil
}
// Checks whether the JSON-RPC request is for the Ethereum engine API.
func isEngineAPICall(reqBytes []byte) bool {
jsonRequest, err := unmarshalRPCObject(reqBytes)
if err != nil {
switch {
case strings.Contains(err.Error(), "cannot unmarshal array"):
return false
default:
return false
}
}
return strings.Contains(jsonRequest.Method, "engine_")
}
func unmarshalRPCObject(b []byte) (*jsonRPCObject, error) {
r := &jsonRPCObject{}
if err := json.Unmarshal(b, r); err != nil {
return nil, err
}
return r, nil
}
func modifyExecutionPayload(execPayload engine.ExecutableData, fees *big.Int) (*engine.ExecutionPayloadEnvelope, error) {
modifiedBlock, err := executableDataToBlock(execPayload)
if err != nil {
return &engine.ExecutionPayloadEnvelope{}, err
}
return engine.BlockToExecutableData(modifiedBlock, fees), nil
}
// This modifies the provided payload to imprint the builder's extra data
func executableDataToBlock(params engine.ExecutableData) (*gethTypes.Block, error) {
txs, err := decodeTransactions(params.Transactions)
if err != nil {
return nil, err
}
// Only set withdrawalsRoot if it is non-nil. This allows CLs to use
// ExecutableData before withdrawals are enabled by marshaling
// Withdrawals as the json null value.
var withdrawalsRoot *common.Hash
if params.Withdrawals != nil {
h := gethTypes.DeriveSha(gethTypes.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil))
withdrawalsRoot = &h
}
header := &gethTypes.Header{
ParentHash: params.ParentHash,
UncleHash: gethTypes.EmptyUncleHash,
Coinbase: params.FeeRecipient,
Root: params.StateRoot,
TxHash: gethTypes.DeriveSha(gethTypes.Transactions(txs), trie.NewStackTrie(nil)),
ReceiptHash: params.ReceiptsRoot,
Bloom: gethTypes.BytesToBloom(params.LogsBloom),
Difficulty: common.Big0,
Number: new(big.Int).SetUint64(params.Number),
GasLimit: params.GasLimit,
GasUsed: params.GasUsed,
Time: params.Timestamp,
BaseFee: params.BaseFeePerGas,
Extra: []byte("prysm-builder"), // add in extra data
MixDigest: params.Random,
WithdrawalsHash: withdrawalsRoot,
}
block := gethTypes.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
return block, nil
}
func decodeTransactions(enc [][]byte) ([]*gethTypes.Transaction, error) {
var txs = make([]*gethTypes.Transaction, len(enc))
for i, encTx := range enc {
var tx gethTypes.Transaction
if err := tx.UnmarshalBinary(encTx); err != nil {
return nil, fmt.Errorf("invalid transaction %d: %v", i, err)
}
txs[i] = &tx
}
return txs, nil
}

View File

@@ -1,79 +0,0 @@
package builder
import (
"net/url"
"os"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
type config struct {
builderPort int
builderHost string
destinationUrl *url.URL
logger *logrus.Logger
secret string
}
type Option func(p *Builder) error
// WithHost sets the proxy server host.
func WithHost(host string) Option {
return func(p *Builder) error {
p.cfg.builderHost = host
return nil
}
}
// WithPort sets the proxy server port.
func WithPort(port int) Option {
return func(p *Builder) error {
p.cfg.builderPort = port
return nil
}
}
// WithDestinationAddress sets the forwarding address requests will be sent to.
func WithDestinationAddress(addr string) Option {
return func(p *Builder) error {
if addr == "" {
return errors.New("must provide a destination address for builder")
}
u, err := url.Parse(addr)
if err != nil {
return errors.Wrapf(err, "could not parse URL for destination address: %s", addr)
}
p.cfg.destinationUrl = u
return nil
}
}
// WithJwtSecret adds in support for jwt authenticated
// connections for our proxy.
func WithJwtSecret(secret string) Option {
return func(p *Builder) error {
p.cfg.secret = secret
return nil
}
}
// WithLogger sets a custom logger for the proxy.
func WithLogger(l *logrus.Logger) Option {
return func(p *Builder) error {
p.cfg.logger = l
return nil
}
}
// WithLogFile specifies a log file to write
// the proxies output to.
func WithLogFile(f *os.File) Option {
return func(p *Builder) error {
if p.cfg.logger == nil {
return errors.New("nil logger provided")
}
p.cfg.logger.SetOutput(f)
return nil
}
}

View File

@@ -108,7 +108,7 @@ func (s *Simulator) generateAttestationsForSlot(
}
func (s *Simulator) aggregateSigForAttestation(
beaconState state.ReadOnlyBeaconState, att *ethpb.IndexedAttestation,
beaconState state.BeaconState, att *ethpb.IndexedAttestation,
) (bls.Signature, error) {
domain, err := signing.Domain(
beaconState.Fork(),

View File

@@ -16,7 +16,7 @@
package usb
// Supported returns whether this platform is supported by the USB library or not.
// The goal of this method is to allow programmatically handling platforms that do
// The goal of this method is to allow programatically handling platforms that do
// not support USB and not having to fall back to build constraints.
func Supported() bool {
return false
@@ -43,7 +43,7 @@ func EnumerateHid(vendorID uint16, productID uint16) ([]DeviceInfo, error) {
return nil, nil
}
// Open connects to a previously discovered USB device.
// Open connects to a previsouly discovered USB device.
func (info DeviceInfo) Open() (Device, error) {
return nil, ErrUnsupportedPlatform
}

View File

@@ -114,13 +114,7 @@ func main() {
mux := http.NewServeMux()
mux.HandleFunc("/p2p", handler.httpHandler)
srv := &http.Server{
Addr: fmt.Sprintf(":%d", *metricsPort),
ReadHeaderTimeout: 3 * time.Second,
Handler: mux,
}
if err := srv.ListenAndServe(); err != nil {
if err := http.ListenAndServe(fmt.Sprintf(":%d", *metricsPort), mux); err != nil {
log.WithError(err).Fatal("Failed to start server")
}

View File

@@ -76,11 +76,7 @@ func main() {
http.HandleFunc("/metrics", MetricsHTTP)
http.HandleFunc("/reload", ReloadHTTP)
srv := &http.Server{
Addr: fmt.Sprintf("127.0.0.1:%d", *port),
ReadHeaderTimeout: 3 * time.Second,
}
log.Fatal(srv.ListenAndServe())
log.Fatal(http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", *port), nil))
}
// Watching address wrapper

View File

@@ -4,7 +4,6 @@ import (
"context"
"flag"
"fmt"
"math"
"time"
"github.com/prysmaticlabs/prysm/v4/config/params"
@@ -26,7 +25,7 @@ func main() {
flag.Parse()
ctx := context.Background()
cc, err := grpc.DialContext(ctx, *beacon, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt64)))
cc, err := grpc.DialContext(ctx, *beacon, grpc.WithInsecure())
if err != nil {
panic(err)
}
@@ -83,8 +82,6 @@ func wrapBlock(b *v1alpha1.BeaconBlockContainer) interfaces.ReadOnlyBeaconBlock
wb, err = blocks.NewSignedBeaconBlock(bb.AltairBlock)
case *v1alpha1.BeaconBlockContainer_BellatrixBlock:
wb, err = blocks.NewSignedBeaconBlock(bb.BellatrixBlock)
case *v1alpha1.BeaconBlockContainer_CapellaBlock:
wb, err = blocks.NewSignedBeaconBlock(bb.CapellaBlock)
}
if err != nil {
panic("no block")

View File

@@ -78,7 +78,7 @@ func displayHeads(clients map[string]pb.BeaconChainClient) {
}
}
// compare heads between all RPC end points, log the mismatch if there's one.
// compare heads between all RPC end points, log the missmatch if there's one.
func compareHeads(clients map[string]pb.BeaconChainClient) {
endpt1 := randomEndpt(clients)
head1, err := clients[endpt1].GetChainHead(context.Background(), &emptypb.Empty{})
@@ -101,7 +101,7 @@ func compareHeads(clients map[string]pb.BeaconChainClient) {
log.Fatal(err)
}
if !reflect.DeepEqual(head1, head2) {
log.Error("Uh oh! Heads mismatched!")
log.Error("Uh oh! Heads missmatched!")
logHead(endpt1, head1)
logHead(endpt2, head2)

View File

@@ -13,7 +13,6 @@ import (
"os"
"path/filepath"
"strconv"
"time"
"github.com/prysmaticlabs/prysm/v4/config/params"
)
@@ -52,11 +51,7 @@ func main() {
}
})
log.Printf("Listening on port %d", *port)
srv := &http.Server{
Addr: ":" + strconv.Itoa(*port),
ReadHeaderTimeout: 3 * time.Second,
}
log.Fatal(srv.ListenAndServe())
log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
}
func captureRequest(f *os.File, m map[string]interface{}) error {

View File

@@ -12,7 +12,7 @@ import (
var (
numKeys = flag.Int("num-keys", 0, "Number of validator private/withdrawal keys to generate")
startIndex = flag.Uint64("start-index", 0, "Start index for the deterministic keygen algorithm")
startIndex = flag.Uint64("start-index", 0, "Start index for the determinstic keygen algorithm")
random = flag.Bool("random", false, "Randomly generate keys")
outputJSON = flag.String("output-json", "", "JSON file to write output to")
overwrite = flag.Bool("overwrite", false, "If the key file exists, it will be overwritten")

View File

@@ -31,7 +31,7 @@ const (
RoleAggregator
// RoleSyncCommittee means that the validator should submit a sync committee message.
RoleSyncCommittee
// RoleSyncCommitteeAggregator means the validator should aggregate sync committee messages and submit a sync committee contribution.
// RoleSyncCommitteeAggregator means the valiator should aggregate sync committee messages and submit a sync committee contribution.
RoleSyncCommitteeAggregator
)

View File

@@ -226,7 +226,7 @@ func TestKeyReload_NoActiveKey(t *testing.T) {
assert.Equal(t, true, v.HandleKeyReloadCalled)
// HandleKeyReloadCalled in the FakeValidator returns true if one of the keys is equal to the
// ActiveKey. Since we are using a key we know is not active, it should return false, which
// should cause the account change handler to call WaitForActivationCalled.
// sould cause the account change handler to call WaitForActivationCalled.
assert.Equal(t, 1, v.WaitForActivationCalled)
}

View File

@@ -1034,7 +1034,6 @@ func (v *validator) PushProposerSettings(ctx context.Context, km keymanager.IKey
return nil
}
func (v *validator) filterAndCacheActiveKeys(ctx context.Context, pubkeys [][fieldparams.BLSPubkeyLength]byte, slot primitives.Slot) ([][fieldparams.BLSPubkeyLength]byte, error) {
filteredKeys := make([][fieldparams.BLSPubkeyLength]byte, 0)
statusRequestKeys := make([][]byte, 0)

View File

@@ -222,7 +222,7 @@ func TestWaitForChainStart_SetsGenesisInfo(t *testing.T) {
assert.Equal(t, genesis, v.genesisTime, "Unexpected chain start time")
assert.NotNil(t, v.ticker, "Expected ticker to be set, received nil")
// Make sure there are no errors running if it is the same data.
// Make sure theres no errors running if its the same data.
client.EXPECT().WaitForChainStart(
gomock.Any(),
&emptypb.Empty{},
@@ -264,7 +264,7 @@ func TestWaitForChainStart_SetsGenesisInfo_IncorrectSecondTry(t *testing.T) {
genesisValidatorsRoot = bytesutil.ToBytes32([]byte("badvalidators"))
// Make sure there are no errors running if it is the same data.
// Make sure theres no errors running if its the same data.
client.EXPECT().WaitForChainStart(
gomock.Any(),
&emptypb.Empty{},

View File

@@ -13,7 +13,7 @@ func (s *Store) SaveGenesisValidatorsRoot(_ context.Context, genValRoot []byte)
bkt := tx.Bucket(genesisInfoBucket)
enc := bkt.Get(genesisValidatorsRootKey)
if len(enc) != 0 {
return fmt.Errorf("cannot overwrite existing genesis validators root: %#x", enc)
return fmt.Errorf("cannot overwite existing genesis validators root: %#x", enc)
}
return bkt.Put(genesisValidatorsRootKey, genValRoot)
})

View File

@@ -151,7 +151,7 @@ func logValidatorWebAuth(validatorWebAddr, token string, tokenPath string) {
url.QueryEscape(token),
)
log.Infof(
"Once your validator process is running, navigate to the link below to authenticate with " +
"Once your validator process is runinng, navigate to the link below to authenticate with " +
"the Prysm web interface",
)
log.Info(webAuthURL)

View File

@@ -112,7 +112,7 @@ func Test_initializeAuthToken(t *testing.T) {
}
// "createTokenString" now uses jwt.RegisteredClaims instead of jwt.StandardClaims (deprecated),
// make sure empty jwt.RegisteredClaims and empty jwt.StandardClaims generates the same token.
// make sure emtpy jwt.RegisteredClaims and empty jwt.StandardClaims generates the same token.
func Test_UseRegisteredClaimInsteadOfStandClaims(t *testing.T) {
jwtsecret, err := hex.DecodeString("12345678900123456789abcdeffedcba")
require.NoError(t, err)