mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
Compare commits
21 Commits
beacon-nod
...
v4.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc9151d647 | ||
|
|
747d7b5190 | ||
|
|
05874df18a | ||
|
|
44973b0bb3 | ||
|
|
de0c7e6256 | ||
|
|
c1c0cd040c | ||
|
|
734eb98941 | ||
|
|
ffaef83634 | ||
|
|
f9a40ef111 | ||
|
|
7454041356 | ||
|
|
f37301c0c0 | ||
|
|
cf1bfb9d67 | ||
|
|
9d8dd5c9ad | ||
|
|
f812bdcf60 | ||
|
|
58c0899676 | ||
|
|
4628c19f51 | ||
|
|
58f23d2302 | ||
|
|
9e33723b26 | ||
|
|
2c32a87d17 | ||
|
|
56f3dafb54 | ||
|
|
70380660b3 |
@@ -206,7 +206,7 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(
|
||||
go_version = "1.20.7",
|
||||
go_version = "1.20.9",
|
||||
nogo = "@//:nogo",
|
||||
)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
"head.go",
|
||||
"head_sync_committee_info.go",
|
||||
"init_sync_process_block.go",
|
||||
"lightclient.go",
|
||||
"log.go",
|
||||
"merge_ascii_art.go",
|
||||
"metrics.go",
|
||||
@@ -77,6 +78,8 @@ go_library(
|
||||
"//monitoring/tracing:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//proto/eth/v2:go_default_library",
|
||||
"//proto/migration:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
|
||||
@@ -70,11 +70,8 @@ func IsInvalidBlock(e error) bool {
|
||||
if e == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := e.(invalidBlockError)
|
||||
if !ok {
|
||||
return IsInvalidBlock(errors.Unwrap(e))
|
||||
}
|
||||
return true
|
||||
var d invalidBlockError
|
||||
return errors.As(e, &d)
|
||||
}
|
||||
|
||||
// InvalidBlockLVH returns the invalid block last valid hash root. If the error
|
||||
@@ -83,7 +80,8 @@ func InvalidBlockLVH(e error) [32]byte {
|
||||
if e == nil {
|
||||
return [32]byte{}
|
||||
}
|
||||
d, ok := e.(invalidBlockError)
|
||||
var d invalidBlockError
|
||||
ok := errors.As(e, &d)
|
||||
if !ok {
|
||||
return [32]byte{}
|
||||
}
|
||||
@@ -96,7 +94,8 @@ func InvalidBlockRoot(e error) [32]byte {
|
||||
if e == nil {
|
||||
return [32]byte{}
|
||||
}
|
||||
d, ok := e.(invalidBlockError)
|
||||
var d invalidBlockError
|
||||
ok := errors.As(e, &d)
|
||||
if !ok {
|
||||
return [32]byte{}
|
||||
}
|
||||
@@ -108,7 +107,8 @@ func InvalidAncestorRoots(e error) [][32]byte {
|
||||
if e == nil {
|
||||
return [][32]byte{}
|
||||
}
|
||||
d, ok := e.(invalidBlockError)
|
||||
var d invalidBlockError
|
||||
ok := errors.As(e, &d)
|
||||
if !ok {
|
||||
return [][32]byte{}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ func TestInvalidBlockRoot(t *testing.T) {
|
||||
err := invalidBlock{error: ErrInvalidPayload, root: [32]byte{'a'}}
|
||||
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(err))
|
||||
require.DeepEqual(t, [][32]byte(nil), InvalidAncestorRoots(err))
|
||||
|
||||
newErr := errors.Wrap(err, "wrap me")
|
||||
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(newErr))
|
||||
}
|
||||
|
||||
func TestInvalidRoots(t *testing.T) {
|
||||
@@ -33,4 +36,9 @@ func TestInvalidRoots(t *testing.T) {
|
||||
require.Equal(t, true, IsInvalidBlock(err))
|
||||
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(err))
|
||||
require.DeepEqual(t, roots, InvalidAncestorRoots(err))
|
||||
|
||||
newErr := errors.Wrap(err, "wrap me")
|
||||
require.Equal(t, true, IsInvalidBlock(err))
|
||||
require.Equal(t, [32]byte{'a'}, InvalidBlockRoot(newErr))
|
||||
require.DeepEqual(t, roots, InvalidAncestorRoots(newErr))
|
||||
}
|
||||
|
||||
246
beacon-chain/blockchain/lightclient.go
Normal file
246
beacon-chain/blockchain/lightclient.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
|
||||
ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2"
|
||||
"github.com/prysmaticlabs/prysm/v4/proto/migration"
|
||||
"github.com/prysmaticlabs/prysm/v4/time/slots"
|
||||
)
|
||||
|
||||
const (
|
||||
finalityBranchNumOfLeaves = 6
|
||||
)
|
||||
|
||||
// CreateLightClientFinalityUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_finality_update
|
||||
// def create_light_client_finality_update(update: LightClientUpdate) -> LightClientFinalityUpdate:
|
||||
//
|
||||
// return LightClientFinalityUpdate(
|
||||
// attested_header=update.attested_header,
|
||||
// finalized_header=update.finalized_header,
|
||||
// finality_branch=update.finality_branch,
|
||||
// sync_aggregate=update.sync_aggregate,
|
||||
// signature_slot=update.signature_slot,
|
||||
// )
|
||||
func CreateLightClientFinalityUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientFinalityUpdate {
|
||||
return ðpbv2.LightClientFinalityUpdate{
|
||||
AttestedHeader: update.AttestedHeader,
|
||||
FinalizedHeader: update.FinalizedHeader,
|
||||
FinalityBranch: update.FinalityBranch,
|
||||
SyncAggregate: update.SyncAggregate,
|
||||
SignatureSlot: update.SignatureSlot,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateLightClientOptimisticUpdate - implements https://github.com/ethereum/consensus-specs/blob/3d235740e5f1e641d3b160c8688f26e7dc5a1894/specs/altair/light-client/full-node.md#create_light_client_optimistic_update
|
||||
// def create_light_client_optimistic_update(update: LightClientUpdate) -> LightClientOptimisticUpdate:
|
||||
//
|
||||
// return LightClientOptimisticUpdate(
|
||||
// attested_header=update.attested_header,
|
||||
// sync_aggregate=update.sync_aggregate,
|
||||
// signature_slot=update.signature_slot,
|
||||
// )
|
||||
func CreateLightClientOptimisticUpdate(update *ethpbv2.LightClientUpdate) *ethpbv2.LightClientOptimisticUpdate {
|
||||
return ðpbv2.LightClientOptimisticUpdate{
|
||||
AttestedHeader: update.AttestedHeader,
|
||||
SyncAggregate: update.SyncAggregate,
|
||||
SignatureSlot: update.SignatureSlot,
|
||||
}
|
||||
}
|
||||
|
||||
func NewLightClientOptimisticUpdateFromBeaconState(
|
||||
ctx context.Context,
|
||||
state state.BeaconState,
|
||||
block interfaces.ReadOnlySignedBeaconBlock,
|
||||
attestedState state.BeaconState) (*ethpbv2.LightClientUpdate, error) {
|
||||
// assert compute_epoch_at_slot(attested_state.slot) >= ALTAIR_FORK_EPOCH
|
||||
attestedEpoch := slots.ToEpoch(attestedState.Slot())
|
||||
if attestedEpoch < types.Epoch(params.BeaconConfig().AltairForkEpoch) {
|
||||
return nil, fmt.Errorf("invalid attested epoch %d", attestedEpoch)
|
||||
}
|
||||
|
||||
// assert sum(block.message.body.sync_aggregate.sync_committee_bits) >= MIN_SYNC_COMMITTEE_PARTICIPANTS
|
||||
syncAggregate, err := block.Block().Body().SyncAggregate()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get sync aggregate %v", err)
|
||||
}
|
||||
|
||||
if syncAggregate.SyncCommitteeBits.Count() < params.BeaconConfig().MinSyncCommitteeParticipants {
|
||||
return nil, fmt.Errorf("invalid sync committee bits count %d", syncAggregate.SyncCommitteeBits.Count())
|
||||
}
|
||||
|
||||
// assert state.slot == state.latest_block_header.slot
|
||||
if state.Slot() != state.LatestBlockHeader().Slot {
|
||||
return nil, fmt.Errorf("state slot %d not equal to latest block header slot %d", state.Slot(), state.LatestBlockHeader().Slot)
|
||||
}
|
||||
|
||||
// assert hash_tree_root(header) == hash_tree_root(block.message)
|
||||
header := state.LatestBlockHeader()
|
||||
stateRoot, err := state.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get state root %v", err)
|
||||
}
|
||||
header.StateRoot = stateRoot[:]
|
||||
|
||||
headerRoot, err := header.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get header root %v", err)
|
||||
}
|
||||
|
||||
blockRoot, err := block.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get block root %v", err)
|
||||
}
|
||||
|
||||
if headerRoot != blockRoot {
|
||||
return nil, fmt.Errorf("header root %#x not equal to block root %#x", headerRoot, blockRoot)
|
||||
}
|
||||
|
||||
// assert attested_state.slot == attested_state.latest_block_header.slot
|
||||
if attestedState.Slot() != attestedState.LatestBlockHeader().Slot {
|
||||
return nil, fmt.Errorf("attested state slot %d not equal to attested latest block header slot %d", attestedState.Slot(), attestedState.LatestBlockHeader().Slot)
|
||||
}
|
||||
|
||||
// attested_header = attested_state.latest_block_header.copy()
|
||||
attestedHeader := attestedState.LatestBlockHeader()
|
||||
|
||||
// attested_header.state_root = hash_tree_root(attested_state)
|
||||
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attested state root %v", err)
|
||||
}
|
||||
attestedHeader.StateRoot = attestedStateRoot[:]
|
||||
|
||||
// assert hash_tree_root(attested_header) == block.message.parent_root
|
||||
attestedHeaderRoot, err := attestedHeader.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attested header root %v", err)
|
||||
}
|
||||
|
||||
if attestedHeaderRoot != block.Block().ParentRoot() {
|
||||
return nil, fmt.Errorf("attested header root %#x not equal to block parent root %#x", attestedHeaderRoot, block.Block().ParentRoot())
|
||||
}
|
||||
|
||||
// Return result
|
||||
attestedHeaderResult := ðpbv1.BeaconBlockHeader{
|
||||
Slot: attestedHeader.Slot,
|
||||
ProposerIndex: attestedHeader.ProposerIndex,
|
||||
ParentRoot: attestedHeader.ParentRoot,
|
||||
StateRoot: attestedHeader.StateRoot,
|
||||
BodyRoot: attestedHeader.BodyRoot,
|
||||
}
|
||||
|
||||
syncAggregateResult := ðpbv1.SyncAggregate{
|
||||
SyncCommitteeBits: syncAggregate.SyncCommitteeBits,
|
||||
SyncCommitteeSignature: syncAggregate.SyncCommitteeSignature,
|
||||
}
|
||||
|
||||
result := ðpbv2.LightClientUpdate{
|
||||
AttestedHeader: attestedHeaderResult,
|
||||
SyncAggregate: syncAggregateResult,
|
||||
SignatureSlot: block.Block().Slot(),
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func NewLightClientFinalityUpdateFromBeaconState(
|
||||
ctx context.Context,
|
||||
state state.BeaconState,
|
||||
block interfaces.ReadOnlySignedBeaconBlock,
|
||||
attestedState state.BeaconState,
|
||||
finalizedBlock interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.LightClientUpdate, error) {
|
||||
result, err := NewLightClientOptimisticUpdateFromBeaconState(
|
||||
ctx,
|
||||
state,
|
||||
block,
|
||||
attestedState,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Indicate finality whenever possible
|
||||
var finalizedHeader *ethpbv1.BeaconBlockHeader
|
||||
var finalityBranch [][]byte
|
||||
|
||||
if finalizedBlock != nil && !finalizedBlock.IsNil() {
|
||||
if finalizedBlock.Block().Slot() != 0 {
|
||||
tempFinalizedHeader, err := finalizedBlock.Header()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get finalized header %v", err)
|
||||
}
|
||||
finalizedHeader = migration.V1Alpha1SignedHeaderToV1(tempFinalizedHeader).GetMessage()
|
||||
|
||||
finalizedHeaderRoot, err := finalizedHeader.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get finalized header root %v", err)
|
||||
}
|
||||
|
||||
if finalizedHeaderRoot != bytesutil.ToBytes32(attestedState.FinalizedCheckpoint().Root) {
|
||||
return nil, fmt.Errorf("finalized header root %#x not equal to attested finalized checkpoint root %#x", finalizedHeaderRoot, bytesutil.ToBytes32(attestedState.FinalizedCheckpoint().Root))
|
||||
}
|
||||
} else {
|
||||
if !bytes.Equal(attestedState.FinalizedCheckpoint().Root, make([]byte, 32)) {
|
||||
return nil, fmt.Errorf("invalid finalized header root %v", attestedState.FinalizedCheckpoint().Root)
|
||||
}
|
||||
|
||||
finalizedHeader = ðpbv1.BeaconBlockHeader{
|
||||
Slot: 0,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
var bErr error
|
||||
finalityBranch, bErr = attestedState.FinalizedRootProof(ctx)
|
||||
if bErr != nil {
|
||||
return nil, fmt.Errorf("could not get finalized root proof %v", bErr)
|
||||
}
|
||||
} else {
|
||||
finalizedHeader = ðpbv1.BeaconBlockHeader{
|
||||
Slot: 0,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: make([]byte, 32),
|
||||
StateRoot: make([]byte, 32),
|
||||
BodyRoot: make([]byte, 32),
|
||||
}
|
||||
|
||||
finalityBranch = make([][]byte, finalityBranchNumOfLeaves)
|
||||
for i := 0; i < finalityBranchNumOfLeaves; i++ {
|
||||
finalityBranch[i] = make([]byte, 32)
|
||||
}
|
||||
}
|
||||
|
||||
result.FinalizedHeader = finalizedHeader
|
||||
result.FinalityBranch = finalityBranch
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func NewLightClientUpdateFromFinalityUpdate(update *ethpbv2.LightClientFinalityUpdate) *ethpbv2.LightClientUpdate {
|
||||
return ðpbv2.LightClientUpdate{
|
||||
AttestedHeader: update.AttestedHeader,
|
||||
FinalizedHeader: update.FinalizedHeader,
|
||||
FinalityBranch: update.FinalityBranch,
|
||||
SyncAggregate: update.SyncAggregate,
|
||||
SignatureSlot: update.SignatureSlot,
|
||||
}
|
||||
}
|
||||
|
||||
func NewLightClientUpdateFromOptimisticUpdate(update *ethpbv2.LightClientOptimisticUpdate) *ethpbv2.LightClientUpdate {
|
||||
return ðpbv2.LightClientUpdate{
|
||||
AttestedHeader: update.AttestedHeader,
|
||||
SyncAggregate: update.SyncAggregate,
|
||||
SignatureSlot: update.SignatureSlot,
|
||||
}
|
||||
}
|
||||
160
beacon-chain/blockchain/lightclient_test.go
Normal file
160
beacon-chain/blockchain/lightclient_test.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
v1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
|
||||
ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/util"
|
||||
)
|
||||
|
||||
type testlc struct {
|
||||
t *testing.T
|
||||
ctx context.Context
|
||||
state state.BeaconState
|
||||
block interfaces.ReadOnlySignedBeaconBlock
|
||||
attestedState state.BeaconState
|
||||
attestedHeader *ethpb.BeaconBlockHeader
|
||||
}
|
||||
|
||||
func newTestLc(t *testing.T) *testlc {
|
||||
return &testlc{t: t}
|
||||
}
|
||||
|
||||
func (l *testlc) setupTest() *testlc {
|
||||
ctx := context.Background()
|
||||
|
||||
slot := primitives.Slot(params.BeaconConfig().AltairForkEpoch * primitives.Epoch(params.BeaconConfig().SlotsPerEpoch)).Add(1)
|
||||
|
||||
attestedState, err := util.NewBeaconStateCapella()
|
||||
require.NoError(l.t, err)
|
||||
err = attestedState.SetSlot(slot)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
parent := util.NewBeaconBlockCapella()
|
||||
parent.Block.Slot = slot
|
||||
|
||||
signedParent, err := blocks.NewSignedBeaconBlock(parent)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
parentHeader, err := signedParent.Header()
|
||||
require.NoError(l.t, err)
|
||||
attestedHeader := parentHeader.Header
|
||||
|
||||
err = attestedState.SetLatestBlockHeader(attestedHeader)
|
||||
require.NoError(l.t, err)
|
||||
attestedStateRoot, err := attestedState.HashTreeRoot(ctx)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
// get a new signed block so the root is updated with the new state root
|
||||
parent.Block.StateRoot = attestedStateRoot[:]
|
||||
signedParent, err = blocks.NewSignedBeaconBlock(parent)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
state, err := util.NewBeaconStateCapella()
|
||||
require.NoError(l.t, err)
|
||||
err = state.SetSlot(slot)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
parentRoot, err := signedParent.Block().HashTreeRoot()
|
||||
require.NoError(l.t, err)
|
||||
|
||||
block := util.NewBeaconBlockCapella()
|
||||
block.Block.Slot = slot
|
||||
block.Block.ParentRoot = parentRoot[:]
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().MinSyncCommitteeParticipants; i++ {
|
||||
block.Block.Body.SyncAggregate.SyncCommitteeBits.SetBitAt(i, true)
|
||||
}
|
||||
|
||||
signedBlock, err := blocks.NewSignedBeaconBlock(block)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
h, err := signedBlock.Header()
|
||||
require.NoError(l.t, err)
|
||||
|
||||
err = state.SetLatestBlockHeader(h.Header)
|
||||
require.NoError(l.t, err)
|
||||
stateRoot, err := state.HashTreeRoot(ctx)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
// get a new signed block so the root is updated with the new state root
|
||||
block.Block.StateRoot = stateRoot[:]
|
||||
signedBlock, err = blocks.NewSignedBeaconBlock(block)
|
||||
require.NoError(l.t, err)
|
||||
|
||||
l.state = state
|
||||
l.attestedState = attestedState
|
||||
l.attestedHeader = attestedHeader
|
||||
l.block = signedBlock
|
||||
l.ctx = ctx
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *testlc) checkAttestedHeader(update *ethpbv2.LightClientUpdate) {
|
||||
require.Equal(l.t, l.attestedHeader.Slot, update.AttestedHeader.Slot, "Attested header slot is not equal")
|
||||
require.Equal(l.t, l.attestedHeader.ProposerIndex, update.AttestedHeader.ProposerIndex, "Attested header proposer index is not equal")
|
||||
require.DeepSSZEqual(l.t, l.attestedHeader.ParentRoot, update.AttestedHeader.ParentRoot, "Attested header parent root is not equal")
|
||||
require.DeepSSZEqual(l.t, l.attestedHeader.BodyRoot, update.AttestedHeader.BodyRoot, "Attested header body root is not equal")
|
||||
|
||||
attestedStateRoot, err := l.attestedState.HashTreeRoot(l.ctx)
|
||||
require.NoError(l.t, err)
|
||||
require.DeepSSZEqual(l.t, attestedStateRoot[:], update.AttestedHeader.StateRoot, "Attested header state root is not equal")
|
||||
}
|
||||
|
||||
func (l *testlc) checkSyncAggregate(update *ethpbv2.LightClientUpdate) {
|
||||
syncAggregate, err := l.block.Block().Body().SyncAggregate()
|
||||
require.NoError(l.t, err)
|
||||
require.DeepSSZEqual(l.t, syncAggregate.SyncCommitteeBits, update.SyncAggregate.SyncCommitteeBits, "SyncAggregate bits is not equal")
|
||||
require.DeepSSZEqual(l.t, syncAggregate.SyncCommitteeSignature, update.SyncAggregate.SyncCommitteeSignature, "SyncAggregate signature is not equal")
|
||||
}
|
||||
|
||||
func TestLightClient_NewLightClientOptimisticUpdateFromBeaconState(t *testing.T) {
|
||||
l := newTestLc(t).setupTest()
|
||||
|
||||
update, err := NewLightClientOptimisticUpdateFromBeaconState(l.ctx, l.state, l.block, l.attestedState)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, update, "update is nil")
|
||||
|
||||
require.Equal(t, l.block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
|
||||
|
||||
l.checkSyncAggregate(update)
|
||||
l.checkAttestedHeader(update)
|
||||
|
||||
require.Equal(t, (*v1.BeaconBlockHeader)(nil), update.FinalizedHeader, "Finalized header is not nil")
|
||||
require.DeepSSZEqual(t, ([][]byte)(nil), update.FinalityBranch, "Finality branch is not nil")
|
||||
}
|
||||
|
||||
func TestLightClient_NewLightClientFinalityUpdateFromBeaconState(t *testing.T) {
|
||||
l := newTestLc(t).setupTest()
|
||||
|
||||
update, err := NewLightClientFinalityUpdateFromBeaconState(l.ctx, l.state, l.block, l.attestedState, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, update, "update is nil")
|
||||
|
||||
require.Equal(t, l.block.Block().Slot(), update.SignatureSlot, "Signature slot is not equal")
|
||||
|
||||
l.checkSyncAggregate(update)
|
||||
l.checkAttestedHeader(update)
|
||||
|
||||
zeroHash := params.BeaconConfig().ZeroHash[:]
|
||||
require.NotNil(t, update.FinalizedHeader, "Finalized header is nil")
|
||||
require.Equal(t, primitives.Slot(0), update.FinalizedHeader.Slot, "Finalized header slot is not zero")
|
||||
require.Equal(t, primitives.ValidatorIndex(0), update.FinalizedHeader.ProposerIndex, "Finalized header proposer index is not zero")
|
||||
require.DeepSSZEqual(t, zeroHash, update.FinalizedHeader.ParentRoot, "Finalized header parent root is not zero")
|
||||
require.DeepSSZEqual(t, zeroHash, update.FinalizedHeader.StateRoot, "Finalized header state root is not zero")
|
||||
require.DeepSSZEqual(t, zeroHash, update.FinalizedHeader.BodyRoot, "Finalized header body root is not zero")
|
||||
require.Equal(t, finalityBranchNumOfLeaves, len(update.FinalityBranch), "Invalid finality branch leaves")
|
||||
for _, leaf := range update.FinalityBranch {
|
||||
require.DeepSSZEqual(t, zeroHash, leaf, "Leaf is not zero")
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ func TestReportEpochMetrics_BadHeadState(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, h.SetValidators(nil))
|
||||
err = reportEpochMetrics(context.Background(), s, h)
|
||||
require.ErrorContains(t, "failed to initialize precompute: nil validators in state", err)
|
||||
require.ErrorContains(t, "failed to initialize precompute: state has nil validator slice", err)
|
||||
}
|
||||
|
||||
func TestReportEpochMetrics_BadAttestation(t *testing.T) {
|
||||
|
||||
@@ -649,11 +649,13 @@ func (s *Service) lateBlockTasks(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
s.headLock.RUnlock()
|
||||
s.cfg.ForkChoiceStore.RLock()
|
||||
_, err = s.notifyForkchoiceUpdate(ctx, ¬ifyForkchoiceUpdateArg{
|
||||
headState: headState,
|
||||
headRoot: headRoot,
|
||||
headBlock: headBlock.Block(),
|
||||
})
|
||||
s.cfg.ForkChoiceStore.RUnlock()
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("could not perform late block tasks: failed to update forkchoice with engine")
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func Test_BaseReward(t *testing.T) {
|
||||
valIdx: 2,
|
||||
st: genState(1),
|
||||
want: 0,
|
||||
errString: "index 2 out of range",
|
||||
errString: "validator index 2 does not exist",
|
||||
},
|
||||
{
|
||||
name: "active balance is 32eth",
|
||||
@@ -89,7 +89,7 @@ func Test_BaseRewardWithTotalBalance(t *testing.T) {
|
||||
valIdx: 2,
|
||||
activeBalance: 1,
|
||||
want: 0,
|
||||
errString: "index 2 out of range",
|
||||
errString: "validator index 2 does not exist",
|
||||
},
|
||||
{
|
||||
name: "active balance is 1",
|
||||
|
||||
@@ -82,7 +82,7 @@ func ProcessRandaoNoVerify(
|
||||
for i, x := range blockRandaoReveal {
|
||||
latestMixSlice[i] ^= x
|
||||
}
|
||||
if err := beaconState.UpdateRandaoMixesAtIndex(uint64(currentEpoch%latestMixesLength), latestMixSlice); err != nil {
|
||||
if err := beaconState.UpdateRandaoMixesAtIndex(uint64(currentEpoch%latestMixesLength), [32]byte(latestMixSlice)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
|
||||
@@ -152,7 +152,7 @@ func TestProcessBLSToExecutionChange(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err = blocks.ProcessBLSToExecutionChange(st, signed)
|
||||
require.ErrorContains(t, "out of range", err)
|
||||
require.ErrorContains(t, "out of bounds", err)
|
||||
})
|
||||
|
||||
t.Run("signature does not verify", func(t *testing.T) {
|
||||
|
||||
@@ -137,16 +137,10 @@ func ProcessRegistryUpdates(ctx context.Context, state state.BeaconState) (state
|
||||
return nil, errors.Wrap(err, "could not get active validator count")
|
||||
}
|
||||
|
||||
churnLimit, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get churn limit")
|
||||
}
|
||||
churnLimit := helpers.ValidatorActivationChurnLimit(activeValidatorCount)
|
||||
|
||||
if state.Version() >= version.Deneb {
|
||||
// Cap churn limit to max per epoch churn limit. New in EIP7514.
|
||||
if churnLimit > params.BeaconConfig().MaxPerEpochActivationChurnLimit {
|
||||
churnLimit = params.BeaconConfig().MaxPerEpochActivationChurnLimit
|
||||
}
|
||||
churnLimit = helpers.ValidatorActivationChurnLimitDeneb(activeValidatorCount)
|
||||
}
|
||||
|
||||
// Prevent churn limit cause index out of bound.
|
||||
@@ -355,7 +349,7 @@ func ProcessRandaoMixesReset(state state.BeaconState) (state.BeaconState, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := state.UpdateRandaoMixesAtIndex(uint64(nextEpoch%randaoMixLength), mix); err != nil {
|
||||
if err := state.UpdateRandaoMixesAtIndex(uint64(nextEpoch%randaoMixLength), [32]byte(mix)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -311,8 +311,7 @@ func TestProcessRegistryUpdates_EligibleToActivate(t *testing.T) {
|
||||
Slot: 5 * params.BeaconConfig().SlotsPerEpoch,
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 6, Root: make([]byte, fieldparams.RootLength)},
|
||||
}
|
||||
limit, err := helpers.ValidatorChurnLimit(0)
|
||||
require.NoError(t, err)
|
||||
limit := helpers.ValidatorActivationChurnLimit(0)
|
||||
for i := uint64(0); i < limit+10; i++ {
|
||||
base.Validators = append(base.Validators, ðpb.Validator{
|
||||
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
|
||||
@@ -99,7 +99,7 @@ func TestIsCurrentEpochSyncCommittee_DoesNotExist(t *testing.T) {
|
||||
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
|
||||
|
||||
ok, err := IsCurrentPeriodSyncCommittee(state, 12390192)
|
||||
require.ErrorContains(t, "index 12390192 out of range", err)
|
||||
require.ErrorContains(t, "validator index 12390192 does not exist", err)
|
||||
require.Equal(t, false, ok)
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func TestIsNextEpochSyncCommittee_DoesNotExist(t *testing.T) {
|
||||
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
|
||||
|
||||
ok, err := IsNextPeriodSyncCommittee(state, 120391029)
|
||||
require.ErrorContains(t, "index 120391029 out of range", err)
|
||||
require.ErrorContains(t, "validator index 120391029 does not exist", err)
|
||||
require.Equal(t, false, ok)
|
||||
}
|
||||
|
||||
@@ -282,7 +282,7 @@ func TestCurrentEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
|
||||
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
|
||||
|
||||
index, err := CurrentPeriodSyncSubcommitteeIndices(state, 129301923)
|
||||
require.ErrorContains(t, "index 129301923 out of range", err)
|
||||
require.ErrorContains(t, "validator index 129301923 does not exist", err)
|
||||
require.DeepEqual(t, []primitives.CommitteeIndex(nil), index)
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ func TestNextEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
|
||||
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
|
||||
|
||||
index, err := NextPeriodSyncSubcommitteeIndices(state, 21093019)
|
||||
require.ErrorContains(t, "index 21093019 out of range", err)
|
||||
require.ErrorContains(t, "validator index 21093019 does not exist", err)
|
||||
require.DeepEqual(t, []primitives.CommitteeIndex(nil), index)
|
||||
}
|
||||
|
||||
|
||||
@@ -206,10 +206,7 @@ func ActivationExitEpoch(epoch primitives.Epoch) primitives.Epoch {
|
||||
return epoch + 1 + params.BeaconConfig().MaxSeedLookahead
|
||||
}
|
||||
|
||||
// ValidatorChurnLimit returns the number of validators that are allowed to
|
||||
// enter and exit validator pool for an epoch.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// calculateChurnLimit based on the formula in the spec.
|
||||
//
|
||||
// def get_validator_churn_limit(state: BeaconState) -> uint64:
|
||||
// """
|
||||
@@ -217,12 +214,32 @@ func ActivationExitEpoch(epoch primitives.Epoch) primitives.Epoch {
|
||||
// """
|
||||
// active_validator_indices = get_active_validator_indices(state, get_current_epoch(state))
|
||||
// return max(MIN_PER_EPOCH_CHURN_LIMIT, uint64(len(active_validator_indices)) // CHURN_LIMIT_QUOTIENT)
|
||||
func ValidatorChurnLimit(activeValidatorCount uint64) (uint64, error) {
|
||||
func calculateChurnLimit(activeValidatorCount uint64) uint64 {
|
||||
churnLimit := activeValidatorCount / params.BeaconConfig().ChurnLimitQuotient
|
||||
if churnLimit < params.BeaconConfig().MinPerEpochChurnLimit {
|
||||
churnLimit = params.BeaconConfig().MinPerEpochChurnLimit
|
||||
return params.BeaconConfig().MinPerEpochChurnLimit
|
||||
}
|
||||
return churnLimit, nil
|
||||
return churnLimit
|
||||
}
|
||||
|
||||
// ValidatorActivationChurnLimit returns the maximum number of validators that can be activated in a slot.
|
||||
func ValidatorActivationChurnLimit(activeValidatorCount uint64) uint64 {
|
||||
return calculateChurnLimit(activeValidatorCount)
|
||||
}
|
||||
|
||||
// ValidatorExitChurnLimit returns the maximum number of validators that can be exited in a slot.
|
||||
func ValidatorExitChurnLimit(activeValidatorCount uint64) uint64 {
|
||||
return calculateChurnLimit(activeValidatorCount)
|
||||
}
|
||||
|
||||
// ValidatorActivationChurnLimitDeneb returns the maximum number of validators that can be activated in a slot post Deneb.
|
||||
func ValidatorActivationChurnLimitDeneb(activeValidatorCount uint64) uint64 {
|
||||
limit := calculateChurnLimit(activeValidatorCount)
|
||||
// New in Deneb.
|
||||
if limit > params.BeaconConfig().MaxPerEpochActivationChurnLimit {
|
||||
return params.BeaconConfig().MaxPerEpochActivationChurnLimit
|
||||
}
|
||||
return limit
|
||||
}
|
||||
|
||||
// BeaconProposerIndex returns proposer index of a current slot.
|
||||
|
||||
@@ -367,9 +367,50 @@ func TestChurnLimit_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
validatorCount, err := ActiveValidatorCount(context.Background(), beaconState, time.CurrentEpoch(beaconState))
|
||||
require.NoError(t, err)
|
||||
resultChurn, err := ValidatorChurnLimit(validatorCount)
|
||||
resultChurn := ValidatorActivationChurnLimit(validatorCount)
|
||||
assert.Equal(t, test.wantedChurn, resultChurn, "ValidatorActivationChurnLimit(%d)", test.validatorCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChurnLimitDeneb_OK(t *testing.T) {
|
||||
tests := []struct {
|
||||
validatorCount int
|
||||
wantedChurn uint64
|
||||
}{
|
||||
{1000, 4},
|
||||
{100000, 4},
|
||||
{1000000, params.BeaconConfig().MaxPerEpochActivationChurnLimit},
|
||||
{2000000, params.BeaconConfig().MaxPerEpochActivationChurnLimit},
|
||||
}
|
||||
|
||||
defer ClearCache()
|
||||
|
||||
for _, test := range tests {
|
||||
ClearCache()
|
||||
|
||||
// Create validators
|
||||
validators := make([]*ethpb.Validator, test.validatorCount)
|
||||
for i := range validators {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize beacon state
|
||||
beaconState, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Slot: 1,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.wantedChurn, resultChurn, "ValidatorChurnLimit(%d)", test.validatorCount)
|
||||
|
||||
// Get active validator count
|
||||
validatorCount, err := ActiveValidatorCount(context.Background(), beaconState, time.CurrentEpoch(beaconState))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test churn limit calculation
|
||||
resultChurn := ValidatorActivationChurnLimitDeneb(validatorCount)
|
||||
assert.Equal(t, test.wantedChurn, resultChurn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,10 +80,7 @@ func ComputeWeakSubjectivityPeriod(ctx context.Context, st state.ReadOnlyBeaconS
|
||||
T := cfg.MaxEffectiveBalance / cfg.GweiPerEth
|
||||
|
||||
// Validator churn limit.
|
||||
delta, err := ValidatorChurnLimit(N)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("cannot obtain active validator churn limit: %w", err)
|
||||
}
|
||||
delta := ValidatorExitChurnLimit(N)
|
||||
|
||||
// Balance top-ups.
|
||||
Delta := uint64(cfg.SlotsPerEpoch.Mul(cfg.MaxDeposits))
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/container/trie"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
@@ -221,6 +222,18 @@ func OptimizedGenesisBeaconState(genesisTime uint64, preState state.BeaconState,
|
||||
|
||||
// EmptyGenesisState returns an empty beacon state object.
|
||||
func EmptyGenesisState() (state.BeaconState, error) {
|
||||
blockRoots := make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range blockRoots {
|
||||
blockRoots[i] = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
stateRoots := make([][]byte, fieldparams.StateRootsLength)
|
||||
for i := range stateRoots {
|
||||
stateRoots[i] = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
mixes := make([][]byte, fieldparams.RandaoMixesLength)
|
||||
for i := range mixes {
|
||||
mixes[i] = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
st := ðpb.BeaconState{
|
||||
// Misc fields.
|
||||
Slot: 0,
|
||||
@@ -229,6 +242,9 @@ func EmptyGenesisState() (state.BeaconState, error) {
|
||||
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||
Epoch: 0,
|
||||
},
|
||||
BlockRoots: blockRoots,
|
||||
StateRoots: stateRoots,
|
||||
RandaoMixes: mixes,
|
||||
// Validator registry fields.
|
||||
Validators: []*ethpb.Validator{},
|
||||
Balances: []uint64{},
|
||||
|
||||
@@ -82,10 +82,7 @@ func InitiateValidatorExit(ctx context.Context, s state.BeaconState, idx primiti
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "could not get active validator count")
|
||||
}
|
||||
currentChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "could not get churn limit")
|
||||
}
|
||||
currentChurn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
|
||||
|
||||
if churn >= currentChurn {
|
||||
exitQueueEpoch, err = exitQueueEpoch.SafeAdd(1)
|
||||
@@ -235,10 +232,7 @@ func ExitedValidatorIndices(epoch primitives.Epoch, validators []*ethpb.Validato
|
||||
exitQueueChurn++
|
||||
}
|
||||
}
|
||||
churn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get churn limit")
|
||||
}
|
||||
churn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
|
||||
if churn < exitQueueChurn {
|
||||
exitQueueEpoch++
|
||||
}
|
||||
@@ -276,10 +270,7 @@ func EjectedValidatorIndices(epoch primitives.Epoch, validators []*ethpb.Validat
|
||||
exitQueueChurn++
|
||||
}
|
||||
}
|
||||
churn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get churn limit")
|
||||
}
|
||||
churn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
|
||||
if churn < exitQueueChurn {
|
||||
exitQueueEpoch++
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ func (f *ForkChoice) LastRoot(epoch primitives.Epoch) [32]byte {
|
||||
if err != nil {
|
||||
return [32]byte{}
|
||||
}
|
||||
if headEpoch < epoch {
|
||||
return [32]byte{}
|
||||
}
|
||||
if headEpoch == epoch {
|
||||
if headEpoch <= epoch {
|
||||
return head.root
|
||||
}
|
||||
for head != nil && head.slot > epochEnd {
|
||||
|
||||
@@ -35,5 +35,5 @@ func TestLastRoot(t *testing.T) {
|
||||
require.Equal(t, [32]byte{'6'}, f.store.headNode.root)
|
||||
require.Equal(t, [32]byte{'2'}, f.LastRoot(0))
|
||||
require.Equal(t, [32]byte{'6'}, f.LastRoot(1))
|
||||
require.Equal(t, [32]byte{}, f.LastRoot(2))
|
||||
require.Equal(t, [32]byte{'6'}, f.LastRoot(2))
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ go_library(
|
||||
"node.go",
|
||||
"options.go",
|
||||
"prometheus.go",
|
||||
"router.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/node",
|
||||
visibility = [
|
||||
@@ -40,6 +41,7 @@ go_library(
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
"//beacon-chain/rpc:go_default_library",
|
||||
"//beacon-chain/rpc/apimiddleware:go_default_library",
|
||||
"//beacon-chain/rpc/eth/helpers:go_default_library",
|
||||
"//beacon-chain/slasher:go_default_library",
|
||||
"//beacon-chain/startup:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
|
||||
@@ -271,6 +271,7 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
|
||||
|
||||
log.Debugln("Registering RPC Service")
|
||||
router := mux.NewRouter()
|
||||
router.Use(middleware)
|
||||
if err := beacon.registerRPCService(router); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
17
beacon-chain/node/router.go
Normal file
17
beacon-chain/node/router.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
|
||||
)
|
||||
|
||||
func middleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
query := r.URL.Query()
|
||||
helpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
@@ -33,6 +33,7 @@ go_test(
|
||||
srcs = [
|
||||
"custom_handlers_test.go",
|
||||
"custom_hooks_test.go",
|
||||
"endpoint_factory_test.go",
|
||||
"structs_marshalling_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
|
||||
@@ -19,7 +19,6 @@ func (_ *BeaconEndpointFactory) Paths() []string {
|
||||
"/eth/v1/beacon/states/{state_id}/root",
|
||||
"/eth/v1/beacon/states/{state_id}/sync_committees",
|
||||
"/eth/v1/beacon/states/{state_id}/randao",
|
||||
"/eth/v1/beacon/blinded_blocks",
|
||||
"/eth/v1/beacon/blocks/{block_id}",
|
||||
"/eth/v2/beacon/blocks/{block_id}",
|
||||
"/eth/v1/beacon/blocks/{block_id}/attestations",
|
||||
|
||||
17
beacon-chain/rpc/apimiddleware/endpoint_factory_test.go
Normal file
17
beacon-chain/rpc/apimiddleware/endpoint_factory_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package apimiddleware_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/apimiddleware"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconEndpointFactory_AllPathsRegistered(t *testing.T) {
|
||||
f := &apimiddleware.BeaconEndpointFactory{}
|
||||
|
||||
for _, p := range f.Paths() {
|
||||
_, err := f.Create(p)
|
||||
require.NoError(t, err, "failed to register %s", p)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/api"
|
||||
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
|
||||
@@ -24,7 +25,7 @@ func (bs *Server) GetBlindedBlock(ctx context.Context, req *ethpbv1.BlockRequest
|
||||
defer span.End()
|
||||
|
||||
blk, err := bs.Blocker.Block(ctx, req.BlockId)
|
||||
err = handleGetBlockError(blk, err)
|
||||
err = rpchelpers.HandleGetBlockError(blk, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func (bs *Server) GetBlindedBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequ
|
||||
defer span.End()
|
||||
|
||||
blk, err := bs.Blocker.Block(ctx, req.BlockId)
|
||||
err = handleGetBlockError(blk, err)
|
||||
err = rpchelpers.HandleGetBlockError(blk, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -9,10 +9,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/api"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
|
||||
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/v4/proto/eth/v1"
|
||||
ethpbv2 "github.com/prysmaticlabs/prysm/v4/proto/eth/v2"
|
||||
@@ -79,7 +77,7 @@ func (bs *Server) GetBlock(ctx context.Context, req *ethpbv1.BlockRequest) (*eth
|
||||
defer span.End()
|
||||
|
||||
blk, err := bs.Blocker.Block(ctx, req.BlockId)
|
||||
err = handleGetBlockError(blk, err)
|
||||
err = rpchelpers.HandleGetBlockError(blk, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -103,7 +101,7 @@ func (bs *Server) GetBlockSSZ(ctx context.Context, req *ethpbv1.BlockRequest) (*
|
||||
defer span.End()
|
||||
|
||||
blk, err := bs.Blocker.Block(ctx, req.BlockId)
|
||||
err = handleGetBlockError(blk, err)
|
||||
err = rpchelpers.HandleGetBlockError(blk, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -125,7 +123,7 @@ func (bs *Server) GetBlockV2(ctx context.Context, req *ethpbv2.BlockRequestV2) (
|
||||
defer span.End()
|
||||
|
||||
blk, err := bs.Blocker.Block(ctx, req.BlockId)
|
||||
err = handleGetBlockError(blk, err)
|
||||
err = rpchelpers.HandleGetBlockError(blk, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -193,7 +191,7 @@ func (bs *Server) GetBlockSSZV2(ctx context.Context, req *ethpbv2.BlockRequestV2
|
||||
defer span.End()
|
||||
|
||||
blk, err := bs.Blocker.Block(ctx, req.BlockId)
|
||||
err = handleGetBlockError(blk, err)
|
||||
err = rpchelpers.HandleGetBlockError(blk, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -258,7 +256,7 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR
|
||||
defer span.End()
|
||||
|
||||
blk, err := bs.Blocker.Block(ctx, req.BlockId)
|
||||
err = handleGetBlockError(blk, err)
|
||||
err = rpchelpers.HandleGetBlockError(blk, err)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -284,19 +282,6 @@ func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpbv1.BlockR
|
||||
}, nil
|
||||
}
|
||||
|
||||
func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) error {
|
||||
if invalidBlockIdErr, ok := err.(*lookup.BlockIdParseError); ok {
|
||||
return status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
|
||||
}
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
|
||||
}
|
||||
if err := blocks.BeaconBlockIsNil(blk); err != nil {
|
||||
return status.Errorf(codes.NotFound, "Could not find requested block: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBlockPhase0(blk interfaces.ReadOnlySignedBeaconBlock) (*ethpbv2.BlockResponseV2, error) {
|
||||
phase0Blk, err := blk.PbPhase0Block()
|
||||
if err != nil {
|
||||
|
||||
@@ -806,10 +806,6 @@ func (s *Server) GetBlockHeaders(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetBlockHeaders")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
helpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
rawSlot := r.URL.Query().Get("slot")
|
||||
rawParentRoot := r.URL.Query().Get("parent_root")
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package beacon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -15,7 +16,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/core"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
|
||||
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v4/crypto/bls"
|
||||
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
|
||||
@@ -228,8 +229,8 @@ func (s *Server) SubmitVoluntaryExit(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
val, err := headState.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex)
|
||||
if err != nil {
|
||||
if outOfRangeErr, ok := err.(*state_native.ValidatorIndexOutOfRangeError); ok {
|
||||
http2.HandleError(w, "Could not get exiting validator: "+outOfRangeErr.Error(), http.StatusBadRequest)
|
||||
if errors.Is(err, consensus_types.ErrOutOfBounds) {
|
||||
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusInternalServerError)
|
||||
|
||||
@@ -485,7 +485,7 @@ func TestSubmitVoluntaryExit(t *testing.T) {
|
||||
e := &http2.DefaultErrorJson{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
|
||||
assert.Equal(t, http.StatusBadRequest, e.Code)
|
||||
assert.Equal(t, true, strings.Contains(e.Message, "Could not get exiting validator"))
|
||||
assert.Equal(t, true, strings.Contains(e.Message, "Could not get validator"))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,6 @@ func (s *Server) GetValidators(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetValidators")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
helpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
stateId := mux.Vars(r)["state_id"]
|
||||
if stateId == "" {
|
||||
http2.HandleError(w, "state_id is required in URL params", http.StatusBadRequest)
|
||||
@@ -215,10 +211,6 @@ func (bs *Server) GetValidatorBalances(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetValidatorBalances")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
helpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
stateId := mux.Vars(r)["state_id"]
|
||||
if stateId == "" {
|
||||
http2.HandleError(w, "state_id is required in URL params", http.StatusBadRequest)
|
||||
|
||||
@@ -154,36 +154,6 @@ func TestGetValidators(t *testing.T) {
|
||||
assert.Equal(t, "20", resp.Data[0].Index)
|
||||
assert.Equal(t, "60", resp.Data[1].Index)
|
||||
})
|
||||
t.Run("multiple comma-separated", func(t *testing.T) {
|
||||
chainService := &chainMock.ChainService{}
|
||||
s := Server{
|
||||
Stater: &testutil.MockStater{
|
||||
BeaconState: st,
|
||||
},
|
||||
HeadFetcher: chainService,
|
||||
OptimisticModeFetcher: chainService,
|
||||
FinalizationFetcher: chainService,
|
||||
}
|
||||
|
||||
pubkey := st.PubkeyAtIndex(primitives.ValidatorIndex(20))
|
||||
hexPubkey := hexutil.Encode(pubkey[:])
|
||||
request := httptest.NewRequest(
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("http://example.com/eth/v1/beacon/states/{state_id}/validators?id=%s,60", hexPubkey),
|
||||
nil,
|
||||
)
|
||||
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetValidators(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
resp := &GetValidatorsResponse{}
|
||||
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
|
||||
require.Equal(t, 2, len(resp.Data))
|
||||
assert.Equal(t, "20", resp.Data[0].Index)
|
||||
assert.Equal(t, "60", resp.Data[1].Index)
|
||||
})
|
||||
t.Run("state ID required", func(t *testing.T) {
|
||||
s := Server{
|
||||
Stater: &testutil.MockStater{
|
||||
|
||||
@@ -108,8 +108,8 @@ func TestGetStateRoot(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetRandao(t *testing.T) {
|
||||
mixCurrent := bytesutil.PadTo([]byte("current"), 32)
|
||||
mixOld := bytesutil.PadTo([]byte("old"), 32)
|
||||
mixCurrent := bytesutil.ToBytes32([]byte("current"))
|
||||
mixOld := bytesutil.ToBytes32([]byte("old"))
|
||||
epochCurrent := primitives.Epoch(100000)
|
||||
epochOld := 100000 - params.BeaconConfig().EpochsPerHistoricalVector + 1
|
||||
|
||||
@@ -125,7 +125,7 @@ func TestGetRandao(t *testing.T) {
|
||||
headSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headSt.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
headRandao := bytesutil.PadTo([]byte("head"), 32)
|
||||
headRandao := bytesutil.ToBytes32([]byte("head"))
|
||||
require.NoError(t, headSt.UpdateRandaoMixesAtIndex(uint64(headEpoch), headRandao))
|
||||
|
||||
db := dbTest.SetupDB(t)
|
||||
@@ -143,17 +143,17 @@ func TestGetRandao(t *testing.T) {
|
||||
t.Run("no epoch requested", func(t *testing.T) {
|
||||
resp, err := server.GetRandao(ctx, ð2.RandaoRequest{StateId: []byte("head")})
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, mixCurrent, resp.Data.Randao)
|
||||
assert.DeepEqual(t, mixCurrent[:], resp.Data.Randao)
|
||||
})
|
||||
t.Run("current epoch requested", func(t *testing.T) {
|
||||
resp, err := server.GetRandao(ctx, ð2.RandaoRequest{StateId: []byte("head"), Epoch: &epochCurrent})
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, mixCurrent, resp.Data.Randao)
|
||||
assert.DeepEqual(t, mixCurrent[:], resp.Data.Randao)
|
||||
})
|
||||
t.Run("old epoch requested", func(t *testing.T) {
|
||||
resp, err := server.GetRandao(ctx, ð2.RandaoRequest{StateId: []byte("head"), Epoch: &epochOld})
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, mixOld, resp.Data.Randao)
|
||||
assert.DeepEqual(t, mixOld[:], resp.Data.Randao)
|
||||
})
|
||||
t.Run("head state below `EpochsPerHistoricalVector`", func(t *testing.T) {
|
||||
server.Stater = &testutil.MockStater{
|
||||
@@ -161,7 +161,7 @@ func TestGetRandao(t *testing.T) {
|
||||
}
|
||||
resp, err := server.GetRandao(ctx, ð2.RandaoRequest{StateId: []byte("head")})
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, headRandao, resp.Data.Randao)
|
||||
assert.DeepEqual(t, headRandao[:], resp.Data.Randao)
|
||||
})
|
||||
t.Run("epoch too old", func(t *testing.T) {
|
||||
epochTooOld := primitives.Epoch(100000 - st.RandaoMixesLength())
|
||||
|
||||
@@ -12,7 +12,6 @@ go_library(
|
||||
deps = [
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/rpc/eth/helpers:go_default_library",
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
|
||||
field_params "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
@@ -122,9 +121,7 @@ func (s *Server) Blobs(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// parseIndices filters out invalid and duplicate blob indices
|
||||
func parseIndices(url *url.URL) []uint64 {
|
||||
query := url.Query()
|
||||
helpers.NormalizeQueryValues(query)
|
||||
rawIndices := query["indices"]
|
||||
rawIndices := url.Query()["indices"]
|
||||
indices := make([]uint64, 0, field_params.MaxBlobsPerBlock)
|
||||
loop:
|
||||
for _, raw := range rawIndices {
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
func TestParseIndices(t *testing.T) {
|
||||
assert.DeepEqual(t, []uint64{1, 2, 3}, parseIndices(&url.URL{RawQuery: "indices=1,2,foo,1&indices=3,1&bar=bar"}))
|
||||
assert.DeepEqual(t, []uint64{1, 2, 3}, parseIndices(&url.URL{RawQuery: "indices=1&indices=2&indices=foo&indices=1&indices=3&bar=bar"}))
|
||||
}
|
||||
|
||||
func TestBlobs(t *testing.T) {
|
||||
|
||||
@@ -20,10 +20,13 @@ go_library(
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//beacon-chain/sync: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",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
@@ -60,6 +63,7 @@ go_test(
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
],
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -34,3 +36,16 @@ type SingleIndexedVerificationFailure struct {
|
||||
Index int `json:"index"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func HandleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) error {
|
||||
if invalidBlockIdErr, ok := err.(*lookup.BlockIdParseError); ok {
|
||||
return status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
|
||||
}
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
|
||||
}
|
||||
if err := blocks.BeaconBlockIsNil(blk); err != nil {
|
||||
return status.Errorf(codes.NotFound, "Could not find requested block: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/api/grpc"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
|
||||
@@ -95,7 +96,13 @@ func IsOptimistic(
|
||||
}
|
||||
return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(jcp.Root))
|
||||
default:
|
||||
if len(stateId) == 32 {
|
||||
if len(stateIdString) >= 2 && stateIdString[:2] == "0x" {
|
||||
id, err := hexutil.Decode(stateIdString)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return isStateRootOptimistic(ctx, id, optimisticModeFetcher, stateFetcher, chainInfo, database)
|
||||
} else if len(stateId) == 32 {
|
||||
return isStateRootOptimistic(ctx, stateId, optimisticModeFetcher, stateFetcher, chainInfo, database)
|
||||
} else {
|
||||
optimistic, err := optimisticModeFetcher.IsOptimistic(ctx)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
grpcutil "github.com/prysmaticlabs/prysm/v4/api/grpc"
|
||||
chainmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
|
||||
@@ -204,6 +205,78 @@ func TestIsOptimistic(t *testing.T) {
|
||||
assert.Equal(t, true, o)
|
||||
})
|
||||
})
|
||||
t.Run("hex", func(t *testing.T) {
|
||||
t.Run("is head and head is optimistic", func(t *testing.T) {
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
cs := &chainmock.ChainService{Optimistic: true}
|
||||
mf := &testutil.MockStater{BeaconState: st}
|
||||
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, o)
|
||||
})
|
||||
t.Run("is head and head is not optimistic", func(t *testing.T) {
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
cs := &chainmock.ChainService{Optimistic: false}
|
||||
mf := &testutil.MockStater{BeaconState: st}
|
||||
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, o)
|
||||
})
|
||||
t.Run("root is optimistic", func(t *testing.T) {
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
b.SetStateRoot(bytesutil.PadTo([]byte("root"), 32))
|
||||
db := dbtest.SetupDB(t)
|
||||
require.NoError(t, db.SaveBlock(ctx, b))
|
||||
fetcherSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
chainSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
|
||||
bRoot, err := b.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cs := &chainmock.ChainService{State: chainSt, OptimisticRoots: map[[32]byte]bool{bRoot: true}}
|
||||
mf := &testutil.MockStater{BeaconState: fetcherSt}
|
||||
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, db)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, o)
|
||||
})
|
||||
t.Run("root is not optimistic", func(t *testing.T) {
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
b.SetStateRoot(bytesutil.PadTo([]byte("root"), 32))
|
||||
db := dbtest.SetupDB(t)
|
||||
require.NoError(t, db.SaveBlock(ctx, b))
|
||||
fetcherSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
chainSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
|
||||
cs := &chainmock.ChainService{State: chainSt}
|
||||
mf := &testutil.MockStater{BeaconState: fetcherSt}
|
||||
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, db)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, o)
|
||||
})
|
||||
t.Run("no canonical blocks", func(t *testing.T) {
|
||||
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
|
||||
require.NoError(t, err)
|
||||
db := dbtest.SetupDB(t)
|
||||
require.NoError(t, db.SaveBlock(ctx, b))
|
||||
fetcherSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
chainSt, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
|
||||
cs := &chainmock.ChainService{Optimistic: false, State: chainSt, CanonicalRoots: map[[32]byte]bool{}}
|
||||
mf := &testutil.MockStater{BeaconState: fetcherSt}
|
||||
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), nil, mf, cs, db)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, o)
|
||||
})
|
||||
})
|
||||
t.Run("slot", func(t *testing.T) {
|
||||
t.Run("head is not optimistic", func(t *testing.T) {
|
||||
cs := &chainmock.ChainService{Optimistic: false}
|
||||
|
||||
@@ -15,18 +15,16 @@ go_library(
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/rpc/eth/shared:go_default_library",
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//network/http:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_wealdtech_go_bytesutil//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -7,17 +7,14 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/altair"
|
||||
coreblocks "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/lookup"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
|
||||
"github.com/prysmaticlabs/prysm/v4/runtime/version"
|
||||
@@ -31,16 +28,11 @@ func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
|
||||
blockId := segments[len(segments)-1]
|
||||
|
||||
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
|
||||
if errJson := handleGetBlockError(blk, err); errJson != nil {
|
||||
http2.WriteError(w, errJson)
|
||||
if !shared.WriteBlockFetchError(w, blk, err) {
|
||||
return
|
||||
}
|
||||
if blk.Version() == version.Phase0 {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Block rewards are not supported for Phase 0 blocks",
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Block rewards are not supported for Phase 0 blocks", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -49,114 +41,66 @@ func (s *Server) BlockRewards(w http.ResponseWriter, r *http.Request) {
|
||||
// To do this, we replay the state up to the block's slot, but before processing the block.
|
||||
st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot())
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get state: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
proposerIndex := blk.Block().ProposerIndex()
|
||||
initBalance, err := st.BalanceAtIndex(proposerIndex)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get proposer's balance: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
st, err = altair.ProcessAttestationsNoVerifySignature(r.Context(), st, blk)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get attestation rewards" + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get attestation rewards"+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
attBalance, err := st.BalanceAtIndex(proposerIndex)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get proposer's balance: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
st, err = coreblocks.ProcessAttesterSlashings(r.Context(), st, blk.Block().Body().AttesterSlashings(), validators.SlashValidator)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get attester slashing rewards: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get attester slashing rewards: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
attSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get proposer's balance: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
st, err = coreblocks.ProcessProposerSlashings(r.Context(), st, blk.Block().Body().ProposerSlashings(), validators.SlashValidator)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get proposer slashing rewards" + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get proposer slashing rewards"+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
proposerSlashingsBalance, err := st.BalanceAtIndex(proposerIndex)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get proposer's balance: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get proposer's balance: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
sa, err := blk.Block().Body().SyncAggregate()
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get sync aggregate: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get sync aggregate: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var syncCommitteeReward uint64
|
||||
_, syncCommitteeReward, err = altair.ProcessSyncAggregate(r.Context(), st, sa)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get sync aggregate rewards: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get sync aggregate rewards: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get optimistic mode info: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get optimistic mode info: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
blkRoot, err := blk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get block root: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -198,20 +142,12 @@ func (s *Server) AttestationRewards(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get optimistic mode info: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get optimistic mode info: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
blkRoot, err := st.LatestBlockHeader().HashTreeRoot()
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get block root: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -233,34 +169,21 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
|
||||
blockId := segments[len(segments)-1]
|
||||
|
||||
blk, err := s.Blocker.Block(r.Context(), []byte(blockId))
|
||||
if errJson := handleGetBlockError(blk, err); errJson != nil {
|
||||
http2.WriteError(w, errJson)
|
||||
if !shared.WriteBlockFetchError(w, blk, err) {
|
||||
return
|
||||
}
|
||||
if blk.Version() == version.Phase0 {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Sync committee rewards are not supported for Phase 0",
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Sync committee rewards are not supported for Phase 0", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
st, err := s.ReplayerBuilder.ReplayerForSlot(blk.Block().Slot()-1).ReplayToSlot(r.Context(), blk.Block().Slot())
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get state: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
sa, err := blk.Block().Body().SyncAggregate()
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get sync aggregate: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get sync aggregate: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -272,22 +195,14 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
|
||||
for i, valIdx := range valIndices {
|
||||
preProcessBals[i], err = st.BalanceAtIndex(valIdx)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get validator's balance: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get validator's balance: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, proposerReward, err := altair.ProcessSyncAggregate(r.Context(), st, sa)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get sync aggregate rewards: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get sync aggregate rewards: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -296,11 +211,7 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
|
||||
for i, valIdx := range valIndices {
|
||||
bal, err := st.BalanceAtIndex(valIdx)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get validator's balance: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get validator's balance: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
rewards[i] = int(bal - preProcessBals[i]) // lint:ignore uintcast
|
||||
@@ -311,20 +222,12 @@ func (s *Server) SyncCommitteeRewards(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
optimistic, err := s.OptimisticModeFetcher.IsOptimistic(r.Context())
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get optimistic mode info: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get optimistic mode info: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
blkRoot, err := blk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get block root: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get block root: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -347,46 +250,28 @@ func (s *Server) attRewardsState(w http.ResponseWriter, r *http.Request) (state.
|
||||
segments := strings.Split(r.URL.Path, "/")
|
||||
requestedEpoch, err := strconv.ParseUint(segments[len(segments)-1], 10, 64)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not decode epoch: " + err.Error(),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not decode epoch: "+err.Error(), http.StatusBadRequest)
|
||||
return nil, false
|
||||
}
|
||||
if primitives.Epoch(requestedEpoch) < params.BeaconConfig().AltairForkEpoch {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Attestation rewards are not supported for Phase 0",
|
||||
Code: http.StatusNotFound,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Attestation rewards are not supported for Phase 0", http.StatusNotFound)
|
||||
return nil, false
|
||||
}
|
||||
currentEpoch := uint64(slots.ToEpoch(s.TimeFetcher.CurrentSlot()))
|
||||
if requestedEpoch+1 >= currentEpoch {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Code: http.StatusNotFound,
|
||||
Message: "Attestation rewards are available after two epoch transitions to ensure all attestations have a chance of inclusion",
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w,
|
||||
"Attestation rewards are available after two epoch transitions to ensure all attestations have a chance of inclusion",
|
||||
http.StatusNotFound)
|
||||
return nil, false
|
||||
}
|
||||
nextEpochEnd, err := slots.EpochEnd(primitives.Epoch(requestedEpoch + 1))
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get next epoch's ending slot: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get next epoch's ending slot: "+err.Error(), http.StatusInternalServerError)
|
||||
return nil, false
|
||||
}
|
||||
st, err := s.Stater.StateBySlot(r.Context(), nextEpochEnd)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get state for epoch's starting slot: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get state for epoch's starting slot: "+err.Error(), http.StatusInternalServerError)
|
||||
return nil, false
|
||||
}
|
||||
return st, true
|
||||
@@ -399,20 +284,12 @@ func attRewardsBalancesAndVals(
|
||||
) (*precompute.Balance, []*precompute.Validator, []primitives.ValidatorIndex, bool) {
|
||||
allVals, bal, err := altair.InitializePrecomputeValidators(r.Context(), st)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not initialize precompute validators: " + err.Error(),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not initialize precompute validators: "+err.Error(), http.StatusBadRequest)
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
allVals, bal, err = altair.ProcessEpochParticipation(r.Context(), st, bal, allVals)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not process epoch participation: " + err.Error(),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not process epoch participation: "+err.Error(), http.StatusBadRequest)
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
valIndices, ok := requestedValIndices(w, r, st, allVals)
|
||||
@@ -463,11 +340,7 @@ func idealAttRewards(
|
||||
}
|
||||
deltas, err := altair.AttestationsDelta(st, bal, idealVals)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get attestations delta: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get attestations delta: "+err.Error(), http.StatusInternalServerError)
|
||||
return nil, false
|
||||
}
|
||||
for i, d := range deltas {
|
||||
@@ -499,11 +372,7 @@ func totalAttRewards(
|
||||
}
|
||||
deltas, err := altair.AttestationsDelta(st, bal, vals)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get attestations delta: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get attestations delta: "+err.Error(), http.StatusInternalServerError)
|
||||
return nil, false
|
||||
}
|
||||
for i, d := range deltas {
|
||||
@@ -529,11 +398,7 @@ func syncRewardsVals(
|
||||
) ([]*precompute.Validator, []primitives.ValidatorIndex, bool) {
|
||||
allVals, _, err := altair.InitializePrecomputeValidators(r.Context(), st)
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not initialize precompute validators: " + err.Error(),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not initialize precompute validators: "+err.Error(), http.StatusBadRequest)
|
||||
return nil, nil, false
|
||||
}
|
||||
valIndices, ok := requestedValIndices(w, r, st, allVals)
|
||||
@@ -543,22 +408,14 @@ func syncRewardsVals(
|
||||
|
||||
sc, err := st.CurrentSyncCommittee()
|
||||
if err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not get current sync committee: " + err.Error(),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not get current sync committee: "+err.Error(), http.StatusBadRequest)
|
||||
return nil, nil, false
|
||||
}
|
||||
allScIndices := make([]primitives.ValidatorIndex, len(sc.Pubkeys))
|
||||
for i, pk := range sc.Pubkeys {
|
||||
valIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(pk))
|
||||
if !ok {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: fmt.Sprintf("No validator index found for pubkey %#x", pk),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, fmt.Sprintf("No validator index found for pubkey %#x", pk), http.StatusBadRequest)
|
||||
return nil, nil, false
|
||||
}
|
||||
allScIndices[i] = valIdx
|
||||
@@ -583,11 +440,7 @@ func requestedValIndices(w http.ResponseWriter, r *http.Request, st state.Beacon
|
||||
var rawValIds []string
|
||||
if r.Body != http.NoBody {
|
||||
if err := json.NewDecoder(r.Body).Decode(&rawValIds); err != nil {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: "Could not decode validators: " + err.Error(),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, "Could not decode validators: "+err.Error(), http.StatusBadRequest)
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
@@ -597,30 +450,18 @@ func requestedValIndices(w http.ResponseWriter, r *http.Request, st state.Beacon
|
||||
if err != nil {
|
||||
pubkey, err := bytesutil.FromHexString(v)
|
||||
if err != nil || len(pubkey) != fieldparams.BLSPubkeyLength {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: fmt.Sprintf("%s is not a validator index or pubkey", v),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, fmt.Sprintf("%s is not a validator index or pubkey", v), http.StatusBadRequest)
|
||||
return nil, false
|
||||
}
|
||||
var ok bool
|
||||
valIndices[i], ok = st.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubkey))
|
||||
if !ok {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: fmt.Sprintf("No validator index found for pubkey %#x", pubkey),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, fmt.Sprintf("No validator index found for pubkey %#x", pubkey), http.StatusBadRequest)
|
||||
return nil, false
|
||||
}
|
||||
} else {
|
||||
if index >= uint64(st.NumValidators()) {
|
||||
errJson := &http2.DefaultErrorJson{
|
||||
Message: fmt.Sprintf("Validator index %d is too large. Maximum allowed index is %d", index, st.NumValidators()-1),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
http2.WriteError(w, errJson)
|
||||
http2.HandleError(w, fmt.Sprintf("Validator index %d is too large. Maximum allowed index is %d", index, st.NumValidators()-1), http.StatusBadRequest)
|
||||
return nil, false
|
||||
}
|
||||
valIndices[i] = primitives.ValidatorIndex(index)
|
||||
@@ -635,25 +476,3 @@ func requestedValIndices(w http.ResponseWriter, r *http.Request, st state.Beacon
|
||||
|
||||
return valIndices, true
|
||||
}
|
||||
|
||||
func handleGetBlockError(blk interfaces.ReadOnlySignedBeaconBlock, err error) *http2.DefaultErrorJson {
|
||||
if errors.Is(err, lookup.BlockIdParseError{}) {
|
||||
return &http2.DefaultErrorJson{
|
||||
Message: "Invalid block ID: " + err.Error(),
|
||||
Code: http.StatusBadRequest,
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return &http2.DefaultErrorJson{
|
||||
Message: "Could not get block from block ID: " + err.Error(),
|
||||
Code: http.StatusInternalServerError,
|
||||
}
|
||||
}
|
||||
if err := blocks.BeaconBlockIsNil(blk); err != nil {
|
||||
return &http2.DefaultErrorJson{
|
||||
Message: "Could not find requested block: " + err.Error(),
|
||||
Code: http.StatusNotFound,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -29,10 +29,10 @@ go_library(
|
||||
"//beacon-chain/rpc/eth/shared:go_default_library",
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//beacon-chain/sync:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
|
||||
@@ -24,9 +24,9 @@ import (
|
||||
rpchelpers "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
validator2 "github.com/prysmaticlabs/prysm/v4/consensus-types/validator"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
@@ -44,10 +44,6 @@ func (s *Server) GetAggregateAttestation(w http.ResponseWriter, r *http.Request)
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.GetAggregateAttestation")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
rpchelpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
attDataRoot := r.URL.Query().Get("attestation_data_root")
|
||||
attDataRootBytes, valid := shared.ValidateHex(w, "Attestation data root", attDataRoot, fieldparams.RootLength)
|
||||
if !valid {
|
||||
@@ -343,8 +339,8 @@ func (s *Server) SubmitBeaconCommitteeSubscription(w http.ResponseWriter, r *htt
|
||||
subscriptions[i] = consensusItem
|
||||
val, err := st.ValidatorAtIndexReadOnly(consensusItem.ValidatorIndex)
|
||||
if err != nil {
|
||||
if outOfRangeErr, ok := err.(*state_native.ValidatorIndexOutOfRangeError); ok {
|
||||
http2.HandleError(w, "Could not get validator: "+outOfRangeErr.Error(), http.StatusBadRequest)
|
||||
if errors.Is(err, consensus_types.ErrOutOfBounds) {
|
||||
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
http2.HandleError(w, "Could not get validator: "+err.Error(), http.StatusInternalServerError)
|
||||
@@ -402,10 +398,6 @@ func (s *Server) GetAttestationData(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.GetAttestationData")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
rpchelpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
if shared.IsSyncing(ctx, w, s.SyncChecker, s.HeadFetcher, s.TimeFetcher, s.OptimisticModeFetcher) {
|
||||
return
|
||||
}
|
||||
@@ -458,10 +450,6 @@ func (s *Server) ProduceSyncCommitteeContribution(w http.ResponseWriter, r *http
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.ProduceSyncCommitteeContribution")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
rpchelpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
subIndex := r.URL.Query().Get("subcommittee_index")
|
||||
index, valid := shared.ValidateUint(w, "Subcommittee Index", subIndex)
|
||||
if !valid {
|
||||
@@ -842,6 +830,7 @@ func (s *Server) GetProposerDuties(w http.ResponseWriter, r *http.Request) {
|
||||
pubkey48 := val.PublicKey()
|
||||
pubkey := pubkey48[:]
|
||||
for _, slot := range proposalSlots {
|
||||
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, index, [8]byte{} /* payloadID */, [32]byte{} /* head root */)
|
||||
duties = append(duties, &ProposerDuty{
|
||||
Pubkey: hexutil.Encode(pubkey),
|
||||
ValidatorIndex: strconv.FormatUint(uint64(index), 10),
|
||||
@@ -850,6 +839,8 @@ func (s *Server) GetProposerDuties(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
s.ProposerSlotIndexCache.PrunePayloadIDs(epochStartSlot)
|
||||
|
||||
dependentRoot, err := proposalDependentRoot(st, requestedEpoch)
|
||||
if err != nil {
|
||||
http2.HandleError(w, "Could not get dependent root: "+err.Error(), http.StatusInternalServerError)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/api"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
@@ -32,10 +31,6 @@ func (s *Server) ProduceBlockV3(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.ProduceBlockV3")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
helpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
if shared.IsSyncing(r.Context(), w, s.SyncChecker, s.HeadFetcher, s.TimeFetcher, s.OptimisticModeFetcher) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1856,6 +1856,9 @@ func TestGetProposerDuties(t *testing.T) {
|
||||
expectedDuty = duty
|
||||
}
|
||||
}
|
||||
vid, _, has := s.ProposerSlotIndexCache.GetProposerPayloadIDs(11, [32]byte{})
|
||||
require.Equal(t, true, has)
|
||||
require.Equal(t, primitives.ValidatorIndex(12289), vid)
|
||||
require.NotNil(t, expectedDuty, "Expected duty for slot 11 not found")
|
||||
assert.Equal(t, "12289", expectedDuty.ValidatorIndex)
|
||||
assert.Equal(t, hexutil.Encode(pubKeys[12289]), expectedDuty.Pubkey)
|
||||
@@ -1895,10 +1898,52 @@ func TestGetProposerDuties(t *testing.T) {
|
||||
expectedDuty = duty
|
||||
}
|
||||
}
|
||||
vid, _, has := s.ProposerSlotIndexCache.GetProposerPayloadIDs(43, [32]byte{})
|
||||
require.Equal(t, true, has)
|
||||
require.Equal(t, primitives.ValidatorIndex(1360), vid)
|
||||
require.NotNil(t, expectedDuty, "Expected duty for slot 43 not found")
|
||||
assert.Equal(t, "1360", expectedDuty.ValidatorIndex)
|
||||
assert.Equal(t, hexutil.Encode(pubKeys[1360]), expectedDuty.Pubkey)
|
||||
})
|
||||
t.Run("prune payload ID cache", func(t *testing.T) {
|
||||
bs, err := transition.GenesisBeaconState(context.Background(), deposits, 0, eth1Data)
|
||||
require.NoError(t, err, "Could not set up genesis state")
|
||||
require.NoError(t, bs.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
require.NoError(t, bs.SetBlockRoots(roots))
|
||||
chainSlot := params.BeaconConfig().SlotsPerEpoch
|
||||
chain := &mockChain.ChainService{
|
||||
State: bs, Root: genesisRoot[:], Slot: &chainSlot,
|
||||
}
|
||||
s := &Server{
|
||||
Stater: &testutil.MockStater{StatesBySlot: map[primitives.Slot]state.BeaconState{params.BeaconConfig().SlotsPerEpoch: bs}},
|
||||
HeadFetcher: chain,
|
||||
TimeFetcher: chain,
|
||||
OptimisticModeFetcher: chain,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
|
||||
}
|
||||
|
||||
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(1, 1, [8]byte{1}, [32]byte{2})
|
||||
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(31, 2, [8]byte{2}, [32]byte{3})
|
||||
s.ProposerSlotIndexCache.SetProposerAndPayloadIDs(32, 4309, [8]byte{3}, [32]byte{4})
|
||||
|
||||
request := httptest.NewRequest(http.MethodGet, "http://www.example.com/eth/v1/validator/duties/proposer/{epoch}", nil)
|
||||
request = mux.SetURLVars(request, map[string]string{"epoch": "1"})
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetProposerDuties(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
vid, _, has := s.ProposerSlotIndexCache.GetProposerPayloadIDs(1, [32]byte{})
|
||||
require.Equal(t, false, has)
|
||||
require.Equal(t, primitives.ValidatorIndex(0), vid)
|
||||
vid, _, has = s.ProposerSlotIndexCache.GetProposerPayloadIDs(2, [32]byte{})
|
||||
require.Equal(t, false, has)
|
||||
require.Equal(t, primitives.ValidatorIndex(0), vid)
|
||||
vid, _, has = s.ProposerSlotIndexCache.GetProposerPayloadIDs(32, [32]byte{})
|
||||
require.Equal(t, true, has)
|
||||
require.Equal(t, primitives.ValidatorIndex(10565), vid)
|
||||
})
|
||||
t.Run("epoch out of bounds", func(t *testing.T) {
|
||||
bs, err := transition.GenesisBeaconState(context.Background(), deposits, 0, eth1Data)
|
||||
require.NoError(t, err, "Could not set up genesis state")
|
||||
|
||||
@@ -19,6 +19,7 @@ go_library(
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
|
||||
@@ -3,7 +3,9 @@ package lookup
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
|
||||
@@ -47,6 +49,7 @@ type BeaconDbBlocker struct {
|
||||
// - "justified"
|
||||
// - <slot>
|
||||
// - <hex encoded block root with '0x' prefix>
|
||||
// - <block root>
|
||||
func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
|
||||
var err error
|
||||
var blk interfaces.ReadOnlySignedBeaconBlock
|
||||
@@ -69,7 +72,18 @@ func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.Read
|
||||
return nil, errors.Wrap(err, "could not retrieve genesis block")
|
||||
}
|
||||
default:
|
||||
if len(id) == 32 {
|
||||
stringId := strings.ToLower(string(id))
|
||||
if len(stringId) >= 2 && stringId[:2] == "0x" {
|
||||
decoded, err := hexutil.Decode(string(id))
|
||||
if err != nil {
|
||||
e := NewBlockIdParseError(err)
|
||||
return nil, &e
|
||||
}
|
||||
blk, err = p.BeaconDB.Block(ctx, bytesutil.ToBytes32(decoded))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not retrieve block")
|
||||
}
|
||||
} else if len(id) == 32 {
|
||||
blk, err = p.BeaconDB.Block(ctx, bytesutil.ToBytes32(id))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not retrieve block")
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
|
||||
dbtesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil"
|
||||
@@ -116,6 +117,11 @@ func TestGetBlock(t *testing.T) {
|
||||
blockID: bytesutil.PadTo([]byte("hi there"), 32),
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "hex",
|
||||
blockID: []byte(hexutil.Encode(blkContainers[20].BlockRoot)),
|
||||
want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
|
||||
},
|
||||
{
|
||||
name: "no block",
|
||||
blockID: []byte("105"),
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
|
||||
@@ -94,6 +95,7 @@ type BeaconDbStater struct {
|
||||
// - "justified"
|
||||
// - <slot>
|
||||
// - <hex encoded state root with '0x' prefix>
|
||||
// - <state root>
|
||||
func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.BeaconState, error) {
|
||||
var (
|
||||
s state.BeaconState
|
||||
@@ -141,7 +143,15 @@ func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.Beaco
|
||||
return nil, errors.Wrap(err, "could not get justified state")
|
||||
}
|
||||
default:
|
||||
if len(stateId) == 32 {
|
||||
stringId := strings.ToLower(string(stateId))
|
||||
if len(stringId) >= 2 && stringId[:2] == "0x" {
|
||||
decoded, parseErr := hexutil.Decode(string(stateId))
|
||||
if parseErr != nil {
|
||||
e := NewStateIdParseError(parseErr)
|
||||
return nil, &e
|
||||
}
|
||||
s, err = p.stateByRoot(ctx, decoded)
|
||||
} else if len(stateId) == 32 {
|
||||
s, err = p.stateByRoot(ctx, stateId)
|
||||
} else {
|
||||
slotNumber, parseErr := strconv.ParseUint(stateIdString, 10, 64)
|
||||
|
||||
@@ -140,7 +140,26 @@ func TestGetState(t *testing.T) {
|
||||
assert.DeepEqual(t, stateRoot, sRoot)
|
||||
})
|
||||
|
||||
t.Run("hex_root", func(t *testing.T) {
|
||||
t.Run("hex", func(t *testing.T) {
|
||||
hex := "0x" + strings.Repeat("0", 63) + "1"
|
||||
root, err := hexutil.Decode(hex)
|
||||
require.NoError(t, err)
|
||||
stateGen := mockstategen.NewMockService()
|
||||
stateGen.StatesByRoot[bytesutil.ToBytes32(root)] = newBeaconState
|
||||
|
||||
p := BeaconDbStater{
|
||||
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
|
||||
StateGenService: stateGen,
|
||||
}
|
||||
|
||||
s, err := p.State(ctx, []byte(hex))
|
||||
require.NoError(t, err)
|
||||
sRoot, err := s.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, stateRoot, sRoot)
|
||||
})
|
||||
|
||||
t.Run("root", func(t *testing.T) {
|
||||
stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1")
|
||||
require.NoError(t, err)
|
||||
stateGen := mockstategen.NewMockService()
|
||||
@@ -158,7 +177,7 @@ func TestGetState(t *testing.T) {
|
||||
assert.DeepEqual(t, stateRoot, sRoot)
|
||||
})
|
||||
|
||||
t.Run("hex_root_not_found", func(t *testing.T) {
|
||||
t.Run("root not found", func(t *testing.T) {
|
||||
p := BeaconDbStater{
|
||||
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
|
||||
}
|
||||
|
||||
@@ -601,10 +601,6 @@ func (bs *Server) GetValidatorQueue(
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get active validator count: %v", err)
|
||||
}
|
||||
churnLimit, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not compute churn limit: %v", err)
|
||||
}
|
||||
|
||||
exitQueueEpoch := primitives.Epoch(0)
|
||||
for _, i := range exitEpochs {
|
||||
@@ -619,7 +615,8 @@ func (bs *Server) GetValidatorQueue(
|
||||
}
|
||||
}
|
||||
// Prevent churn limit from causing index out of bound issues.
|
||||
if churnLimit < exitQueueChurn {
|
||||
exitChurnLimit := helpers.ValidatorExitChurnLimit(activeValidatorCount)
|
||||
if exitChurnLimit < exitQueueChurn {
|
||||
// If we are above the churn limit, we simply increase the churn by one.
|
||||
exitQueueEpoch++
|
||||
}
|
||||
@@ -645,6 +642,10 @@ func (bs *Server) GetValidatorQueue(
|
||||
exitQueueKeys[i] = vals[idx].PublicKey
|
||||
}
|
||||
|
||||
churnLimit := helpers.ValidatorActivationChurnLimit(activeValidatorCount)
|
||||
if headState.Version() >= version.Deneb {
|
||||
churnLimit = helpers.ValidatorActivationChurnLimitDeneb(activeValidatorCount)
|
||||
}
|
||||
return ðpb.ValidatorQueue{
|
||||
ChurnLimit: churnLimit,
|
||||
ActivationPublicKeys: activationQueueKeys,
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/runtime/version"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -422,10 +423,11 @@ func (is *infostream) calculateActivationTimeForPendingValidators(res []*ethpb.V
|
||||
|
||||
// Loop over epochs, roughly simulating progression.
|
||||
for curEpoch := epoch + 1; len(sortedIndices) > 0 && len(pendingValidators) > 0; curEpoch++ {
|
||||
toProcess, err := helpers.ValidatorChurnLimit(numAttestingValidators)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not determine validator churn limit")
|
||||
toProcess := helpers.ValidatorActivationChurnLimit(numAttestingValidators)
|
||||
if headState.Version() >= version.Deneb {
|
||||
toProcess = helpers.ValidatorActivationChurnLimitDeneb(numAttestingValidators)
|
||||
}
|
||||
|
||||
if toProcess > uint64(len(sortedIndices)) {
|
||||
toProcess = uint64(len(sortedIndices))
|
||||
}
|
||||
|
||||
@@ -1370,8 +1370,7 @@ func TestServer_GetValidatorQueue_PendingActivation(t *testing.T) {
|
||||
}
|
||||
activeValidatorCount, err := helpers.ActiveValidatorCount(context.Background(), headState, coreTime.CurrentEpoch(headState))
|
||||
require.NoError(t, err)
|
||||
wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
require.NoError(t, err)
|
||||
wantChurn := helpers.ValidatorActivationChurnLimit(activeValidatorCount)
|
||||
assert.Equal(t, wantChurn, res.ChurnLimit)
|
||||
assert.DeepEqual(t, wanted, res.ActivationPublicKeys)
|
||||
wantedActiveIndices := []primitives.ValidatorIndex{2, 1, 0}
|
||||
@@ -1412,8 +1411,7 @@ func TestServer_GetValidatorQueue_ExitedValidatorLeavesQueue(t *testing.T) {
|
||||
}
|
||||
activeValidatorCount, err := helpers.ActiveValidatorCount(context.Background(), headState, coreTime.CurrentEpoch(headState))
|
||||
require.NoError(t, err)
|
||||
wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
require.NoError(t, err)
|
||||
wantChurn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
|
||||
assert.Equal(t, wantChurn, res.ChurnLimit)
|
||||
assert.DeepEqual(t, wanted, res.ExitPublicKeys)
|
||||
wantedExitIndices := []primitives.ValidatorIndex{1}
|
||||
@@ -1472,8 +1470,7 @@ func TestServer_GetValidatorQueue_PendingExit(t *testing.T) {
|
||||
}
|
||||
activeValidatorCount, err := helpers.ActiveValidatorCount(context.Background(), headState, coreTime.CurrentEpoch(headState))
|
||||
require.NoError(t, err)
|
||||
wantChurn, err := helpers.ValidatorChurnLimit(activeValidatorCount)
|
||||
require.NoError(t, err)
|
||||
wantChurn := helpers.ValidatorExitChurnLimit(activeValidatorCount)
|
||||
assert.Equal(t, wantChurn, res.ChurnLimit)
|
||||
assert.DeepEqual(t, wanted, res.ExitPublicKeys)
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"attestations.go",
|
||||
"blocks.go",
|
||||
"server.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/prysm/v1alpha1/slasher",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/slasher:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"attestations_test.go",
|
||||
"server_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/slasher/mock:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,43 +0,0 @@
|
||||
package slasher
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// IsSlashableAttestation returns an attester slashing if an input
|
||||
// attestation is found to be slashable.
|
||||
func (s *Server) IsSlashableAttestation(
|
||||
ctx context.Context, req *ethpb.IndexedAttestation,
|
||||
) (*ethpb.AttesterSlashingResponse, error) {
|
||||
attesterSlashings, err := s.SlashingChecker.IsSlashableAttestation(ctx, req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not determine if attestation is slashable: %v", err)
|
||||
}
|
||||
if len(attesterSlashings) > 0 {
|
||||
return ðpb.AttesterSlashingResponse{
|
||||
AttesterSlashings: attesterSlashings,
|
||||
}, nil
|
||||
}
|
||||
return ðpb.AttesterSlashingResponse{}, nil
|
||||
}
|
||||
|
||||
// HighestAttestations returns the highest source and target epochs attested for
|
||||
// validator indices that have been observed by slasher.
|
||||
func (s *Server) HighestAttestations(
|
||||
ctx context.Context, req *ethpb.HighestAttestationRequest,
|
||||
) (*ethpb.HighestAttestationResponse, error) {
|
||||
valIndices := make([]primitives.ValidatorIndex, len(req.ValidatorIndices))
|
||||
for i, valIdx := range req.ValidatorIndices {
|
||||
valIndices[i] = primitives.ValidatorIndex(valIdx)
|
||||
}
|
||||
atts, err := s.SlashingChecker.HighestAttestations(ctx, valIndices)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get highest attestations: %v", err)
|
||||
}
|
||||
return ðpb.HighestAttestationResponse{Attestations: atts}, nil
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package slasher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
)
|
||||
|
||||
func TestServer_HighestAttestations(t *testing.T) {
|
||||
highestAtts := map[primitives.ValidatorIndex]*ethpb.HighestAttestation{
|
||||
0: {
|
||||
ValidatorIndex: 0,
|
||||
HighestSourceEpoch: 1,
|
||||
HighestTargetEpoch: 2,
|
||||
},
|
||||
1: {
|
||||
ValidatorIndex: 1,
|
||||
HighestSourceEpoch: 2,
|
||||
HighestTargetEpoch: 3,
|
||||
},
|
||||
}
|
||||
mockSlasher := &mock.MockSlashingChecker{
|
||||
HighestAtts: highestAtts,
|
||||
}
|
||||
s := Server{SlashingChecker: mockSlasher}
|
||||
ctx := context.Background()
|
||||
t.Run("single index found", func(t *testing.T) {
|
||||
resp, err := s.HighestAttestations(ctx, ðpb.HighestAttestationRequest{
|
||||
ValidatorIndices: []uint64{0},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(resp.Attestations))
|
||||
require.DeepEqual(t, highestAtts[0], resp.Attestations[0])
|
||||
})
|
||||
t.Run("single index not found", func(t *testing.T) {
|
||||
resp, err := s.HighestAttestations(ctx, ðpb.HighestAttestationRequest{
|
||||
ValidatorIndices: []uint64{3},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(resp.Attestations))
|
||||
})
|
||||
t.Run("multiple indices all found", func(t *testing.T) {
|
||||
resp, err := s.HighestAttestations(ctx, ðpb.HighestAttestationRequest{
|
||||
ValidatorIndices: []uint64{0, 1},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(resp.Attestations))
|
||||
require.DeepEqual(t, highestAtts[0], resp.Attestations[0])
|
||||
require.DeepEqual(t, highestAtts[1], resp.Attestations[1])
|
||||
})
|
||||
t.Run("multiple indices some not found", func(t *testing.T) {
|
||||
resp, err := s.HighestAttestations(ctx, ðpb.HighestAttestationRequest{
|
||||
ValidatorIndices: []uint64{0, 3},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(resp.Attestations))
|
||||
require.DeepEqual(t, highestAtts[0], resp.Attestations[0])
|
||||
})
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package slasher
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// IsSlashableBlock returns a proposer slashing if an input
|
||||
// signed beacon block header is found to be slashable.
|
||||
func (s *Server) IsSlashableBlock(
|
||||
ctx context.Context, req *ethpb.SignedBeaconBlockHeader,
|
||||
) (*ethpb.ProposerSlashingResponse, error) {
|
||||
proposerSlashing, err := s.SlashingChecker.IsSlashableBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not determine if block is slashable: %v", err)
|
||||
}
|
||||
if proposerSlashing == nil {
|
||||
return ðpb.ProposerSlashingResponse{
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{},
|
||||
}, nil
|
||||
}
|
||||
return ðpb.ProposerSlashingResponse{
|
||||
ProposerSlashings: []*ethpb.ProposerSlashing{proposerSlashing},
|
||||
}, nil
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// Package slasher defines a gRPC server implementation of a slasher service
|
||||
// which allows for checking if attestations or blocks are slashable.
|
||||
package slasher
|
||||
|
||||
import (
|
||||
slasherservice "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher"
|
||||
)
|
||||
|
||||
// Server defines a server implementation of the gRPC slasher service.
|
||||
type Server struct {
|
||||
SlashingChecker slasherservice.SlashingChecker
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package slasher
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
)
|
||||
|
||||
func TestServer_IsSlashableAttestation_SlashingFound(t *testing.T) {
|
||||
mockSlasher := &mock.MockSlashingChecker{
|
||||
AttesterSlashingFound: true,
|
||||
}
|
||||
s := Server{SlashingChecker: mockSlasher}
|
||||
ctx := context.Background()
|
||||
slashing, err := s.IsSlashableAttestation(ctx, ðpb.IndexedAttestation{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, len(slashing.AttesterSlashings) > 0)
|
||||
}
|
||||
|
||||
func TestServer_IsSlashableAttestation_SlashingNotFound(t *testing.T) {
|
||||
mockSlasher := &mock.MockSlashingChecker{
|
||||
AttesterSlashingFound: false,
|
||||
}
|
||||
s := Server{SlashingChecker: mockSlasher}
|
||||
ctx := context.Background()
|
||||
slashing, err := s.IsSlashableAttestation(ctx, ðpb.IndexedAttestation{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, len(slashing.AttesterSlashings) == 0)
|
||||
}
|
||||
|
||||
func TestServer_IsSlashableBlock_SlashingFound(t *testing.T) {
|
||||
mockSlasher := &mock.MockSlashingChecker{
|
||||
ProposerSlashingFound: true,
|
||||
}
|
||||
s := Server{SlashingChecker: mockSlasher}
|
||||
ctx := context.Background()
|
||||
slashing, err := s.IsSlashableBlock(ctx, ðpb.SignedBeaconBlockHeader{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, len(slashing.ProposerSlashings) > 0)
|
||||
}
|
||||
|
||||
func TestServer_IsSlashableBlock_SlashingNotFound(t *testing.T) {
|
||||
mockSlasher := &mock.MockSlashingChecker{
|
||||
ProposerSlashingFound: false,
|
||||
}
|
||||
s := Server{SlashingChecker: mockSlasher}
|
||||
ctx := context.Background()
|
||||
slashing, err := s.IsSlashableBlock(ctx, ðpb.SignedBeaconBlockHeader{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, len(slashing.ProposerSlashings) == 0)
|
||||
}
|
||||
@@ -191,8 +191,6 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
|
||||
for _, slot := range nextProposerIndexToSlots[idx] {
|
||||
vs.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, idx, [8]byte{} /* payloadID */, [32]byte{} /* head root */)
|
||||
}
|
||||
// Prune payload ID cache for any slots before request slot.
|
||||
vs.ProposerSlotIndexCache.PrunePayloadIDs(epochStartSlot)
|
||||
} else {
|
||||
// If the validator isn't in the beacon state, try finding their deposit to determine their status.
|
||||
// We don't need the lastActiveValidatorFn because we don't use the response in this.
|
||||
@@ -237,6 +235,8 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
|
||||
core.AssignValidatorToSubnetProto(pubKey, assignment.Status)
|
||||
core.AssignValidatorToSubnetProto(pubKey, nextAssignment.Status)
|
||||
}
|
||||
// Prune payload ID cache for any slots before request slot.
|
||||
vs.ProposerSlotIndexCache.PrunePayloadIDs(epochStartSlot)
|
||||
|
||||
return ðpb.DutiesResponse{
|
||||
Duties: validatorAssignments,
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/blocks"
|
||||
@@ -109,70 +108,9 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
||||
|
||||
var blobBundle *enginev1.BlobsBundle
|
||||
var blindBlobBundle *enginev1.BlindedBlobsBundle
|
||||
if features.Get().BuildBlockParallel {
|
||||
blindBlobBundle, blobBundle, err = vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not build block in parallel")
|
||||
}
|
||||
} else {
|
||||
// Set eth1 data.
|
||||
eth1Data, err := vs.eth1DataMajorityVote(ctx, head)
|
||||
if err != nil {
|
||||
eth1Data = ðpb.Eth1Data{DepositRoot: params.BeaconConfig().ZeroHash[:], BlockHash: params.BeaconConfig().ZeroHash[:]}
|
||||
log.WithError(err).Error("Could not get eth1data")
|
||||
}
|
||||
sBlk.SetEth1Data(eth1Data)
|
||||
|
||||
// Set deposit and attestation.
|
||||
deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data) // TODO: split attestations and deposits
|
||||
if err != nil {
|
||||
sBlk.SetDeposits([]*ethpb.Deposit{})
|
||||
sBlk.SetAttestations([]*ethpb.Attestation{})
|
||||
log.WithError(err).Error("Could not pack deposits and attestations")
|
||||
} else {
|
||||
sBlk.SetDeposits(deposits)
|
||||
sBlk.SetAttestations(atts)
|
||||
}
|
||||
|
||||
// Set slashings.
|
||||
validProposerSlashings, validAttSlashings := vs.getSlashings(ctx, head)
|
||||
sBlk.SetProposerSlashings(validProposerSlashings)
|
||||
sBlk.SetAttesterSlashings(validAttSlashings)
|
||||
|
||||
// Set exits.
|
||||
sBlk.SetVoluntaryExits(vs.getExits(head, req.Slot))
|
||||
|
||||
// Set sync aggregate. New in Altair.
|
||||
vs.setSyncAggregate(ctx, sBlk)
|
||||
|
||||
// Get local and builder (if enabled) payloads. Set execution data. New in Bellatrix.
|
||||
var overrideBuilder bool
|
||||
var localPayload interfaces.ExecutionData
|
||||
localPayload, blobBundle, overrideBuilder, err = vs.getLocalPayloadAndBlobs(ctx, sBlk.Block(), head)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get local payload: %v", err)
|
||||
}
|
||||
// There's no reason to try to get a builder bid if local override is true.
|
||||
var builderPayload interfaces.ExecutionData
|
||||
|
||||
overrideBuilder = req.SkipMevBoost || overrideBuilder // Skip using mev-boost if requested by the caller.
|
||||
if !overrideBuilder {
|
||||
builderPayload, blindBlobBundle, err = vs.getBuilderPayloadAndBlobs(ctx, sBlk.Block().Slot(), sBlk.Block().ProposerIndex())
|
||||
if err != nil {
|
||||
builderGetPayloadMissCount.Inc()
|
||||
log.WithError(err).Error("Could not get builder payload")
|
||||
}
|
||||
}
|
||||
if err := setExecutionData(ctx, sBlk, localPayload, builderPayload); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not set execution data: %v", err)
|
||||
}
|
||||
|
||||
// Set bls to execution change. New in Capella.
|
||||
vs.setBlsToExecData(sBlk, head)
|
||||
|
||||
if err := setKzgCommitments(sBlk, blobBundle, blindBlobBundle); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not set kzg commitment: %v", err)
|
||||
}
|
||||
blindBlobBundle, blobBundle, err = vs.BuildBlockParallel(ctx, sBlk, head, req.SkipMevBoost)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not build block in parallel")
|
||||
}
|
||||
|
||||
sr, err := vs.computeStateRoot(ctx, sBlk)
|
||||
|
||||
@@ -63,10 +63,6 @@ func (vs *Server) GetValidatorCount(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetValidatorCount")
|
||||
defer span.End()
|
||||
|
||||
query := r.URL.Query()
|
||||
helpers.NormalizeQueryValues(query)
|
||||
r.URL.RawQuery = query.Encode()
|
||||
|
||||
stateID := mux.Vars(r)["state_id"]
|
||||
|
||||
isOptimistic, err := helpers.IsOptimistic(ctx, []byte(stateID), vs.OptimisticModeFetcher, vs.Stater, vs.ChainInfoFetcher, vs.BeaconDB)
|
||||
|
||||
@@ -74,7 +74,6 @@ go_test(
|
||||
"//beacon-chain/db/testing:go_default_library",
|
||||
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
|
||||
"//beacon-chain/operations/slashings/mock:go_default_library",
|
||||
"//beacon-chain/slasher/mock:go_default_library",
|
||||
"//beacon-chain/slasher/types:go_default_library",
|
||||
"//beacon-chain/startup:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["mock_slashing_checker.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,73 +0,0 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
type MockSlashingChecker struct {
|
||||
AttesterSlashingFound bool
|
||||
ProposerSlashingFound bool
|
||||
HighestAtts map[primitives.ValidatorIndex]*ethpb.HighestAttestation
|
||||
}
|
||||
|
||||
func (s *MockSlashingChecker) HighestAttestations(
|
||||
_ context.Context, indices []primitives.ValidatorIndex,
|
||||
) ([]*ethpb.HighestAttestation, error) {
|
||||
atts := make([]*ethpb.HighestAttestation, 0, len(indices))
|
||||
for _, valIdx := range indices {
|
||||
att, ok := s.HighestAtts[valIdx]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
atts = append(atts, att)
|
||||
}
|
||||
return atts, nil
|
||||
}
|
||||
|
||||
func (s *MockSlashingChecker) IsSlashableBlock(_ context.Context, _ *ethpb.SignedBeaconBlockHeader) (*ethpb.ProposerSlashing, error) {
|
||||
if s.ProposerSlashingFound {
|
||||
return ðpb.ProposerSlashing{
|
||||
Header_1: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 0,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: params.BeaconConfig().ZeroHash[:],
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
BodyRoot: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
},
|
||||
Header_2: ðpb.SignedBeaconBlockHeader{
|
||||
Header: ðpb.BeaconBlockHeader{
|
||||
Slot: 0,
|
||||
ProposerIndex: 0,
|
||||
ParentRoot: params.BeaconConfig().ZeroHash[:],
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
BodyRoot: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *MockSlashingChecker) IsSlashableAttestation(_ context.Context, _ *ethpb.IndexedAttestation) ([]*ethpb.AttesterSlashing, error) {
|
||||
if s.AttesterSlashingFound {
|
||||
return []*ethpb.AttesterSlashing{
|
||||
{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{},
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
Data: ðpb.AttestationData{},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/async/event"
|
||||
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
|
||||
dbtest "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
|
||||
mockslasher "github.com/prysmaticlabs/prysm/v4/beacon-chain/slasher/mock"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
|
||||
mockSync "github.com/prysmaticlabs/prysm/v4/beacon-chain/sync/initial-sync/testing"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
@@ -21,7 +20,6 @@ import (
|
||||
)
|
||||
|
||||
var _ = SlashingChecker(&Service{})
|
||||
var _ = SlashingChecker(&mockslasher.MockSlashingChecker{})
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
|
||||
@@ -7,12 +7,11 @@ go_library(
|
||||
"field_trie_helpers.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/fieldtrie",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||
"//beacon-chain/state/state-native/types:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
||||
@@ -31,11 +31,11 @@ type FieldTrie struct {
|
||||
// NewFieldTrie is the constructor for the field trie data structure. It creates the corresponding
|
||||
// trie according to the given parameters. Depending on whether the field is a basic/composite array
|
||||
// which is either fixed/variable length, it will appropriately determine the trie.
|
||||
func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
|
||||
func NewFieldTrie(field types.FieldIndex, fieldInfo types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
|
||||
if elements == nil {
|
||||
return &FieldTrie{
|
||||
field: field,
|
||||
dataType: dataType,
|
||||
dataType: fieldInfo,
|
||||
reference: stateutil.NewRef(1),
|
||||
RWMutex: new(sync.RWMutex),
|
||||
length: length,
|
||||
@@ -48,10 +48,10 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := validateElements(field, dataType, elements, length); err != nil {
|
||||
if err := validateElements(field, fieldInfo, elements, length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch dataType {
|
||||
switch fieldInfo {
|
||||
case types.BasicArray:
|
||||
fl, err := stateutil.ReturnTrieLayer(fieldRoots, length)
|
||||
if err != nil {
|
||||
@@ -60,7 +60,7 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
|
||||
return &FieldTrie{
|
||||
fieldLayers: fl,
|
||||
field: field,
|
||||
dataType: dataType,
|
||||
dataType: fieldInfo,
|
||||
reference: stateutil.NewRef(1),
|
||||
RWMutex: new(sync.RWMutex),
|
||||
length: length,
|
||||
@@ -70,14 +70,14 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
|
||||
return &FieldTrie{
|
||||
fieldLayers: stateutil.ReturnTrieLayerVariable(fieldRoots, length),
|
||||
field: field,
|
||||
dataType: dataType,
|
||||
dataType: fieldInfo,
|
||||
reference: stateutil.NewRef(1),
|
||||
RWMutex: new(sync.RWMutex),
|
||||
length: length,
|
||||
numOfElems: reflect.Indirect(reflect.ValueOf(elements)).Len(),
|
||||
}, nil
|
||||
default:
|
||||
return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(dataType).Name())
|
||||
return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(fieldInfo).Name())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
pmath "github.com/prysmaticlabs/prysm/v4/math"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
)
|
||||
@@ -46,8 +45,8 @@ func (f *FieldTrie) validateIndices(idxs []uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateElements(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) error {
|
||||
if dataType == types.CompressedArray {
|
||||
func validateElements(field types.FieldIndex, fieldInfo types.DataType, elements interface{}, length uint64) error {
|
||||
if fieldInfo == types.CompressedArray {
|
||||
comLength, err := field.ElemsInChunk()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -65,11 +64,11 @@ func validateElements(field types.FieldIndex, dataType types.DataType, elements
|
||||
func fieldConverters(field types.FieldIndex, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
switch field {
|
||||
case types.BlockRoots:
|
||||
return convertBlockRoots(indices, elements, convertAll)
|
||||
return convert32ByteArrays[customtypes.BlockRoots](indices, elements, convertAll)
|
||||
case types.StateRoots:
|
||||
return convertStateRoots(indices, elements, convertAll)
|
||||
return convert32ByteArrays[customtypes.StateRoots](indices, elements, convertAll)
|
||||
case types.RandaoMixes:
|
||||
return convertRandaoMixes(indices, elements, convertAll)
|
||||
return convert32ByteArrays[customtypes.RandaoMixes](indices, elements, convertAll)
|
||||
case types.Eth1DataVotes:
|
||||
return convertEth1DataVotes(indices, elements, convertAll)
|
||||
case types.Validators:
|
||||
@@ -83,37 +82,13 @@ func fieldConverters(field types.FieldIndex, indices []uint64, elements interfac
|
||||
}
|
||||
}
|
||||
|
||||
func convertBlockRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.BlockRoots:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for block roots")
|
||||
}
|
||||
}
|
||||
|
||||
func convertStateRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.StateRoots:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for state roots")
|
||||
}
|
||||
}
|
||||
|
||||
func convertRandaoMixes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.RandaoMixes:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for randao mixes")
|
||||
func convert32ByteArrays[T ~[][32]byte](indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
val, ok := elements.(T)
|
||||
if !ok {
|
||||
var t T
|
||||
return nil, errors.Errorf("Wanted type of %T but got %T", t, elements)
|
||||
}
|
||||
return handle32ByteArrays(val, indices, convertAll)
|
||||
}
|
||||
|
||||
func convertEth1DataVotes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
@@ -148,34 +123,6 @@ func convertBalances(indices []uint64, elements interface{}, convertAll bool) ([
|
||||
return handleBalanceSlice(val, indices, convertAll)
|
||||
}
|
||||
|
||||
// handleByteArrays computes and returns byte arrays in a slice of root format.
|
||||
func handleByteArrays(val [][]byte, indices []uint64, convertAll bool) ([][32]byte, error) {
|
||||
length := len(indices)
|
||||
if convertAll {
|
||||
length = len(val)
|
||||
}
|
||||
roots := make([][32]byte, 0, length)
|
||||
rootCreator := func(input []byte) {
|
||||
newRoot := bytesutil.ToBytes32(input)
|
||||
roots = append(roots, newRoot)
|
||||
}
|
||||
if convertAll {
|
||||
for i := range val {
|
||||
rootCreator(val[i])
|
||||
}
|
||||
return roots, nil
|
||||
}
|
||||
if len(val) > 0 {
|
||||
for _, idx := range indices {
|
||||
if idx > uint64(len(val))-1 {
|
||||
return nil, fmt.Errorf("index %d greater than number of byte arrays %d", idx, len(val))
|
||||
}
|
||||
rootCreator(val[idx])
|
||||
}
|
||||
}
|
||||
return roots, nil
|
||||
}
|
||||
|
||||
// handle32ByteArrays computes and returns 32 byte arrays in a slice of root format.
|
||||
func handle32ByteArrays(val [][32]byte, indices []uint64, convertAll bool) ([][32]byte, error) {
|
||||
length := len(indices)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/fieldtrie"
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
@@ -16,11 +17,15 @@ import (
|
||||
|
||||
func TestFieldTrie_NewTrie(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 40)
|
||||
roots := newState.BlockRoots()
|
||||
blockRoots := make([][32]byte, len(roots))
|
||||
for i, r := range roots {
|
||||
blockRoots[i] = [32]byte(r)
|
||||
}
|
||||
|
||||
// 5 represents the enum value of state roots
|
||||
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(5), types.BasicArray, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
trie, err := fieldtrie.NewFieldTrie(types.BlockRoots, types.BasicArray, customtypes.BlockRoots(blockRoots), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
require.NoError(t, err)
|
||||
root, err := stateutil.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
root, err := stateutil.RootsArrayHashTreeRoot(newState.BlockRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
require.NoError(t, err)
|
||||
newRoot, err := trie.TrieRoot()
|
||||
require.NoError(t, err)
|
||||
@@ -28,7 +33,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFieldTrie_NewTrie_NilElements(t *testing.T) {
|
||||
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(5), types.BasicArray, nil, 8234)
|
||||
trie, err := fieldtrie.NewFieldTrie(types.BlockRoots, types.BasicArray, nil, 8234)
|
||||
require.NoError(t, err)
|
||||
_, err = trie.TrieRoot()
|
||||
require.ErrorIs(t, err, fieldtrie.ErrEmptyFieldTrie)
|
||||
@@ -36,8 +41,7 @@ func TestFieldTrie_NewTrie_NilElements(t *testing.T) {
|
||||
|
||||
func TestFieldTrie_RecomputeTrie(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 32)
|
||||
// 10 represents the enum value of validators
|
||||
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(11), types.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
|
||||
trie, err := fieldtrie.NewFieldTrie(types.Validators, types.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
|
||||
require.NoError(t, err)
|
||||
|
||||
oldroot, err := trie.TrieRoot()
|
||||
@@ -68,7 +72,7 @@ func TestFieldTrie_RecomputeTrie(t *testing.T) {
|
||||
|
||||
func TestFieldTrie_RecomputeTrie_CompressedArray(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 32)
|
||||
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(12), types.CompressedArray, newState.Balances(), stateutil.ValidatorLimitForBalancesChunks())
|
||||
trie, err := fieldtrie.NewFieldTrie(types.Balances, types.CompressedArray, newState.Balances(), stateutil.ValidatorLimitForBalancesChunks())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, trie.Length(), stateutil.ValidatorLimitForBalancesChunks())
|
||||
changedIdx := []uint64{4, 8}
|
||||
@@ -85,14 +89,19 @@ func TestFieldTrie_RecomputeTrie_CompressedArray(t *testing.T) {
|
||||
|
||||
func TestNewFieldTrie_UnknownType(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 32)
|
||||
_, err := fieldtrie.NewFieldTrie(types.FieldIndex(12), 4, newState.Balances(), 32)
|
||||
_, err := fieldtrie.NewFieldTrie(types.Balances, 4, newState.Balances(), 32)
|
||||
require.ErrorContains(t, "unrecognized data type", err)
|
||||
}
|
||||
|
||||
func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 32)
|
||||
// 12 represents the enum value of randao mixes.
|
||||
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(13), types.BasicArray, newState.RandaoMixes(), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
|
||||
mixes := newState.RandaoMixes()
|
||||
randaoMixes := make([][32]byte, len(mixes))
|
||||
for i, r := range mixes {
|
||||
randaoMixes[i] = [32]byte(r)
|
||||
}
|
||||
|
||||
trie, err := fieldtrie.NewFieldTrie(types.RandaoMixes, types.BasicArray, customtypes.RandaoMixes(randaoMixes), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
|
||||
require.NoError(t, err)
|
||||
|
||||
newTrie := trie.CopyTrie()
|
||||
@@ -100,10 +109,15 @@ func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
|
||||
changedIdx := []uint64{2, 29}
|
||||
|
||||
changedVals := [][32]byte{{'A', 'B'}, {'C', 'D'}}
|
||||
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[0], changedVals[0][:]))
|
||||
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[1], changedVals[1][:]))
|
||||
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[0], changedVals[0]))
|
||||
require.NoError(t, newState.UpdateRandaoMixesAtIndex(changedIdx[1], changedVals[1]))
|
||||
|
||||
root, err := trie.RecomputeTrie(changedIdx, newState.RandaoMixes())
|
||||
mixes = newState.RandaoMixes()
|
||||
randaoMixes = make([][32]byte, len(mixes))
|
||||
for i, r := range mixes {
|
||||
randaoMixes[i] = [32]byte(r)
|
||||
}
|
||||
root, err := trie.RecomputeTrie(changedIdx, customtypes.RandaoMixes(randaoMixes))
|
||||
require.NoError(t, err)
|
||||
newRoot, err := newTrie.TrieRoot()
|
||||
require.NoError(t, err)
|
||||
@@ -113,7 +127,7 @@ func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFieldTrie_CopyAndTransferEmpty(t *testing.T) {
|
||||
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(13), types.BasicArray, nil, uint64(params.BeaconConfig().EpochsPerHistoricalVector))
|
||||
trie, err := fieldtrie.NewFieldTrie(types.RandaoMixes, types.BasicArray, nil, uint64(params.BeaconConfig().EpochsPerHistoricalVector))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.DeepEqual(t, trie, trie.CopyTrie())
|
||||
@@ -123,7 +137,7 @@ func TestFieldTrie_CopyAndTransferEmpty(t *testing.T) {
|
||||
func TestFieldTrie_TransferTrie(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 32)
|
||||
maxLength := (params.BeaconConfig().ValidatorRegistryLimit*8 + 31) / 32
|
||||
trie, err := fieldtrie.NewFieldTrie(types.FieldIndex(12), types.CompressedArray, newState.Balances(), maxLength)
|
||||
trie, err := fieldtrie.NewFieldTrie(types.Balances, types.CompressedArray, newState.Balances(), maxLength)
|
||||
require.NoError(t, err)
|
||||
oldRoot, err := trie.TrieRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -103,22 +103,12 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
|
||||
errMsg string
|
||||
expectedLength int
|
||||
}{
|
||||
{
|
||||
name: "BlockRoots [][]bytes",
|
||||
args: &args{
|
||||
field: types.FieldIndex(5),
|
||||
indices: []uint64{},
|
||||
elements: [][]byte{[]byte("dfsadfsadf")},
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
|
||||
},
|
||||
{
|
||||
name: "BlockRoots customtypes.BlockRoots",
|
||||
args: &args{
|
||||
field: types.FieldIndex(5),
|
||||
indices: []uint64{},
|
||||
elements: &customtypes.BlockRoots{},
|
||||
elements: customtypes.BlockRoots{},
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
@@ -133,34 +123,14 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: nil,
|
||||
errMsg: "Incorrect type used for block roots",
|
||||
},
|
||||
{
|
||||
name: "BlockRoots [][]bytes",
|
||||
args: &args{
|
||||
field: types.FieldIndex(5),
|
||||
indices: []uint64{},
|
||||
elements: [][]byte{[]byte("dfsadfsadf")},
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
|
||||
},
|
||||
{
|
||||
name: "StateRoots [][]bytes",
|
||||
args: &args{
|
||||
field: types.FieldIndex(6),
|
||||
indices: []uint64{},
|
||||
elements: [][]byte{[]byte("dfsadfsadf")},
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
|
||||
errMsg: "Wanted type of customtypes.BlockRoots",
|
||||
},
|
||||
{
|
||||
name: "StateRoots customtypes.StateRoots",
|
||||
args: &args{
|
||||
field: types.FieldIndex(6),
|
||||
indices: []uint64{},
|
||||
elements: &customtypes.StateRoots{},
|
||||
elements: customtypes.StateRoots{},
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
@@ -175,45 +145,25 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: nil,
|
||||
errMsg: "Incorrect type used for state roots",
|
||||
},
|
||||
{
|
||||
name: "StateRoots [][]bytes convert all false",
|
||||
args: &args{
|
||||
field: types.FieldIndex(6),
|
||||
indices: []uint64{},
|
||||
elements: [][]byte{[]byte("dfsadfsadf")},
|
||||
convertAll: false,
|
||||
},
|
||||
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
|
||||
errMsg: "Wanted type of customtypes.StateRoots",
|
||||
},
|
||||
{
|
||||
name: "StateRoots customtypes.StateRoots convert all false",
|
||||
args: &args{
|
||||
field: types.FieldIndex(6),
|
||||
indices: []uint64{},
|
||||
elements: &customtypes.StateRoots{},
|
||||
elements: customtypes.StateRoots{},
|
||||
convertAll: false,
|
||||
},
|
||||
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
expectedLength: 8192,
|
||||
},
|
||||
{
|
||||
name: "RandaoMixes [][]bytes",
|
||||
args: &args{
|
||||
field: types.FieldIndex(13),
|
||||
indices: []uint64{},
|
||||
elements: [][]byte{[]byte("dfsadfsadf")},
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: []string{"0x6466736164667361646600000000000000000000000000000000000000000000"},
|
||||
},
|
||||
{
|
||||
name: "RandaoMixes customtypes.RandaoMixes",
|
||||
args: &args{
|
||||
field: types.FieldIndex(13),
|
||||
indices: []uint64{},
|
||||
elements: &customtypes.RandaoMixes{},
|
||||
elements: customtypes.RandaoMixes{},
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: []string{"0x0000000000000000000000000000000000000000000000000000000000000000"},
|
||||
@@ -228,7 +178,7 @@ func TestFieldTrie_NativeState_fieldConvertersNative(t *testing.T) {
|
||||
convertAll: true,
|
||||
},
|
||||
wantHex: nil,
|
||||
errMsg: "Incorrect type used for randao mixes",
|
||||
errMsg: "Wanted type of customtypes.RandaoMixes",
|
||||
},
|
||||
{
|
||||
name: "Eth1DataVotes type not found",
|
||||
|
||||
@@ -237,7 +237,7 @@ type WriteOnlyBalances interface {
|
||||
// WriteOnlyRandaoMixes defines a struct which only has write access to randao mixes methods.
|
||||
type WriteOnlyRandaoMixes interface {
|
||||
SetRandaoMixes(val [][]byte) error
|
||||
UpdateRandaoMixesAtIndex(idx uint64, val []byte) error
|
||||
UpdateRandaoMixesAtIndex(idx uint64, val [32]byte) error
|
||||
}
|
||||
|
||||
// WriteOnlyCheckpoint defines a struct which only has write access to check point methods.
|
||||
|
||||
@@ -18,6 +18,7 @@ go_library(
|
||||
"getters_validator.go",
|
||||
"getters_withdrawal.go",
|
||||
"hasher.go",
|
||||
"multi_value_slices.go",
|
||||
"proofs.go",
|
||||
"readonly_validator.go",
|
||||
"setters_attestation.go",
|
||||
@@ -49,11 +50,14 @@ go_library(
|
||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||
"//beacon-chain/state/state-native/types:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//container/multi-value-slice:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
@@ -64,6 +68,8 @@ go_library(
|
||||
"//runtime/version:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
@@ -82,16 +88,22 @@ go_test(
|
||||
"getters_validator_test.go",
|
||||
"getters_withdrawal_test.go",
|
||||
"hasher_test.go",
|
||||
"mvslice_fuzz_test.go",
|
||||
"proofs_test.go",
|
||||
"readonly_validator_test.go",
|
||||
"references_test.go",
|
||||
"setters_attestation_test.go",
|
||||
"setters_eth1_test.go",
|
||||
"setters_misc_test.go",
|
||||
"setters_participation_test.go",
|
||||
"setters_validator_test.go",
|
||||
"setters_withdrawal_test.go",
|
||||
"state_fuzz_test.go",
|
||||
"state_test.go",
|
||||
"state_trie_test.go",
|
||||
"types_test.go",
|
||||
],
|
||||
data = glob(["testdata/**"]),
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
@@ -99,6 +111,7 @@ go_test(
|
||||
"//beacon-chain/state/state-native/types:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/testing:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
@@ -25,16 +26,21 @@ type BeaconState struct {
|
||||
slot primitives.Slot
|
||||
fork *ethpb.Fork
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader
|
||||
blockRoots *customtypes.BlockRoots
|
||||
stateRoots *customtypes.StateRoots
|
||||
blockRoots customtypes.BlockRoots
|
||||
blockRootsMultiValue *MultiValueBlockRoots
|
||||
stateRoots customtypes.StateRoots
|
||||
stateRootsMultiValue *MultiValueStateRoots
|
||||
historicalRoots customtypes.HistoricalRoots
|
||||
historicalSummaries []*ethpb.HistoricalSummary
|
||||
eth1Data *ethpb.Eth1Data
|
||||
eth1DataVotes []*ethpb.Eth1Data
|
||||
eth1DepositIndex uint64
|
||||
validators []*ethpb.Validator
|
||||
validatorsMultiValue *MultiValueValidators
|
||||
balances []uint64
|
||||
randaoMixes *customtypes.RandaoMixes
|
||||
balancesMultiValue *MultiValueBalances
|
||||
randaoMixes customtypes.RandaoMixes
|
||||
randaoMixesMultiValue *MultiValueRandaoMixes
|
||||
slashings []uint64
|
||||
previousEpochAttestations []*ethpb.PendingAttestation
|
||||
currentEpochAttestations []*ethpb.PendingAttestation
|
||||
@@ -45,6 +51,7 @@ type BeaconState struct {
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint
|
||||
finalizedCheckpoint *ethpb.Checkpoint
|
||||
inactivityScores []uint64
|
||||
inactivityScoresMultiValue *MultiValueInactivityScores
|
||||
currentSyncCommittee *ethpb.SyncCommittee
|
||||
nextSyncCommittee *ethpb.SyncCommittee
|
||||
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
|
||||
@@ -53,6 +60,7 @@ type BeaconState struct {
|
||||
nextWithdrawalIndex uint64
|
||||
nextWithdrawalValidatorIndex primitives.ValidatorIndex
|
||||
|
||||
id uint64
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[types.FieldIndex]bool
|
||||
dirtyIndices map[types.FieldIndex][]uint64
|
||||
@@ -70,8 +78,8 @@ type beaconStateMarshalable struct {
|
||||
Slot primitives.Slot `json:"slot" yaml:"slot"`
|
||||
Fork *ethpb.Fork `json:"fork" yaml:"fork"`
|
||||
LatestBlockHeader *ethpb.BeaconBlockHeader `json:"latest_block_header" yaml:"latest_block_header"`
|
||||
BlockRoots *customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
|
||||
StateRoots *customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
|
||||
BlockRoots customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
|
||||
StateRoots customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
|
||||
HistoricalRoots customtypes.HistoricalRoots `json:"historical_roots" yaml:"historical_roots"`
|
||||
HistoricalSummaries []*ethpb.HistoricalSummary `json:"historical_summaries" yaml:"historical_summaries"`
|
||||
Eth1Data *ethpb.Eth1Data `json:"eth_1_data" yaml:"eth_1_data"`
|
||||
@@ -79,7 +87,7 @@ type beaconStateMarshalable struct {
|
||||
Eth1DepositIndex uint64 `json:"eth_1_deposit_index" yaml:"eth_1_deposit_index"`
|
||||
Validators []*ethpb.Validator `json:"validators" yaml:"validators"`
|
||||
Balances []uint64 `json:"balances" yaml:"balances"`
|
||||
RandaoMixes *customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
|
||||
RandaoMixes customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
|
||||
Slashings []uint64 `json:"slashings" yaml:"slashings"`
|
||||
PreviousEpochAttestations []*ethpb.PendingAttestation `json:"previous_epoch_attestations" yaml:"previous_epoch_attestations"`
|
||||
CurrentEpochAttestations []*ethpb.PendingAttestation `json:"current_epoch_attestations" yaml:"current_epoch_attestations"`
|
||||
@@ -99,6 +107,29 @@ type beaconStateMarshalable struct {
|
||||
}
|
||||
|
||||
func (b *BeaconState) MarshalJSON() ([]byte, error) {
|
||||
var bRoots customtypes.BlockRoots
|
||||
var sRoots customtypes.StateRoots
|
||||
var mixes customtypes.RandaoMixes
|
||||
var balances []uint64
|
||||
var inactivityScores []uint64
|
||||
var vals []*ethpb.Validator
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
bRoots = b.blockRootsMultiValue.Value(b)
|
||||
sRoots = b.stateRootsMultiValue.Value(b)
|
||||
mixes = b.randaoMixesMultiValue.Value(b)
|
||||
balances = b.balancesMultiValue.Value(b)
|
||||
inactivityScores = b.inactivityScoresMultiValue.Value(b)
|
||||
vals = b.validatorsMultiValue.Value(b)
|
||||
} else {
|
||||
bRoots = b.blockRoots
|
||||
sRoots = b.stateRoots
|
||||
mixes = b.randaoMixes
|
||||
balances = b.balances
|
||||
inactivityScores = b.inactivityScores
|
||||
vals = b.validators
|
||||
}
|
||||
|
||||
marshalable := &beaconStateMarshalable{
|
||||
Version: b.version,
|
||||
GenesisTime: b.genesisTime,
|
||||
@@ -106,16 +137,16 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots,
|
||||
StateRoots: b.stateRoots,
|
||||
BlockRoots: bRoots,
|
||||
StateRoots: sRoots,
|
||||
HistoricalRoots: b.historicalRoots,
|
||||
HistoricalSummaries: b.historicalSummaries,
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes,
|
||||
Validators: vals,
|
||||
Balances: balances,
|
||||
RandaoMixes: mixes,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochAttestations: b.previousEpochAttestations,
|
||||
CurrentEpochAttestations: b.currentEpochAttestations,
|
||||
@@ -125,7 +156,7 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: b.inactivityScores,
|
||||
InactivityScores: inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v4/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
@@ -25,16 +26,21 @@ type BeaconState struct {
|
||||
slot primitives.Slot
|
||||
fork *ethpb.Fork
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader
|
||||
blockRoots *customtypes.BlockRoots
|
||||
stateRoots *customtypes.StateRoots
|
||||
blockRoots customtypes.BlockRoots
|
||||
blockRootsMultiValue *MultiValueBlockRoots
|
||||
stateRoots customtypes.StateRoots
|
||||
stateRootsMultiValue *MultiValueStateRoots
|
||||
historicalRoots customtypes.HistoricalRoots
|
||||
historicalSummaries []*ethpb.HistoricalSummary
|
||||
eth1Data *ethpb.Eth1Data
|
||||
eth1DataVotes []*ethpb.Eth1Data
|
||||
eth1DepositIndex uint64
|
||||
validators []*ethpb.Validator
|
||||
validatorsMultiValue *MultiValueValidators
|
||||
balances []uint64
|
||||
randaoMixes *customtypes.RandaoMixes
|
||||
balancesMultiValue *MultiValueBalances
|
||||
randaoMixes customtypes.RandaoMixes
|
||||
randaoMixesMultiValue *MultiValueRandaoMixes
|
||||
slashings []uint64
|
||||
previousEpochAttestations []*ethpb.PendingAttestation
|
||||
currentEpochAttestations []*ethpb.PendingAttestation
|
||||
@@ -45,6 +51,7 @@ type BeaconState struct {
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint
|
||||
finalizedCheckpoint *ethpb.Checkpoint
|
||||
inactivityScores []uint64
|
||||
inactivityScoresMultiValue *MultiValueInactivityScores
|
||||
currentSyncCommittee *ethpb.SyncCommittee
|
||||
nextSyncCommittee *ethpb.SyncCommittee
|
||||
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
|
||||
@@ -53,6 +60,7 @@ type BeaconState struct {
|
||||
nextWithdrawalIndex uint64
|
||||
nextWithdrawalValidatorIndex primitives.ValidatorIndex
|
||||
|
||||
id uint64
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[types.FieldIndex]bool
|
||||
dirtyIndices map[types.FieldIndex][]uint64
|
||||
@@ -70,8 +78,8 @@ type beaconStateMarshalable struct {
|
||||
Slot primitives.Slot `json:"slot" yaml:"slot"`
|
||||
Fork *ethpb.Fork `json:"fork" yaml:"fork"`
|
||||
LatestBlockHeader *ethpb.BeaconBlockHeader `json:"latest_block_header" yaml:"latest_block_header"`
|
||||
BlockRoots *customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
|
||||
StateRoots *customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
|
||||
BlockRoots customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
|
||||
StateRoots customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
|
||||
HistoricalRoots customtypes.HistoricalRoots `json:"historical_roots" yaml:"historical_roots"`
|
||||
HistoricalSummaries []*ethpb.HistoricalSummary `json:"historical_summaries" yaml:"historical_summaries"`
|
||||
Eth1Data *ethpb.Eth1Data `json:"eth_1_data" yaml:"eth_1_data"`
|
||||
@@ -79,7 +87,7 @@ type beaconStateMarshalable struct {
|
||||
Eth1DepositIndex uint64 `json:"eth_1_deposit_index" yaml:"eth_1_deposit_index"`
|
||||
Validators []*ethpb.Validator `json:"validators" yaml:"validators"`
|
||||
Balances []uint64 `json:"balances" yaml:"balances"`
|
||||
RandaoMixes *customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
|
||||
RandaoMixes customtypes.RandaoMixes `json:"randao_mixes" yaml:"randao_mixes"`
|
||||
Slashings []uint64 `json:"slashings" yaml:"slashings"`
|
||||
PreviousEpochAttestations []*ethpb.PendingAttestation `json:"previous_epoch_attestations" yaml:"previous_epoch_attestations"`
|
||||
CurrentEpochAttestations []*ethpb.PendingAttestation `json:"current_epoch_attestations" yaml:"current_epoch_attestations"`
|
||||
@@ -99,6 +107,29 @@ type beaconStateMarshalable struct {
|
||||
}
|
||||
|
||||
func (b *BeaconState) MarshalJSON() ([]byte, error) {
|
||||
var bRoots customtypes.BlockRoots
|
||||
var sRoots customtypes.StateRoots
|
||||
var mixes customtypes.RandaoMixes
|
||||
var balances []uint64
|
||||
var inactivityScores []uint64
|
||||
var vals []*ethpb.Validator
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
bRoots = b.blockRootsMultiValue.Value(b)
|
||||
sRoots = b.stateRootsMultiValue.Value(b)
|
||||
mixes = b.randaoMixesMultiValue.Value(b)
|
||||
balances = b.balancesMultiValue.Value(b)
|
||||
inactivityScores = b.inactivityScoresMultiValue.Value(b)
|
||||
vals = b.validatorsMultiValue.Value(b)
|
||||
} else {
|
||||
bRoots = b.blockRoots
|
||||
sRoots = b.stateRoots
|
||||
mixes = b.randaoMixes
|
||||
balances = b.balances
|
||||
inactivityScores = b.inactivityScores
|
||||
vals = b.validators
|
||||
}
|
||||
|
||||
marshalable := &beaconStateMarshalable{
|
||||
Version: b.version,
|
||||
GenesisTime: b.genesisTime,
|
||||
@@ -106,16 +137,16 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots,
|
||||
StateRoots: b.stateRoots,
|
||||
BlockRoots: bRoots,
|
||||
StateRoots: sRoots,
|
||||
HistoricalRoots: b.historicalRoots,
|
||||
HistoricalSummaries: b.historicalSummaries,
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes,
|
||||
Validators: vals,
|
||||
Balances: balances,
|
||||
RandaoMixes: mixes,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochAttestations: b.previousEpochAttestations,
|
||||
CurrentEpochAttestations: b.currentEpochAttestations,
|
||||
@@ -125,7 +156,7 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: b.inactivityScores,
|
||||
InactivityScores: inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
)
|
||||
|
||||
var _ fssz.HashRoot = (BlockRoots)([fieldparams.BlockRootsLength][32]byte{})
|
||||
var _ fssz.HashRoot = (BlockRoots)([][32]byte{})
|
||||
var _ fssz.Marshaler = (*BlockRoots)(nil)
|
||||
var _ fssz.Unmarshaler = (*BlockRoots)(nil)
|
||||
|
||||
// BlockRoots represents block roots of the beacon state.
|
||||
type BlockRoots [fieldparams.BlockRootsLength][32]byte
|
||||
type BlockRoots [][32]byte
|
||||
|
||||
// HashTreeRoot returns calculated hash root.
|
||||
func (r BlockRoots) HashTreeRoot() ([32]byte, error) {
|
||||
@@ -35,7 +35,7 @@ func (r *BlockRoots) UnmarshalSSZ(buf []byte) error {
|
||||
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
|
||||
}
|
||||
|
||||
var roots BlockRoots
|
||||
roots := BlockRoots(make([][32]byte, fieldparams.BlockRootsLength))
|
||||
for i := range roots {
|
||||
copy(roots[i][:], buf[i*32:(i+1)*32])
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func (r *BlockRoots) UnmarshalSSZ(buf []byte) error {
|
||||
}
|
||||
|
||||
// MarshalSSZTo marshals BlockRoots with the provided byte slice.
|
||||
func (r *BlockRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
func (r BlockRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
marshalled, err := r.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -53,7 +53,7 @@ func (r *BlockRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// MarshalSSZ marshals BlockRoots into a serialized object.
|
||||
func (r *BlockRoots) MarshalSSZ() ([]byte, error) {
|
||||
func (r BlockRoots) MarshalSSZ() ([]byte, error) {
|
||||
marshalled := make([]byte, fieldparams.BlockRootsLength*32)
|
||||
for i, r32 := range r {
|
||||
for j, rr := range r32 {
|
||||
@@ -64,12 +64,13 @@ func (r *BlockRoots) MarshalSSZ() ([]byte, error) {
|
||||
}
|
||||
|
||||
// SizeSSZ returns the size of the serialized object.
|
||||
func (_ *BlockRoots) SizeSSZ() int {
|
||||
func (_ BlockRoots) SizeSSZ() int {
|
||||
return fieldparams.BlockRootsLength * 32
|
||||
}
|
||||
|
||||
// Slice converts a customtypes.BlockRoots object into a 2D byte slice.
|
||||
func (r *BlockRoots) Slice() [][]byte {
|
||||
// Each item in the slice is a copy of the original item.
|
||||
func (r BlockRoots) Slice() [][]byte {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,14 +8,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/assert"
|
||||
)
|
||||
|
||||
func TestBlockRoots_Casting(t *testing.T) {
|
||||
var b [fieldparams.BlockRootsLength][32]byte
|
||||
d := BlockRoots(b)
|
||||
if !reflect.DeepEqual([fieldparams.BlockRootsLength][32]byte(d), b) {
|
||||
t.Errorf("Unequal: %v = %v", d, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockRoots_UnmarshalSSZ(t *testing.T) {
|
||||
t.Run("Ok", func(t *testing.T) {
|
||||
d := BlockRoots{}
|
||||
@@ -70,7 +62,7 @@ func TestBlockRoots_MarshalSSZTo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBlockRoots_MarshalSSZ(t *testing.T) {
|
||||
d := BlockRoots{}
|
||||
d := BlockRoots(make([][32]byte, fieldparams.BlockRootsLength))
|
||||
d[0] = [32]byte{'f', 'o', 'o'}
|
||||
d[1] = [32]byte{'b', 'a', 'r'}
|
||||
b, err := d.MarshalSSZ()
|
||||
@@ -94,7 +86,7 @@ func TestBlockRoots_SizeSSZ(t *testing.T) {
|
||||
|
||||
func TestBlockRoots_Slice(t *testing.T) {
|
||||
a, b, c := [32]byte{'a'}, [32]byte{'b'}, [32]byte{'c'}
|
||||
roots := BlockRoots{}
|
||||
roots := BlockRoots(make([][32]byte, fieldparams.BlockRootsLength))
|
||||
roots[1] = a
|
||||
roots[10] = b
|
||||
roots[100] = c
|
||||
|
||||
@@ -43,7 +43,7 @@ func (r *HistoricalRoots) UnmarshalSSZ(buf []byte) error {
|
||||
}
|
||||
|
||||
// MarshalSSZTo marshals HistoricalRoots with the provided byte slice.
|
||||
func (r *HistoricalRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
func (r HistoricalRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
marshalled, err := r.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -52,9 +52,9 @@ func (r *HistoricalRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// MarshalSSZ marshals HistoricalRoots into a serialized object.
|
||||
func (r *HistoricalRoots) MarshalSSZ() ([]byte, error) {
|
||||
marshalled := make([]byte, len(*r)*32)
|
||||
for i, r32 := range *r {
|
||||
func (r HistoricalRoots) MarshalSSZ() ([]byte, error) {
|
||||
marshalled := make([]byte, len(r)*32)
|
||||
for i, r32 := range r {
|
||||
for j, rr := range r32 {
|
||||
marshalled[i*32+j] = rr
|
||||
}
|
||||
@@ -63,17 +63,17 @@ func (r *HistoricalRoots) MarshalSSZ() ([]byte, error) {
|
||||
}
|
||||
|
||||
// SizeSSZ returns the size of the serialized object.
|
||||
func (r *HistoricalRoots) SizeSSZ() int {
|
||||
return len(*r) * 32
|
||||
func (r HistoricalRoots) SizeSSZ() int {
|
||||
return len(r) * 32
|
||||
}
|
||||
|
||||
// Slice converts a customtypes.HistoricalRoots object into a 2D byte slice.
|
||||
func (r *HistoricalRoots) Slice() [][]byte {
|
||||
func (r HistoricalRoots) Slice() [][]byte {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
hRoots := make([][]byte, len(*r))
|
||||
for i, root := range *r {
|
||||
hRoots := make([][]byte, len(r))
|
||||
for i, root := range r {
|
||||
tmp := root
|
||||
hRoots[i] = tmp[:]
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
)
|
||||
|
||||
var _ fssz.HashRoot = (RandaoMixes)([fieldparams.RandaoMixesLength][32]byte{})
|
||||
var _ fssz.HashRoot = (RandaoMixes)([][32]byte{})
|
||||
var _ fssz.Marshaler = (*RandaoMixes)(nil)
|
||||
var _ fssz.Unmarshaler = (*RandaoMixes)(nil)
|
||||
|
||||
// RandaoMixes represents RANDAO mixes of the beacon state.
|
||||
type RandaoMixes [fieldparams.RandaoMixesLength][32]byte
|
||||
type RandaoMixes [][32]byte
|
||||
|
||||
// HashTreeRoot returns calculated hash root.
|
||||
func (r RandaoMixes) HashTreeRoot() ([32]byte, error) {
|
||||
@@ -35,7 +35,7 @@ func (r *RandaoMixes) UnmarshalSSZ(buf []byte) error {
|
||||
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
|
||||
}
|
||||
|
||||
var roots RandaoMixes
|
||||
roots := RandaoMixes(make([][32]byte, fieldparams.RandaoMixesLength))
|
||||
for i := range roots {
|
||||
copy(roots[i][:], buf[i*32:(i+1)*32])
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func (r *RandaoMixes) UnmarshalSSZ(buf []byte) error {
|
||||
}
|
||||
|
||||
// MarshalSSZTo marshals RandaoMixes with the provided byte slice.
|
||||
func (r *RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
func (r RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
marshalled, err := r.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -53,7 +53,7 @@ func (r *RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// MarshalSSZ marshals RandaoMixes into a serialized object.
|
||||
func (r *RandaoMixes) MarshalSSZ() ([]byte, error) {
|
||||
func (r RandaoMixes) MarshalSSZ() ([]byte, error) {
|
||||
marshalled := make([]byte, fieldparams.RandaoMixesLength*32)
|
||||
for i, r32 := range r {
|
||||
for j, rr := range r32 {
|
||||
@@ -64,12 +64,13 @@ func (r *RandaoMixes) MarshalSSZ() ([]byte, error) {
|
||||
}
|
||||
|
||||
// SizeSSZ returns the size of the serialized object.
|
||||
func (_ *RandaoMixes) SizeSSZ() int {
|
||||
func (_ RandaoMixes) SizeSSZ() int {
|
||||
return fieldparams.RandaoMixesLength * 32
|
||||
}
|
||||
|
||||
// Slice converts a customtypes.RandaoMixes object into a 2D byte slice.
|
||||
func (r *RandaoMixes) Slice() [][]byte {
|
||||
// Each item in the slice is a copy of the original item.
|
||||
func (r RandaoMixes) Slice() [][]byte {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,14 +8,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/assert"
|
||||
)
|
||||
|
||||
func TestRandaoMixes_Casting(t *testing.T) {
|
||||
var b [fieldparams.RandaoMixesLength][32]byte
|
||||
d := RandaoMixes(b)
|
||||
if !reflect.DeepEqual([fieldparams.RandaoMixesLength][32]byte(d), b) {
|
||||
t.Errorf("Unequal: %v = %v", d, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandaoMixes_UnmarshalSSZ(t *testing.T) {
|
||||
t.Run("Ok", func(t *testing.T) {
|
||||
d := RandaoMixes{}
|
||||
@@ -70,7 +62,7 @@ func TestRandaoMixes_MarshalSSZTo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRandaoMixes_MarshalSSZ(t *testing.T) {
|
||||
d := RandaoMixes{}
|
||||
d := RandaoMixes(make([][32]byte, fieldparams.RandaoMixesLength))
|
||||
d[0] = [32]byte{'f', 'o', 'o'}
|
||||
d[1] = [32]byte{'b', 'a', 'r'}
|
||||
b, err := d.MarshalSSZ()
|
||||
@@ -94,7 +86,7 @@ func TestRandaoMixes_SizeSSZ(t *testing.T) {
|
||||
|
||||
func TestRandaoMixes_Slice(t *testing.T) {
|
||||
a, b, c := [32]byte{'a'}, [32]byte{'b'}, [32]byte{'c'}
|
||||
roots := RandaoMixes{}
|
||||
roots := RandaoMixes(make([][32]byte, fieldparams.RandaoMixesLength))
|
||||
roots[1] = a
|
||||
roots[10] = b
|
||||
roots[100] = c
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
)
|
||||
|
||||
var _ fssz.HashRoot = (StateRoots)([fieldparams.StateRootsLength][32]byte{})
|
||||
var _ fssz.HashRoot = (StateRoots)([][32]byte{})
|
||||
var _ fssz.Marshaler = (*StateRoots)(nil)
|
||||
var _ fssz.Unmarshaler = (*StateRoots)(nil)
|
||||
|
||||
// StateRoots represents block roots of the beacon state.
|
||||
type StateRoots [fieldparams.StateRootsLength][32]byte
|
||||
type StateRoots [][32]byte
|
||||
|
||||
// HashTreeRoot returns calculated hash root.
|
||||
func (r StateRoots) HashTreeRoot() ([32]byte, error) {
|
||||
@@ -35,7 +35,7 @@ func (r *StateRoots) UnmarshalSSZ(buf []byte) error {
|
||||
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
|
||||
}
|
||||
|
||||
var roots StateRoots
|
||||
roots := StateRoots(make([][32]byte, fieldparams.StateRootsLength))
|
||||
for i := range roots {
|
||||
copy(roots[i][:], buf[i*32:(i+1)*32])
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func (r *StateRoots) UnmarshalSSZ(buf []byte) error {
|
||||
}
|
||||
|
||||
// MarshalSSZTo marshals StateRoots with the provided byte slice.
|
||||
func (r *StateRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
func (r StateRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
marshalled, err := r.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -53,7 +53,7 @@ func (r *StateRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// MarshalSSZ marshals StateRoots into a serialized object.
|
||||
func (r *StateRoots) MarshalSSZ() ([]byte, error) {
|
||||
func (r StateRoots) MarshalSSZ() ([]byte, error) {
|
||||
marshalled := make([]byte, fieldparams.StateRootsLength*32)
|
||||
for i, r32 := range r {
|
||||
for j, rr := range r32 {
|
||||
@@ -64,12 +64,13 @@ func (r *StateRoots) MarshalSSZ() ([]byte, error) {
|
||||
}
|
||||
|
||||
// SizeSSZ returns the size of the serialized object.
|
||||
func (_ *StateRoots) SizeSSZ() int {
|
||||
func (_ StateRoots) SizeSSZ() int {
|
||||
return fieldparams.StateRootsLength * 32
|
||||
}
|
||||
|
||||
// Slice converts a customtypes.StateRoots object into a 2D byte slice.
|
||||
func (r *StateRoots) Slice() [][]byte {
|
||||
// Each item in the slice is a copy of the original item.
|
||||
func (r StateRoots) Slice() [][]byte {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,14 +8,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/assert"
|
||||
)
|
||||
|
||||
func TestStateRoots_Casting(t *testing.T) {
|
||||
var b [fieldparams.StateRootsLength][32]byte
|
||||
d := StateRoots(b)
|
||||
if !reflect.DeepEqual([fieldparams.StateRootsLength][32]byte(d), b) {
|
||||
t.Errorf("Unequal: %v = %v", d, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateRoots_UnmarshalSSZ(t *testing.T) {
|
||||
t.Run("Ok", func(t *testing.T) {
|
||||
d := StateRoots{}
|
||||
@@ -70,7 +62,7 @@ func TestStateRoots_MarshalSSZTo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStateRoots_MarshalSSZ(t *testing.T) {
|
||||
d := StateRoots{}
|
||||
d := StateRoots(make([][32]byte, fieldparams.StateRootsLength))
|
||||
d[0] = [32]byte{'f', 'o', 'o'}
|
||||
d[1] = [32]byte{'b', 'a', 'r'}
|
||||
b, err := d.MarshalSSZ()
|
||||
@@ -94,7 +86,7 @@ func TestStateRoots_SizeSSZ(t *testing.T) {
|
||||
|
||||
func TestStateRoots_Slice(t *testing.T) {
|
||||
a, b, c := [32]byte{'a'}, [32]byte{'b'}, [32]byte{'c'}
|
||||
roots := StateRoots{}
|
||||
roots := StateRoots(make([][32]byte, fieldparams.StateRootsLength))
|
||||
roots[1] = a
|
||||
roots[10] = b
|
||||
roots[100] = c
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -45,26 +47,46 @@ func (b *BeaconState) latestBlockHeaderVal() *ethpb.BeaconBlockHeader {
|
||||
|
||||
// BlockRoots kept track of in the beacon state.
|
||||
func (b *BeaconState) BlockRoots() [][]byte {
|
||||
if b.blockRoots == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.blockRoots.Slice()
|
||||
roots := b.blockRootsVal()
|
||||
if roots == nil {
|
||||
return nil
|
||||
}
|
||||
return roots.Slice()
|
||||
}
|
||||
|
||||
func (b *BeaconState) blockRootsVal() customtypes.BlockRoots {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.blockRootsMultiValue == nil {
|
||||
return nil
|
||||
}
|
||||
return b.blockRootsMultiValue.Value(b)
|
||||
}
|
||||
return b.blockRoots
|
||||
}
|
||||
|
||||
// BlockRootAtIndex retrieves a specific block root based on an
|
||||
// input index value.
|
||||
func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
|
||||
if b.blockRoots == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.blockRootsMultiValue == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
r, err := b.blockRootsMultiValue.At(b, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r[:], nil
|
||||
}
|
||||
|
||||
if b.blockRoots == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
r, err := b.blockRootAtIndex(idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -77,7 +99,7 @@ func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) blockRootAtIndex(idx uint64) ([32]byte, error) {
|
||||
if uint64(len(b.blockRoots)) <= idx {
|
||||
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
|
||||
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "block root index %d does not exist", idx)
|
||||
}
|
||||
return b.blockRoots[idx], nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v4/runtime/version"
|
||||
)
|
||||
|
||||
// Id is the identifier of the beacon state.
|
||||
func (b *BeaconState) Id() uint64 {
|
||||
return b.id
|
||||
}
|
||||
|
||||
// GenesisTime of the beacon state as a uint64.
|
||||
func (b *BeaconState) GenesisTime() uint64 {
|
||||
b.lock.RLock()
|
||||
@@ -79,16 +84,6 @@ func (b *BeaconState) HistoricalRoots() ([][]byte, error) {
|
||||
return b.historicalRoots.Slice(), nil
|
||||
}
|
||||
|
||||
// balancesLength returns the length of the balances slice.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) balancesLength() int {
|
||||
if b.balances == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(b.balances)
|
||||
}
|
||||
|
||||
// HistoricalSummaries of the beacon state.
|
||||
func (b *BeaconState) HistoricalSummaries() ([]*ethpb.HistoricalSummary, error) {
|
||||
if b.version < version.Capella {
|
||||
|
||||
@@ -3,6 +3,7 @@ package state_native
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v4/runtime/version"
|
||||
)
|
||||
|
||||
@@ -56,7 +57,11 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er
|
||||
return 0, 0, 0, ErrNilParticipation
|
||||
}
|
||||
|
||||
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validators, currentEpoch)
|
||||
if features.Get().EnableExperimentalState {
|
||||
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validatorsVal(), currentEpoch)
|
||||
} else {
|
||||
return stateutil.UnrealizedCheckpointBalances(cp, pp, b.validators, currentEpoch)
|
||||
}
|
||||
}
|
||||
|
||||
// currentEpochParticipationVal corresponding to participation bits on the beacon chain.
|
||||
|
||||
@@ -1,31 +1,54 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
)
|
||||
|
||||
// RandaoMixes of block proposers on the beacon chain.
|
||||
func (b *BeaconState) RandaoMixes() [][]byte {
|
||||
if b.randaoMixes == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.randaoMixes.Slice()
|
||||
mixes := b.randaoMixesVal()
|
||||
if mixes == nil {
|
||||
return nil
|
||||
}
|
||||
return mixes.Slice()
|
||||
}
|
||||
|
||||
func (b *BeaconState) randaoMixesVal() customtypes.RandaoMixes {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.randaoMixesMultiValue == nil {
|
||||
return nil
|
||||
}
|
||||
return b.randaoMixesMultiValue.Value(b)
|
||||
}
|
||||
return b.randaoMixes
|
||||
}
|
||||
|
||||
// RandaoMixAtIndex retrieves a specific block root based on an
|
||||
// input index value.
|
||||
func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
|
||||
if b.randaoMixes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.randaoMixesMultiValue == nil {
|
||||
return nil, nil
|
||||
}
|
||||
r, err := b.randaoMixesMultiValue.At(b, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r[:], nil
|
||||
}
|
||||
|
||||
if b.randaoMixes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m, err := b.randaoMixAtIndex(idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -38,7 +61,7 @@ func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
|
||||
if uint64(len(b.randaoMixes)) <= idx {
|
||||
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
|
||||
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "randao mix index %d does not exist", idx)
|
||||
}
|
||||
|
||||
return b.randaoMixes[idx], nil
|
||||
@@ -46,22 +69,17 @@ func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
|
||||
|
||||
// RandaoMixesLength returns the length of the randao mixes slice.
|
||||
func (b *BeaconState) RandaoMixesLength() int {
|
||||
if b.randaoMixes == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.randaoMixesLength()
|
||||
}
|
||||
|
||||
// randaoMixesLength returns the length of the randao mixes slice.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) randaoMixesLength() int {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.randaoMixesMultiValue == nil {
|
||||
return 0
|
||||
}
|
||||
return b.randaoMixesMultiValue.Len(b)
|
||||
}
|
||||
if b.randaoMixes == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(b.randaoMixes)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/runtime/version"
|
||||
)
|
||||
@@ -16,6 +17,18 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
}
|
||||
|
||||
gvrCopy := b.genesisValidatorsRoot
|
||||
br := b.blockRootsVal().Slice()
|
||||
sr := b.stateRootsVal().Slice()
|
||||
rm := b.randaoMixesVal().Slice()
|
||||
var vals []*ethpb.Validator
|
||||
var bals []uint64
|
||||
if features.Get().EnableExperimentalState {
|
||||
vals = b.validatorsVal()
|
||||
bals = b.balancesVal()
|
||||
} else {
|
||||
vals = b.validators
|
||||
bals = b.balances
|
||||
}
|
||||
|
||||
switch b.version {
|
||||
case version.Phase0:
|
||||
@@ -25,15 +38,15 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Validators: vals,
|
||||
Balances: bals,
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochAttestations: b.previousEpochAttestations,
|
||||
CurrentEpochAttestations: b.currentEpochAttestations,
|
||||
@@ -49,15 +62,15 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Validators: vals,
|
||||
Balances: bals,
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochParticipation: b.previousEpochParticipation,
|
||||
CurrentEpochParticipation: b.currentEpochParticipation,
|
||||
@@ -65,7 +78,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: b.inactivityScores,
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
}
|
||||
@@ -76,15 +89,15 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Validators: vals,
|
||||
Balances: bals,
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochParticipation: b.previousEpochParticipation,
|
||||
CurrentEpochParticipation: b.currentEpochParticipation,
|
||||
@@ -92,7 +105,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: b.inactivityScores,
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,
|
||||
@@ -104,15 +117,15 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Validators: vals,
|
||||
Balances: bals,
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochParticipation: b.previousEpochParticipation,
|
||||
CurrentEpochParticipation: b.currentEpochParticipation,
|
||||
@@ -120,7 +133,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: b.inactivityScores,
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderCapella,
|
||||
@@ -135,15 +148,15 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Validators: vals,
|
||||
Balances: bals,
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochParticipation: b.previousEpochParticipation,
|
||||
CurrentEpochParticipation: b.currentEpochParticipation,
|
||||
@@ -174,6 +187,14 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
gvrCopy := b.genesisValidatorsRoot
|
||||
br := b.blockRootsVal().Slice()
|
||||
sr := b.stateRootsVal().Slice()
|
||||
rm := b.randaoMixesVal().Slice()
|
||||
|
||||
var inactivityScores []uint64
|
||||
if b.version > version.Phase0 {
|
||||
inactivityScores = b.inactivityScoresVal()
|
||||
}
|
||||
|
||||
switch b.version {
|
||||
case version.Phase0:
|
||||
@@ -183,15 +204,15 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.forkVal(),
|
||||
LatestBlockHeader: b.latestBlockHeaderVal(),
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1DataVal(),
|
||||
Eth1DataVotes: b.eth1DataVotesVal(),
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validatorsVal(),
|
||||
Balances: b.balancesVal(),
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashingsVal(),
|
||||
PreviousEpochAttestations: b.previousEpochAttestationsVal(),
|
||||
CurrentEpochAttestations: b.currentEpochAttestationsVal(),
|
||||
@@ -207,15 +228,15 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.forkVal(),
|
||||
LatestBlockHeader: b.latestBlockHeaderVal(),
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1DataVal(),
|
||||
Eth1DataVotes: b.eth1DataVotesVal(),
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validatorsVal(),
|
||||
Balances: b.balancesVal(),
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashingsVal(),
|
||||
PreviousEpochParticipation: b.previousEpochParticipationVal(),
|
||||
CurrentEpochParticipation: b.currentEpochParticipationVal(),
|
||||
@@ -223,7 +244,7 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
|
||||
FinalizedCheckpoint: b.finalizedCheckpointVal(),
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
InactivityScores: inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
|
||||
NextSyncCommittee: b.nextSyncCommitteeVal(),
|
||||
}
|
||||
@@ -234,15 +255,15 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.forkVal(),
|
||||
LatestBlockHeader: b.latestBlockHeaderVal(),
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1DataVal(),
|
||||
Eth1DataVotes: b.eth1DataVotesVal(),
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validatorsVal(),
|
||||
Balances: b.balancesVal(),
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashingsVal(),
|
||||
PreviousEpochParticipation: b.previousEpochParticipationVal(),
|
||||
CurrentEpochParticipation: b.currentEpochParticipationVal(),
|
||||
@@ -250,7 +271,7 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
|
||||
FinalizedCheckpoint: b.finalizedCheckpointVal(),
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
InactivityScores: inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
|
||||
NextSyncCommittee: b.nextSyncCommitteeVal(),
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderVal(),
|
||||
@@ -262,15 +283,15 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.forkVal(),
|
||||
LatestBlockHeader: b.latestBlockHeaderVal(),
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1DataVal(),
|
||||
Eth1DataVotes: b.eth1DataVotesVal(),
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validatorsVal(),
|
||||
Balances: b.balancesVal(),
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashingsVal(),
|
||||
PreviousEpochParticipation: b.previousEpochParticipationVal(),
|
||||
CurrentEpochParticipation: b.currentEpochParticipationVal(),
|
||||
@@ -278,7 +299,7 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
|
||||
FinalizedCheckpoint: b.finalizedCheckpointVal(),
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
InactivityScores: inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
|
||||
NextSyncCommittee: b.nextSyncCommitteeVal(),
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderCapellaVal(),
|
||||
@@ -293,15 +314,15 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
Slot: b.slot,
|
||||
Fork: b.forkVal(),
|
||||
LatestBlockHeader: b.latestBlockHeaderVal(),
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
BlockRoots: br,
|
||||
StateRoots: sr,
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1DataVal(),
|
||||
Eth1DataVotes: b.eth1DataVotesVal(),
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validatorsVal(),
|
||||
Balances: b.balancesVal(),
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
RandaoMixes: rm,
|
||||
Slashings: b.slashingsVal(),
|
||||
PreviousEpochParticipation: b.previousEpochParticipationVal(),
|
||||
CurrentEpochParticipation: b.currentEpochParticipationVal(),
|
||||
@@ -324,26 +345,46 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
|
||||
// StateRoots kept track of in the beacon state.
|
||||
func (b *BeaconState) StateRoots() [][]byte {
|
||||
if b.stateRoots == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.stateRoots.Slice()
|
||||
roots := b.stateRootsVal()
|
||||
if roots == nil {
|
||||
return nil
|
||||
}
|
||||
return roots.Slice()
|
||||
}
|
||||
|
||||
func (b *BeaconState) stateRootsVal() customtypes.StateRoots {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.stateRootsMultiValue == nil {
|
||||
return nil
|
||||
}
|
||||
return b.stateRootsMultiValue.Value(b)
|
||||
}
|
||||
return b.stateRoots
|
||||
}
|
||||
|
||||
// StateRootAtIndex retrieves a specific state root based on an
|
||||
// input index value.
|
||||
func (b *BeaconState) StateRootAtIndex(idx uint64) ([]byte, error) {
|
||||
if b.stateRoots == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.stateRootsMultiValue == nil {
|
||||
return nil, nil
|
||||
}
|
||||
r, err := b.stateRootsMultiValue.At(b, idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r[:], nil
|
||||
}
|
||||
|
||||
if b.stateRoots == nil {
|
||||
return nil, nil
|
||||
}
|
||||
r, err := b.stateRootAtIndex(idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -354,9 +395,11 @@ func (b *BeaconState) StateRootAtIndex(idx uint64) ([]byte, error) {
|
||||
// stateRootAtIndex retrieves a specific state root based on an
|
||||
// input index value.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
//
|
||||
// WARNING: This function does not work with the multi-value slice feature.
|
||||
func (b *BeaconState) stateRootAtIndex(idx uint64) ([32]byte, error) {
|
||||
if uint64(len(b.stateRoots)) <= idx {
|
||||
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
|
||||
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "state root index %d does not exist", idx)
|
||||
}
|
||||
return b.stateRoots[idx], nil
|
||||
}
|
||||
|
||||
@@ -1,57 +1,42 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/runtime/version"
|
||||
)
|
||||
|
||||
// ValidatorIndexOutOfRangeError represents an error scenario where a validator does not exist
|
||||
// at a given index in the validator's array.
|
||||
type ValidatorIndexOutOfRangeError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
// NewValidatorIndexOutOfRangeError creates a new error instance.
|
||||
func NewValidatorIndexOutOfRangeError(index primitives.ValidatorIndex) ValidatorIndexOutOfRangeError {
|
||||
return ValidatorIndexOutOfRangeError{
|
||||
message: fmt.Sprintf("index %d out of range", index),
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns the underlying error message.
|
||||
func (e *ValidatorIndexOutOfRangeError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
// Validators participating in consensus on the beacon chain.
|
||||
func (b *BeaconState) Validators() []*ethpb.Validator {
|
||||
if b.validators == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.validatorsVal()
|
||||
}
|
||||
|
||||
// validatorsVal participating in consensus on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) validatorsVal() []*ethpb.Validator {
|
||||
if b.validators == nil {
|
||||
return nil
|
||||
var v []*ethpb.Validator
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.validatorsMultiValue == nil {
|
||||
return nil
|
||||
}
|
||||
v = b.validatorsMultiValue.Value(b)
|
||||
} else {
|
||||
if b.validators == nil {
|
||||
return nil
|
||||
}
|
||||
v = b.validators
|
||||
}
|
||||
|
||||
res := make([]*ethpb.Validator, len(b.validators))
|
||||
res := make([]*ethpb.Validator, len(v))
|
||||
for i := 0; i < len(res); i++ {
|
||||
val := b.validators[i]
|
||||
val := v[i]
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
@@ -80,19 +65,42 @@ func (b *BeaconState) validatorsReferences() []*ethpb.Validator {
|
||||
return res
|
||||
}
|
||||
|
||||
func (b *BeaconState) validatorsLen() int {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.validatorsMultiValue == nil {
|
||||
return 0
|
||||
}
|
||||
return b.validatorsMultiValue.Len(b)
|
||||
}
|
||||
return len(b.validators)
|
||||
}
|
||||
|
||||
// ValidatorAtIndex is the validator at the provided index.
|
||||
func (b *BeaconState) ValidatorAtIndex(idx primitives.ValidatorIndex) (*ethpb.Validator, error) {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.validatorAtIndex(idx)
|
||||
}
|
||||
|
||||
func (b *BeaconState) validatorAtIndex(idx primitives.ValidatorIndex) (*ethpb.Validator, error) {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.validatorsMultiValue == nil {
|
||||
return ðpb.Validator{}, nil
|
||||
}
|
||||
v, err := b.validatorsMultiValue.At(b, uint64(idx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ethpb.CopyValidator(v), nil
|
||||
}
|
||||
|
||||
if b.validators == nil {
|
||||
return ðpb.Validator{}, nil
|
||||
}
|
||||
if uint64(len(b.validators)) <= uint64(idx) {
|
||||
e := NewValidatorIndexOutOfRangeError(idx)
|
||||
return nil, &e
|
||||
return nil, errors.Wrapf(consensus_types.ErrOutOfBounds, "validator index %d does not exist", idx)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
val := b.validators[idx]
|
||||
return ethpb.CopyValidator(val), nil
|
||||
}
|
||||
@@ -100,18 +108,28 @@ func (b *BeaconState) ValidatorAtIndex(idx primitives.ValidatorIndex) (*ethpb.Va
|
||||
// ValidatorAtIndexReadOnly is the validator at the provided index. This method
|
||||
// doesn't clone the validator.
|
||||
func (b *BeaconState) ValidatorAtIndexReadOnly(idx primitives.ValidatorIndex) (state.ReadOnlyValidator, error) {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.validatorsMultiValue == nil {
|
||||
return nil, state.ErrNilValidatorsInState
|
||||
}
|
||||
v, err := b.validatorsMultiValue.At(b, uint64(idx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewValidator(v)
|
||||
}
|
||||
|
||||
if b.validators == nil {
|
||||
return nil, state.ErrNilValidatorsInState
|
||||
}
|
||||
if uint64(len(b.validators)) <= uint64(idx) {
|
||||
e := NewValidatorIndexOutOfRangeError(idx)
|
||||
return nil, &e
|
||||
return nil, errors.Wrapf(consensus_types.ErrOutOfBounds, "validator index %d does not exist", idx)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return NewValidator(b.validators[idx])
|
||||
val := b.validators[idx]
|
||||
return NewValidator(val)
|
||||
}
|
||||
|
||||
// ValidatorIndexByPubkey returns a given validator by its 48-byte public key.
|
||||
@@ -121,7 +139,13 @@ func (b *BeaconState) ValidatorIndexByPubkey(key [fieldparams.BLSPubkeyLength]by
|
||||
}
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
numOfVals := len(b.validators)
|
||||
|
||||
var numOfVals int
|
||||
if features.Get().EnableExperimentalState {
|
||||
numOfVals = b.validatorsMultiValue.Len(b)
|
||||
} else {
|
||||
numOfVals = len(b.validators)
|
||||
}
|
||||
|
||||
idx, ok := b.valMapHandler.Get(key)
|
||||
if ok && primitives.ValidatorIndex(numOfVals) <= idx {
|
||||
@@ -133,16 +157,27 @@ func (b *BeaconState) ValidatorIndexByPubkey(key [fieldparams.BLSPubkeyLength]by
|
||||
// PubkeyAtIndex returns the pubkey at the given
|
||||
// validator index.
|
||||
func (b *BeaconState) PubkeyAtIndex(idx primitives.ValidatorIndex) [fieldparams.BLSPubkeyLength]byte {
|
||||
if uint64(idx) >= uint64(len(b.validators)) {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}
|
||||
}
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if b.validators[idx] == nil {
|
||||
var v *ethpb.Validator
|
||||
if features.Get().EnableExperimentalState {
|
||||
var err error
|
||||
v, err = b.validatorsMultiValue.At(b, uint64(idx))
|
||||
if err != nil {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}
|
||||
}
|
||||
} else {
|
||||
if uint64(idx) >= uint64(len(b.validators)) {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}
|
||||
}
|
||||
v = b.validators[idx]
|
||||
}
|
||||
|
||||
if v == nil {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}
|
||||
}
|
||||
return bytesutil.ToBytes48(b.validators[idx].PublicKey)
|
||||
return bytesutil.ToBytes48(v.PublicKey)
|
||||
}
|
||||
|
||||
// NumValidators returns the size of the validator registry.
|
||||
@@ -150,26 +185,54 @@ func (b *BeaconState) NumValidators() int {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return len(b.validators)
|
||||
return b.validatorsLen()
|
||||
}
|
||||
|
||||
// ReadFromEveryValidator reads values from every validator and applies it to the provided function.
|
||||
//
|
||||
// WARNING: This method is potentially unsafe, as it exposes the actual validator registry.
|
||||
func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val state.ReadOnlyValidator) error) error {
|
||||
if b.validators == nil {
|
||||
return errors.New("nil validators in state")
|
||||
}
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if features.Get().EnableExperimentalState {
|
||||
return b.readFromEveryValidatorMVSlice(f)
|
||||
}
|
||||
|
||||
if b.validators == nil {
|
||||
return state.ErrNilValidatorsInState
|
||||
}
|
||||
|
||||
validators := b.validators
|
||||
b.lock.RUnlock()
|
||||
|
||||
for i, v := range validators {
|
||||
v, err := NewValidator(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f(i, v); err != nil {
|
||||
if err = f(i, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WARNING: This function works only for the multi-value slice feature.
|
||||
func (b *BeaconState) readFromEveryValidatorMVSlice(f func(idx int, val state.ReadOnlyValidator) error) error {
|
||||
if b.validatorsMultiValue == nil {
|
||||
return state.ErrNilValidatorsInState
|
||||
}
|
||||
l := b.validatorsMultiValue.Len(b)
|
||||
for i := 0; i < l; i++ {
|
||||
v, err := b.validatorsMultiValue.At(b, uint64(i))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rov, err := NewValidator(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = f(i, rov); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -178,23 +241,22 @@ func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val state.ReadOnlyV
|
||||
|
||||
// Balances of validators participating in consensus on the beacon chain.
|
||||
func (b *BeaconState) Balances() []uint64 {
|
||||
if b.balances == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.balancesVal()
|
||||
}
|
||||
|
||||
// balancesVal of validators participating in consensus on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) balancesVal() []uint64 {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.balancesMultiValue == nil {
|
||||
return nil
|
||||
}
|
||||
return b.balancesMultiValue.Value(b)
|
||||
}
|
||||
if b.balances == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]uint64, len(b.balances))
|
||||
copy(res, b.balances)
|
||||
return res
|
||||
@@ -202,29 +264,40 @@ func (b *BeaconState) balancesVal() []uint64 {
|
||||
|
||||
// BalanceAtIndex of validator with the provided index.
|
||||
func (b *BeaconState) BalanceAtIndex(idx primitives.ValidatorIndex) (uint64, error) {
|
||||
if b.balances == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.balanceAtIndex(idx)
|
||||
}
|
||||
|
||||
func (b *BeaconState) balanceAtIndex(idx primitives.ValidatorIndex) (uint64, error) {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.balancesMultiValue == nil {
|
||||
return 0, nil
|
||||
}
|
||||
return b.balancesMultiValue.At(b, uint64(idx))
|
||||
}
|
||||
if b.balances == nil {
|
||||
return 0, nil
|
||||
}
|
||||
if uint64(len(b.balances)) <= uint64(idx) {
|
||||
return 0, fmt.Errorf("index of %d does not exist", idx)
|
||||
return 0, errors.Wrapf(consensus_types.ErrOutOfBounds, "balance index %d does not exist", idx)
|
||||
}
|
||||
return b.balances[idx], nil
|
||||
}
|
||||
|
||||
// BalancesLength returns the length of the balances slice.
|
||||
func (b *BeaconState) BalancesLength() int {
|
||||
if b.balances == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.balancesLength()
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.balancesMultiValue == nil {
|
||||
return 0
|
||||
}
|
||||
return b.balancesMultiValue.Len(b)
|
||||
}
|
||||
return len(b.balances)
|
||||
}
|
||||
|
||||
// Slashings of validators on the beacon chain.
|
||||
@@ -257,23 +330,22 @@ func (b *BeaconState) InactivityScores() ([]uint64, error) {
|
||||
return nil, errNotSupported("InactivityScores", b.version)
|
||||
}
|
||||
|
||||
if b.inactivityScores == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.inactivityScoresVal(), nil
|
||||
}
|
||||
|
||||
// inactivityScoresVal of validators participating in consensus on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) inactivityScoresVal() []uint64 {
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.inactivityScoresMultiValue == nil {
|
||||
return nil
|
||||
}
|
||||
return b.inactivityScoresMultiValue.Value(b)
|
||||
}
|
||||
if b.inactivityScores == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]uint64, len(b.inactivityScores))
|
||||
copy(res, b.inactivityScores)
|
||||
return res
|
||||
|
||||
@@ -52,11 +52,6 @@ func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice_Deneb(t *testing.T
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidatorIndexOutOfRangeError(t *testing.T) {
|
||||
err := statenative.NewValidatorIndexOutOfRangeError(1)
|
||||
require.Equal(t, err.Error(), "index 1 out of range")
|
||||
}
|
||||
|
||||
func TestValidatorIndexes(t *testing.T) {
|
||||
dState, _ := util.DeterministicGenesisState(t, 10)
|
||||
byteValue := dState.PubkeyAtIndex(1)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
@@ -54,10 +55,17 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, error) {
|
||||
withdrawalIndex := b.nextWithdrawalIndex
|
||||
epoch := slots.ToEpoch(b.slot)
|
||||
|
||||
bound := mathutil.Min(uint64(len(b.validators)), params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep)
|
||||
validatorsLen := b.validatorsLen()
|
||||
bound := mathutil.Min(uint64(validatorsLen), params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep)
|
||||
for i := uint64(0); i < bound; i++ {
|
||||
val := b.validators[validatorIndex]
|
||||
balance := b.balances[validatorIndex]
|
||||
val, err := b.validatorAtIndex(validatorIndex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not retrieve validator at index %d", validatorIndex)
|
||||
}
|
||||
balance, err := b.balanceAtIndex(validatorIndex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not retrieve balance at index %d", validatorIndex)
|
||||
}
|
||||
if balance > 0 && isFullyWithdrawableValidator(val, epoch) {
|
||||
withdrawals = append(withdrawals, &enginev1.Withdrawal{
|
||||
Index: withdrawalIndex,
|
||||
@@ -79,7 +87,7 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, error) {
|
||||
break
|
||||
}
|
||||
validatorIndex += 1
|
||||
if uint64(validatorIndex) == uint64(len(b.validators)) {
|
||||
if uint64(validatorIndex) == uint64(validatorsLen) {
|
||||
validatorIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,22 +65,14 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
|
||||
fieldRoots[types.LatestBlockHeader.RealPosition()] = headerHashTreeRoot[:]
|
||||
|
||||
// BlockRoots array root.
|
||||
bRoots := make([][]byte, len(state.blockRoots))
|
||||
for i := range bRoots {
|
||||
bRoots[i] = state.blockRoots[i][:]
|
||||
}
|
||||
blockRootsRoot, err := stateutil.ArraysRoot(bRoots, fieldparams.BlockRootsLength)
|
||||
blockRootsRoot, err := stateutil.ArraysRoot(state.blockRootsVal().Slice(), fieldparams.BlockRootsLength)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute block roots merkleization")
|
||||
}
|
||||
fieldRoots[types.BlockRoots.RealPosition()] = blockRootsRoot[:]
|
||||
|
||||
// StateRoots array root.
|
||||
sRoots := make([][]byte, len(state.stateRoots))
|
||||
for i := range sRoots {
|
||||
sRoots[i] = state.stateRoots[i][:]
|
||||
}
|
||||
stateRootsRoot, err := stateutil.ArraysRoot(sRoots, fieldparams.StateRootsLength)
|
||||
stateRootsRoot, err := stateutil.ArraysRoot(state.stateRootsVal().Slice(), fieldparams.StateRootsLength)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute state roots merkleization")
|
||||
}
|
||||
@@ -118,25 +110,21 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
|
||||
fieldRoots[types.Eth1DepositIndex.RealPosition()] = eth1DepositBuf[:]
|
||||
|
||||
// Validators slice root.
|
||||
validatorsRoot, err := stateutil.ValidatorRegistryRoot(state.validators)
|
||||
validatorsRoot, err := stateutil.ValidatorRegistryRoot(state.validatorsVal())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute validator registry merkleization")
|
||||
}
|
||||
fieldRoots[types.Validators.RealPosition()] = validatorsRoot[:]
|
||||
|
||||
// Balances slice root.
|
||||
balancesRoot, err := stateutil.Uint64ListRootWithRegistryLimit(state.balances)
|
||||
balancesRoot, err := stateutil.Uint64ListRootWithRegistryLimit(state.balancesVal())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute validator balances merkleization")
|
||||
}
|
||||
fieldRoots[types.Balances.RealPosition()] = balancesRoot[:]
|
||||
|
||||
// RandaoMixes array root.
|
||||
mixes := make([][]byte, len(state.randaoMixes))
|
||||
for i := range mixes {
|
||||
mixes[i] = state.randaoMixes[i][:]
|
||||
}
|
||||
randaoRootsRoot, err := stateutil.ArraysRoot(mixes, fieldparams.RandaoMixesLength)
|
||||
randaoRootsRoot, err := stateutil.ArraysRoot(state.randaoMixesVal().Slice(), fieldparams.RandaoMixesLength)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute randao roots merkleization")
|
||||
}
|
||||
@@ -208,7 +196,7 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
|
||||
|
||||
if state.version >= version.Altair {
|
||||
// Inactivity scores root.
|
||||
inactivityScoresRoot, err := stateutil.Uint64ListRootWithRegistryLimit(state.inactivityScores)
|
||||
inactivityScoresRoot, err := stateutil.Uint64ListRootWithRegistryLimit(state.inactivityScoresVal())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute inactivityScoreRoot")
|
||||
}
|
||||
|
||||
145
beacon-chain/state/state-native/multi_value_slices.go
Normal file
145
beacon-chain/state/state-native/multi_value_slices.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
multi_value_slice "github.com/prysmaticlabs/prysm/v4/container/multi-value-slice"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
multiValueRandaoMixesCountGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "multi_value_randao_mixes_count",
|
||||
})
|
||||
multiValueBlockRootsCountGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "multi_value_block_roots_count",
|
||||
})
|
||||
multiValueStateRootsCountGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "multi_value_state_roots_count",
|
||||
})
|
||||
multiValueBalancesCountGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "multi_value_balances_count",
|
||||
})
|
||||
multiValueValidatorsCountGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "multi_value_validators_count",
|
||||
})
|
||||
multiValueInactivityScoresCountGauge = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "multi_value_inactivity_scores_count",
|
||||
})
|
||||
)
|
||||
|
||||
// MultiValueRandaoMixes is a multi-value slice of randao mixes.
|
||||
type MultiValueRandaoMixes = multi_value_slice.Slice[[32]byte, *BeaconState]
|
||||
|
||||
// NewMultiValueRandaoMixes creates a new slice whose shared items will be populated with copies of input values.
|
||||
func NewMultiValueRandaoMixes(mixes [][]byte) *MultiValueRandaoMixes {
|
||||
items := make([][32]byte, fieldparams.RandaoMixesLength)
|
||||
for i, v := range mixes {
|
||||
items[i] = [32]byte(bytesutil.PadTo(v, 32))
|
||||
}
|
||||
mv := &MultiValueRandaoMixes{}
|
||||
mv.Init(items)
|
||||
multiValueRandaoMixesCountGauge.Inc()
|
||||
runtime.SetFinalizer(mv, randaoMixesFinalizer)
|
||||
return mv
|
||||
}
|
||||
|
||||
// MultiValueBlockRoots is a multi-value slice of block roots.
|
||||
type MultiValueBlockRoots = multi_value_slice.Slice[[32]byte, *BeaconState]
|
||||
|
||||
// NewMultiValueBlockRoots creates a new slice whose shared items will be populated with copies of input values.
|
||||
func NewMultiValueBlockRoots(roots [][]byte) *MultiValueBlockRoots {
|
||||
items := make([][32]byte, fieldparams.BlockRootsLength)
|
||||
for i, v := range roots {
|
||||
items[i] = [32]byte(bytesutil.PadTo(v, 32))
|
||||
}
|
||||
mv := &MultiValueBlockRoots{}
|
||||
mv.Init(items)
|
||||
multiValueBlockRootsCountGauge.Inc()
|
||||
runtime.SetFinalizer(mv, blockRootsFinalizer)
|
||||
return mv
|
||||
}
|
||||
|
||||
// MultiValueStateRoots is a multi-value slice of state roots.
|
||||
type MultiValueStateRoots = multi_value_slice.Slice[[32]byte, *BeaconState]
|
||||
|
||||
// NewMultiValueStateRoots creates a new slice whose shared items will be populated with copies of input values.
|
||||
func NewMultiValueStateRoots(roots [][]byte) *MultiValueStateRoots {
|
||||
items := make([][32]byte, fieldparams.StateRootsLength)
|
||||
for i, v := range roots {
|
||||
items[i] = [32]byte(bytesutil.PadTo(v, 32))
|
||||
}
|
||||
mv := &MultiValueStateRoots{}
|
||||
mv.Init(items)
|
||||
multiValueStateRootsCountGauge.Inc()
|
||||
runtime.SetFinalizer(mv, stateRootsFinalizer)
|
||||
return mv
|
||||
}
|
||||
|
||||
// MultiValueBalances is a multi-value slice of balances.
|
||||
type MultiValueBalances = multi_value_slice.Slice[uint64, *BeaconState]
|
||||
|
||||
// NewMultiValueBalances creates a new slice whose shared items will be populated with copies of input values.
|
||||
func NewMultiValueBalances(balances []uint64) *MultiValueBalances {
|
||||
items := make([]uint64, len(balances))
|
||||
copy(items, balances)
|
||||
mv := &MultiValueBalances{}
|
||||
mv.Init(items)
|
||||
multiValueBalancesCountGauge.Inc()
|
||||
runtime.SetFinalizer(mv, balancesFinalizer)
|
||||
return mv
|
||||
}
|
||||
|
||||
// MultiValueInactivityScores is a multi-value slice of inactivity scores.
|
||||
type MultiValueInactivityScores = multi_value_slice.Slice[uint64, *BeaconState]
|
||||
|
||||
// NewMultiValueInactivityScores creates a new slice whose shared items will be populated with copies of input values.
|
||||
func NewMultiValueInactivityScores(scores []uint64) *MultiValueInactivityScores {
|
||||
items := make([]uint64, len(scores))
|
||||
copy(items, scores)
|
||||
mv := &MultiValueInactivityScores{}
|
||||
mv.Init(items)
|
||||
multiValueInactivityScoresCountGauge.Inc()
|
||||
runtime.SetFinalizer(mv, inactivityScoresFinalizer)
|
||||
return mv
|
||||
}
|
||||
|
||||
// MultiValueValidators is a multi-value slice of validator references.
|
||||
type MultiValueValidators = multi_value_slice.Slice[*ethpb.Validator, *BeaconState]
|
||||
|
||||
// NewMultiValueValidators creates a new slice whose shared items will be populated with input values.
|
||||
func NewMultiValueValidators(vals []*ethpb.Validator) *MultiValueValidators {
|
||||
mv := &MultiValueValidators{}
|
||||
mv.Init(vals)
|
||||
multiValueValidatorsCountGauge.Inc()
|
||||
runtime.SetFinalizer(mv, validatorsFinalizer)
|
||||
return mv
|
||||
}
|
||||
|
||||
func randaoMixesFinalizer(m *MultiValueRandaoMixes) {
|
||||
multiValueRandaoMixesCountGauge.Dec()
|
||||
}
|
||||
|
||||
func blockRootsFinalizer(m *MultiValueBlockRoots) {
|
||||
multiValueBlockRootsCountGauge.Dec()
|
||||
}
|
||||
|
||||
func stateRootsFinalizer(m *MultiValueStateRoots) {
|
||||
multiValueStateRootsCountGauge.Dec()
|
||||
}
|
||||
|
||||
func balancesFinalizer(m *MultiValueBalances) {
|
||||
multiValueBalancesCountGauge.Dec()
|
||||
}
|
||||
|
||||
func validatorsFinalizer(m *MultiValueValidators) {
|
||||
multiValueValidatorsCountGauge.Dec()
|
||||
}
|
||||
|
||||
func inactivityScoresFinalizer(m *MultiValueInactivityScores) {
|
||||
multiValueInactivityScoresCountGauge.Dec()
|
||||
}
|
||||
71
beacon-chain/state/state-native/mvslice_fuzz_test.go
Normal file
71
beacon-chain/state/state-native/mvslice_fuzz_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
||||
)
|
||||
|
||||
func FuzzMultiValueBalances(f *testing.F) {
|
||||
resetFn := features.InitWithReset(&features.Flags{
|
||||
EnableExperimentalState: true,
|
||||
})
|
||||
defer resetFn()
|
||||
|
||||
bals := make([]uint64, 65536)
|
||||
firstState, err := InitializeFromProtoPhase0(ðpb.BeaconState{Balances: bals})
|
||||
require.NoError(f, err)
|
||||
|
||||
f.Fuzz(func(t *testing.T, index uint16, value uint64) {
|
||||
secondState := firstState
|
||||
// there's a 25% chance we will copy the state
|
||||
copyState := index%4 == 0
|
||||
if copyState {
|
||||
secondState = firstState.Copy()
|
||||
}
|
||||
if index%2 == 0 {
|
||||
// update existing balance
|
||||
|
||||
oldValue, err := firstState.BalanceAtIndex(primitives.ValidatorIndex(index))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, secondState.UpdateBalancesAtIndex(primitives.ValidatorIndex(index), value))
|
||||
|
||||
firstValue, err := firstState.BalanceAtIndex(primitives.ValidatorIndex(index))
|
||||
require.NoError(t, err)
|
||||
secondValue, err := secondState.BalanceAtIndex(primitives.ValidatorIndex(index))
|
||||
require.NoError(t, err)
|
||||
if copyState {
|
||||
require.Equal(t, oldValue, firstValue)
|
||||
require.Equal(t, value, secondValue)
|
||||
} else {
|
||||
require.Equal(t, value, firstValue)
|
||||
require.Equal(t, value, secondValue)
|
||||
}
|
||||
} else {
|
||||
// append new balance
|
||||
|
||||
firstLength := firstState.BalancesLength()
|
||||
|
||||
require.NoError(t, secondState.AppendBalance(value))
|
||||
|
||||
if copyState {
|
||||
require.Equal(t, firstLength, secondState.BalancesLength())
|
||||
v, err := firstState.BalanceAtIndex(primitives.ValidatorIndex(firstLength - 1))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value, v)
|
||||
v, err = secondState.BalanceAtIndex(primitives.ValidatorIndex(secondState.BalancesLength() - 1))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value, v)
|
||||
} else {
|
||||
require.Equal(t, firstLength+1, secondState.BalancesLength())
|
||||
v, err := secondState.BalanceAtIndex(primitives.ValidatorIndex(secondState.BalancesLength() - 1))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, value, v)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v4/testing/assert"
|
||||
@@ -38,7 +39,7 @@ func TestStateReferenceSharing_Finalizer_Phase0(t *testing.T) {
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
|
||||
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
@@ -67,7 +68,7 @@ func TestStateReferenceSharing_Finalizer_Altair(t *testing.T) {
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
|
||||
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
@@ -96,7 +97,7 @@ func TestStateReferenceSharing_Finalizer_Bellatrix(t *testing.T) {
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
|
||||
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
@@ -125,7 +126,7 @@ func TestStateReferenceSharing_Finalizer_Capella(t *testing.T) {
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
|
||||
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
@@ -154,7 +155,7 @@ func TestStateReferenceSharing_Finalizer_Deneb(t *testing.T) {
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
|
||||
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
@@ -482,7 +483,7 @@ func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Phase0(t *testing.T) {
|
||||
assertValFound(t, mixesB, val1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValFound(t, a.RandaoMixes(), val2[:])
|
||||
@@ -526,7 +527,7 @@ func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Altair(t *testing.T) {
|
||||
assertValFound(t, mixesB, val1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValFound(t, a.RandaoMixes(), val2[:])
|
||||
@@ -570,7 +571,7 @@ func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Bellatrix(t *testing.T) {
|
||||
assertValFound(t, mixesB, val1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValFound(t, a.RandaoMixes(), val2[:])
|
||||
@@ -614,7 +615,7 @@ func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Capella(t *testing.T) {
|
||||
assertValFound(t, mixesB, val1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValFound(t, a.RandaoMixes(), val2[:])
|
||||
@@ -658,7 +659,7 @@ func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Deneb(t *testing.T) {
|
||||
assertValFound(t, mixesB, val1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValFound(t, a.RandaoMixes(), val2[:])
|
||||
@@ -1015,6 +1016,43 @@ func TestValidatorReferences_RemainsConsistent_Bellatrix(t *testing.T) {
|
||||
}))
|
||||
}
|
||||
|
||||
func TestValidatorReferences_ApplyValidator_BalancesRead(t *testing.T) {
|
||||
resetCfg := features.InitWithReset(&features.Flags{
|
||||
EnableExperimentalState: true,
|
||||
})
|
||||
defer resetCfg()
|
||||
s, err := InitializeFromProtoUnsafeAltair(ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{
|
||||
{PublicKey: []byte{'A'}},
|
||||
{PublicKey: []byte{'B'}},
|
||||
{PublicKey: []byte{'C'}},
|
||||
{PublicKey: []byte{'D'}},
|
||||
{PublicKey: []byte{'E'}},
|
||||
},
|
||||
Balances: []uint64{0, 0, 0, 0, 0},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
// Create a second state.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
// Modify all validators from copied state, it should not deadlock.
|
||||
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
|
||||
b, err := b.BalanceAtIndex(0)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
newVal := ethpb.CopyValidator(val)
|
||||
newVal.EffectiveBalance += b
|
||||
val.EffectiveBalance += b
|
||||
return true, val, nil
|
||||
}))
|
||||
}
|
||||
|
||||
// assertRefCount checks whether reference count for a given state
|
||||
// at a given index is equal to expected amount.
|
||||
func assertRefCount(t *testing.T, b *BeaconState, idx types.FieldIndex, want uint) {
|
||||
|
||||
@@ -90,8 +90,8 @@ func (b *BeaconState) AppendPreviousEpochAttestations(val *ethpb.PendingAttestat
|
||||
}
|
||||
|
||||
if b.sharedFieldReferences[types.PreviousEpochAttestations].Refs() > 1 {
|
||||
atts = make([]*ethpb.PendingAttestation, len(b.previousEpochAttestations))
|
||||
copy(atts, b.previousEpochAttestations)
|
||||
atts = make([]*ethpb.PendingAttestation, 0, len(b.previousEpochAttestations)+1)
|
||||
atts = append(atts, b.previousEpochAttestations...)
|
||||
b.sharedFieldReferences[types.PreviousEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[types.PreviousEpochAttestations] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
@@ -74,3 +74,27 @@ func TestAppendBeyondIndicesLimit(t *testing.T) {
|
||||
assert.Equal(t, true, s.rebuildTrie[types.Validators])
|
||||
assert.Equal(t, len(s.dirtyIndices[types.Validators]), 0)
|
||||
}
|
||||
|
||||
func BenchmarkAppendPreviousEpochAttestations(b *testing.B) {
|
||||
st, err := InitializeFromProtoPhase0(ðpb.BeaconState{})
|
||||
require.NoError(b, err)
|
||||
|
||||
max := uint64(params.BeaconConfig().PreviousEpochAttestationsLength())
|
||||
if max < 2 {
|
||||
b.Fatalf("previous epoch attestations length is less than 2: %d", max)
|
||||
}
|
||||
|
||||
for i := uint64(0); i < max-2; i++ {
|
||||
err := st.AppendPreviousEpochAttestations(ðpb.PendingAttestation{Data: ðpb.AttestationData{Slot: primitives.Slot(i)}})
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
ref := st.Copy()
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := ref.AppendPreviousEpochAttestations(ðpb.PendingAttestation{Data: ðpb.AttestationData{Slot: primitives.Slot(i)}})
|
||||
require.NoError(b, err)
|
||||
ref = st.Copy()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
customtypes "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v4/consensus-types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -26,15 +26,22 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[types.BlockRoots].MinusRef()
|
||||
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
|
||||
if features.Get().EnableExperimentalState {
|
||||
if b.blockRootsMultiValue != nil {
|
||||
b.blockRootsMultiValue.Detach(b)
|
||||
}
|
||||
b.blockRootsMultiValue = NewMultiValueBlockRoots(val)
|
||||
} else {
|
||||
b.sharedFieldReferences[types.BlockRoots].MinusRef()
|
||||
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
|
||||
|
||||
var rootsArr [fieldparams.BlockRootsLength][32]byte
|
||||
for i := 0; i < len(rootsArr); i++ {
|
||||
copy(rootsArr[i][:], val[i])
|
||||
rootsArr := make([][32]byte, fieldparams.BlockRootsLength)
|
||||
for i := 0; i < len(rootsArr); i++ {
|
||||
copy(rootsArr[i][:], val[i])
|
||||
}
|
||||
b.blockRoots = rootsArr
|
||||
}
|
||||
roots := customtypes.BlockRoots(rootsArr)
|
||||
b.blockRoots = &roots
|
||||
|
||||
b.markFieldAsDirty(types.BlockRoots)
|
||||
b.rebuildTrie[types.BlockRoots] = true
|
||||
return nil
|
||||
@@ -43,24 +50,29 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
|
||||
// UpdateBlockRootAtIndex for the beacon state. Updates the block root
|
||||
// at a specific index to a new value.
|
||||
func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error {
|
||||
if uint64(len(b.blockRoots)) <= idx {
|
||||
return fmt.Errorf("invalid index provided %d", idx)
|
||||
}
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
r := b.blockRoots
|
||||
if ref := b.sharedFieldReferences[types.BlockRoots]; ref.Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
roots := *b.blockRoots
|
||||
rootsCopy := roots
|
||||
r = &rootsCopy
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
|
||||
}
|
||||
if features.Get().EnableExperimentalState {
|
||||
if err := b.blockRootsMultiValue.UpdateAt(b, idx, blockRoot); err != nil {
|
||||
return errors.Wrap(err, "could not update block roots")
|
||||
}
|
||||
} else {
|
||||
if uint64(len(b.blockRoots)) <= idx {
|
||||
return errors.Wrapf(consensus_types.ErrOutOfBounds, "block root index %d does not exist", idx)
|
||||
}
|
||||
|
||||
r[idx] = blockRoot
|
||||
b.blockRoots = r
|
||||
r := b.blockRoots
|
||||
if ref := b.sharedFieldReferences[types.BlockRoots]; ref.Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
r = make([][32]byte, len(b.blockRoots))
|
||||
copy(r, b.blockRoots)
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
|
||||
}
|
||||
r[idx] = blockRoot
|
||||
b.blockRoots = r
|
||||
}
|
||||
|
||||
b.markFieldAsDirty(types.BlockRoots)
|
||||
b.addDirtyIndices(types.BlockRoots, []uint64{idx})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user