mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
18 Commits
set-invali
...
update-qui
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87357f1226 | ||
|
|
807b71244b | ||
|
|
2744eba391 | ||
|
|
5507558678 | ||
|
|
8cecd4e8bf | ||
|
|
69a9388515 | ||
|
|
bd308b6d73 | ||
|
|
9abea200a5 | ||
|
|
730678bf21 | ||
|
|
0b1a777d62 | ||
|
|
5461c5b84f | ||
|
|
03e7acbf9f | ||
|
|
6cc88e6454 | ||
|
|
65cea17268 | ||
|
|
aa86c94a91 | ||
|
|
75bb25d515 | ||
|
|
1e845bc276 | ||
|
|
58f7e942f2 |
@@ -1 +1 @@
|
||||
4.2.2
|
||||
5.0.0
|
||||
|
||||
@@ -10,26 +10,26 @@
|
||||
|
||||
# Prysm specific remote-cache properties.
|
||||
#build:remote-cache --disk_cache=
|
||||
build:remote-cache --remote_download_toplevel
|
||||
build:remote-cache --remote_download_minimal
|
||||
build:remote-cache --remote_cache=grpc://bazel-remote-cache:9092
|
||||
build:remote-cache --experimental_remote_downloader=grpc://bazel-remote-cache:9092
|
||||
build:remote-cache --remote_local_fallback
|
||||
build:remote-cache --experimental_remote_cache_async
|
||||
build:remote-cache --experimental_remote_merkle_tree_cache
|
||||
build:remote-cache --experimental_action_cache_store_output_metadata
|
||||
build:remote-cache --experimental_remote_cache_compression
|
||||
# Enforce stricter environment rules, which eliminates some non-hermetic
|
||||
# behavior and therefore improves both the remote cache hit rate and the
|
||||
# correctness and repeatability of the build.
|
||||
build:remote-cache --incompatible_strict_action_env=true
|
||||
|
||||
build --experimental_use_hermetic_linux_sandbox
|
||||
|
||||
# Import workspace options.
|
||||
import %workspace%/.bazelrc
|
||||
|
||||
startup --host_jvm_args=-Xmx2g --host_jvm_args=-Xms2g
|
||||
query --repository_cache=/tmp/repositorycache
|
||||
query --experimental_repository_cache_hardlinks
|
||||
build --repository_cache=/tmp/repositorycache
|
||||
build --experimental_repository_cache_hardlinks
|
||||
startup --host_jvm_args=-Xmx4g --host_jvm_args=-Xms2g
|
||||
build --experimental_strict_action_env
|
||||
build --disk_cache=/tmp/bazelbuilds
|
||||
build --experimental_multi_threaded_digest
|
||||
build --sandbox_tmpfs_path=/tmp
|
||||
build --verbose_failures
|
||||
build --announce_rc
|
||||
|
||||
@@ -3,7 +3,7 @@ load("@com_github_atlassian_bazel_tools//gometalinter:def.bzl", "gometalinter")
|
||||
load("@com_github_atlassian_bazel_tools//goimports:def.bzl", "goimports")
|
||||
load("@io_kubernetes_build//defs:run_in_workspace.bzl", "workspace_binary")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "nogo")
|
||||
load("@graknlabs_bazel_distribution//common:rules.bzl", "assemble_targz", "assemble_versioned")
|
||||
load("@vaticle_bazel_distribution//common:rules.bzl", "assemble_targz", "assemble_versioned")
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "string_setting")
|
||||
|
||||
prefix = "github.com/prysmaticlabs/prysm"
|
||||
|
||||
17
WORKSPACE
17
WORKSPACE
@@ -117,13 +117,6 @@ http_archive(
|
||||
urls = ["https://github.com/fuzzitdev/fuzzit/releases/download/v2.4.76/fuzzit_Linux_x86_64.zip"],
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "graknlabs_bazel_distribution",
|
||||
commit = "962f3a7e56942430c0ec120c24f9e9f2a9c2ce1a",
|
||||
remote = "https://github.com/graknlabs/bazel-distribution",
|
||||
shallow_since = "1569509514 +0300",
|
||||
)
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_docker//repositories:repositories.bzl",
|
||||
container_repositories = "repositories",
|
||||
@@ -222,7 +215,7 @@ filegroup(
|
||||
url = "https://github.com/eth-clients/slashing-protection-interchange-tests/archive/b8413ca42dc92308019d0d4db52c87e9e125c4e9.tar.gz",
|
||||
)
|
||||
|
||||
consensus_spec_version = "v1.1.9"
|
||||
consensus_spec_version = "v1.1.10"
|
||||
|
||||
bls_test_version = "v0.1.1"
|
||||
|
||||
@@ -238,7 +231,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "207d9c326ba4fa1f34bab7b6169201c32f2611755db030909a3405873445e0ba",
|
||||
sha256 = "28043009cc2f6fc9804e73c8c1fc2cb27062f1591e6884f3015ae1dd7a276883",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -254,7 +247,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "a3995b39f412db236b2f1db909f288218da53cb53b9923b71dda9d144d68f40a",
|
||||
sha256 = "bc1a283ca068f310f04d70c4f6a8eaa0b8f7e9318073a8bdc2ee233111b4e339",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -270,7 +263,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "76cea7a4c8e32d458ad456b54bfbb30bc772481a91954a4cd97e229aa3023b1d",
|
||||
sha256 = "bbabb482c229ff9d4e2c7b77c992edb452f9d0af7c6d8dd4f922f06a7b101e81",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -285,7 +278,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "0fc429684775f943250dce1f9c485ac25e26c6395d7f585c8d1317becec2ace7",
|
||||
sha256 = "408a5524548ad3fcf387f65ac7ec52781d9ee899499720bb12451b48a15818d4",
|
||||
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
|
||||
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
@@ -323,13 +325,44 @@ func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return s.cfg.ForkChoiceStore.IsOptimistic(ctx, s.head.root)
|
||||
return s.IsOptimisticForRoot(ctx, s.head.root)
|
||||
}
|
||||
|
||||
// IsOptimisticForRoot takes the root and slot as aguments instead of the current head
|
||||
// and returns true if it is optimistic.
|
||||
func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool, error) {
|
||||
return s.cfg.ForkChoiceStore.IsOptimistic(ctx, root)
|
||||
optimistic, err := s.cfg.ForkChoiceStore.IsOptimistic(ctx, root)
|
||||
if err == nil {
|
||||
return optimistic, nil
|
||||
}
|
||||
if err != protoarray.ErrUnknownNodeRoot && err != doublylinkedtree.ErrNilNode {
|
||||
return false, err
|
||||
}
|
||||
ss, err := s.cfg.BeaconDB.StateSummary(ctx, root)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if ss == nil {
|
||||
return false, errInvalidNilSummary
|
||||
}
|
||||
|
||||
validatedCheckpoint, err := s.cfg.BeaconDB.LastValidatedCheckpoint(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if slots.ToEpoch(ss.Slot) > validatedCheckpoint.Epoch {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if slots.ToEpoch(ss.Slot)+1 < validatedCheckpoint.Epoch {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
lastValidated, err := s.cfg.BeaconDB.StateSummary(ctx, bytesutil.ToBytes32(validatedCheckpoint.Root))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return ss.Slot > lastValidated.Slot, nil
|
||||
}
|
||||
|
||||
// SetGenesisTime sets the genesis time of beacon chain.
|
||||
|
||||
@@ -16,10 +16,13 @@ func TestHeadSlot_DataRace(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB},
|
||||
}
|
||||
wait := make(chan struct{})
|
||||
go func() {
|
||||
defer close(wait)
|
||||
require.NoError(t, s.saveHead(context.Background(), [32]byte{}))
|
||||
}()
|
||||
s.HeadSlot()
|
||||
<-wait
|
||||
}
|
||||
|
||||
func TestHeadRoot_DataRace(t *testing.T) {
|
||||
@@ -28,11 +31,14 @@ func TestHeadRoot_DataRace(t *testing.T) {
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
head: &head{root: [32]byte{'A'}},
|
||||
}
|
||||
wait := make(chan struct{})
|
||||
go func() {
|
||||
defer close(wait)
|
||||
require.NoError(t, s.saveHead(context.Background(), [32]byte{}))
|
||||
}()
|
||||
_, err := s.HeadRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
<-wait
|
||||
}
|
||||
|
||||
func TestHeadBlock_DataRace(t *testing.T) {
|
||||
@@ -41,11 +47,14 @@ func TestHeadBlock_DataRace(t *testing.T) {
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
head: &head{block: wrapper.WrappedPhase0SignedBeaconBlock(ðpb.SignedBeaconBlock{})},
|
||||
}
|
||||
wait := make(chan struct{})
|
||||
go func() {
|
||||
defer close(wait)
|
||||
require.NoError(t, s.saveHead(context.Background(), [32]byte{}))
|
||||
}()
|
||||
_, err := s.HeadBlock(context.Background())
|
||||
require.NoError(t, err)
|
||||
<-wait
|
||||
}
|
||||
|
||||
func TestHeadState_DataRace(t *testing.T) {
|
||||
@@ -53,9 +62,12 @@ func TestHeadState_DataRace(t *testing.T) {
|
||||
s := &Service{
|
||||
cfg: &config{BeaconDB: beaconDB, StateGen: stategen.New(beaconDB)},
|
||||
}
|
||||
wait := make(chan struct{})
|
||||
go func() {
|
||||
defer close(wait)
|
||||
require.NoError(t, s.saveHead(context.Background(), [32]byte{}))
|
||||
}()
|
||||
_, err := s.HeadState(context.Background())
|
||||
require.NoError(t, err)
|
||||
<-wait
|
||||
}
|
||||
|
||||
@@ -437,3 +437,79 @@ func TestService_IsOptimisticForRoot_DoublyLinkedTree(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, opt)
|
||||
}
|
||||
|
||||
func TestService_IsOptimisticForRoot_DB_ProtoArray(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
c.head = &head{root: params.BeaconConfig().ZeroHash}
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 10
|
||||
br, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b)))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: br[:], Slot: 10}))
|
||||
|
||||
optimisticBlock := util.NewBeaconBlock()
|
||||
optimisticBlock.Block.Slot = 11
|
||||
optimisticRoot, err := optimisticBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(optimisticBlock)))
|
||||
|
||||
validatedBlock := util.NewBeaconBlock()
|
||||
validatedBlock.Block.Slot = 9
|
||||
validatedRoot, err := validatedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(validatedBlock)))
|
||||
|
||||
validatedCheckpoint := ðpb.Checkpoint{Root: br[:]}
|
||||
require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, validatedCheckpoint))
|
||||
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: optimisticRoot[:], Slot: 11}))
|
||||
optimistic, err := c.IsOptimisticForRoot(ctx, optimisticRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: validatedRoot[:], Slot: 9}))
|
||||
validated, err := c.IsOptimisticForRoot(ctx, validatedRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, validated)
|
||||
}
|
||||
|
||||
func TestService_IsOptimisticForRoot__DB_DoublyLinkedTree(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{BeaconDB: beaconDB, ForkChoiceStore: doublylinkedtree.New(0, 0)}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
c.head = &head{root: params.BeaconConfig().ZeroHash}
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 10
|
||||
br, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(b)))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: br[:], Slot: 10}))
|
||||
|
||||
optimisticBlock := util.NewBeaconBlock()
|
||||
optimisticBlock.Block.Slot = 11
|
||||
optimisticRoot, err := optimisticBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(optimisticBlock)))
|
||||
|
||||
validatedBlock := util.NewBeaconBlock()
|
||||
validatedBlock.Block.Slot = 9
|
||||
validatedRoot, err := validatedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(validatedBlock)))
|
||||
|
||||
validatedCheckpoint := ðpb.Checkpoint{Root: br[:]}
|
||||
require.NoError(t, beaconDB.SaveLastValidatedCheckpoint(ctx, validatedCheckpoint))
|
||||
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: optimisticRoot[:], Slot: 11}))
|
||||
optimistic, err := c.IsOptimisticForRoot(ctx, optimisticRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
|
||||
require.NoError(t, beaconDB.SaveStateSummary(context.Background(), ðpb.StateSummary{Root: validatedRoot[:], Slot: 9}))
|
||||
validated, err := c.IsOptimisticForRoot(ctx, validatedRoot)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, validated)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !develop
|
||||
// +build !develop
|
||||
|
||||
package blockchain
|
||||
|
||||
@@ -9,4 +9,8 @@ var (
|
||||
errNilBestJustifiedInStore = errors.New("nil best justified checkpoint returned from store")
|
||||
// errNilFinalizedInStore is returned when a nil finalized checkpt is returned from store.
|
||||
errNilFinalizedInStore = errors.New("nil finalized checkpoint returned from store")
|
||||
// errInvalidNilSummary is returned when a nil summary is returned from the DB.
|
||||
errInvalidNilSummary = errors.New("nil summary returned from the DB")
|
||||
// errNilParentInDB is returned when a nil parent block is returned from the DB.
|
||||
errNilParentInDB = errors.New("nil parent block in DB")
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
@@ -17,7 +18,7 @@ import (
|
||||
var log = logrus.WithField("prefix", "blockchain")
|
||||
|
||||
// logs state transition related data every slot.
|
||||
func logStateTransitionData(b block.BeaconBlock) {
|
||||
func logStateTransitionData(b block.BeaconBlock) error {
|
||||
log := log.WithField("slot", b.Slot())
|
||||
if len(b.Body().Attestations()) > 0 {
|
||||
log = log.WithField("attestations", len(b.Body().Attestations()))
|
||||
@@ -34,13 +35,23 @@ func logStateTransitionData(b block.BeaconBlock) {
|
||||
if len(b.Body().VoluntaryExits()) > 0 {
|
||||
log = log.WithField("voluntaryExits", len(b.Body().VoluntaryExits()))
|
||||
}
|
||||
if b.Version() == version.Altair {
|
||||
if b.Version() == version.Altair || b.Version() == version.Bellatrix {
|
||||
agg, err := b.Body().SyncAggregate()
|
||||
if err == nil {
|
||||
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log = log.WithField("syncBitsCount", agg.SyncCommitteeBits.Count())
|
||||
}
|
||||
if b.Version() == version.Bellatrix {
|
||||
p, err := b.Body().ExecutionPayload()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log = log.WithField("payloadHash", fmt.Sprintf("%#x", bytesutil.Trunc(p.BlockHash)))
|
||||
log = log.WithField("txCount", len(p.Transactions))
|
||||
}
|
||||
log.Info("Finished applying state transition")
|
||||
return nil
|
||||
}
|
||||
|
||||
func logBlockSyncStatus(block block.BeaconBlock, blockRoot [32]byte, finalized *ethpb.Checkpoint, receivedTime time.Time, genesisTime uint64) error {
|
||||
|
||||
@@ -3,6 +3,7 @@ package blockchain
|
||||
import (
|
||||
"testing"
|
||||
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
@@ -11,6 +12,17 @@ import (
|
||||
)
|
||||
|
||||
func Test_logStateTransitionData(t *testing.T) {
|
||||
payloadBlk := ðpb.BeaconBlockBellatrix{
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
SyncAggregate: ðpb.SyncAggregate{},
|
||||
ExecutionPayload: &enginev1.ExecutionPayload{
|
||||
BlockHash: []byte{1, 2, 3},
|
||||
Transactions: [][]byte{{}, {}},
|
||||
},
|
||||
},
|
||||
}
|
||||
wrappedPayloadBlk, err := wrapper.WrappedBeaconBlock(payloadBlk)
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
name string
|
||||
b block.BeaconBlock
|
||||
@@ -55,11 +67,15 @@ func Test_logStateTransitionData(t *testing.T) {
|
||||
VoluntaryExits: []*ethpb.SignedVoluntaryExit{{}}}}),
|
||||
want: "\"Finished applying state transition\" attestations=1 attesterSlashings=1 deposits=1 prefix=blockchain proposerSlashings=1 slot=0 voluntaryExits=1",
|
||||
},
|
||||
{name: "has payload",
|
||||
b: wrappedPayloadBlk,
|
||||
want: "\"Finished applying state transition\" payloadHash=0x010203 prefix=blockchain slot=0 syncBitsCount=0 txCount=2",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
hook := logTest.NewGlobal()
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
logStateTransitionData(tt.b)
|
||||
require.NoError(t, logStateTransitionData(tt.b))
|
||||
require.LogsContain(t, hook, tt.want)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -76,6 +76,9 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, headBlk block.Beac
|
||||
return nil, errors.Wrap(err, "could not notify forkchoice update from execution engine")
|
||||
}
|
||||
}
|
||||
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, s.headRoot()); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set block to valid")
|
||||
}
|
||||
return payloadID, nil
|
||||
}
|
||||
|
||||
@@ -119,7 +122,9 @@ func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion int, hea
|
||||
|
||||
// During the transition event, the transition block should be verified for sanity.
|
||||
if isPreBellatrix(preStateVersion) {
|
||||
return nil
|
||||
// Handle case where pre-state is Altair but block contains payload.
|
||||
// To reach here, the block must have contained a valid payload.
|
||||
return s.validateMergeBlock(ctx, blk)
|
||||
}
|
||||
atTransition, err := blocks.IsMergeTransitionBlockUsingPayloadHeader(header, body)
|
||||
if err != nil {
|
||||
@@ -140,14 +145,38 @@ func isPreBellatrix(v int) bool {
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def is_optimistic_candidate_block(opt_store: OptimisticStore, current_slot: Slot, block: BeaconBlock) -> bool:
|
||||
// justified_root = opt_store.block_states[opt_store.head_block_root].current_justified_checkpoint.root
|
||||
// justified_is_execution_block = is_execution_block(opt_store.blocks[justified_root])
|
||||
// block_is_deep = block.slot + SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY <= current_slot
|
||||
// return justified_is_execution_block or block_is_deep
|
||||
// if is_execution_block(opt_store.blocks[block.parent_root]):
|
||||
// return True
|
||||
//
|
||||
// justified_root = opt_store.block_states[opt_store.head_block_root].current_justified_checkpoint.root
|
||||
// if is_execution_block(opt_store.blocks[justified_root]):
|
||||
// return True
|
||||
//
|
||||
// if block.slot + SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY <= current_slot:
|
||||
// return True
|
||||
//
|
||||
// return False
|
||||
func (s *Service) optimisticCandidateBlock(ctx context.Context, blk block.BeaconBlock) (bool, error) {
|
||||
if blk.Slot()+params.BeaconConfig().SafeSlotsToImportOptimistically <= s.CurrentSlot() {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
parent, err := s.cfg.BeaconDB.Block(ctx, bytesutil.ToBytes32(blk.ParentRoot()))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if parent == nil {
|
||||
return false, errNilParentInDB
|
||||
}
|
||||
|
||||
parentIsExecutionBlock, err := blocks.ExecutionBlock(parent.Block().Body())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if parentIsExecutionBlock {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
j := s.store.JustifiedCheckpt()
|
||||
if j == nil {
|
||||
return false, errNilJustifiedInStore
|
||||
|
||||
@@ -36,7 +36,6 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(ctx, altairBlk))
|
||||
require.NoError(t, beaconDB.SaveBlock(ctx, bellatrixBlk))
|
||||
|
||||
fcs := protoarray.New(0, 0, [32]byte{'a'})
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
@@ -45,6 +44,7 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fcs.InsertOptimisticBlock(ctx, 0, [32]byte{}, [32]byte{}, 0, 0))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -188,6 +188,13 @@ func Test_NotifyNewPayload(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
a := ðpb.SignedBeaconBlockAltair{
|
||||
Block: ðpb.BeaconBlockAltair{
|
||||
Body: ðpb.BeaconBlockBodyAltair{},
|
||||
},
|
||||
}
|
||||
altairBlk, err := wrapper.WrappedSignedBeaconBlock(a)
|
||||
require.NoError(t, err)
|
||||
bellatrixBlk, err := wrapper.WrappedSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
service, err := NewService(ctx, opts...)
|
||||
@@ -238,10 +245,29 @@ func Test_NotifyNewPayload(t *testing.T) {
|
||||
errString: "could not validate execution payload from execution engine: payload status is INVALID",
|
||||
},
|
||||
{
|
||||
name: "altair pre state",
|
||||
name: "altair pre state, altair block",
|
||||
postState: bellatrixState,
|
||||
preState: altairState,
|
||||
blk: bellatrixBlk,
|
||||
blk: altairBlk,
|
||||
},
|
||||
{
|
||||
name: "altair pre state, happy case",
|
||||
postState: bellatrixState,
|
||||
preState: altairState,
|
||||
blk: func() block.SignedBeaconBlock {
|
||||
blk := ðpb.SignedBeaconBlockBellatrix{
|
||||
Block: ðpb.BeaconBlockBellatrix{
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
ExecutionPayload: &v1.ExecutionPayload{
|
||||
ParentHash: bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
b, err := wrapper.WrappedSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
return b
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "could not get merge block",
|
||||
@@ -304,27 +330,29 @@ func Test_NotifyNewPayload(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
engine := &mockEngineService{newPayloadError: tt.newPayloadErr, blks: map[[32]byte]*v1.ExecutionBlock{}}
|
||||
engine.blks[[32]byte{'a'}] = &v1.ExecutionBlock{
|
||||
ParentHash: bytesutil.PadTo([]byte{'b'}, fieldparams.RootLength),
|
||||
TotalDifficulty: "0x2",
|
||||
}
|
||||
engine.blks[[32]byte{'b'}] = &v1.ExecutionBlock{
|
||||
ParentHash: bytesutil.PadTo([]byte{'3'}, fieldparams.RootLength),
|
||||
TotalDifficulty: "0x1",
|
||||
}
|
||||
service.cfg.ExecutionEngineCaller = engine
|
||||
var payload *ethpb.ExecutionPayloadHeader
|
||||
if tt.preState.Version() == version.Bellatrix {
|
||||
payload, err = tt.preState.LatestExecutionPayloadHeader()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
err := service.notifyNewPayload(ctx, tt.preState.Version(), payload, tt.postState, tt.blk)
|
||||
if tt.errString != "" {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
engine := &mockEngineService{newPayloadError: tt.newPayloadErr, blks: map[[32]byte]*v1.ExecutionBlock{}}
|
||||
engine.blks[[32]byte{'a'}] = &v1.ExecutionBlock{
|
||||
ParentHash: bytesutil.PadTo([]byte{'b'}, fieldparams.RootLength),
|
||||
TotalDifficulty: "0x2",
|
||||
}
|
||||
engine.blks[[32]byte{'b'}] = &v1.ExecutionBlock{
|
||||
ParentHash: bytesutil.PadTo([]byte{'3'}, fieldparams.RootLength),
|
||||
TotalDifficulty: "0x1",
|
||||
}
|
||||
service.cfg.ExecutionEngineCaller = engine
|
||||
var payload *ethpb.ExecutionPayloadHeader
|
||||
if tt.preState.Version() == version.Bellatrix {
|
||||
payload, err = tt.preState.LatestExecutionPayloadHeader()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
err := service.notifyNewPayload(ctx, tt.preState.Version(), payload, tt.postState, tt.blk)
|
||||
if tt.errString != "" {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,6 +375,12 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
params.BeaconConfig().SafeSlotsToImportOptimistically = 128
|
||||
service.genesisTime = time.Now().Add(-time.Second * 12 * 2 * 128)
|
||||
|
||||
parentBlk := util.NewBeaconBlockBellatrix()
|
||||
wrappedParentBlock, err := wrapper.WrappedBellatrixSignedBeaconBlock(parentBlk)
|
||||
require.NoError(t, err)
|
||||
parentRoot, err := wrappedParentBlock.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
blk block.BeaconBlock
|
||||
@@ -358,6 +392,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 1
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := wrapper.WrappedBellatrixBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
@@ -365,6 +400,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := wrapper.WrappedBellatrixSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
@@ -376,6 +412,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockAltair()
|
||||
blk.Block.Slot = 200
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := wrapper.WrappedAltairBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
@@ -383,6 +420,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockAltair()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := wrapper.WrappedAltairSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
@@ -394,6 +432,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 200
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := wrapper.WrappedBellatrixBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
@@ -401,6 +440,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := wrapper.WrappedBellatrixSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
@@ -412,6 +452,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 200
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
wr, err := wrapper.WrappedBellatrixBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
@@ -419,6 +460,7 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.ParentRoot = parentRoot[:]
|
||||
blk.Block.Body.ExecutionPayload.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
blk.Block.Body.ExecutionPayload.FeeRecipient = bytesutil.PadTo([]byte{'a'}, fieldparams.FeeRecipientLength)
|
||||
blk.Block.Body.ExecutionPayload.StateRoot = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
@@ -443,8 +485,59 @@ func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
Root: jroot[:],
|
||||
Epoch: slots.ToEpoch(tt.justified.Block().Slot()),
|
||||
})
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wrappedParentBlock))
|
||||
|
||||
candidate, err := service.optimisticCandidateBlock(ctx, tt.blk)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.want, candidate, tt.name)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_IsOptimisticShallowExecutionParent(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
}
|
||||
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
params.BeaconConfig().SafeSlotsToImportOptimistically = 128
|
||||
service.genesisTime = time.Now().Add(-time.Second * 12 * 2 * 128)
|
||||
payload := &v1.ExecutionPayload{
|
||||
ParentHash: make([]byte, 32),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, 32),
|
||||
ReceiptsRoot: make([]byte, 32),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, 32),
|
||||
BaseFeePerGas: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
BlockNumber: 100,
|
||||
}
|
||||
body := ðpb.BeaconBlockBodyBellatrix{ExecutionPayload: payload}
|
||||
block := ðpb.BeaconBlockBellatrix{Body: body, Slot: 200}
|
||||
rawSigned := ðpb.SignedBeaconBlockBellatrix{Block: block}
|
||||
blk := util.HydrateSignedBeaconBlockBellatrix(rawSigned)
|
||||
wr, err := wrapper.WrappedBellatrixSignedBeaconBlock(blk)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wr))
|
||||
blkRoot, err := wr.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
childBlock := util.NewBeaconBlockBellatrix()
|
||||
childBlock.Block.ParentRoot = blkRoot[:]
|
||||
// shallow block
|
||||
childBlock.Block.Slot = 201
|
||||
wrappedChild, err := wrapper.WrappedBellatrixSignedBeaconBlock(childBlock)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wrappedChild))
|
||||
candidate, err := service.optimisticCandidateBlock(ctx, wrappedChild.Block())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, candidate)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,6 @@ func (s *Service) onBlock(ctx context.Context, signed block.SignedBeaconBlock, b
|
||||
return errors.Wrap(err, "could not verify new payload")
|
||||
}
|
||||
|
||||
// TODO(10261) Check optimistic status
|
||||
if err := s.savePostStateInfo(ctx, blockRoot, signed, postState, false /* reg sync */); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ func (s *Service) ReceiveBlock(ctx context.Context, block block.SignedBeaconBloc
|
||||
return err
|
||||
}
|
||||
// Log state transition data.
|
||||
logStateTransitionData(blockCopy.Block())
|
||||
if err := logStateTransitionData(blockCopy.Block()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s *Service) Start() {
|
||||
saved := s.cfg.FinalizedStateAtStartUp
|
||||
|
||||
if saved != nil && !saved.IsNil() {
|
||||
if err := s.startFromSavedState(saved); err != nil {
|
||||
if err := s.StartFromSavedState(saved); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
@@ -164,7 +164,7 @@ func (s *Service) Status() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) startFromSavedState(saved state.BeaconState) error {
|
||||
func (s *Service) StartFromSavedState(saved state.BeaconState) error {
|
||||
log.Info("Blockchain data already exists in DB, initializing...")
|
||||
s.genesisTime = time.Unix(int64(saved.GenesisTime()), 0) // lint:ignore uintcast -- Genesis time will not exceed int64 in your lifetime.
|
||||
s.cfg.AttService.SetGenesisTime(saved.GenesisTime())
|
||||
|
||||
@@ -290,7 +290,7 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
c, err := NewService(ctx, WithDatabase(beaconDB), WithStateGen(stategen.New(beaconDB)), WithAttestationService(attSrv), WithStateNotifier(&mock.MockStateNotifier{}), WithFinalizedStateAtStartUp(headState))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.startFromSavedState(headState))
|
||||
require.NoError(t, c.StartFromSavedState(headState))
|
||||
headBlk, err := c.HeadBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, headBlock, headBlk.Proto(), "Head block incorrect")
|
||||
@@ -333,7 +333,7 @@ func TestChainService_InitializeChainInfo_SetHeadAtGenesis(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
c, err := NewService(ctx, WithDatabase(beaconDB), WithStateGen(stategen.New(beaconDB)), WithAttestationService(attSrv), WithStateNotifier(&mock.MockStateNotifier{}))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.startFromSavedState(headState))
|
||||
require.NoError(t, c.StartFromSavedState(headState))
|
||||
s, err := c.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepSSZEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Head state incorrect")
|
||||
@@ -393,7 +393,7 @@ func TestChainService_InitializeChainInfo_HeadSync(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
c, err := NewService(ctx, WithDatabase(beaconDB), WithStateGen(stategen.New(beaconDB)), WithAttestationService(attSrv), WithStateNotifier(&mock.MockStateNotifier{}), WithFinalizedStateAtStartUp(headState))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.startFromSavedState(headState))
|
||||
require.NoError(t, c.StartFromSavedState(headState))
|
||||
s, err := c.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepSSZEqual(t, headState.InnerStateUnsafe(), s.InnerStateUnsafe(), "Head state incorrect")
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build fuzz
|
||||
// +build fuzz
|
||||
|
||||
package cache
|
||||
|
||||
1
beacon-chain/cache/committee_disabled.go
vendored
1
beacon-chain/cache/committee_disabled.go
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build fuzz
|
||||
// +build fuzz
|
||||
|
||||
// This file is used in fuzzer builds to bypass global committee caches.
|
||||
|
||||
1
beacon-chain/cache/proposer_indices.go
vendored
1
beacon-chain/cache/proposer_indices.go
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build !fuzz
|
||||
// +build !fuzz
|
||||
|
||||
package cache
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build fuzz
|
||||
// +build fuzz
|
||||
|
||||
// This file is used in fuzzer builds to bypass proposer indices caches.
|
||||
|
||||
1
beacon-chain/cache/sync_committee.go
vendored
1
beacon-chain/cache/sync_committee.go
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build !fuzz
|
||||
// +build !fuzz
|
||||
|
||||
package cache
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build fuzz
|
||||
// +build fuzz
|
||||
|
||||
package cache
|
||||
|
||||
@@ -17,13 +17,15 @@ go_library(
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["slot_epoch_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
":go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
],
|
||||
|
||||
@@ -46,9 +46,9 @@ func NextEpoch(state state.ReadOnlyBeaconState) types.Epoch {
|
||||
return slots.ToEpoch(state.Slot()) + 1
|
||||
}
|
||||
|
||||
// AltairCompatible returns if the input state `s` is altair compatible and input epoch `e` is higher equal than fork epoch.
|
||||
func AltairCompatible(s state.BeaconState, e types.Epoch) bool {
|
||||
return s.Version() == version.Altair && e >= params.BeaconConfig().AltairForkEpoch
|
||||
// HigherEqualThanAltairVersionAndEpoch returns if the input state `s` has a higher version number than Altair state and input epoch `e` is higher equal than fork epoch.
|
||||
func HigherEqualThanAltairVersionAndEpoch(s state.BeaconState, e types.Epoch) bool {
|
||||
return s.Version() >= version.Altair && e >= params.BeaconConfig().AltairForkEpoch
|
||||
}
|
||||
|
||||
// CanUpgradeToAltair returns true if the input `slot` can upgrade to Altair.
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package time
|
||||
package time_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
)
|
||||
|
||||
@@ -42,7 +45,7 @@ func TestCurrentEpoch_OK(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
state, err := v1.InitializeFromProto(ð.BeaconState{Slot: tt.slot})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.epoch, CurrentEpoch(state), "ActiveCurrentEpoch(%d)", state.Slot())
|
||||
assert.Equal(t, tt.epoch, time.CurrentEpoch(state), "ActiveCurrentEpoch(%d)", state.Slot())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +61,7 @@ func TestPrevEpoch_OK(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
state, err := v1.InitializeFromProto(ð.BeaconState{Slot: tt.slot})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.epoch, PrevEpoch(state), "ActivePrevEpoch(%d)", state.Slot())
|
||||
assert.Equal(t, tt.epoch, time.PrevEpoch(state), "ActivePrevEpoch(%d)", state.Slot())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +79,7 @@ func TestNextEpoch_OK(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
state, err := v1.InitializeFromProto(ð.BeaconState{Slot: tt.slot})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.epoch, NextEpoch(state), "NextEpoch(%d)", state.Slot())
|
||||
assert.Equal(t, tt.epoch, time.NextEpoch(state), "NextEpoch(%d)", state.Slot())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +111,7 @@ func TestCanUpgradeToAltair(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := CanUpgradeToAltair(tt.slot); got != tt.want {
|
||||
if got := time.CanUpgradeToAltair(tt.slot); got != tt.want {
|
||||
t.Errorf("canUpgradeToAltair() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
@@ -143,7 +146,7 @@ func TestCanUpgradeBellatrix(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := CanUpgradeToBellatrix(tt.slot); got != tt.want {
|
||||
if got := time.CanUpgradeToBellatrix(tt.slot); got != tt.want {
|
||||
t.Errorf("CanUpgradeToBellatrix() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
@@ -178,6 +181,85 @@ func TestCanProcessEpoch_TrueOnEpochsLastSlot(t *testing.T) {
|
||||
b := ð.BeaconState{Slot: tt.slot}
|
||||
s, err := v1.InitializeFromProto(b)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.canProcessEpoch, CanProcessEpoch(s), "CanProcessEpoch(%d)", tt.slot)
|
||||
assert.Equal(t, tt.canProcessEpoch, time.CanProcessEpoch(s), "CanProcessEpoch(%d)", tt.slot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAltairCompatible(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.AltairForkEpoch = 1
|
||||
cfg.BellatrixForkEpoch = 2
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
type args struct {
|
||||
s state.BeaconState
|
||||
e types.Epoch
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "phase0 state",
|
||||
args: args{
|
||||
s: func() state.BeaconState {
|
||||
st, _ := util.DeterministicGenesisState(t, 1)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "altair state, altair epoch",
|
||||
args: args{
|
||||
s: func() state.BeaconState {
|
||||
st, _ := util.DeterministicGenesisStateAltair(t, 1)
|
||||
return st
|
||||
}(),
|
||||
e: params.BeaconConfig().AltairForkEpoch,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "bellatrix state, bellatrix epoch",
|
||||
args: args{
|
||||
s: func() state.BeaconState {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
return st
|
||||
}(),
|
||||
e: params.BeaconConfig().BellatrixForkEpoch,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "bellatrix state, altair epoch",
|
||||
args: args{
|
||||
s: func() state.BeaconState {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
return st
|
||||
}(),
|
||||
e: params.BeaconConfig().AltairForkEpoch,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "bellatrix state, phase0 epoch",
|
||||
args: args{
|
||||
s: func() state.BeaconState {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
return st
|
||||
}(),
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := time.HigherEqualThanAltairVersionAndEpoch(tt.args.s, tt.args.e); got != tt.want {
|
||||
t.Errorf("HigherEqualThanAltairVersionAndEpoch() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,12 +45,13 @@ type ReadOnlyDatabase interface {
|
||||
HasArchivedPoint(ctx context.Context, slot types.Slot) bool
|
||||
LastArchivedRoot(ctx context.Context) [32]byte
|
||||
LastArchivedSlot(ctx context.Context) (types.Slot, error)
|
||||
LastValidatedCheckpoint(ctx context.Context) (*ethpb.Checkpoint, error)
|
||||
// Deposit contract related handlers.
|
||||
DepositContractAddress(ctx context.Context) ([]byte, error)
|
||||
// Powchain operations.
|
||||
PowchainData(ctx context.Context) (*ethpb.ETH1ChainData, error)
|
||||
// Fee reicipients operations.
|
||||
FeeRecipientByValidatorID(ctx context.Context, id uint64) (common.Address, error)
|
||||
FeeRecipientByValidatorID(ctx context.Context, id types.ValidatorIndex) (common.Address, error)
|
||||
// origin checkpoint sync support
|
||||
OriginBlockRoot(ctx context.Context) ([32]byte, error)
|
||||
}
|
||||
@@ -74,6 +75,7 @@ type NoHeadAccessDatabase interface {
|
||||
// Checkpoint operations.
|
||||
SaveJustifiedCheckpoint(ctx context.Context, checkpoint *ethpb.Checkpoint) error
|
||||
SaveFinalizedCheckpoint(ctx context.Context, checkpoint *ethpb.Checkpoint) error
|
||||
SaveLastValidatedCheckpoint(ctx context.Context, checkpoint *ethpb.Checkpoint) error
|
||||
// Deposit contract related handlers.
|
||||
SaveDepositContractAddress(ctx context.Context, addr common.Address) error
|
||||
// Powchain operations.
|
||||
@@ -81,7 +83,7 @@ type NoHeadAccessDatabase interface {
|
||||
// Run any required database migrations.
|
||||
RunMigrations(ctx context.Context) error
|
||||
// Fee reicipients operations.
|
||||
SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []uint64, addrs []common.Address) error
|
||||
SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []types.ValidatorIndex, addrs []common.Address) error
|
||||
|
||||
CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint types.Slot) error
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ go_library(
|
||||
"state_summary.go",
|
||||
"state_summary_cache.go",
|
||||
"utils.go",
|
||||
"validated_checkpoint.go",
|
||||
"wss.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/db/kv",
|
||||
@@ -91,6 +92,7 @@ go_test(
|
||||
"state_summary_test.go",
|
||||
"state_test.go",
|
||||
"utils_test.go",
|
||||
"validated_checkpoint_test.go",
|
||||
],
|
||||
data = glob(["testdata/**"]),
|
||||
embed = [":go_default_library"],
|
||||
|
||||
@@ -395,13 +395,13 @@ func (s *Store) HighestSlotBlocksBelow(ctx context.Context, slot types.Slot) ([]
|
||||
|
||||
// FeeRecipientByValidatorID returns the fee recipient for a validator id.
|
||||
// `ErrNotFoundFeeRecipient` is returned if the validator id is not found.
|
||||
func (s *Store) FeeRecipientByValidatorID(ctx context.Context, id uint64) (common.Address, error) {
|
||||
func (s *Store) FeeRecipientByValidatorID(ctx context.Context, id types.ValidatorIndex) (common.Address, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.FeeRecipientByValidatorID")
|
||||
defer span.End()
|
||||
var addr []byte
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(feeRecipientBucket)
|
||||
addr = bkt.Get(bytesutil.Uint64ToBytesBigEndian(id))
|
||||
addr = bkt.Get(bytesutil.Uint64ToBytesBigEndian(uint64(id)))
|
||||
if addr == nil {
|
||||
return errors.Wrapf(ErrNotFoundFeeRecipient, "validator id %d", id)
|
||||
}
|
||||
@@ -412,7 +412,7 @@ func (s *Store) FeeRecipientByValidatorID(ctx context.Context, id uint64) (commo
|
||||
|
||||
// SaveFeeRecipientsByValidatorIDs saves the fee recipients for validator ids.
|
||||
// Error is returned if `ids` and `recipients` are not the same length.
|
||||
func (s *Store) SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []uint64, feeRecipients []common.Address) error {
|
||||
func (s *Store) SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []types.ValidatorIndex, feeRecipients []common.Address) error {
|
||||
_, span := trace.StartSpan(ctx, "BeaconDB.SaveFeeRecipientByValidatorID")
|
||||
defer span.End()
|
||||
|
||||
@@ -423,7 +423,7 @@ func (s *Store) SaveFeeRecipientsByValidatorIDs(ctx context.Context, ids []uint6
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(feeRecipientBucket)
|
||||
for i, id := range ids {
|
||||
if err := bkt.Put(bytesutil.Uint64ToBytesBigEndian(id), feeRecipients[i].Bytes()); err != nil {
|
||||
if err := bkt.Put(bytesutil.Uint64ToBytesBigEndian(uint64(id)), feeRecipients[i].Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,11 +595,11 @@ func TestStore_BlocksBySlot_BlockRootsBySlot(t *testing.T) {
|
||||
func TestStore_FeeRecipientByValidatorID(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
ids := []uint64{0, 0, 0}
|
||||
ids := []types.ValidatorIndex{0, 0, 0}
|
||||
feeRecipients := []common.Address{{}, {}, {}, {}}
|
||||
require.ErrorContains(t, "validatorIDs and feeRecipients must be the same length", db.SaveFeeRecipientsByValidatorIDs(ctx, ids, feeRecipients))
|
||||
|
||||
ids = []uint64{0, 1, 2}
|
||||
ids = []types.ValidatorIndex{0, 1, 2}
|
||||
feeRecipients = []common.Address{{'a'}, {'b'}, {'c'}}
|
||||
require.NoError(t, db.SaveFeeRecipientsByValidatorIDs(ctx, ids, feeRecipients))
|
||||
f, err := db.FeeRecipientByValidatorID(ctx, 0)
|
||||
|
||||
@@ -175,7 +175,6 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
|
||||
powchainBucket,
|
||||
stateSummaryBucket,
|
||||
stateValidatorsBucket,
|
||||
validatedTips,
|
||||
// Indices buckets.
|
||||
attestationHeadBlockRootBucket,
|
||||
attestationSourceRootIndicesBucket,
|
||||
|
||||
@@ -19,7 +19,6 @@ var (
|
||||
powchainBucket = []byte("powchain")
|
||||
stateValidatorsBucket = []byte("state-validators")
|
||||
feeRecipientBucket = []byte("fee-recipient")
|
||||
validatedTips = []byte("validated-synced-tips")
|
||||
|
||||
// Deprecated: This bucket was migrated in PR 6461. Do not use, except for migrations.
|
||||
slotsHasObjectBucket = []byte("slots-has-objects")
|
||||
@@ -39,12 +38,13 @@ var (
|
||||
blockRootValidatorHashesBucket = []byte("block-root-validator-hashes")
|
||||
|
||||
// Specific item keys.
|
||||
headBlockRootKey = []byte("head-root")
|
||||
genesisBlockRootKey = []byte("genesis-root")
|
||||
depositContractAddressKey = []byte("deposit-contract")
|
||||
justifiedCheckpointKey = []byte("justified-checkpoint")
|
||||
finalizedCheckpointKey = []byte("finalized-checkpoint")
|
||||
powchainDataKey = []byte("powchain-data")
|
||||
headBlockRootKey = []byte("head-root")
|
||||
genesisBlockRootKey = []byte("genesis-root")
|
||||
depositContractAddressKey = []byte("deposit-contract")
|
||||
justifiedCheckpointKey = []byte("justified-checkpoint")
|
||||
finalizedCheckpointKey = []byte("finalized-checkpoint")
|
||||
powchainDataKey = []byte("powchain-data")
|
||||
lastValidatedCheckpointKey = []byte("last-validated-checkpoint")
|
||||
|
||||
// Below keys are used to identify objects are to be fork compatible.
|
||||
// Objects that are only compatible with specific forks should be prefixed with such keys.
|
||||
|
||||
49
beacon-chain/db/kv/validated_checkpoint.go
Normal file
49
beacon-chain/db/kv/validated_checkpoint.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// LastValidatedCheckpoint returns the latest fully validated checkpoint in beacon chain.
|
||||
func (s *Store) LastValidatedCheckpoint(ctx context.Context) (*ethpb.Checkpoint, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.LastValidatedCheckpoint")
|
||||
defer span.End()
|
||||
var checkpoint *ethpb.Checkpoint
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(checkpointBucket)
|
||||
enc := bkt.Get(lastValidatedCheckpointKey)
|
||||
if enc == nil {
|
||||
var finErr error
|
||||
checkpoint, finErr = s.FinalizedCheckpoint(ctx)
|
||||
return finErr
|
||||
}
|
||||
checkpoint = ðpb.Checkpoint{}
|
||||
return decode(ctx, enc, checkpoint)
|
||||
})
|
||||
return checkpoint, err
|
||||
}
|
||||
|
||||
// SaveLastValidatedCheckpoint saves the last validated checkpoint in beacon chain.
|
||||
func (s *Store) SaveLastValidatedCheckpoint(ctx context.Context, checkpoint *ethpb.Checkpoint) error {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveLastValidatedCheckpoint")
|
||||
defer span.End()
|
||||
|
||||
enc, err := encode(ctx, checkpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(checkpointBucket)
|
||||
hasStateSummary := s.hasStateSummaryBytes(tx, bytesutil.ToBytes32(checkpoint.Root))
|
||||
hasStateInDB := tx.Bucket(stateBucket).Get(checkpoint.Root) != nil
|
||||
if !(hasStateInDB || hasStateSummary) {
|
||||
return errMissingStateForCheckpoint
|
||||
}
|
||||
return bucket.Put(lastValidatedCheckpointKey, enc)
|
||||
})
|
||||
}
|
||||
67
beacon-chain/db/kv/validated_checkpoint_test.go
Normal file
67
beacon-chain/db/kv/validated_checkpoint_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestStore_LastValidatedCheckpoint_CanSaveRetrieve(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
root := bytesutil.ToBytes32([]byte{'A'})
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 10,
|
||||
Root: root[:],
|
||||
}
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(1))
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, cp))
|
||||
|
||||
retrieved, err := db.LastValidatedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, proto.Equal(cp, retrieved), "Wanted %v, received %v", cp, retrieved)
|
||||
}
|
||||
|
||||
func TestStore_LastValidatedCheckpoint_DefaultIsFinalized(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := bytesutil.ToBytes32([]byte{'G', 'E', 'N', 'E', 'S', 'I', 'S'})
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesis))
|
||||
|
||||
blk := util.NewBeaconBlock()
|
||||
blk.Block.ParentRoot = genesis[:]
|
||||
blk.Block.Slot = 40
|
||||
|
||||
root, err := blk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 5,
|
||||
Root: root[:],
|
||||
}
|
||||
|
||||
// a valid chain is required to save finalized checkpoint.
|
||||
require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk)))
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(1))
|
||||
// a state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
retrieved, err := db.LastValidatedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, proto.Equal(cp, retrieved), "Wanted %v, received %v", cp, retrieved)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package doublylinkedtree
|
||||
|
||||
import "errors"
|
||||
|
||||
var errNilNode = errors.New("invalid nil or unknown node")
|
||||
var ErrNilNode = errors.New("invalid nil or unknown node")
|
||||
var errInvalidBalance = errors.New("invalid node balance")
|
||||
var errInvalidProposerBoostRoot = errors.New("invalid proposer boost root")
|
||||
var errUnknownFinalizedRoot = errors.New("unknown finalized root")
|
||||
|
||||
@@ -174,7 +174,7 @@ func (f *ForkChoice) IsOptimistic(_ context.Context, root [32]byte) (bool, error
|
||||
|
||||
node, ok := f.store.nodeByRoot[root]
|
||||
if !ok || node == nil {
|
||||
return false, errNilNode
|
||||
return false, ErrNilNode
|
||||
}
|
||||
|
||||
return node.optimistic, nil
|
||||
@@ -190,7 +190,7 @@ func (f *ForkChoice) AncestorRoot(ctx context.Context, root [32]byte, slot types
|
||||
|
||||
node, ok := f.store.nodeByRoot[root]
|
||||
if !ok || node == nil {
|
||||
return nil, errNilNode
|
||||
return nil, ErrNilNode
|
||||
}
|
||||
|
||||
n := node
|
||||
@@ -202,7 +202,7 @@ func (f *ForkChoice) AncestorRoot(ctx context.Context, root [32]byte, slot types
|
||||
}
|
||||
|
||||
if n == nil {
|
||||
return nil, errNilNode
|
||||
return nil, ErrNilNode
|
||||
}
|
||||
|
||||
return n.root[:], nil
|
||||
@@ -237,7 +237,7 @@ func (f *ForkChoice) updateBalances(newBalances []uint64) error {
|
||||
if ok && vote.nextRoot != params.BeaconConfig().ZeroHash {
|
||||
// Protection against nil node
|
||||
if nextNode == nil {
|
||||
return errNilNode
|
||||
return ErrNilNode
|
||||
}
|
||||
nextNode.balance += newBalance
|
||||
}
|
||||
@@ -246,7 +246,7 @@ func (f *ForkChoice) updateBalances(newBalances []uint64) error {
|
||||
if ok && vote.currentRoot != params.BeaconConfig().ZeroHash {
|
||||
// Protection against nil node
|
||||
if currentNode == nil {
|
||||
return errNilNode
|
||||
return ErrNilNode
|
||||
}
|
||||
if currentNode.balance < oldBalance {
|
||||
return errInvalidBalance
|
||||
@@ -279,7 +279,7 @@ func (f *ForkChoice) SetOptimisticToValid(ctx context.Context, root [fieldparams
|
||||
defer f.store.nodesLock.Unlock()
|
||||
node, ok := f.store.nodeByRoot[root]
|
||||
if !ok || node == nil {
|
||||
return errNilNode
|
||||
return ErrNilNode
|
||||
}
|
||||
return node.setNodeAndParentValidated(ctx)
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ func TestForkChoice_AncestorRoot(t *testing.T) {
|
||||
assert.Equal(t, bytesutil.ToBytes32(r), indexToHash(3))
|
||||
|
||||
_, err = f.AncestorRoot(ctx, indexToHash(3), 0)
|
||||
assert.ErrorContains(t, errNilNode.Error(), err)
|
||||
assert.ErrorContains(t, ErrNilNode.Error(), err)
|
||||
|
||||
root, err := f.AncestorRoot(ctx, indexToHash(3), 5)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -55,7 +55,7 @@ func (n *Node) updateBestDescendant(ctx context.Context, justifiedEpoch, finaliz
|
||||
hasViableDescendant := false
|
||||
for _, child := range n.children {
|
||||
if child == nil {
|
||||
return errNilNode
|
||||
return ErrNilNode
|
||||
}
|
||||
if err := child.updateBestDescendant(ctx, justifiedEpoch, finalizedEpoch); err != nil {
|
||||
return err
|
||||
|
||||
@@ -12,7 +12,7 @@ func (s *Store) removeNode(ctx context.Context, root [32]byte) error {
|
||||
|
||||
node, ok := s.nodeByRoot[root]
|
||||
if !ok || node == nil {
|
||||
return errNilNode
|
||||
return ErrNilNode
|
||||
}
|
||||
if !node.optimistic || node.parent == nil {
|
||||
return errInvalidOptimisticStatus
|
||||
|
||||
@@ -5,7 +5,7 @@ import "errors"
|
||||
var errUnknownFinalizedRoot = errors.New("unknown finalized root")
|
||||
var errUnknownJustifiedRoot = errors.New("unknown justified root")
|
||||
var errInvalidNodeIndex = errors.New("node index is invalid")
|
||||
var errUnknownNodeRoot = errors.New("unknown block root")
|
||||
var ErrUnknownNodeRoot = errors.New("unknown block root")
|
||||
var errInvalidJustifiedIndex = errors.New("justified index is invalid")
|
||||
var errInvalidBestChildIndex = errors.New("best child index is invalid")
|
||||
var errInvalidBestDescendantIndex = errors.New("best descendant index is invalid")
|
||||
|
||||
@@ -40,7 +40,7 @@ func (f *ForkChoice) IsOptimistic(ctx context.Context, root [32]byte) (bool, err
|
||||
index, ok := f.store.nodesIndices[root]
|
||||
if !ok {
|
||||
f.store.nodesLock.RUnlock()
|
||||
return false, errUnknownNodeRoot
|
||||
return false, ErrUnknownNodeRoot
|
||||
}
|
||||
node := f.store.nodes[index]
|
||||
slot := node.slot
|
||||
|
||||
@@ -147,10 +147,10 @@ func TestOptimistic(t *testing.T) {
|
||||
|
||||
// We test first nodes outside the Fork Choice store
|
||||
_, err := f.IsOptimistic(ctx, root0)
|
||||
require.ErrorIs(t, errUnknownNodeRoot, err)
|
||||
require.ErrorIs(t, ErrUnknownNodeRoot, err)
|
||||
|
||||
_, err = f.IsOptimistic(ctx, root1)
|
||||
require.ErrorIs(t, errUnknownNodeRoot, err)
|
||||
require.ErrorIs(t, ErrUnknownNodeRoot, err)
|
||||
|
||||
// We check all nodes in the Fork Choice store.
|
||||
op, err := f.IsOptimistic(ctx, nodeA.root)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/cmd"
|
||||
@@ -105,10 +107,17 @@ func configureInteropConfig(cliCtx *cli.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func configureExecutionSetting(cliCtx *cli.Context) {
|
||||
if cliCtx.IsSet(flags.FeeRecipient.Name) {
|
||||
c := params.BeaconConfig()
|
||||
c.FeeRecipient = common.HexToAddress(cliCtx.String(flags.FeeRecipient.Name))
|
||||
params.OverrideBeaconConfig(c)
|
||||
func configureExecutionSetting(cliCtx *cli.Context) error {
|
||||
if !cliCtx.IsSet(flags.FeeRecipient.Name) {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := params.BeaconConfig()
|
||||
ha := cliCtx.String(flags.FeeRecipient.Name)
|
||||
if !common.IsHexAddress(ha) {
|
||||
return fmt.Errorf("%s is not a valid fee recipient address", ha)
|
||||
}
|
||||
c.DefaultFeeRecipient = common.HexToAddress(ha)
|
||||
params.OverrideBeaconConfig(c)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -93,9 +93,20 @@ func TestConfigureExecutionSetting(t *testing.T) {
|
||||
set.String(flags.FeeRecipient.Name, "", "")
|
||||
require.NoError(t, set.Set(flags.FeeRecipient.Name, "0xB"))
|
||||
cliCtx := cli.NewContext(&app, set, nil)
|
||||
err := configureExecutionSetting(cliCtx)
|
||||
require.ErrorContains(t, "0xB is not a valid fee recipient address", err)
|
||||
|
||||
configureExecutionSetting(cliCtx)
|
||||
assert.Equal(t, common.HexToAddress("0xB"), params.BeaconConfig().FeeRecipient)
|
||||
require.NoError(t, set.Set(flags.FeeRecipient.Name, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
|
||||
cliCtx = cli.NewContext(&app, set, nil)
|
||||
err = configureExecutionSetting(cliCtx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, common.HexToAddress("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), params.BeaconConfig().DefaultFeeRecipient)
|
||||
|
||||
require.NoError(t, set.Set(flags.FeeRecipient.Name, "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
|
||||
cliCtx = cli.NewContext(&app, set, nil)
|
||||
err = configureExecutionSetting(cliCtx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, common.HexToAddress("0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), params.BeaconConfig().DefaultFeeRecipient)
|
||||
}
|
||||
|
||||
func TestConfigureNetwork(t *testing.T) {
|
||||
|
||||
@@ -120,7 +120,9 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
|
||||
configureEth1Config(cliCtx)
|
||||
configureNetwork(cliCtx)
|
||||
configureInteropConfig(cliCtx)
|
||||
configureExecutionSetting(cliCtx)
|
||||
if err := configureExecutionSetting(cliCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initializes any forks here.
|
||||
params.BeaconConfig().InitializeForkSchedule()
|
||||
|
||||
@@ -181,9 +181,14 @@ type altairPublishBlockRequestJson struct {
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
type bellatrixPublishBlockRequestJson struct {
|
||||
BellatrixBlock *beaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
// setInitialPublishBlockPostRequest is triggered before we deserialize the request JSON into a struct.
|
||||
// We don't know which version of the block got posted, but we can determine it from the slot.
|
||||
// We know that both Phase 0 and Altair blocks have a Message field with a Slot field,
|
||||
// We know that blocks of all versions have a Message field with a Slot field,
|
||||
// so we deserialize the request into a struct s, which has the right fields, to obtain the slot.
|
||||
// Once we know the slot, we can determine what the PostRequest field of the endpoint should be, and we set it appropriately.
|
||||
func setInitialPublishBlockPostRequest(endpoint *apimiddleware.Endpoint,
|
||||
@@ -207,17 +212,20 @@ func setInitialPublishBlockPostRequest(endpoint *apimiddleware.Endpoint,
|
||||
if err != nil {
|
||||
return false, apimiddleware.InternalServerErrorWithMessage(err, "slot is not an unsigned integer")
|
||||
}
|
||||
if slots.ToEpoch(types.Slot(slot)) < params.BeaconConfig().AltairForkEpoch {
|
||||
currentEpoch := slots.ToEpoch(types.Slot(slot))
|
||||
if currentEpoch < params.BeaconConfig().AltairForkEpoch {
|
||||
endpoint.PostRequest = &signedBeaconBlockContainerJson{}
|
||||
} else {
|
||||
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
|
||||
endpoint.PostRequest = &signedBeaconBlockAltairContainerJson{}
|
||||
} else {
|
||||
endpoint.PostRequest = &signedBeaconBlockBellatrixContainerJson{}
|
||||
}
|
||||
req.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// In preparePublishedBlock we transform the PostRequest.
|
||||
// gRPC expects either a phase0_block or an altair_block field in the JSON object, but we have a message field at this point.
|
||||
// gRPC expects an XXX_block field in the JSON object, but we have a message field at this point.
|
||||
// We do a simple conversion depending on the type of endpoint.PostRequest
|
||||
// (which was filled out previously in setInitialPublishBlockPostRequest).
|
||||
func preparePublishedBlock(endpoint *apimiddleware.Endpoint, _ http.ResponseWriter, _ *http.Request) apimiddleware.ErrorJson {
|
||||
@@ -239,6 +247,15 @@ func preparePublishedBlock(endpoint *apimiddleware.Endpoint, _ http.ResponseWrit
|
||||
endpoint.PostRequest = actualPostReq
|
||||
return nil
|
||||
}
|
||||
if block, ok := endpoint.PostRequest.(*signedBeaconBlockBellatrixContainerJson); ok {
|
||||
// Prepare post request that can be properly decoded on gRPC side.
|
||||
actualPostReq := &bellatrixPublishBlockRequestJson{
|
||||
BellatrixBlock: block.Message,
|
||||
Signature: block.Signature,
|
||||
}
|
||||
endpoint.PostRequest = actualPostReq
|
||||
return nil
|
||||
}
|
||||
return apimiddleware.InternalServerError(errors.New("unsupported block type"))
|
||||
}
|
||||
|
||||
|
||||
@@ -363,6 +363,11 @@ func TestWrapSignedContributionAndProofsArray(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetInitialPublishBlockPostRequest(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.BellatrixForkEpoch = params.BeaconConfig().AltairForkEpoch + 1
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
endpoint := &apimiddleware.Endpoint{}
|
||||
s := struct {
|
||||
Message struct {
|
||||
@@ -397,6 +402,21 @@ func TestSetInitialPublishBlockPostRequest(t *testing.T) {
|
||||
assert.Equal(t, apimiddleware.RunDefault(true), runDefault)
|
||||
assert.Equal(t, reflect.TypeOf(signedBeaconBlockAltairContainerJson{}).Name(), reflect.Indirect(reflect.ValueOf(endpoint.PostRequest)).Type().Name())
|
||||
})
|
||||
t.Run("Bellatrix", func(t *testing.T) {
|
||||
slot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
|
||||
require.NoError(t, err)
|
||||
s.Message = struct{ Slot string }{Slot: strconv.FormatUint(uint64(slot), 10)}
|
||||
j, err := json.Marshal(s)
|
||||
require.NoError(t, err)
|
||||
var body bytes.Buffer
|
||||
_, err = body.Write(j)
|
||||
require.NoError(t, err)
|
||||
request := httptest.NewRequest("POST", "http://foo.example", &body)
|
||||
runDefault, errJson := setInitialPublishBlockPostRequest(endpoint, nil, request)
|
||||
require.Equal(t, true, errJson == nil)
|
||||
assert.Equal(t, apimiddleware.RunDefault(true), runDefault)
|
||||
assert.Equal(t, reflect.TypeOf(signedBeaconBlockBellatrixContainerJson{}).Name(), reflect.Indirect(reflect.ValueOf(endpoint.PostRequest)).Type().Name())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPreparePublishedBlock(t *testing.T) {
|
||||
@@ -428,6 +448,20 @@ func TestPreparePublishedBlock(t *testing.T) {
|
||||
assert.Equal(t, true, ok)
|
||||
})
|
||||
|
||||
t.Run("Bellatrix", func(t *testing.T) {
|
||||
endpoint := &apimiddleware.Endpoint{
|
||||
PostRequest: &signedBeaconBlockBellatrixContainerJson{
|
||||
Message: &beaconBlockBellatrixJson{
|
||||
Body: &beaconBlockBodyBellatrixJson{},
|
||||
},
|
||||
},
|
||||
}
|
||||
errJson := preparePublishedBlock(endpoint, nil, nil)
|
||||
require.Equal(t, true, errJson == nil)
|
||||
_, ok := endpoint.PostRequest.(*bellatrixPublishBlockRequestJson)
|
||||
assert.Equal(t, true, ok)
|
||||
})
|
||||
|
||||
t.Run("unsupported block type", func(t *testing.T) {
|
||||
errJson := preparePublishedBlock(&apimiddleware.Endpoint{}, nil, nil)
|
||||
assert.Equal(t, true, strings.Contains(errJson.Msg(), "unsupported block type"))
|
||||
@@ -471,8 +505,7 @@ func TestSerializeV2Block(t *testing.T) {
|
||||
StateRoot: "root",
|
||||
Body: &beaconBlockBodyJson{},
|
||||
},
|
||||
AltairBlock: nil,
|
||||
Signature: "sig",
|
||||
Signature: "sig",
|
||||
},
|
||||
}
|
||||
runDefault, j, errJson := serializeV2Block(response)
|
||||
@@ -495,7 +528,6 @@ func TestSerializeV2Block(t *testing.T) {
|
||||
response := &blockV2ResponseJson{
|
||||
Version: ethpbv2.Version_ALTAIR.String(),
|
||||
Data: &signedBeaconBlockContainerV2Json{
|
||||
Phase0Block: nil,
|
||||
AltairBlock: &beaconBlockAltairJson{
|
||||
Slot: "1",
|
||||
ProposerIndex: "1",
|
||||
@@ -522,6 +554,36 @@ func TestSerializeV2Block(t *testing.T) {
|
||||
require.NotNil(t, beaconBlock.Body)
|
||||
})
|
||||
|
||||
t.Run("Bellatrix", func(t *testing.T) {
|
||||
response := &blockV2ResponseJson{
|
||||
Version: ethpbv2.Version_BELLATRIX.String(),
|
||||
Data: &signedBeaconBlockContainerV2Json{
|
||||
BellatrixBlock: &beaconBlockBellatrixJson{
|
||||
Slot: "1",
|
||||
ProposerIndex: "1",
|
||||
ParentRoot: "root",
|
||||
StateRoot: "root",
|
||||
Body: &beaconBlockBodyBellatrixJson{},
|
||||
},
|
||||
Signature: "sig",
|
||||
},
|
||||
}
|
||||
runDefault, j, errJson := serializeV2Block(response)
|
||||
require.Equal(t, nil, errJson)
|
||||
require.Equal(t, apimiddleware.RunDefault(false), runDefault)
|
||||
require.NotNil(t, j)
|
||||
resp := &bellatrixBlockResponseJson{}
|
||||
require.NoError(t, json.Unmarshal(j, resp))
|
||||
require.NotNil(t, resp.Data)
|
||||
require.NotNil(t, resp.Data.Message)
|
||||
beaconBlock := resp.Data.Message
|
||||
assert.Equal(t, "1", beaconBlock.Slot)
|
||||
assert.Equal(t, "1", beaconBlock.ProposerIndex)
|
||||
assert.Equal(t, "root", beaconBlock.ParentRoot)
|
||||
assert.Equal(t, "root", beaconBlock.StateRoot)
|
||||
require.NotNil(t, beaconBlock.Body)
|
||||
})
|
||||
|
||||
t.Run("incorrect response type", func(t *testing.T) {
|
||||
response := &types.Empty{}
|
||||
runDefault, j, errJson := serializeV2Block(response)
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestGetSpec(t *testing.T) {
|
||||
config.TerminalBlockHash = common.HexToHash("TerminalBlockHash")
|
||||
config.TerminalBlockHashActivationEpoch = 72
|
||||
config.TerminalTotalDifficulty = "73"
|
||||
config.FeeRecipient = common.HexToAddress("FeeRecipient")
|
||||
config.DefaultFeeRecipient = common.HexToAddress("DefaultFeeRecipient")
|
||||
|
||||
var dbp [4]byte
|
||||
copy(dbp[:], []byte{'0', '0', '0', '1'})
|
||||
@@ -329,8 +329,8 @@ func TestGetSpec(t *testing.T) {
|
||||
assert.Equal(t, common.HexToHash("TerminalBlockHash"), common.HexToHash(v))
|
||||
case "TERMINAL_TOTAL_DIFFICULTY":
|
||||
assert.Equal(t, "73", v)
|
||||
case "FeeRecipient":
|
||||
assert.Equal(t, common.HexToAddress("FeeRecipient"), v)
|
||||
case "DefaultFeeRecipient":
|
||||
assert.Equal(t, common.HexToAddress("DefaultFeeRecipient"), v)
|
||||
case "PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX":
|
||||
assert.Equal(t, "3", v)
|
||||
case "MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX":
|
||||
|
||||
@@ -61,6 +61,7 @@ go_test(
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
"//beacon-chain/p2p/testing:go_default_library",
|
||||
"//beacon-chain/p2p/types:go_default_library",
|
||||
"//beacon-chain/powchain/engine-api-client/v1/mocks:go_default_library",
|
||||
"//beacon-chain/powchain/testing:go_default_library",
|
||||
"//beacon-chain/rpc/prysm/v1alpha1/validator:go_default_library",
|
||||
"//beacon-chain/rpc/testutil:go_default_library",
|
||||
@@ -71,6 +72,7 @@ go_test(
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil: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",
|
||||
|
||||
@@ -252,6 +252,11 @@ func (vs *Server) ProduceBlock(ctx context.Context, req *ethpbv1.ProduceBlockReq
|
||||
ctx, span := trace.StartSpan(ctx, "validator.ProduceBlock")
|
||||
defer span.End()
|
||||
|
||||
if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher); err != nil {
|
||||
// We simply return the error because it's already a gRPC error.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, err := vs.v1BeaconBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get block: %v", err)
|
||||
@@ -263,18 +268,9 @@ func (vs *Server) ProduceBlockV2(ctx context.Context, req *ethpbv1.ProduceBlockR
|
||||
_, span := trace.StartSpan(ctx, "validator.ProduceBlockV2")
|
||||
defer span.End()
|
||||
|
||||
epoch := slots.ToEpoch(req.Slot)
|
||||
if epoch < params.BeaconConfig().AltairForkEpoch {
|
||||
block, err := vs.v1BeaconBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||
}
|
||||
return ðpbv2.ProduceBlockResponseV2{
|
||||
Version: ethpbv2.Version_PHASE0,
|
||||
Data: ðpbv2.BeaconBlockContainerV2{
|
||||
Block: ðpbv2.BeaconBlockContainerV2_Phase0Block{Phase0Block: block},
|
||||
},
|
||||
}, nil
|
||||
if err := rpchelpers.ValidateSync(ctx, vs.SyncChecker, vs.HeadFetcher, vs.TimeFetcher); err != nil {
|
||||
// We simply return the error because it's already a gRPC error.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v1alpha1req := ðpbalpha.BlockRequest{
|
||||
@@ -287,20 +283,46 @@ func (vs *Server) ProduceBlockV2(ctx context.Context, req *ethpbv1.ProduceBlockR
|
||||
// We simply return err because it's already of a gRPC error type.
|
||||
return nil, err
|
||||
}
|
||||
phase0Block, ok := v1alpha1resp.Block.(*ethpbalpha.GenericBeaconBlock_Phase0)
|
||||
if ok {
|
||||
block, err := migration.V1Alpha1ToV1Block(phase0Block.Phase0)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||
}
|
||||
return ðpbv2.ProduceBlockResponseV2{
|
||||
Version: ethpbv2.Version_PHASE0,
|
||||
Data: ðpbv2.BeaconBlockContainerV2{
|
||||
Block: ðpbv2.BeaconBlockContainerV2_Phase0Block{Phase0Block: block},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
altairBlock, ok := v1alpha1resp.Block.(*ethpbalpha.GenericBeaconBlock_Altair)
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get Altair block: %v", err)
|
||||
if ok {
|
||||
block, err := migration.V1Alpha1BeaconBlockAltairToV2(altairBlock.Altair)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||
}
|
||||
return ðpbv2.ProduceBlockResponseV2{
|
||||
Version: ethpbv2.Version_ALTAIR,
|
||||
Data: ðpbv2.BeaconBlockContainerV2{
|
||||
Block: ðpbv2.BeaconBlockContainerV2_AltairBlock{AltairBlock: block},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
block, err := migration.V1Alpha1BeaconBlockAltairToV2(altairBlock.Altair)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||
bellatrixBlock, ok := v1alpha1resp.Block.(*ethpbalpha.GenericBeaconBlock_Bellatrix)
|
||||
if ok {
|
||||
block, err := migration.V1Alpha1BeaconBlockBellatrixToV2(bellatrixBlock.Bellatrix)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not prepare beacon block: %v", err)
|
||||
}
|
||||
return ðpbv2.ProduceBlockResponseV2{
|
||||
Version: ethpbv2.Version_BELLATRIX,
|
||||
Data: ðpbv2.BeaconBlockContainerV2{
|
||||
Block: ðpbv2.BeaconBlockContainerV2_BellatrixBlock{BellatrixBlock: block},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return ðpbv2.ProduceBlockResponseV2{
|
||||
Version: ethpbv2.Version_ALTAIR,
|
||||
Data: ðpbv2.BeaconBlockContainerV2{
|
||||
Block: ðpbv2.BeaconBlockContainerV2_AltairBlock{AltairBlock: block},
|
||||
},
|
||||
}, nil
|
||||
return nil, status.Error(codes.InvalidArgument, "Unsupported block type")
|
||||
}
|
||||
|
||||
// PrepareBeaconProposer --
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
|
||||
p2pmock "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
|
||||
p2pType "github.com/prysmaticlabs/prysm/beacon-chain/p2p/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1/mocks"
|
||||
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
|
||||
v1alpha1validator "github.com/prysmaticlabs/prysm/beacon-chain/rpc/prysm/v1alpha1/validator"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/rpc/testutil"
|
||||
@@ -34,6 +35,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
|
||||
ethpbv2 "github.com/prysmaticlabs/prysm/proto/eth/v2"
|
||||
"github.com/prysmaticlabs/prysm/proto/migration"
|
||||
@@ -610,6 +612,7 @@ func TestProduceBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
v1Server := &Server{
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
V1Alpha1Server: v1Alpha1Server,
|
||||
}
|
||||
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
|
||||
@@ -641,6 +644,17 @@ func TestProduceBlock(t *testing.T) {
|
||||
assert.DeepEqual(t, expectedAttSlashings, resp.Data.Body.AttesterSlashings)
|
||||
}
|
||||
|
||||
func TestProduceBlock_SyncNotReady(t *testing.T) {
|
||||
chainService := &mockChain.ChainService{}
|
||||
vs := &Server{
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: true},
|
||||
HeadFetcher: chainService,
|
||||
TimeFetcher: chainService,
|
||||
}
|
||||
_, err := vs.ProduceBlock(context.Background(), ðpbv1.ProduceBlockRequest{})
|
||||
assert.ErrorContains(t, "Syncing to latest head, not ready to respond", err)
|
||||
}
|
||||
|
||||
func TestProduceBlockV2(t *testing.T) {
|
||||
t.Run("Phase 0", func(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
@@ -701,6 +715,7 @@ func TestProduceBlockV2(t *testing.T) {
|
||||
|
||||
v1Server := &Server{
|
||||
V1Alpha1Server: v1Alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
}
|
||||
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
|
||||
require.NoError(t, err)
|
||||
@@ -834,6 +849,7 @@ func TestProduceBlockV2(t *testing.T) {
|
||||
|
||||
v1Server := &Server{
|
||||
V1Alpha1Server: v1Alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
}
|
||||
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
|
||||
require.NoError(t, err)
|
||||
@@ -874,6 +890,166 @@ func TestProduceBlockV2(t *testing.T) {
|
||||
assert.DeepEqual(t, expectedBits, blk.Body.SyncAggregate.SyncCommitteeBits)
|
||||
assert.DeepEqual(t, aggregatedSig, blk.Body.SyncAggregate.SyncCommitteeSignature)
|
||||
})
|
||||
|
||||
t.Run("Bellatrix", func(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
bc := params.BeaconConfig()
|
||||
bc.AltairForkEpoch = types.Epoch(0)
|
||||
bc.BellatrixForkEpoch = types.Epoch(1)
|
||||
params.OverrideBeaconConfig(bc)
|
||||
|
||||
beaconState, privKeys := util.DeterministicGenesisStateBellatrix(t, params.BeaconConfig().SyncCommitteeSize)
|
||||
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
syncCommittee, err := altair.NextSyncCommittee(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetCurrentSyncCommittee(syncCommittee))
|
||||
require.NoError(t, beaconState.SetNextSyncCommittee(syncCommittee))
|
||||
|
||||
stateRoot, err := beaconState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err, "Could not hash genesis state")
|
||||
genesisBlock := util.NewBeaconBlockBellatrix()
|
||||
genesisBlock.Block.StateRoot = stateRoot[:]
|
||||
wrappedBellatrixBlock, err := wrapper.WrappedBellatrixSignedBeaconBlock(genesisBlock)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, wrappedBellatrixBlock))
|
||||
parentRoot, err := genesisBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state")
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
|
||||
|
||||
v1Alpha1Server := &v1alpha1validator.Server{
|
||||
ExecutionEngineCaller: &mocks.EngineClient{
|
||||
ExecutionBlock: &enginev1.ExecutionBlock{
|
||||
TotalDifficulty: "0x1",
|
||||
},
|
||||
},
|
||||
TimeFetcher: &mockChain.ChainService{},
|
||||
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
BlockReceiver: &mockChain.ChainService{},
|
||||
ChainStartFetcher: &mockPOW.POWChain{},
|
||||
Eth1InfoFetcher: &mockPOW.POWChain{},
|
||||
Eth1BlockFetcher: &mockPOW.POWChain{},
|
||||
MockEth1Votes: true,
|
||||
AttPool: attestations.NewPool(),
|
||||
SlashingsPool: slashings.NewPool(),
|
||||
ExitPool: voluntaryexits.NewPool(),
|
||||
StateGen: stategen.New(db),
|
||||
SyncCommitteePool: synccommittee.NewStore(),
|
||||
}
|
||||
|
||||
proposerSlashings := make([]*ethpbalpha.ProposerSlashing, params.BeaconConfig().MaxProposerSlashings)
|
||||
for i := types.ValidatorIndex(0); uint64(i) < params.BeaconConfig().MaxProposerSlashings; i++ {
|
||||
proposerSlashing, err := util.GenerateProposerSlashingForValidator(
|
||||
beaconState,
|
||||
privKeys[i],
|
||||
i,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
proposerSlashings[i] = proposerSlashing
|
||||
err = v1Alpha1Server.SlashingsPool.InsertProposerSlashing(context.Background(), beaconState, proposerSlashing)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
attSlashings := make([]*ethpbalpha.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings)
|
||||
for i := uint64(0); i < params.BeaconConfig().MaxAttesterSlashings; i++ {
|
||||
attesterSlashing, err := util.GenerateAttesterSlashingForValidator(
|
||||
beaconState,
|
||||
privKeys[i+params.BeaconConfig().MaxProposerSlashings],
|
||||
types.ValidatorIndex(i+params.BeaconConfig().MaxProposerSlashings), /* validator index */
|
||||
)
|
||||
require.NoError(t, err)
|
||||
attSlashings[i] = attesterSlashing
|
||||
err = v1Alpha1Server.SlashingsPool.InsertAttesterSlashing(context.Background(), beaconState, attesterSlashing)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
aggregationBits := bitfield.NewBitvector128()
|
||||
for i := range aggregationBits {
|
||||
aggregationBits[i] = 0xAA
|
||||
}
|
||||
|
||||
syncCommitteeIndices, err := altair.NextSyncCommitteeIndices(context.Background(), beaconState)
|
||||
require.NoError(t, err)
|
||||
sigs := make([]bls.Signature, 0, len(syncCommitteeIndices))
|
||||
for i, indice := range syncCommitteeIndices {
|
||||
if aggregationBits.BitAt(uint64(i)) {
|
||||
b := p2pType.SSZBytes(parentRoot[:])
|
||||
sb, err := signing.ComputeDomainAndSign(beaconState, coreTime.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
||||
require.NoError(t, err)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
require.NoError(t, err)
|
||||
sigs = append(sigs, sig)
|
||||
}
|
||||
}
|
||||
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
||||
contribution := ðpbalpha.SyncCommitteeContribution{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch,
|
||||
BlockRoot: parentRoot[:],
|
||||
SubcommitteeIndex: 0,
|
||||
AggregationBits: aggregationBits,
|
||||
Signature: aggregatedSig,
|
||||
}
|
||||
require.NoError(t, v1Alpha1Server.SyncCommitteePool.SaveSyncCommitteeContribution(contribution))
|
||||
|
||||
v1Server := &Server{
|
||||
V1Alpha1Server: v1Alpha1Server,
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
}
|
||||
randaoReveal, err := util.RandaoReveal(beaconState, 1, privKeys)
|
||||
require.NoError(t, err)
|
||||
graffiti := bytesutil.ToBytes32([]byte("eth2"))
|
||||
|
||||
req := ðpbv1.ProduceBlockRequest{
|
||||
Slot: params.BeaconConfig().SlotsPerEpoch + 1,
|
||||
RandaoReveal: randaoReveal,
|
||||
Graffiti: graffiti[:],
|
||||
}
|
||||
resp, err := v1Server.ProduceBlockV2(ctx, req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ethpbv2.Version_BELLATRIX, resp.Version)
|
||||
|
||||
containerBlock, ok := resp.Data.Block.(*ethpbv2.BeaconBlockContainerV2_BellatrixBlock)
|
||||
require.Equal(t, true, ok)
|
||||
blk := containerBlock.BellatrixBlock
|
||||
assert.Equal(t, req.Slot, blk.Slot, "Expected block to have slot of 1")
|
||||
assert.DeepEqual(t, parentRoot[:], blk.ParentRoot, "Expected block to have correct parent root")
|
||||
assert.DeepEqual(t, randaoReveal, blk.Body.RandaoReveal, "Expected block to have correct randao reveal")
|
||||
assert.DeepEqual(t, req.Graffiti, blk.Body.Graffiti, "Expected block to have correct graffiti")
|
||||
assert.Equal(t, params.BeaconConfig().MaxProposerSlashings, uint64(len(blk.Body.ProposerSlashings)))
|
||||
expectedPropSlashings := make([]*ethpbv1.ProposerSlashing, len(proposerSlashings))
|
||||
for i, slash := range proposerSlashings {
|
||||
expectedPropSlashings[i] = migration.V1Alpha1ProposerSlashingToV1(slash)
|
||||
}
|
||||
assert.DeepEqual(t, expectedPropSlashings, blk.Body.ProposerSlashings)
|
||||
assert.Equal(t, params.BeaconConfig().MaxAttesterSlashings, uint64(len(blk.Body.AttesterSlashings)))
|
||||
expectedAttSlashings := make([]*ethpbv1.AttesterSlashing, len(attSlashings))
|
||||
for i, slash := range attSlashings {
|
||||
expectedAttSlashings[i] = migration.V1Alpha1AttSlashingToV1(slash)
|
||||
}
|
||||
assert.DeepEqual(t, expectedAttSlashings, blk.Body.AttesterSlashings)
|
||||
expectedBits := bitfield.NewBitvector512()
|
||||
for i := 0; i <= 15; i++ {
|
||||
expectedBits[i] = 0xAA
|
||||
}
|
||||
assert.DeepEqual(t, expectedBits, blk.Body.SyncAggregate.SyncCommitteeBits)
|
||||
assert.DeepEqual(t, aggregatedSig, blk.Body.SyncAggregate.SyncCommitteeSignature)
|
||||
})
|
||||
}
|
||||
|
||||
func TestProduceBlockV2_SyncNotReady(t *testing.T) {
|
||||
chainService := &mockChain.ChainService{}
|
||||
vs := &Server{
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: true},
|
||||
HeadFetcher: chainService,
|
||||
TimeFetcher: chainService,
|
||||
}
|
||||
_, err := vs.ProduceBlockV2(context.Background(), ðpbv1.ProduceBlockRequest{})
|
||||
assert.ErrorContains(t, "Syncing to latest head, not ready to respond", err)
|
||||
}
|
||||
|
||||
func TestProduceAttestationData(t *testing.T) {
|
||||
|
||||
@@ -42,6 +42,7 @@ go_library(
|
||||
"//beacon-chain/core/transition/interop:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/db/kv:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/operations/synccommittee:go_default_library",
|
||||
@@ -117,6 +118,7 @@ go_test(
|
||||
"//beacon-chain/cache/depositcache:go_default_library",
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/execution:go_default_library",
|
||||
"//beacon-chain/core/feed:go_default_library",
|
||||
"//beacon-chain/core/feed/block:go_default_library",
|
||||
"//beacon-chain/core/feed/operation:go_default_library",
|
||||
|
||||
@@ -187,7 +187,7 @@ func (vs *Server) duties(ctx context.Context, req *ethpb.DutiesRequest) (*ethpb.
|
||||
}
|
||||
|
||||
// Are the validators in current or next epoch sync committee.
|
||||
if ok && coreTime.AltairCompatible(s, req.Epoch) {
|
||||
if ok && coreTime.HigherEqualThanAltairVersionAndEpoch(s, req.Epoch) {
|
||||
assignment.IsSyncCommittee, err = helpers.IsCurrentPeriodSyncCommittee(s, idx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not determine current epoch sync committee: %v", err)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/execution"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
@@ -200,6 +201,111 @@ func TestGetAltairDuties_SyncCommitteeOK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBellatrixDuties_SyncCommitteeOK(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.MainnetConfig()
|
||||
cfg.AltairForkEpoch = types.Epoch(0)
|
||||
cfg.BellatrixForkEpoch = types.Epoch(1)
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
genesis := util.NewBeaconBlock()
|
||||
deposits, _, err := util.DeterministicDepositsAndKeys(params.BeaconConfig().SyncCommitteeSize)
|
||||
require.NoError(t, err)
|
||||
eth1Data, err := util.DeterministicEth1Data(len(deposits))
|
||||
require.NoError(t, err)
|
||||
bs, err := util.GenesisBeaconState(context.Background(), deposits, 0, eth1Data)
|
||||
h := ðpb.BeaconBlockHeader{
|
||||
StateRoot: bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength),
|
||||
ParentRoot: bytesutil.PadTo([]byte{'b'}, fieldparams.RootLength),
|
||||
BodyRoot: bytesutil.PadTo([]byte{'c'}, fieldparams.RootLength),
|
||||
}
|
||||
require.NoError(t, bs.SetLatestBlockHeader(h))
|
||||
require.NoError(t, err, "Could not setup genesis bs")
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not get signing root")
|
||||
|
||||
syncCommittee, err := altair.NextSyncCommittee(context.Background(), bs)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, bs.SetCurrentSyncCommittee(syncCommittee))
|
||||
pubKeys := make([][]byte, len(deposits))
|
||||
indices := make([]uint64, len(deposits))
|
||||
for i := 0; i < len(deposits); i++ {
|
||||
pubKeys[i] = deposits[i].Data.PublicKey
|
||||
indices[i] = uint64(i)
|
||||
}
|
||||
require.NoError(t, bs.SetSlot(params.BeaconConfig().SlotsPerEpoch*types.Slot(params.BeaconConfig().EpochsPerSyncCommitteePeriod)-1))
|
||||
require.NoError(t, helpers.UpdateSyncCommitteeCache(bs))
|
||||
|
||||
bs, err = execution.UpgradeToBellatrix(context.Background(), bs)
|
||||
require.NoError(t, err)
|
||||
|
||||
pubkeysAs48ByteType := make([][fieldparams.BLSPubkeyLength]byte, len(pubKeys))
|
||||
for i, pk := range pubKeys {
|
||||
pubkeysAs48ByteType[i] = bytesutil.ToBytes48(pk)
|
||||
}
|
||||
|
||||
slot := uint64(params.BeaconConfig().SlotsPerEpoch) * uint64(params.BeaconConfig().EpochsPerSyncCommitteePeriod) * params.BeaconConfig().SecondsPerSlot
|
||||
chain := &mockChain.ChainService{
|
||||
State: bs, Root: genesisRoot[:], Genesis: time.Now().Add(time.Duration(-1*int64(slot-1)) * time.Second),
|
||||
}
|
||||
vs := &Server{
|
||||
HeadFetcher: chain,
|
||||
TimeFetcher: chain,
|
||||
Eth1InfoFetcher: &mockPOW.POWChain{},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
}
|
||||
|
||||
// Test the first validator in registry.
|
||||
req := ðpb.DutiesRequest{
|
||||
PublicKeys: [][]byte{deposits[0].Data.PublicKey},
|
||||
}
|
||||
res, err := vs.GetDuties(context.Background(), req)
|
||||
require.NoError(t, err, "Could not call epoch committee assignment")
|
||||
if res.CurrentEpochDuties[0].AttesterSlot > bs.Slot()+params.BeaconConfig().SlotsPerEpoch {
|
||||
t.Errorf("Assigned slot %d can't be higher than %d",
|
||||
res.CurrentEpochDuties[0].AttesterSlot, bs.Slot()+params.BeaconConfig().SlotsPerEpoch)
|
||||
}
|
||||
|
||||
// Test the last validator in registry.
|
||||
lastValidatorIndex := params.BeaconConfig().SyncCommitteeSize - 1
|
||||
req = ðpb.DutiesRequest{
|
||||
PublicKeys: [][]byte{deposits[lastValidatorIndex].Data.PublicKey},
|
||||
}
|
||||
res, err = vs.GetDuties(context.Background(), req)
|
||||
require.NoError(t, err, "Could not call epoch committee assignment")
|
||||
if res.CurrentEpochDuties[0].AttesterSlot > bs.Slot()+params.BeaconConfig().SlotsPerEpoch {
|
||||
t.Errorf("Assigned slot %d can't be higher than %d",
|
||||
res.CurrentEpochDuties[0].AttesterSlot, bs.Slot()+params.BeaconConfig().SlotsPerEpoch)
|
||||
}
|
||||
|
||||
// We request for duties for all validators.
|
||||
req = ðpb.DutiesRequest{
|
||||
PublicKeys: pubKeys,
|
||||
Epoch: 0,
|
||||
}
|
||||
res, err = vs.GetDuties(context.Background(), req)
|
||||
require.NoError(t, err, "Could not call epoch committee assignment")
|
||||
for i := 0; i < len(res.CurrentEpochDuties); i++ {
|
||||
assert.Equal(t, types.ValidatorIndex(i), res.CurrentEpochDuties[i].ValidatorIndex)
|
||||
}
|
||||
for i := 0; i < len(res.CurrentEpochDuties); i++ {
|
||||
assert.Equal(t, true, res.CurrentEpochDuties[i].IsSyncCommittee)
|
||||
// Current epoch and next epoch duties should be equal before the sync period epoch boundary.
|
||||
assert.Equal(t, res.CurrentEpochDuties[i].IsSyncCommittee, res.NextEpochDuties[i].IsSyncCommittee)
|
||||
}
|
||||
|
||||
// Current epoch and next epoch duties should not be equal at the sync period epoch boundary.
|
||||
req = ðpb.DutiesRequest{
|
||||
PublicKeys: pubKeys,
|
||||
Epoch: params.BeaconConfig().EpochsPerSyncCommitteePeriod - 1,
|
||||
}
|
||||
res, err = vs.GetDuties(context.Background(), req)
|
||||
require.NoError(t, err, "Could not call epoch committee assignment")
|
||||
for i := 0; i < len(res.CurrentEpochDuties); i++ {
|
||||
assert.NotEqual(t, res.CurrentEpochDuties[i].IsSyncCommittee, res.NextEpochDuties[i].IsSyncCommittee)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAltairDuties_UnknownPubkey(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.MainnetConfig()
|
||||
|
||||
@@ -16,7 +16,7 @@ func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payload, err := vs.getExecutionPayload(ctx, req.Slot)
|
||||
payload, err := vs.getExecutionPayload(ctx, req.Slot, altairBlk.ProposerIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db/kv"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
|
||||
// This returns the execution payload of a given slot. The function has full awareness of pre and post merge.
|
||||
// The payload is computed given the respected time of merge.
|
||||
func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot) (*enginev1.ExecutionPayload, error) {
|
||||
func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx types.ValidatorIndex) (*enginev1.ExecutionPayload, error) {
|
||||
st, err := vs.HeadFetcher.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -94,10 +95,24 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot) (*en
|
||||
SafeBlockHash: parentHash,
|
||||
FinalizedBlockHash: finalizedBlockHash,
|
||||
}
|
||||
|
||||
feeRecipient := params.BeaconConfig().DefaultFeeRecipient
|
||||
recipient, err := vs.BeaconDB.FeeRecipientByValidatorID(ctx, vIdx)
|
||||
switch err == nil {
|
||||
case true:
|
||||
feeRecipient = recipient
|
||||
case errors.As(err, kv.ErrNotFoundFeeRecipient): // If fee recipient is not found, use the default fee recipient.
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"validatorIndex": vIdx,
|
||||
"defaultFeeRecipient": feeRecipient,
|
||||
}).Error("Fee recipient not found. Using default fee recipient")
|
||||
default:
|
||||
return nil, errors.Wrap(err, "could not get fee recipient in db")
|
||||
}
|
||||
p := &enginev1.PayloadAttributes{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: random,
|
||||
SuggestedFeeRecipient: params.BeaconConfig().FeeRecipient.Bytes(),
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
}
|
||||
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdated(ctx, f, p)
|
||||
if err != nil {
|
||||
@@ -204,6 +219,8 @@ func (vs *Server) getPowBlockHashAtTerminalTotalDifficulty(ctx context.Context)
|
||||
}).Info("Retrieved terminal block hash")
|
||||
return blk.Hash, true, nil
|
||||
}
|
||||
} else {
|
||||
return nil, false, nil
|
||||
}
|
||||
blk = parentBlk
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), b1))
|
||||
require.NoError(t, beaconDB.SaveBlock(context.Background(), b2))
|
||||
require.NoError(t, beaconDB.SaveFeeRecipientsByValidatorIDs(context.Background(), []types.ValidatorIndex{0}, []common.Address{{}}))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -88,6 +89,7 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
payloadID *pb.PayloadIDBytes
|
||||
terminalBlockHash common.Hash
|
||||
activationEpoch types.Epoch
|
||||
validatorIndx types.ValidatorIndex
|
||||
}{
|
||||
{
|
||||
name: "transition completed, nil payload id",
|
||||
@@ -95,10 +97,16 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
errString: "nil payload id",
|
||||
},
|
||||
{
|
||||
name: "transition completed, happy case",
|
||||
name: "transition completed, happy case (has fee recipient in Db)",
|
||||
st: transitionSt,
|
||||
payloadID: &pb.PayloadIDBytes{0x1},
|
||||
},
|
||||
{
|
||||
name: "transition completed, happy case (doesn't have fee recipient in Db)",
|
||||
st: transitionSt,
|
||||
payloadID: &pb.PayloadIDBytes{0x1},
|
||||
validatorIndx: 1,
|
||||
},
|
||||
{
|
||||
name: "transition completed, could not prepare payload",
|
||||
st: transitionSt,
|
||||
@@ -129,7 +137,7 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
HeadFetcher: &chainMock.ChainService{State: tt.st},
|
||||
BeaconDB: beaconDB,
|
||||
}
|
||||
_, err := vs.getExecutionPayload(context.Background(), tt.st.Slot())
|
||||
_, err := vs.getExecutionPayload(context.Background(), tt.st.Slot(), tt.validatorIndx)
|
||||
if tt.errString != "" {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
} else {
|
||||
@@ -225,6 +233,20 @@ func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
|
||||
wantExists: true,
|
||||
wantTerminalBlockHash: []byte{'a'},
|
||||
},
|
||||
{
|
||||
name: "ttd not reached",
|
||||
paramsTd: "3",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: []byte{'b'},
|
||||
TotalDifficulty: "0x2",
|
||||
},
|
||||
parentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'b'},
|
||||
ParentHash: []byte{'c'},
|
||||
TotalDifficulty: "0x1",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -2233,6 +2234,7 @@ func TestProposer_GetBeaconBlock_PostForkEpoch(t *testing.T) {
|
||||
func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
hook := logTest.NewGlobal()
|
||||
|
||||
terminalBlockHash := bytesutil.PadTo([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 32)
|
||||
@@ -2333,6 +2335,7 @@ func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
|
||||
PayloadIDBytes: &enginev1.PayloadIDBytes{1},
|
||||
ExecutionPayload: payload,
|
||||
},
|
||||
BeaconDB: db,
|
||||
}
|
||||
|
||||
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
|
||||
@@ -2346,6 +2349,10 @@ func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
|
||||
Graffiti: graffiti[:],
|
||||
}
|
||||
|
||||
proposerIndex := types.ValidatorIndex(40)
|
||||
addr := common.Address{'a'}
|
||||
require.NoError(t, proposerServer.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{proposerIndex}, []common.Address{addr}))
|
||||
|
||||
block, err := proposerServer.GetBeaconBlock(ctx, req)
|
||||
require.NoError(t, err)
|
||||
bellatrixBlk, ok := block.GetBlock().(*ethpb.GenericBeaconBlock_Bellatrix)
|
||||
@@ -2356,6 +2363,7 @@ func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
|
||||
assert.DeepEqual(t, randaoReveal, bellatrixBlk.Bellatrix.Body.RandaoReveal, "Expected block to have correct randao reveal")
|
||||
assert.DeepEqual(t, req.Graffiti, bellatrixBlk.Bellatrix.Body.Graffiti, "Expected block to have correct Graffiti")
|
||||
|
||||
require.LogsDoNotContain(t, hook, "Fee recipient not found. Using default fee recipient.")
|
||||
require.DeepEqual(t, payload, bellatrixBlk.Bellatrix.Body.ExecutionPayload) // Payload should equal.
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v1
|
||||
|
||||
@@ -3,75 +3,43 @@ package v1
|
||||
import (
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_LatestBlockHeader(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
got := s.LatestBlockHeader()
|
||||
require.DeepEqual(t, (*ethpb.BeaconBlockHeader)(nil), got)
|
||||
|
||||
want := ðpb.BeaconBlockHeader{Slot: 100}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{LatestBlockHeader: want})
|
||||
require.NoError(t, err)
|
||||
got = s.LatestBlockHeader()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got.Slot = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateLatestBlockHeader(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
},
|
||||
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{LatestBlockHeader: BH})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRoots(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
want := make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
want[i] = make([]byte, 32)
|
||||
}
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
want = make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
if i == 0 {
|
||||
want[i] = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
} else {
|
||||
want[i] = make([]byte, 32)
|
||||
}
|
||||
|
||||
}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{BlockRoots: want})
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootsNative(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRootAtIndex(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, bytesutil.PadTo([]byte{}, 32), got)
|
||||
|
||||
r := [fieldparams.BlockRootsLength][32]byte{{'a'}}
|
||||
bRoots := make([][]byte, len(r))
|
||||
for i, root := range r {
|
||||
tmp := root
|
||||
bRoots[i] = tmp[:]
|
||||
}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{BlockRoots: bRoots})
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, 32)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootAtIndexNative(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_SlotDataRace(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_SlotDataRace(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{Slot: 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchCurrentJustifiedCheckptNative(
|
||||
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{CurrentJustifiedCheckpoint: cp})
|
||||
@@ -24,7 +24,7 @@ func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchPreviousJustifiedCheckptNative(
|
||||
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{PreviousJustifiedCheckpoint: cp})
|
||||
@@ -33,7 +33,7 @@ func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
return v1.InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
Validators: nil,
|
||||
})
|
||||
|
||||
@@ -86,6 +86,7 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/testing:go_default_library",
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v2
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v2
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v2
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v2
|
||||
|
||||
@@ -3,74 +3,43 @@ package v2
|
||||
import (
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_LatestBlockHeader(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
got := s.LatestBlockHeader()
|
||||
require.DeepEqual(t, (*ethpb.BeaconBlockHeader)(nil), got)
|
||||
|
||||
want := ðpb.BeaconBlockHeader{Slot: 100}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateAltair{LatestBlockHeader: want})
|
||||
require.NoError(t, err)
|
||||
got = s.LatestBlockHeader()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got.Slot = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateLatestBlockHeader(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
},
|
||||
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{LatestBlockHeader: BH})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRoots(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
want := make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
want[i] = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
want = make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
if i == 0 {
|
||||
want[i] = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
} else {
|
||||
want[i] = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: want})
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootsNative(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRootAtIndex(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, bytesutil.PadTo([]byte{}, fieldparams.RootLength), got)
|
||||
|
||||
r := [fieldparams.BlockRootsLength][fieldparams.RootLength]byte{{'a'}}
|
||||
bRoots := make([][]byte, len(r))
|
||||
for i, root := range r {
|
||||
tmp := root
|
||||
bRoots[i] = tmp[:]
|
||||
}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: bRoots})
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootAtIndexNative(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_SlotDataRace(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_SlotDataRace(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{Slot: 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchCurrentJustifiedCheckptNative(
|
||||
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{CurrentJustifiedCheckpoint: cp})
|
||||
@@ -24,7 +24,7 @@ func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchPreviousJustifiedCheckptNative(
|
||||
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{PreviousJustifiedCheckpoint: cp})
|
||||
@@ -33,7 +33,7 @@ func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
return v2.InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
Validators: nil,
|
||||
})
|
||||
|
||||
223
beacon-chain/state/state-native/v2/references_test.go
Normal file
223
beacon-chain/state/state-native/v2/references_test.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestStateReferenceSharing_Finalizer(t *testing.T) {
|
||||
// This test showcases the logic on a the RandaoMixes field with the GC finalizer.
|
||||
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{RandaoMixes: [][]byte{[]byte("foo")}})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, uint(1), s.sharedFieldReferences[randaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
|
||||
|
||||
func() {
|
||||
// Create object in a different scope for GC
|
||||
b := s.Copy()
|
||||
assert.Equal(t, uint(2), s.sharedFieldReferences[randaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
|
||||
_ = b
|
||||
}()
|
||||
|
||||
runtime.GC() // Should run finalizer on object b
|
||||
assert.Equal(t, uint(1), s.sharedFieldReferences[randaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
|
||||
|
||||
copied := s.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[randaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
if b.sharedFieldReferences[randaoMixes].Refs() != 1 || s.sharedFieldReferences[randaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateReferenceCopy_NoUnexpectedRootsMutation(t *testing.T) {
|
||||
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
BlockRoots: [][]byte{
|
||||
root1[:],
|
||||
},
|
||||
StateRoots: [][]byte{
|
||||
root1[:],
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assertRefCount(t, s, blockRoots, 1)
|
||||
assertRefCount(t, s, stateRoots, 1)
|
||||
|
||||
// Copy, increases reference count.
|
||||
copied := s.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, blockRoots, 2)
|
||||
assertRefCount(t, s, stateRoots, 2)
|
||||
assertRefCount(t, b, blockRoots, 2)
|
||||
assertRefCount(t, b, stateRoots, 2)
|
||||
assert.Equal(t, 8192, len(b.BlockRoots()), "Wrong number of block roots found")
|
||||
assert.Equal(t, 8192, len(b.StateRoots()), "Wrong number of state roots found")
|
||||
|
||||
// Assert shared state.
|
||||
blockRootsA := s.BlockRoots()
|
||||
stateRootsA := s.StateRoots()
|
||||
blockRootsB := b.BlockRoots()
|
||||
stateRootsB := b.StateRoots()
|
||||
if len(blockRootsA) != len(blockRootsB) || len(blockRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of block roots, want: %v", 1)
|
||||
}
|
||||
if len(stateRootsA) != len(stateRootsB) || len(stateRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of state roots, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, blockRootsA, root1[:])
|
||||
assertValFound(t, blockRootsB, root1[:])
|
||||
assertValFound(t, stateRootsA, root1[:])
|
||||
assertValFound(t, stateRootsB, root1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, s.UpdateBlockRootAtIndex(0, root2))
|
||||
require.NoError(t, s.UpdateStateRootAtIndex(0, root2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValNotFound(t, s.BlockRoots(), root1[:])
|
||||
assertValNotFound(t, s.StateRoots(), root1[:])
|
||||
assertValFound(t, s.BlockRoots(), root2[:])
|
||||
assertValFound(t, s.StateRoots(), root2[:])
|
||||
assertValFound(t, b.BlockRoots(), root1[:])
|
||||
assertValFound(t, b.StateRoots(), root1[:])
|
||||
if len(blockRootsA) != len(blockRootsB) || len(blockRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of block roots, want: %v", 1)
|
||||
}
|
||||
if len(stateRootsA) != len(stateRootsB) || len(stateRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of state roots, want: %v", 1)
|
||||
}
|
||||
assert.DeepEqual(t, root2[:], s.BlockRoots()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, root2[:], s.StateRoots()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
|
||||
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
|
||||
|
||||
// Copy on write happened, reference counters are reset.
|
||||
assertRefCount(t, s, blockRoots, 1)
|
||||
assertRefCount(t, s, stateRoots, 1)
|
||||
assertRefCount(t, b, blockRoots, 1)
|
||||
assertRefCount(t, b, stateRoots, 1)
|
||||
}
|
||||
|
||||
func TestStateReferenceCopy_NoUnexpectedRandaoMutation(t *testing.T) {
|
||||
|
||||
val1, val2 := bytesutil.PadTo([]byte("foo"), 32), bytesutil.PadTo([]byte("bar"), 32)
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
RandaoMixes: [][]byte{
|
||||
val1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assertRefCount(t, s, randaoMixes, 1)
|
||||
|
||||
// Copy, increases reference count.
|
||||
copied := s.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, randaoMixes, 2)
|
||||
assertRefCount(t, b, randaoMixes, 2)
|
||||
|
||||
// Assert shared state.
|
||||
mixesA := s.RandaoMixes()
|
||||
mixesB := b.RandaoMixes()
|
||||
if len(mixesA) != len(mixesB) || len(mixesA) < 1 {
|
||||
t.Errorf("Unexpected number of mix values, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, mixesA, val1)
|
||||
assertValFound(t, mixesB, val1)
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, s.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
if len(mixesA) != len(mixesB) || len(mixesA) < 1 {
|
||||
t.Errorf("Unexpected number of mix values, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, s.RandaoMixes(), val2)
|
||||
assertValNotFound(t, s.RandaoMixes(), val1)
|
||||
assertValFound(t, b.RandaoMixes(), val1)
|
||||
assertValNotFound(t, b.RandaoMixes(), val2)
|
||||
assertValFound(t, mixesB, val1)
|
||||
assertValNotFound(t, mixesB, val2)
|
||||
assert.DeepEqual(t, val2, s.RandaoMixes()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, val1, mixesB[0], "Unexpected mutation found")
|
||||
|
||||
// Copy on write happened, reference counters are reset.
|
||||
assertRefCount(t, s, randaoMixes, 1)
|
||||
assertRefCount(t, b, randaoMixes, 1)
|
||||
}
|
||||
|
||||
func TestValidatorReferences_RemainsConsistent(t *testing.T) {
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{
|
||||
{PublicKey: []byte{'A'}},
|
||||
{PublicKey: []byte{'B'}},
|
||||
{PublicKey: []byte{'C'}},
|
||||
{PublicKey: []byte{'D'}},
|
||||
{PublicKey: []byte{'E'}},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a second state.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
// Update First Validator.
|
||||
assert.NoError(t, a.UpdateValidatorAtIndex(0, ðpb.Validator{PublicKey: []byte{'Z'}}))
|
||||
|
||||
assert.DeepNotEqual(t, a.Validators()[0], b.Validators()[0], "validators are equal when they are supposed to be different")
|
||||
// Modify all validators from copied state.
|
||||
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
|
||||
return true, ðpb.Validator{PublicKey: []byte{'V'}}, nil
|
||||
}))
|
||||
|
||||
// Ensure reference is properly accounted for.
|
||||
assert.NoError(t, a.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
|
||||
assert.NotEqual(t, bytesutil.ToBytes48([]byte{'V'}), val.PublicKey())
|
||||
return 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) {
|
||||
if cnt := b.sharedFieldReferences[idx].Refs(); cnt != want {
|
||||
t.Errorf("Unexpected count of references for index %d, want: %v, got: %v", idx, want, cnt)
|
||||
}
|
||||
}
|
||||
|
||||
// assertValFound checks whether item with a given value exists in list.
|
||||
func assertValFound(t *testing.T, vals [][]byte, val []byte) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i], val) {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Fatalf("Expected value not found (%v), want: %v", vals, val)
|
||||
}
|
||||
|
||||
// assertValNotFound checks whether item with a given value doesn't exist in list.
|
||||
func assertValNotFound(t *testing.T, vals [][]byte, val []byte) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i], val) {
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Errorf("Unexpected value found (%v),: %v", vals, val)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,7 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/testing:go_default_library",
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//beacon-chain/state/v3:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v3
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v3
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v3
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v3
|
||||
|
||||
@@ -3,75 +3,43 @@ package v3
|
||||
import (
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_LatestBlockHeader(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
got := s.LatestBlockHeader()
|
||||
require.DeepEqual(t, (*ethpb.BeaconBlockHeader)(nil), got)
|
||||
|
||||
want := ðpb.BeaconBlockHeader{Slot: 100}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateBellatrix{LatestBlockHeader: want})
|
||||
require.NoError(t, err)
|
||||
got = s.LatestBlockHeader()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got.Slot = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateLatestBlockHeader(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
},
|
||||
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{LatestBlockHeader: BH})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRoots(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
want := make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
want[i] = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
want = make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
if i == 0 {
|
||||
want[i] = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
} else {
|
||||
want[i] = make([]byte, fieldparams.RootLength)
|
||||
}
|
||||
|
||||
}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: want})
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootsNative(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRootAtIndex(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, bytesutil.PadTo([]byte{}, fieldparams.RootLength), got)
|
||||
|
||||
r := [fieldparams.BlockRootsLength][fieldparams.RootLength]byte{{'a'}}
|
||||
bRoots := make([][]byte, len(r))
|
||||
for i, root := range r {
|
||||
tmp := root
|
||||
bRoots[i] = tmp[:]
|
||||
}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: bRoots})
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootAtIndexNative(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_SlotDataRace(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_SlotDataRace(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{Slot: 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchCurrentJustifiedCheckptNative(
|
||||
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{CurrentJustifiedCheckpoint: cp})
|
||||
@@ -24,7 +24,7 @@ func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchPreviousJustifiedCheckptNative(
|
||||
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{PreviousJustifiedCheckpoint: cp})
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
return v3.InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{
|
||||
Validators: nil,
|
||||
})
|
||||
|
||||
229
beacon-chain/state/state-native/v3/references_test.go
Normal file
229
beacon-chain/state/state-native/v3/references_test.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestStateReferenceSharing_Finalizer(t *testing.T) {
|
||||
// This test showcases the logic on a the RandaoMixes field with the GC finalizer.
|
||||
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{RandaoMixes: [][]byte{[]byte("foo")}})
|
||||
require.NoError(t, err)
|
||||
s, ok := a.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(1), s.sharedFieldReferences[randaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
|
||||
|
||||
func() {
|
||||
// Create object in a different scope for GC
|
||||
b := a.Copy()
|
||||
assert.Equal(t, uint(2), s.sharedFieldReferences[randaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
|
||||
_ = b
|
||||
}()
|
||||
|
||||
runtime.GC() // Should run finalizer on object b
|
||||
assert.Equal(t, uint(1), s.sharedFieldReferences[randaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
|
||||
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[randaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
if b.sharedFieldReferences[randaoMixes].Refs() != 1 || s.sharedFieldReferences[randaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateReferenceCopy_NoUnexpectedRootsMutation(t *testing.T) {
|
||||
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{
|
||||
BlockRoots: [][]byte{
|
||||
root1[:],
|
||||
},
|
||||
StateRoots: [][]byte{
|
||||
root1[:],
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
s, ok := a.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, blockRoots, 1)
|
||||
assertRefCount(t, s, stateRoots, 1)
|
||||
|
||||
// Copy, increases reference count.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, blockRoots, 2)
|
||||
assertRefCount(t, s, stateRoots, 2)
|
||||
assertRefCount(t, b, blockRoots, 2)
|
||||
assertRefCount(t, b, stateRoots, 2)
|
||||
assert.Equal(t, 8192, len(b.BlockRoots()), "Wrong number of block roots found")
|
||||
assert.Equal(t, 8192, len(b.StateRoots()), "Wrong number of state roots found")
|
||||
|
||||
// Assert shared state.
|
||||
blockRootsA := a.BlockRoots()
|
||||
stateRootsA := a.StateRoots()
|
||||
blockRootsB := b.BlockRoots()
|
||||
stateRootsB := b.StateRoots()
|
||||
if len(blockRootsA) != len(blockRootsB) || len(blockRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of block roots, want: %v", 1)
|
||||
}
|
||||
if len(stateRootsA) != len(stateRootsB) || len(stateRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of state roots, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, blockRootsA, root1[:])
|
||||
assertValFound(t, blockRootsB, root1[:])
|
||||
assertValFound(t, stateRootsA, root1[:])
|
||||
assertValFound(t, stateRootsB, root1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
|
||||
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValNotFound(t, a.BlockRoots(), root1[:])
|
||||
assertValNotFound(t, a.StateRoots(), root1[:])
|
||||
assertValFound(t, a.BlockRoots(), root2[:])
|
||||
assertValFound(t, a.StateRoots(), root2[:])
|
||||
assertValFound(t, b.BlockRoots(), root1[:])
|
||||
assertValFound(t, b.StateRoots(), root1[:])
|
||||
if len(blockRootsA) != len(blockRootsB) || len(blockRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of block roots, want: %v", 1)
|
||||
}
|
||||
if len(stateRootsA) != len(stateRootsB) || len(stateRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of state roots, want: %v", 1)
|
||||
}
|
||||
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
|
||||
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
|
||||
|
||||
// Copy on write happened, reference counters are reset.
|
||||
assertRefCount(t, s, blockRoots, 1)
|
||||
assertRefCount(t, s, stateRoots, 1)
|
||||
assertRefCount(t, b, blockRoots, 1)
|
||||
assertRefCount(t, b, stateRoots, 1)
|
||||
}
|
||||
|
||||
func TestStateReferenceCopy_NoUnexpectedRandaoMutation(t *testing.T) {
|
||||
|
||||
val1, val2 := bytesutil.PadTo([]byte("foo"), 32), bytesutil.PadTo([]byte("bar"), 32)
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{
|
||||
RandaoMixes: [][]byte{
|
||||
val1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
s, ok := a.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, randaoMixes, 1)
|
||||
|
||||
// Copy, increases reference count.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, randaoMixes, 2)
|
||||
assertRefCount(t, b, randaoMixes, 2)
|
||||
|
||||
// Assert shared state.
|
||||
mixesA := a.RandaoMixes()
|
||||
mixesB := b.RandaoMixes()
|
||||
if len(mixesA) != len(mixesB) || len(mixesA) < 1 {
|
||||
t.Errorf("Unexpected number of mix values, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, mixesA, val1)
|
||||
assertValFound(t, mixesB, val1)
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
if len(mixesA) != len(mixesB) || len(mixesA) < 1 {
|
||||
t.Errorf("Unexpected number of mix values, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, a.RandaoMixes(), val2)
|
||||
assertValNotFound(t, a.RandaoMixes(), val1)
|
||||
assertValFound(t, b.RandaoMixes(), val1)
|
||||
assertValNotFound(t, b.RandaoMixes(), val2)
|
||||
assertValFound(t, mixesB, val1)
|
||||
assertValNotFound(t, mixesB, val2)
|
||||
assert.DeepEqual(t, val2, a.RandaoMixes()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, val1, mixesB[0], "Unexpected mutation found")
|
||||
|
||||
// Copy on write happened, reference counters are reset.
|
||||
assertRefCount(t, s, randaoMixes, 1)
|
||||
assertRefCount(t, b, randaoMixes, 1)
|
||||
}
|
||||
|
||||
func TestValidatorReferences_RemainsConsistent(t *testing.T) {
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{
|
||||
Validators: []*ethpb.Validator{
|
||||
{PublicKey: []byte{'A'}},
|
||||
{PublicKey: []byte{'B'}},
|
||||
{PublicKey: []byte{'C'}},
|
||||
{PublicKey: []byte{'D'}},
|
||||
{PublicKey: []byte{'E'}},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a second state.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
// Update First Validator.
|
||||
assert.NoError(t, a.UpdateValidatorAtIndex(0, ðpb.Validator{PublicKey: []byte{'Z'}}))
|
||||
|
||||
assert.DeepNotEqual(t, a.Validators()[0], b.Validators()[0], "validators are equal when they are supposed to be different")
|
||||
// Modify all validators from copied state.
|
||||
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
|
||||
return true, ðpb.Validator{PublicKey: []byte{'V'}}, nil
|
||||
}))
|
||||
|
||||
// Ensure reference is properly accounted for.
|
||||
assert.NoError(t, a.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
|
||||
assert.NotEqual(t, bytesutil.ToBytes48([]byte{'V'}), val.PublicKey())
|
||||
return 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) {
|
||||
if cnt := b.sharedFieldReferences[idx].Refs(); cnt != want {
|
||||
t.Errorf("Unexpected count of references for index %d, want: %v, got: %v", idx, want, cnt)
|
||||
}
|
||||
}
|
||||
|
||||
// assertValFound checks whether item with a given value exists in list.
|
||||
func assertValFound(t *testing.T, vals [][]byte, val []byte) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i], val) {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Fatalf("Expected value not found (%v), want: %v", vals, val)
|
||||
}
|
||||
|
||||
// assertValNotFound checks whether item with a given value doesn't exist in list.
|
||||
func assertValNotFound(t *testing.T, vals [][]byte, val []byte) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i], val) {
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Errorf("Unexpected value found (%v),: %v", vals, val)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"getters.go",
|
||||
"getters_block.go",
|
||||
"getters_validator.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/testing",
|
||||
@@ -12,6 +13,7 @@ go_library(
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func VerifyBeaconState_SlotDataRace(t *testing.T, factory getState) {
|
||||
func VerifyBeaconStateSlotDataRace(t *testing.T, factory getState) {
|
||||
headState, err := factory()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -33,7 +33,7 @@ func VerifyBeaconState_SlotDataRace(t *testing.T, factory getState) {
|
||||
type getStateWithCurrentJustifiedCheckpoint func(*ethpb.Checkpoint) (state.BeaconState, error)
|
||||
type clearInternalState func(state.BeaconState)
|
||||
|
||||
func VerifyBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint, clear clearInternalState) {
|
||||
func VerifyBeaconStateMatchCurrentJustifiedCheckpt(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint, clear clearInternalState) {
|
||||
c1 := ðpb.Checkpoint{Epoch: 1}
|
||||
c2 := ðpb.Checkpoint{Epoch: 2}
|
||||
beaconState, err := factory(c1)
|
||||
@@ -46,7 +46,7 @@ func VerifyBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T, factory getSta
|
||||
require.Equal(t, false, beaconState.MatchCurrentJustifiedCheckpoint(c1))
|
||||
}
|
||||
|
||||
func VerifyBeaconState_MatchCurrentJustifiedCheckptNative(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint) {
|
||||
func VerifyBeaconStateMatchCurrentJustifiedCheckptNative(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint) {
|
||||
c1 := ðpb.Checkpoint{Epoch: 1}
|
||||
c2 := ðpb.Checkpoint{Epoch: 2}
|
||||
beaconState, err := factory(c1)
|
||||
@@ -57,7 +57,7 @@ func VerifyBeaconState_MatchCurrentJustifiedCheckptNative(t *testing.T, factory
|
||||
require.Equal(t, false, beaconState.MatchPreviousJustifiedCheckpoint(c2))
|
||||
}
|
||||
|
||||
func VerifyBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint, clear clearInternalState) {
|
||||
func VerifyBeaconStateMatchPreviousJustifiedCheckpt(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint, clear clearInternalState) {
|
||||
c1 := ðpb.Checkpoint{Epoch: 1}
|
||||
c2 := ðpb.Checkpoint{Epoch: 2}
|
||||
beaconState, err := factory(c1)
|
||||
@@ -70,7 +70,7 @@ func VerifyBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T, factory getSt
|
||||
require.Equal(t, false, beaconState.MatchPreviousJustifiedCheckpoint(c1))
|
||||
}
|
||||
|
||||
func VerifyBeaconState_MatchPreviousJustifiedCheckptNative(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint) {
|
||||
func VerifyBeaconStateMatchPreviousJustifiedCheckptNative(t *testing.T, factory getStateWithCurrentJustifiedCheckpoint) {
|
||||
c1 := ðpb.Checkpoint{Epoch: 1}
|
||||
c2 := ðpb.Checkpoint{Epoch: 2}
|
||||
beaconState, err := factory(c1)
|
||||
@@ -81,7 +81,7 @@ func VerifyBeaconState_MatchPreviousJustifiedCheckptNative(t *testing.T, factory
|
||||
require.Equal(t, false, beaconState.MatchPreviousJustifiedCheckpoint(c2))
|
||||
}
|
||||
|
||||
func VerifyBeaconState_MarshalSSZ_NilState(t *testing.T, factory getState, clear clearInternalState) {
|
||||
func VerifyBeaconStateMarshalSSZNilState(t *testing.T, factory getState, clear clearInternalState) {
|
||||
s, err := factory()
|
||||
require.NoError(t, err)
|
||||
clear(s)
|
||||
@@ -89,7 +89,7 @@ func VerifyBeaconState_MarshalSSZ_NilState(t *testing.T, factory getState, clear
|
||||
require.ErrorContains(t, "nil beacon state", err)
|
||||
}
|
||||
|
||||
func VerifyBeaconState_ValidatorByPubkey(t *testing.T, factory getState) {
|
||||
func VerifyBeaconStateValidatorByPubkey(t *testing.T, factory getState) {
|
||||
keyCreator := func(input []byte) [fieldparams.BLSPubkeyLength]byte {
|
||||
nKey := [fieldparams.BLSPubkeyLength]byte{}
|
||||
copy(nKey[:1], input)
|
||||
|
||||
135
beacon-chain/state/testing/getters_block.go
Normal file
135
beacon-chain/state/testing/getters_block.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
type getStateWithLatestBlockHeader func(*ethpb.BeaconBlockHeader) (state.BeaconState, error)
|
||||
|
||||
func VerifyBeaconStateLatestBlockHeader(
|
||||
t *testing.T,
|
||||
factory getState,
|
||||
factoryLBH getStateWithLatestBlockHeader,
|
||||
) {
|
||||
s, err := factory()
|
||||
require.NoError(t, err)
|
||||
got := s.LatestBlockHeader()
|
||||
require.DeepEqual(t, (*ethpb.BeaconBlockHeader)(nil), got)
|
||||
|
||||
want := ðpb.BeaconBlockHeader{Slot: 100}
|
||||
s, err = factoryLBH(want)
|
||||
require.NoError(t, err)
|
||||
got = s.LatestBlockHeader()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got.Slot = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
}
|
||||
|
||||
type getStateWithLBlockRoots func([][]byte) (state.BeaconState, error)
|
||||
|
||||
func VerifyBeaconStateBlockRoots(
|
||||
t *testing.T,
|
||||
factory getState,
|
||||
factoryBR getStateWithLBlockRoots,
|
||||
) {
|
||||
s, err := factory()
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
require.DeepEqual(t, ([][]byte)(nil), got)
|
||||
|
||||
want := [][]byte{{'a'}}
|
||||
s, err = factoryBR(want)
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
}
|
||||
|
||||
func VerifyBeaconStateBlockRootsNative(
|
||||
t *testing.T,
|
||||
factory getState,
|
||||
factoryBR getStateWithLBlockRoots,
|
||||
) {
|
||||
s, err := factory()
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
want := make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
want[i] = make([]byte, 32)
|
||||
}
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
want = make([][]byte, fieldparams.BlockRootsLength)
|
||||
for i := range want {
|
||||
if i == 0 {
|
||||
want[i] = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
} else {
|
||||
want[i] = make([]byte, 32)
|
||||
}
|
||||
|
||||
}
|
||||
s, err = factoryBR(want)
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
}
|
||||
|
||||
func VerifyBeaconStateBlockRootAtIndex(
|
||||
t *testing.T,
|
||||
factory getState,
|
||||
factoryBR getStateWithLBlockRoots,
|
||||
) {
|
||||
s, err := factory()
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, ([]byte)(nil), got)
|
||||
|
||||
r := [][]byte{{'a'}}
|
||||
s, err = factoryBR(r)
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
}
|
||||
|
||||
func VerifyBeaconStateBlockRootAtIndexNative(
|
||||
t *testing.T,
|
||||
factory getState,
|
||||
factoryBR getStateWithLBlockRoots,
|
||||
) {
|
||||
s, err := factory()
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, bytesutil.PadTo([]byte{}, 32), got)
|
||||
|
||||
r := [fieldparams.BlockRootsLength][32]byte{{'a'}}
|
||||
bRoots := make([][]byte, len(r))
|
||||
for i, root := range r {
|
||||
tmp := root
|
||||
bRoots[i] = tmp[:]
|
||||
}
|
||||
s, err = factoryBR(bRoots)
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, 32)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
type getState func() (state.BeaconState, error)
|
||||
|
||||
func VerifyBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T, factory getState) {
|
||||
func VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t *testing.T, factory getState) {
|
||||
st, err := factory()
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -3,57 +3,43 @@ package v1
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_LatestBlockHeader(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
got := s.LatestBlockHeader()
|
||||
require.DeepEqual(t, (*ethpb.BeaconBlockHeader)(nil), got)
|
||||
|
||||
want := ðpb.BeaconBlockHeader{Slot: 100}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{LatestBlockHeader: want})
|
||||
require.NoError(t, err)
|
||||
got = s.LatestBlockHeader()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got.Slot = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateLatestBlockHeader(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
},
|
||||
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{LatestBlockHeader: BH})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRoots(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
require.DeepEqual(t, ([][]byte)(nil), got)
|
||||
|
||||
want := [][]byte{{'a'}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{BlockRoots: want})
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRoots(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRootAtIndex(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, ([]byte)(nil), got)
|
||||
|
||||
r := [][]byte{{'a'}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{BlockRoots: r})
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, 32)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootAtIndex(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_SlotDataRace(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_SlotDataRace(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{Slot: 1})
|
||||
})
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func TestNilState_NoPanic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchCurrentJustifiedCheckpt(
|
||||
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckpt(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{CurrentJustifiedCheckpoint: cp})
|
||||
@@ -82,7 +82,7 @@ func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchPreviousJustifiedCheckpt(
|
||||
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckpt(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{PreviousJustifiedCheckpoint: cp})
|
||||
@@ -98,7 +98,7 @@ func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MarshalSSZ_NilState(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MarshalSSZ_NilState(
|
||||
testtmpl.VerifyBeaconStateMarshalSSZNilState(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
@@ -114,7 +114,7 @@ func TestBeaconState_MarshalSSZ_NilState(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
return v1.InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
Validators: nil,
|
||||
})
|
||||
|
||||
@@ -68,6 +68,7 @@ go_test(
|
||||
"getters_test.go",
|
||||
"getters_validator_test.go",
|
||||
"proofs_test.go",
|
||||
"references_test.go",
|
||||
"setters_test.go",
|
||||
"state_trie_test.go",
|
||||
],
|
||||
|
||||
@@ -7,6 +7,13 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_PreviousEpochAttestations(t *testing.T) {
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
_, err = s.PreviousEpochAttestations()
|
||||
require.ErrorContains(t, "PreviousEpochAttestations is not supported for hard fork 1 beacon state", err)
|
||||
}
|
||||
|
||||
func TestBeaconState_CurrentEpochAttestations(t *testing.T) {
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
@@ -14,9 +21,9 @@ func TestBeaconState_CurrentEpochAttestations(t *testing.T) {
|
||||
require.ErrorContains(t, "CurrentEpochAttestations is not supported for hard fork 1 beacon state", err)
|
||||
}
|
||||
|
||||
func TestBeaconState_PreviousEpochAttestations(t *testing.T) {
|
||||
func TestBeaconState_LatestExecutionPayloadHeader(t *testing.T) {
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
_, err = s.PreviousEpochAttestations()
|
||||
require.ErrorContains(t, "PreviousEpochAttestations is not supported for hard fork 1 beacon state", err)
|
||||
_, err = s.LatestExecutionPayloadHeader()
|
||||
require.ErrorContains(t, "LatestExecutionPayloadHeader is not supported for hard fork 1 beacon state", err)
|
||||
}
|
||||
|
||||
@@ -3,58 +3,43 @@ package v2
|
||||
import (
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_LatestBlockHeader(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
got := s.LatestBlockHeader()
|
||||
require.DeepEqual(t, (*ethpb.BeaconBlockHeader)(nil), got)
|
||||
|
||||
want := ðpb.BeaconBlockHeader{Slot: 100}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateAltair{LatestBlockHeader: want})
|
||||
require.NoError(t, err)
|
||||
got = s.LatestBlockHeader()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got.Slot = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateLatestBlockHeader(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
},
|
||||
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{LatestBlockHeader: BH})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRoots(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
require.DeepEqual(t, ([][]byte)(nil), got)
|
||||
|
||||
want := [][]byte{{'a'}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: want})
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRoots(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRootAtIndex(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, ([]byte)(nil), got)
|
||||
|
||||
r := [][]byte{{'a'}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: r})
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootAtIndex(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_SlotDataRace(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_SlotDataRace(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{Slot: 1})
|
||||
})
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func TestNilState_NoPanic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchCurrentJustifiedCheckpt(
|
||||
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckpt(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{CurrentJustifiedCheckpoint: cp})
|
||||
@@ -91,7 +91,7 @@ func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchPreviousJustifiedCheckpt(
|
||||
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckpt(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{PreviousJustifiedCheckpoint: cp})
|
||||
@@ -107,7 +107,7 @@ func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MarshalSSZ_NilState(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MarshalSSZ_NilState(
|
||||
testtmpl.VerifyBeaconStateMarshalSSZNilState(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
@@ -123,7 +123,7 @@ func TestBeaconState_MarshalSSZ_NilState(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateAltair{})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
return v2.InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
Validators: nil,
|
||||
})
|
||||
|
||||
234
beacon-chain/state/v2/references_test.go
Normal file
234
beacon-chain/state/v2/references_test.go
Normal file
@@ -0,0 +1,234 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestStateReferenceSharing_Finalizer(t *testing.T) {
|
||||
// This test showcases the logic on a the RandaoMixes field with the GC finalizer.
|
||||
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{RandaoMixes: [][]byte{[]byte("foo")}})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(1), a.sharedFieldReferences[randaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
|
||||
|
||||
func() {
|
||||
// Create object in a different scope for GC
|
||||
b := a.Copy()
|
||||
assert.Equal(t, uint(2), a.sharedFieldReferences[randaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
|
||||
_ = b
|
||||
}()
|
||||
|
||||
runtime.GC() // Should run finalizer on object b
|
||||
assert.Equal(t, uint(1), a.sharedFieldReferences[randaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
|
||||
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(2), b.sharedFieldReferences[randaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
|
||||
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
|
||||
if b.sharedFieldReferences[randaoMixes].Refs() != 1 || a.sharedFieldReferences[randaoMixes].Refs() != 1 {
|
||||
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateReferenceCopy_NoUnexpectedRootsMutation(t *testing.T) {
|
||||
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
BlockRoots: [][]byte{
|
||||
root1[:],
|
||||
},
|
||||
StateRoots: [][]byte{
|
||||
root1[:],
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, err)
|
||||
assertRefCount(t, a, blockRoots, 1)
|
||||
assertRefCount(t, a, stateRoots, 1)
|
||||
|
||||
// Copy, increases reference count.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, a, blockRoots, 2)
|
||||
assertRefCount(t, a, stateRoots, 2)
|
||||
assertRefCount(t, b, blockRoots, 2)
|
||||
assertRefCount(t, b, stateRoots, 2)
|
||||
assert.Equal(t, 1, len(b.state.GetBlockRoots()), "No block roots found")
|
||||
assert.Equal(t, 1, len(b.state.GetStateRoots()), "No state roots found")
|
||||
|
||||
// Assert shared state.
|
||||
blockRootsA := a.state.GetBlockRoots()
|
||||
stateRootsA := a.state.GetStateRoots()
|
||||
blockRootsB := b.state.GetBlockRoots()
|
||||
stateRootsB := b.state.GetStateRoots()
|
||||
if len(blockRootsA) != len(blockRootsB) || len(blockRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of block roots, want: %v", 1)
|
||||
}
|
||||
if len(stateRootsA) != len(stateRootsB) || len(stateRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of state roots, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, blockRootsA, root1[:])
|
||||
assertValFound(t, blockRootsB, root1[:])
|
||||
assertValFound(t, stateRootsA, root1[:])
|
||||
assertValFound(t, stateRootsB, root1[:])
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
|
||||
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertValNotFound(t, a.state.GetBlockRoots(), root1[:])
|
||||
assertValNotFound(t, a.state.GetStateRoots(), root1[:])
|
||||
assertValFound(t, a.state.GetBlockRoots(), root2[:])
|
||||
assertValFound(t, a.state.GetStateRoots(), root2[:])
|
||||
assertValFound(t, b.state.GetBlockRoots(), root1[:])
|
||||
assertValFound(t, b.state.GetStateRoots(), root1[:])
|
||||
if len(blockRootsA) != len(blockRootsB) || len(blockRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of block roots, want: %v", 1)
|
||||
}
|
||||
if len(stateRootsA) != len(stateRootsB) || len(stateRootsA) < 1 {
|
||||
t.Errorf("Unexpected number of state roots, want: %v", 1)
|
||||
}
|
||||
assert.DeepEqual(t, root2[:], a.state.GetBlockRoots()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, root2[:], a.state.GetStateRoots()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
|
||||
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
|
||||
|
||||
// Copy on write happened, reference counters are reset.
|
||||
assertRefCount(t, a, blockRoots, 1)
|
||||
assertRefCount(t, a, stateRoots, 1)
|
||||
assertRefCount(t, b, blockRoots, 1)
|
||||
assertRefCount(t, b, stateRoots, 1)
|
||||
}
|
||||
|
||||
func TestStateReferenceCopy_NoUnexpectedRandaoMutation(t *testing.T) {
|
||||
|
||||
val1, val2 := []byte("foo"), []byte("bar")
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
RandaoMixes: [][]byte{
|
||||
val1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, err)
|
||||
assertRefCount(t, a, randaoMixes, 1)
|
||||
|
||||
// Copy, increases reference count.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, a, randaoMixes, 2)
|
||||
assertRefCount(t, b, randaoMixes, 2)
|
||||
assert.Equal(t, 1, len(b.state.GetRandaoMixes()), "No randao mixes found")
|
||||
|
||||
// Assert shared state.
|
||||
mixesA := a.state.GetRandaoMixes()
|
||||
mixesB := b.state.GetRandaoMixes()
|
||||
if len(mixesA) != len(mixesB) || len(mixesA) < 1 {
|
||||
t.Errorf("Unexpected number of mix values, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, mixesA, val1)
|
||||
assertValFound(t, mixesB, val1)
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
|
||||
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
if len(mixesA) != len(mixesB) || len(mixesA) < 1 {
|
||||
t.Errorf("Unexpected number of mix values, want: %v", 1)
|
||||
}
|
||||
assertValFound(t, a.state.GetRandaoMixes(), val2)
|
||||
assertValNotFound(t, a.state.GetRandaoMixes(), val1)
|
||||
assertValFound(t, b.state.GetRandaoMixes(), val1)
|
||||
assertValNotFound(t, b.state.GetRandaoMixes(), val2)
|
||||
assertValFound(t, mixesB, val1)
|
||||
assertValNotFound(t, mixesB, val2)
|
||||
assert.DeepEqual(t, val2, a.state.GetRandaoMixes()[0], "Expected mutation not found")
|
||||
assert.DeepEqual(t, val1, mixesB[0], "Unexpected mutation found")
|
||||
|
||||
// Copy on write happened, reference counters are reset.
|
||||
assertRefCount(t, a, randaoMixes, 1)
|
||||
assertRefCount(t, b, randaoMixes, 1)
|
||||
}
|
||||
|
||||
func TestValidatorReferences_RemainsConsistent(t *testing.T) {
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
Validators: []*ethpb.Validator{
|
||||
{PublicKey: []byte{'A'}},
|
||||
{PublicKey: []byte{'B'}},
|
||||
{PublicKey: []byte{'C'}},
|
||||
{PublicKey: []byte{'D'}},
|
||||
{PublicKey: []byte{'E'}},
|
||||
},
|
||||
})
|
||||
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)
|
||||
|
||||
// Update First Validator.
|
||||
assert.NoError(t, a.UpdateValidatorAtIndex(0, ðpb.Validator{PublicKey: []byte{'Z'}}))
|
||||
|
||||
assert.DeepNotEqual(t, a.state.Validators[0], b.state.Validators[0], "validators are equal when they are supposed to be different")
|
||||
// Modify all validators from copied state.
|
||||
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
|
||||
return true, ðpb.Validator{PublicKey: []byte{'V'}}, nil
|
||||
}))
|
||||
|
||||
// Ensure reference is properly accounted for.
|
||||
assert.NoError(t, a.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
|
||||
assert.NotEqual(t, bytesutil.ToBytes48([]byte{'V'}), val.PublicKey())
|
||||
return 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) {
|
||||
if cnt := b.sharedFieldReferences[idx].Refs(); cnt != want {
|
||||
t.Errorf("Unexpected count of references for index %d, want: %v, got: %v", idx, want, cnt)
|
||||
}
|
||||
}
|
||||
|
||||
// assertValFound checks whether item with a given value exists in list.
|
||||
func assertValFound(t *testing.T, vals [][]byte, val []byte) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i], val) {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Fatalf("Expected value not found (%v), want: %v", vals, val)
|
||||
}
|
||||
|
||||
// assertValNotFound checks whether item with a given value doesn't exist in list.
|
||||
func assertValNotFound(t *testing.T, vals [][]byte, val []byte) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i], val) {
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Errorf("Unexpected value found (%v),: %v", vals, val)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,6 +69,7 @@ go_test(
|
||||
"getters_test.go",
|
||||
"getters_validator_test.go",
|
||||
"proofs_test.go",
|
||||
"references_test.go",
|
||||
"setters_test.go",
|
||||
"state_trie_test.go",
|
||||
],
|
||||
|
||||
@@ -3,57 +3,43 @@ package v3
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_LatestBlockHeader(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
got := s.LatestBlockHeader()
|
||||
require.DeepEqual(t, (*ethpb.BeaconBlockHeader)(nil), got)
|
||||
|
||||
want := ðpb.BeaconBlockHeader{Slot: 100}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateBellatrix{LatestBlockHeader: want})
|
||||
require.NoError(t, err)
|
||||
got = s.LatestBlockHeader()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got.Slot = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateLatestBlockHeader(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
},
|
||||
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{LatestBlockHeader: BH})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRoots(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
got := s.BlockRoots()
|
||||
require.DeepEqual(t, ([][]byte)(nil), got)
|
||||
|
||||
want := [][]byte{{'a'}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: want})
|
||||
require.NoError(t, err)
|
||||
got = s.BlockRoots()
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0][0] = 'b'
|
||||
require.DeepNotEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRoots(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_BlockRootAtIndex(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
got, err := s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, ([]byte)(nil), got)
|
||||
|
||||
r := [][]byte{{'a'}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: r})
|
||||
require.NoError(t, err)
|
||||
got, err = s.BlockRootAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
want := bytesutil.PadTo([]byte{'a'}, 32)
|
||||
require.DeepSSZEqual(t, want, got)
|
||||
testtmpl.VerifyBeaconStateBlockRootAtIndex(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_SlotDataRace(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_SlotDataRace(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{Slot: 1})
|
||||
})
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func TestNilState_NoPanic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchCurrentJustifiedCheckpt(
|
||||
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckpt(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{CurrentJustifiedCheckpoint: cp})
|
||||
@@ -91,7 +91,7 @@ func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MatchPreviousJustifiedCheckpt(
|
||||
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckpt(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{PreviousJustifiedCheckpoint: cp})
|
||||
@@ -107,7 +107,7 @@ func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_MarshalSSZ_NilState(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_MarshalSSZ_NilState(
|
||||
testtmpl.VerifyBeaconStateMarshalSSZNilState(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
@@ -123,7 +123,7 @@ func TestBeaconState_MarshalSSZ_NilState(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconStateBellatrix{})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
testtmpl.VerifyBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
return v3.InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{
|
||||
Validators: nil,
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user