mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 22:07:59 -05:00
Compare commits
21 Commits
e2ez
...
improveDif
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e97651512 | ||
|
|
5cb1cb2e15 | ||
|
|
b3cb2770df | ||
|
|
a12f6ae30a | ||
|
|
cc23b8311a | ||
|
|
cbe54fe3f9 | ||
|
|
1b6adca3ca | ||
|
|
1651649e5a | ||
|
|
56187edb98 | ||
|
|
ecad5bbffc | ||
|
|
407182387b | ||
|
|
ad0b0b503d | ||
|
|
58f4ba758c | ||
|
|
64f64f06bf | ||
|
|
e70055733f | ||
|
|
36e4f49af0 | ||
|
|
d98428dec4 | ||
|
|
00b92e01d3 | ||
|
|
ca5adbf7e4 | ||
|
|
a083b7a0a5 | ||
|
|
dd5995b665 |
13
BUILD.bazel
13
BUILD.bazel
@@ -115,18 +115,19 @@ nogo(
|
||||
"@org_golang_x_tools//go/analysis/passes/assign:go_default_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/inspect:go_default_library",
|
||||
"@org_golang_x_tools//go/analysis/passes/asmdecl:go_default_library",
|
||||
"//tools/analyzers/maligned:go_default_library",
|
||||
"//tools/analyzers/comparesame:go_default_library",
|
||||
"//tools/analyzers/cryptorand:go_default_library",
|
||||
"//tools/analyzers/errcheck:go_default_library",
|
||||
"//tools/analyzers/featureconfig:go_default_library",
|
||||
"//tools/analyzers/comparesame:go_default_library",
|
||||
"//tools/analyzers/shadowpredecl:go_default_library",
|
||||
"//tools/analyzers/nop:go_default_library",
|
||||
"//tools/analyzers/slicedirect:go_default_library",
|
||||
"//tools/analyzers/interfacechecker:go_default_library",
|
||||
"//tools/analyzers/gocognit:go_default_library",
|
||||
"//tools/analyzers/ineffassign:go_default_library",
|
||||
"//tools/analyzers/interfacechecker:go_default_library",
|
||||
"//tools/analyzers/maligned:go_default_library",
|
||||
"//tools/analyzers/nop:go_default_library",
|
||||
"//tools/analyzers/properpermissions:go_default_library",
|
||||
"//tools/analyzers/recursivelock:go_default_library",
|
||||
"//tools/analyzers/shadowpredecl:go_default_library",
|
||||
"//tools/analyzers/slicedirect:go_default_library",
|
||||
"//tools/analyzers/uintcast:go_default_library",
|
||||
] + select({
|
||||
# nogo checks that fail with coverage enabled.
|
||||
|
||||
@@ -176,7 +176,7 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe
|
||||
go_rules_dependencies()
|
||||
|
||||
go_register_toolchains(
|
||||
go_version = "1.17.6",
|
||||
go_version = "1.17.9",
|
||||
nogo = "@//:nogo",
|
||||
)
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ go_library(
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//monitoring/tracing:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
|
||||
@@ -273,13 +273,13 @@ func (s *Service) CurrentFork() *ethpb.Fork {
|
||||
|
||||
// IsCanonical returns true if the input block root is part of the canonical chain.
|
||||
func (s *Service) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error) {
|
||||
// If the block has been finalized, the block will always be part of the canonical chain.
|
||||
if s.cfg.BeaconDB.IsFinalizedBlock(ctx, blockRoot) {
|
||||
return true, nil
|
||||
// If the block has not been finalized, check fork choice store to see if the block is canonical
|
||||
if s.cfg.ForkChoiceStore.HasNode(blockRoot) {
|
||||
return s.cfg.ForkChoiceStore.IsCanonical(blockRoot), nil
|
||||
}
|
||||
|
||||
// If the block has not been finalized, check fork choice store to see if the block is canonical
|
||||
return s.cfg.ForkChoiceStore.IsCanonical(blockRoot), nil
|
||||
// If the block has been finalized, the block will always be part of the canonical chain.
|
||||
return s.cfg.BeaconDB.IsFinalizedBlock(ctx, blockRoot), nil
|
||||
}
|
||||
|
||||
// ChainHeads returns all possible chain heads (leaves of fork choice tree).
|
||||
|
||||
@@ -138,6 +138,26 @@ var (
|
||||
Name: "state_balance_cache_miss",
|
||||
Help: "Count the number of state balance cache hits.",
|
||||
})
|
||||
newPayloadValidNodeCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "new_payload_valid_node_count",
|
||||
Help: "Count the number of valid nodes after newPayload EE call",
|
||||
})
|
||||
newPayloadOptimisticNodeCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "new_payload_optimistic_node_count",
|
||||
Help: "Count the number of optimistic nodes after newPayload EE call",
|
||||
})
|
||||
newPayloadInvalidNodeCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "new_payload_invalid_node_count",
|
||||
Help: "Count the number of invalid nodes after newPayload EE call",
|
||||
})
|
||||
forkchoiceUpdatedValidNodeCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "forkchoice_updated_valid_node_count",
|
||||
Help: "Count the number of valid nodes after forkchoiceUpdated EE call",
|
||||
})
|
||||
forkchoiceUpdatedOptimisticNodeCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "forkchoice_updated_optimistic_node_count",
|
||||
Help: "Count the number of optimistic nodes after forkchoiceUpdated EE call",
|
||||
})
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
|
||||
@@ -83,16 +83,18 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, headState state.Be
|
||||
if err != nil {
|
||||
switch err {
|
||||
case powchain.ErrAcceptedSyncingPayloadStatus:
|
||||
forkchoiceUpdatedOptimisticNodeCount.Inc()
|
||||
log.WithFields(logrus.Fields{
|
||||
"headSlot": headBlk.Slot(),
|
||||
"headHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash)),
|
||||
"finalizedHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash)),
|
||||
"headSlot": headBlk.Slot(),
|
||||
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash)),
|
||||
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash)),
|
||||
}).Info("Called fork choice updated with optimistic block")
|
||||
return payloadID, nil
|
||||
default:
|
||||
return nil, errors.Wrap(err, "could not notify forkchoice update from execution engine")
|
||||
}
|
||||
}
|
||||
forkchoiceUpdatedValidNodeCount.Inc()
|
||||
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, headRoot); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set block to valid")
|
||||
}
|
||||
@@ -135,12 +137,14 @@ func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion, postSta
|
||||
if err != nil {
|
||||
switch err {
|
||||
case powchain.ErrAcceptedSyncingPayloadStatus:
|
||||
newPayloadOptimisticNodeCount.Inc()
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": blk.Block().Slot(),
|
||||
"blockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash)),
|
||||
"slot": blk.Block().Slot(),
|
||||
"payloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash)),
|
||||
}).Info("Called new payload with optimistic block")
|
||||
return false, nil
|
||||
case powchain.ErrInvalidPayloadStatus:
|
||||
newPayloadInvalidNodeCount.Inc()
|
||||
root, err := blk.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -157,7 +161,7 @@ func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion, postSta
|
||||
return false, errors.Wrap(err, "could not validate execution payload from execution engine")
|
||||
}
|
||||
}
|
||||
|
||||
newPayloadValidNodeCount.Inc()
|
||||
// During the transition event, the transition block should be verified for sanity.
|
||||
if blocks.IsPreBellatrixVersion(preStateVersion) {
|
||||
// Handle case where pre-state is Altair but block contains payload.
|
||||
|
||||
@@ -127,8 +127,8 @@ func (s *Service) onBlock(ctx context.Context, signed block.SignedBeaconBlock, b
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.savePostStateInfo(ctx, blockRoot, signed, postState, false /* reg sync */); err != nil {
|
||||
return err
|
||||
if err := s.insertBlockAndAttestationsToForkChoiceStore(ctx, signed.Block(), blockRoot, postState); err != nil {
|
||||
return errors.Wrapf(err, "could not insert block %d to fork choice store", signed.Block().Slot())
|
||||
}
|
||||
if isValidPayload {
|
||||
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, blockRoot); err != nil {
|
||||
@@ -148,6 +148,9 @@ func (s *Service) onBlock(ctx context.Context, signed block.SignedBeaconBlock, b
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.savePostStateInfo(ctx, blockRoot, signed, postState, false /* reg sync */); err != nil {
|
||||
return err
|
||||
}
|
||||
// If slasher is configured, forward the attestations in the block via
|
||||
// an event feed for processing.
|
||||
if features.Get().EnableSlasher {
|
||||
@@ -609,9 +612,6 @@ func (s *Service) savePostStateInfo(ctx context.Context, r [32]byte, b block.Sig
|
||||
if err := s.cfg.StateGen.SaveState(ctx, r, st); err != nil {
|
||||
return errors.Wrap(err, "could not save state")
|
||||
}
|
||||
if err := s.insertBlockAndAttestationsToForkChoiceStore(ctx, b.Block(), r, st); err != nil {
|
||||
return errors.Wrapf(err, "could not insert block %d to fork choice store", b.Block().Slot())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
mathutil "github.com/prysmaticlabs/prysm/math"
|
||||
"github.com/prysmaticlabs/prysm/monitoring/tracing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
@@ -402,10 +403,13 @@ func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) e
|
||||
// We update the cache up to the last deposit index in the finalized block's state.
|
||||
// We can be confident that these deposits will be included in some block
|
||||
// because the Eth1 follow distance makes such long-range reorgs extremely unlikely.
|
||||
eth1DepositIndex := int64(finalizedState.Eth1Data().DepositCount - 1)
|
||||
s.cfg.DepositCache.InsertFinalizedDeposits(ctx, eth1DepositIndex)
|
||||
eth1DepositIndex, err := mathutil.Int(finalizedState.Eth1DepositIndex())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not cast eth1 deposit index")
|
||||
}
|
||||
s.cfg.DepositCache.InsertFinalizedDeposits(ctx, int64(eth1DepositIndex))
|
||||
// Deposit proofs are only used during state transition and can be safely removed to save space.
|
||||
if err = s.cfg.DepositCache.PruneProofs(ctx, eth1DepositIndex); err != nil {
|
||||
if err = s.cfg.DepositCache.PruneProofs(ctx, int64(eth1DepositIndex)); err != nil {
|
||||
return errors.Wrap(err, "could not prune deposit proofs")
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -1516,6 +1516,7 @@ func TestInsertFinalizedDeposits(t *testing.T) {
|
||||
service.store.SetFinalizedCheckpt(ðpb.Checkpoint{Root: gRoot[:]})
|
||||
gs = gs.Copy()
|
||||
assert.NoError(t, gs.SetEth1Data(ðpb.Eth1Data{DepositCount: 10}))
|
||||
assert.NoError(t, gs.SetEth1DepositIndex(7))
|
||||
assert.NoError(t, service.cfg.StateGen.SaveState(ctx, [32]byte{'m', 'o', 'c', 'k'}, gs))
|
||||
zeroSig := [96]byte{}
|
||||
for i := uint64(0); i < uint64(4*params.BeaconConfig().SlotsPerEpoch); i++ {
|
||||
@@ -1529,8 +1530,64 @@ func TestInsertFinalizedDeposits(t *testing.T) {
|
||||
}
|
||||
assert.NoError(t, service.insertFinalizedDeposits(ctx, [32]byte{'m', 'o', 'c', 'k'}))
|
||||
fDeposits := depositCache.FinalizedDeposits(ctx)
|
||||
assert.Equal(t, 9, int(fDeposits.MerkleTrieIndex), "Finalized deposits not inserted correctly")
|
||||
deps := depositCache.AllDeposits(ctx, big.NewInt(109))
|
||||
assert.Equal(t, 7, int(fDeposits.MerkleTrieIndex), "Finalized deposits not inserted correctly")
|
||||
deps := depositCache.AllDeposits(ctx, big.NewInt(107))
|
||||
for _, d := range deps {
|
||||
assert.DeepEqual(t, [][]byte(nil), d.Proof, "Proofs are not empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertFinalizedDeposits_MultipleFinalizedRoutines(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
opts := testServiceOptsWithDB(t)
|
||||
depositCache, err := depositcache.New()
|
||||
require.NoError(t, err)
|
||||
opts = append(opts, WithDepositCache(depositCache))
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
gs, _ := util.DeterministicGenesisState(t, 32)
|
||||
require.NoError(t, service.saveGenesisData(ctx, gs))
|
||||
gBlk, err := service.cfg.BeaconDB.GenesisBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
gRoot, err := gBlk.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
service.store.SetFinalizedCheckpt(ðpb.Checkpoint{Root: gRoot[:]})
|
||||
gs = gs.Copy()
|
||||
assert.NoError(t, gs.SetEth1Data(ðpb.Eth1Data{DepositCount: 7}))
|
||||
assert.NoError(t, gs.SetEth1DepositIndex(5))
|
||||
assert.NoError(t, service.cfg.StateGen.SaveState(ctx, [32]byte{'m', 'o', 'c', 'k'}, gs))
|
||||
gs2 := gs.Copy()
|
||||
assert.NoError(t, gs2.SetEth1Data(ðpb.Eth1Data{DepositCount: 15}))
|
||||
assert.NoError(t, gs2.SetEth1DepositIndex(12))
|
||||
assert.NoError(t, service.cfg.StateGen.SaveState(ctx, [32]byte{'m', 'o', 'c', 'k', '2'}, gs2))
|
||||
zeroSig := [96]byte{}
|
||||
for i := uint64(0); i < uint64(4*params.BeaconConfig().SlotsPerEpoch); i++ {
|
||||
root := []byte(strconv.Itoa(int(i)))
|
||||
assert.NoError(t, depositCache.InsertDeposit(ctx, ðpb.Deposit{Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.FromBytes48([fieldparams.BLSPubkeyLength]byte{}),
|
||||
WithdrawalCredentials: params.BeaconConfig().ZeroHash[:],
|
||||
Amount: 0,
|
||||
Signature: zeroSig[:],
|
||||
}, Proof: [][]byte{root}}, 100+i, int64(i), bytesutil.ToBytes32(root)))
|
||||
}
|
||||
// Insert 3 deposits before hand.
|
||||
depositCache.InsertFinalizedDeposits(ctx, 2)
|
||||
|
||||
assert.NoError(t, service.insertFinalizedDeposits(ctx, [32]byte{'m', 'o', 'c', 'k'}))
|
||||
fDeposits := depositCache.FinalizedDeposits(ctx)
|
||||
assert.Equal(t, 5, int(fDeposits.MerkleTrieIndex), "Finalized deposits not inserted correctly")
|
||||
|
||||
deps := depositCache.AllDeposits(ctx, big.NewInt(105))
|
||||
for _, d := range deps {
|
||||
assert.DeepEqual(t, [][]byte(nil), d.Proof, "Proofs are not empty")
|
||||
}
|
||||
|
||||
// Insert New Finalized State with higher deposit count.
|
||||
assert.NoError(t, service.insertFinalizedDeposits(ctx, [32]byte{'m', 'o', 'c', 'k', '2'}))
|
||||
fDeposits = depositCache.FinalizedDeposits(ctx)
|
||||
assert.Equal(t, 12, int(fDeposits.MerkleTrieIndex), "Finalized deposits not inserted correctly")
|
||||
deps = depositCache.AllDeposits(ctx, big.NewInt(112))
|
||||
for _, d := range deps {
|
||||
assert.DeepEqual(t, [][]byte(nil), d.Proof, "Proofs are not empty")
|
||||
}
|
||||
|
||||
@@ -83,7 +83,8 @@ func (s *Service) VerifyLmdFfgConsistency(ctx context.Context, a *ethpb.Attestat
|
||||
func (s *Service) VerifyFinalizedConsistency(ctx context.Context, root []byte) error {
|
||||
// A canonical root implies the root to has an ancestor that aligns with finalized check point.
|
||||
// In this case, we could exit early to save on additional computation.
|
||||
if s.cfg.ForkChoiceStore.IsCanonical(bytesutil.ToBytes32(root)) {
|
||||
blockRoot := bytesutil.ToBytes32(root)
|
||||
if s.cfg.ForkChoiceStore.HasNode(blockRoot) && s.cfg.ForkChoiceStore.IsCanonical(blockRoot) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ type DepositFetcher interface {
|
||||
DepositByPubkey(ctx context.Context, pubKey []byte) (*ethpb.Deposit, *big.Int)
|
||||
DepositsNumberAndRootAtHeight(ctx context.Context, blockHeight *big.Int) (uint64, [32]byte)
|
||||
FinalizedDeposits(ctx context.Context) *FinalizedDeposits
|
||||
NonFinalizedDeposits(ctx context.Context, untilBlk *big.Int) []*ethpb.Deposit
|
||||
NonFinalizedDeposits(ctx context.Context, lastFinalizedIndex int64, untilBlk *big.Int) []*ethpb.Deposit
|
||||
}
|
||||
|
||||
// FinalizedDeposits stores the trie of deposits that have been included
|
||||
@@ -137,6 +137,22 @@ func (dc *DepositCache) InsertFinalizedDeposits(ctx context.Context, eth1Deposit
|
||||
|
||||
depositTrie := dc.finalizedDeposits.Deposits
|
||||
insertIndex := int(dc.finalizedDeposits.MerkleTrieIndex + 1)
|
||||
|
||||
// Don't insert into finalized trie if there is no deposit to
|
||||
// insert.
|
||||
if len(dc.deposits) == 0 {
|
||||
return
|
||||
}
|
||||
// In the event we have less deposits than we need to
|
||||
// finalize we finalize till the index on which we do have it.
|
||||
if len(dc.deposits) <= int(eth1DepositIndex) {
|
||||
eth1DepositIndex = int64(len(dc.deposits)) - 1
|
||||
}
|
||||
// If we finalize to some lower deposit index, we
|
||||
// ignore it.
|
||||
if int(eth1DepositIndex) < insertIndex {
|
||||
return
|
||||
}
|
||||
for _, d := range dc.deposits {
|
||||
if d.Index <= dc.finalizedDeposits.MerkleTrieIndex {
|
||||
continue
|
||||
@@ -246,7 +262,7 @@ func (dc *DepositCache) FinalizedDeposits(ctx context.Context) *FinalizedDeposit
|
||||
|
||||
// NonFinalizedDeposits returns the list of non-finalized deposits until the given block number (inclusive).
|
||||
// If no block is specified then this method returns all non-finalized deposits.
|
||||
func (dc *DepositCache) NonFinalizedDeposits(ctx context.Context, untilBlk *big.Int) []*ethpb.Deposit {
|
||||
func (dc *DepositCache) NonFinalizedDeposits(ctx context.Context, lastFinalizedIndex int64, untilBlk *big.Int) []*ethpb.Deposit {
|
||||
ctx, span := trace.StartSpan(ctx, "DepositsCache.NonFinalizedDeposits")
|
||||
defer span.End()
|
||||
dc.depositsLock.RLock()
|
||||
@@ -256,10 +272,9 @@ func (dc *DepositCache) NonFinalizedDeposits(ctx context.Context, untilBlk *big.
|
||||
return dc.allDeposits(untilBlk)
|
||||
}
|
||||
|
||||
lastFinalizedDepositIndex := dc.finalizedDeposits.MerkleTrieIndex
|
||||
var deposits []*ethpb.Deposit
|
||||
for _, d := range dc.deposits {
|
||||
if (d.Index > lastFinalizedDepositIndex) && (untilBlk == nil || untilBlk.Uint64() >= d.Eth1BlockHeight) {
|
||||
if (d.Index > lastFinalizedIndex) && (untilBlk == nil || untilBlk.Uint64() >= d.Eth1BlockHeight) {
|
||||
deposits = append(deposits, d.Deposit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
Index: 1,
|
||||
},
|
||||
}
|
||||
newFinalizedDeposit := ethpb.DepositContainer{
|
||||
newFinalizedDeposit := ðpb.DepositContainer{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
@@ -471,17 +471,17 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
}
|
||||
dc.deposits = oldFinalizedDeposits
|
||||
dc.InsertFinalizedDeposits(context.Background(), 1)
|
||||
// Artificially exclude old deposits so that they can only be retrieved from previously finalized deposits.
|
||||
dc.deposits = []*ethpb.DepositContainer{&newFinalizedDeposit}
|
||||
|
||||
dc.InsertFinalizedDeposits(context.Background(), 2)
|
||||
|
||||
dc.deposits = append(dc.deposits, []*ethpb.DepositContainer{newFinalizedDeposit}...)
|
||||
|
||||
cachedDeposits := dc.FinalizedDeposits(context.Background())
|
||||
require.NotNil(t, cachedDeposits, "Deposits not cached")
|
||||
assert.Equal(t, int64(2), cachedDeposits.MerkleTrieIndex)
|
||||
assert.Equal(t, int64(1), cachedDeposits.MerkleTrieIndex)
|
||||
|
||||
var deps [][]byte
|
||||
for _, d := range append(oldFinalizedDeposits, &newFinalizedDeposit) {
|
||||
for _, d := range oldFinalizedDeposits {
|
||||
hash, err := d.Deposit.Data.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not hash deposit data")
|
||||
deps = append(deps, hash[:])
|
||||
@@ -491,6 +491,140 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
|
||||
assert.Equal(t, trie.HashTreeRoot(), cachedDeposits.Deposits.HashTreeRoot())
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_HandleZeroDeposits(t *testing.T) {
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
dc.InsertFinalizedDeposits(context.Background(), 2)
|
||||
|
||||
cachedDeposits := dc.FinalizedDeposits(context.Background())
|
||||
require.NotNil(t, cachedDeposits, "Deposits not cached")
|
||||
assert.Equal(t, int64(-1), cachedDeposits.MerkleTrieIndex)
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_HandleSmallerThanExpectedDeposits(t *testing.T) {
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*ethpb.DepositContainer{
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
},
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
},
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
},
|
||||
}
|
||||
dc.deposits = finalizedDeposits
|
||||
|
||||
dc.InsertFinalizedDeposits(context.Background(), 5)
|
||||
|
||||
cachedDeposits := dc.FinalizedDeposits(context.Background())
|
||||
require.NotNil(t, cachedDeposits, "Deposits not cached")
|
||||
assert.Equal(t, int64(2), cachedDeposits.MerkleTrieIndex)
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_HandleLowerEth1DepositIndex(t *testing.T) {
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
|
||||
finalizedDeposits := []*ethpb.DepositContainer{
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{0}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 0,
|
||||
},
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{1}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 1,
|
||||
},
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{2}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 2,
|
||||
},
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{3}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 3,
|
||||
},
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{4}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 4,
|
||||
},
|
||||
{
|
||||
Deposit: ðpb.Deposit{
|
||||
Data: ðpb.Deposit_Data{
|
||||
PublicKey: bytesutil.PadTo([]byte{5}, 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
Signature: make([]byte, 96),
|
||||
},
|
||||
},
|
||||
Index: 5,
|
||||
},
|
||||
}
|
||||
dc.deposits = finalizedDeposits
|
||||
|
||||
dc.InsertFinalizedDeposits(context.Background(), 5)
|
||||
|
||||
// Reinsert finalized deposits with a lower index.
|
||||
dc.InsertFinalizedDeposits(context.Background(), 2)
|
||||
|
||||
cachedDeposits := dc.FinalizedDeposits(context.Background())
|
||||
require.NotNil(t, cachedDeposits, "Deposits not cached")
|
||||
assert.Equal(t, int64(5), cachedDeposits.MerkleTrieIndex)
|
||||
}
|
||||
|
||||
func TestFinalizedDeposits_InitializedCorrectly(t *testing.T) {
|
||||
dc, err := New()
|
||||
require.NoError(t, err)
|
||||
@@ -554,7 +688,7 @@ func TestNonFinalizedDeposits_ReturnsAllNonFinalizedDeposits(t *testing.T) {
|
||||
})
|
||||
dc.InsertFinalizedDeposits(context.Background(), 1)
|
||||
|
||||
deps := dc.NonFinalizedDeposits(context.Background(), nil)
|
||||
deps := dc.NonFinalizedDeposits(context.Background(), 1, nil)
|
||||
assert.Equal(t, 2, len(deps))
|
||||
}
|
||||
|
||||
@@ -611,7 +745,7 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
|
||||
})
|
||||
dc.InsertFinalizedDeposits(context.Background(), 1)
|
||||
|
||||
deps := dc.NonFinalizedDeposits(context.Background(), big.NewInt(10))
|
||||
deps := dc.NonFinalizedDeposits(context.Background(), 1, big.NewInt(10))
|
||||
assert.Equal(t, 1, len(deps))
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ func (_ *Service) FinalizedDeposits(_ context.Context) *depositcache.FinalizedDe
|
||||
}
|
||||
|
||||
// NonFinalizedDeposits mocks out the deposit cache functionality for interop.
|
||||
func (_ *Service) NonFinalizedDeposits(_ context.Context, _ *big.Int) []*ethpb.Deposit {
|
||||
func (_ *Service) NonFinalizedDeposits(_ context.Context, _ int64, _ *big.Int) []*ethpb.Deposit {
|
||||
return []*ethpb.Deposit{}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,10 +51,4 @@ var (
|
||||
Help: "The number of times pruning happened.",
|
||||
},
|
||||
)
|
||||
validatedCount = promauto.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "doublylinkedtree_validated_count",
|
||||
Help: "The number of blocks that have been fully validated.",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@@ -120,7 +120,6 @@ func (n *Node) setNodeAndParentValidated(ctx context.Context) error {
|
||||
}
|
||||
|
||||
n.optimistic = false
|
||||
validatedCount.Inc()
|
||||
return n.parent.setNodeAndParentValidated(ctx)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,10 +51,4 @@ var (
|
||||
Help: "The number of times pruning happened.",
|
||||
},
|
||||
)
|
||||
validatedNodesCount = promauto.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "proto_array_validated_nodes_count",
|
||||
Help: "The number of nodes that have been fully validated.",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@@ -43,7 +43,6 @@ func (f *ForkChoice) SetOptimisticToValid(ctx context.Context, root [32]byte) er
|
||||
if index == NonExistentNode {
|
||||
break
|
||||
}
|
||||
validatedNodesCount.Inc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -614,16 +614,22 @@ func (s *Store) prune(ctx context.Context, finalizedRoot [32]byte) error {
|
||||
node := copyNode(s.nodes[idx])
|
||||
parentIdx, ok := canonicalNodesMap[node.parent]
|
||||
if ok {
|
||||
s.nodesIndices[node.root] = uint64(len(canonicalNodes))
|
||||
canonicalNodesMap[idx] = uint64(len(canonicalNodes))
|
||||
currentIndex := uint64(len(canonicalNodes))
|
||||
s.nodesIndices[node.root] = currentIndex
|
||||
s.payloadIndices[node.payloadHash] = currentIndex
|
||||
canonicalNodesMap[idx] = currentIndex
|
||||
node.parent = parentIdx
|
||||
canonicalNodes = append(canonicalNodes, node)
|
||||
} else {
|
||||
// Remove node and synced tip that is not part of finalized branch.
|
||||
// Remove node that is not part of finalized branch.
|
||||
delete(s.nodesIndices, node.root)
|
||||
delete(s.canonicalNodes, node.root)
|
||||
delete(s.payloadIndices, node.payloadHash)
|
||||
}
|
||||
}
|
||||
s.nodesIndices[finalizedRoot] = uint64(0)
|
||||
s.canonicalNodes[finalizedRoot] = true
|
||||
s.payloadIndices[finalizedNode.payloadHash] = uint64(0)
|
||||
|
||||
// Recompute the best child and descendant for each canonical nodes.
|
||||
for _, node := range canonicalNodes {
|
||||
|
||||
@@ -375,7 +375,7 @@ func TestStore_Prune_MoreThanThreshold(t *testing.T) {
|
||||
parent: uint64(numOfNodes - 2),
|
||||
})
|
||||
indices[indexToHash(uint64(numOfNodes-1))] = uint64(numOfNodes - 1)
|
||||
s := &Store{nodes: nodes, nodesIndices: indices}
|
||||
s := &Store{nodes: nodes, nodesIndices: indices, canonicalNodes: map[[32]byte]bool{}, payloadIndices: map[[32]byte]uint64{}}
|
||||
|
||||
// Finalized root is at index 99 so everything before 99 should be pruned.
|
||||
require.NoError(t, s.prune(context.Background(), indexToHash(99)))
|
||||
@@ -413,7 +413,7 @@ func TestStore_Prune_MoreThanOnce(t *testing.T) {
|
||||
parent: uint64(numOfNodes - 2),
|
||||
})
|
||||
|
||||
s := &Store{nodes: nodes, nodesIndices: indices}
|
||||
s := &Store{nodes: nodes, nodesIndices: indices, canonicalNodes: map[[32]byte]bool{}, payloadIndices: map[[32]byte]uint64{}}
|
||||
|
||||
// Finalized root is at index 11 so everything before 11 should be pruned.
|
||||
require.NoError(t, s.prune(context.Background(), indexToHash(10)))
|
||||
@@ -441,6 +441,7 @@ func TestStore_Prune_NoDanglingBranch(t *testing.T) {
|
||||
bestDescendant: 1,
|
||||
root: indexToHash(uint64(0)),
|
||||
parent: NonExistentNode,
|
||||
payloadHash: [32]byte{'A'},
|
||||
},
|
||||
{
|
||||
slot: 101,
|
||||
@@ -448,6 +449,7 @@ func TestStore_Prune_NoDanglingBranch(t *testing.T) {
|
||||
bestChild: NonExistentNode,
|
||||
bestDescendant: NonExistentNode,
|
||||
parent: 0,
|
||||
payloadHash: [32]byte{'B'},
|
||||
},
|
||||
{
|
||||
slot: 101,
|
||||
@@ -455,6 +457,7 @@ func TestStore_Prune_NoDanglingBranch(t *testing.T) {
|
||||
parent: 0,
|
||||
bestChild: NonExistentNode,
|
||||
bestDescendant: NonExistentNode,
|
||||
payloadHash: [32]byte{'C'},
|
||||
},
|
||||
}
|
||||
s := &Store{
|
||||
@@ -465,9 +468,22 @@ func TestStore_Prune_NoDanglingBranch(t *testing.T) {
|
||||
indexToHash(uint64(1)): 1,
|
||||
indexToHash(uint64(2)): 2,
|
||||
},
|
||||
canonicalNodes: map[[32]byte]bool{
|
||||
indexToHash(uint64(0)): true,
|
||||
indexToHash(uint64(1)): true,
|
||||
indexToHash(uint64(2)): true,
|
||||
},
|
||||
payloadIndices: map[[32]byte]uint64{
|
||||
[32]byte{'A'}: 0,
|
||||
[32]byte{'B'}: 1,
|
||||
[32]byte{'C'}: 2,
|
||||
},
|
||||
}
|
||||
require.NoError(t, s.prune(context.Background(), indexToHash(uint64(1))))
|
||||
require.Equal(t, len(s.nodes), 1)
|
||||
require.Equal(t, 1, len(s.nodes))
|
||||
require.Equal(t, 1, len(s.nodesIndices))
|
||||
require.Equal(t, 1, len(s.canonicalNodes))
|
||||
require.Equal(t, 1, len(s.payloadIndices))
|
||||
}
|
||||
|
||||
// This test starts with the following branching diagram
|
||||
@@ -482,25 +498,74 @@ func TestStore_Prune_NoDanglingBranch(t *testing.T) {
|
||||
// J -- K -- L
|
||||
//
|
||||
//
|
||||
func TestStore_PruneSyncedTips(t *testing.T) {
|
||||
func TestStore_PruneBranched(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := setup(1, 1)
|
||||
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'j'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'e'}, [32]byte{'d'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'g'}, [32]byte{'d'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'f'}, [32]byte{'e'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'h'}, [32]byte{'g'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'k'}, [32]byte{'g'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'i'}, [32]byte{'h'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'l'}, [32]byte{'k'}, params.BeaconConfig().ZeroHash, 1, 1))
|
||||
f.store.pruneThreshold = 0
|
||||
require.NoError(t, f.Prune(ctx, [32]byte{'f'}))
|
||||
require.Equal(t, 1, f.NodeCount())
|
||||
tests := []struct {
|
||||
finalizedRoot [32]byte
|
||||
wantedCanonical [32]byte
|
||||
wantedNonCanonical [32]byte
|
||||
canonicalCount int
|
||||
payloadHash [32]byte
|
||||
payloadIndex uint64
|
||||
nonExistentPayload [32]byte
|
||||
}{
|
||||
{
|
||||
[32]byte{'f'},
|
||||
[32]byte{'f'},
|
||||
[32]byte{'a'},
|
||||
1,
|
||||
[32]byte{'F'},
|
||||
0,
|
||||
[32]byte{'H'},
|
||||
},
|
||||
{
|
||||
[32]byte{'d'},
|
||||
[32]byte{'e'},
|
||||
[32]byte{'i'},
|
||||
3,
|
||||
[32]byte{'E'},
|
||||
1,
|
||||
[32]byte{'C'},
|
||||
},
|
||||
{
|
||||
[32]byte{'b'},
|
||||
[32]byte{'f'},
|
||||
[32]byte{'h'},
|
||||
5,
|
||||
[32]byte{'D'},
|
||||
3,
|
||||
[32]byte{'A'},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
f := setup(1, 1)
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, [32]byte{'C'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 102, [32]byte{'j'}, [32]byte{'b'}, [32]byte{'J'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, [32]byte{'D'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'e'}, [32]byte{'d'}, [32]byte{'E'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 104, [32]byte{'g'}, [32]byte{'d'}, [32]byte{'G'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'f'}, [32]byte{'e'}, [32]byte{'F'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'h'}, [32]byte{'g'}, [32]byte{'H'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 105, [32]byte{'k'}, [32]byte{'g'}, [32]byte{'K'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'i'}, [32]byte{'h'}, [32]byte{'I'}, 1, 1))
|
||||
require.NoError(t, f.InsertOptimisticBlock(ctx, 106, [32]byte{'l'}, [32]byte{'k'}, [32]byte{'L'}, 1, 1))
|
||||
f.store.pruneThreshold = 0
|
||||
require.NoError(t, f.store.updateCanonicalNodes(ctx, [32]byte{'f'}))
|
||||
require.Equal(t, true, f.IsCanonical([32]byte{'a'}))
|
||||
require.Equal(t, true, f.IsCanonical([32]byte{'f'}))
|
||||
|
||||
require.NoError(t, f.Prune(ctx, tc.finalizedRoot))
|
||||
require.Equal(t, tc.canonicalCount, len(f.store.canonicalNodes))
|
||||
require.Equal(t, true, f.IsCanonical(tc.wantedCanonical))
|
||||
require.Equal(t, false, f.IsCanonical(tc.wantedNonCanonical))
|
||||
require.Equal(t, tc.payloadIndex, f.store.payloadIndices[tc.payloadHash])
|
||||
_, ok := f.store.payloadIndices[tc.nonExistentPayload]
|
||||
require.Equal(t, false, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_LeadsToViableHead(t *testing.T) {
|
||||
|
||||
@@ -3,7 +3,6 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"auth.go",
|
||||
"block_cache.go",
|
||||
"block_reader.go",
|
||||
"check_transition_config.go",
|
||||
@@ -16,6 +15,7 @@ go_library(
|
||||
"options.go",
|
||||
"prometheus.go",
|
||||
"provider.go",
|
||||
"rpc_connection.go",
|
||||
"service.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/powchain",
|
||||
@@ -59,7 +59,6 @@ go_library(
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//ethclient:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_golang_jwt_jwt_v4//:go_default_library",
|
||||
"@com_github_holiman_uint256//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
@@ -74,7 +73,6 @@ go_test(
|
||||
name = "go_default_test",
|
||||
size = "medium",
|
||||
srcs = [
|
||||
"auth_test.go",
|
||||
"block_cache_test.go",
|
||||
"block_reader_test.go",
|
||||
"check_transition_config_test.go",
|
||||
@@ -125,7 +123,6 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//trie:go_default_library",
|
||||
"@com_github_golang_jwt_jwt_v4//:go_default_library",
|
||||
"@com_github_holiman_uint256//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/network"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -81,7 +82,7 @@ func (s *Service) checkTransitionConfiguration(
|
||||
return
|
||||
}
|
||||
case tm := <-ticker.C:
|
||||
ctx, cancel := context.WithDeadline(ctx, tm.Add(DefaultRPCHTTPTimeout))
|
||||
ctx, cancel := context.WithDeadline(ctx, tm.Add(network.DefaultRPCHTTPTimeout))
|
||||
err = s.ExchangeTransitionConfiguration(ctx, cfg)
|
||||
s.handleExchangeConfigurationError(err)
|
||||
if !hasTtdReached {
|
||||
@@ -119,11 +120,16 @@ func (s *Service) handleExchangeConfigurationError(err error) {
|
||||
// Logs the terminal total difficulty status.
|
||||
func (s *Service) logTtdStatus(ctx context.Context, ttd *uint256.Int) (bool, error) {
|
||||
latest, err := s.LatestExecutionBlock(ctx)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, hexutil.ErrEmptyString):
|
||||
return false, nil
|
||||
case err != nil:
|
||||
return false, err
|
||||
}
|
||||
if latest == nil {
|
||||
case latest == nil:
|
||||
return false, errors.New("latest block is nil")
|
||||
case latest.TotalDifficulty == "":
|
||||
return false, nil
|
||||
default:
|
||||
}
|
||||
latestTtd, err := hexutil.DecodeBig(latest.TotalDifficulty)
|
||||
if err != nil {
|
||||
|
||||
@@ -190,6 +190,38 @@ func TestService_logTtdStatus(t *testing.T) {
|
||||
require.Equal(t, false, reached)
|
||||
}
|
||||
|
||||
func TestService_logTtdStatus_NotSyncedClient(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
defer func() {
|
||||
require.NoError(t, r.Body.Close())
|
||||
}()
|
||||
|
||||
resp := (*pb.ExecutionBlock)(nil) // Nil response when a client is not synced
|
||||
respJSON := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": resp,
|
||||
}
|
||||
require.NoError(t, json.NewEncoder(w).Encode(respJSON))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||
require.NoError(t, err)
|
||||
defer rpcClient.Close()
|
||||
|
||||
service := &Service{
|
||||
cfg: &config{},
|
||||
}
|
||||
service.rpcClient = rpcClient
|
||||
|
||||
ttd := new(uint256.Int)
|
||||
reached, err := service.logTtdStatus(context.Background(), ttd.SetUint64(24343))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, reached)
|
||||
}
|
||||
|
||||
func emptyPayload() *pb.ExecutionPayload {
|
||||
return &pb.ExecutionPayload{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
|
||||
@@ -10,9 +10,12 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -49,8 +52,8 @@ type EngineCaller interface {
|
||||
ExchangeTransitionConfiguration(
|
||||
ctx context.Context, cfg *pb.TransitionConfiguration,
|
||||
) error
|
||||
LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock, error)
|
||||
ExecutionBlockByHash(ctx context.Context, hash common.Hash) (*pb.ExecutionBlock, error)
|
||||
GetTerminalBlockHash(ctx context.Context) ([]byte, bool, error)
|
||||
}
|
||||
|
||||
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
||||
@@ -174,6 +177,78 @@ func (s *Service) ExchangeTransitionConfiguration(
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTerminalBlockHash returns the valid terminal block hash based on total difficulty.
|
||||
//
|
||||
// Spec code:
|
||||
// def get_pow_block_at_terminal_total_difficulty(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlock]:
|
||||
// # `pow_chain` abstractly represents all blocks in the PoW chain
|
||||
// for block in pow_chain:
|
||||
// parent = pow_chain[block.parent_hash]
|
||||
// block_reached_ttd = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
|
||||
// parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
|
||||
// if block_reached_ttd and not parent_reached_ttd:
|
||||
// return block
|
||||
//
|
||||
// return None
|
||||
func (s *Service) GetTerminalBlockHash(ctx context.Context) ([]byte, bool, error) {
|
||||
ttd := new(big.Int)
|
||||
ttd.SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
|
||||
terminalTotalDifficulty, overflows := uint256.FromBig(ttd)
|
||||
if overflows {
|
||||
return nil, false, errors.New("could not convert terminal total difficulty to uint256")
|
||||
}
|
||||
blk, err := s.LatestExecutionBlock(ctx)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not get latest execution block")
|
||||
}
|
||||
if blk == nil {
|
||||
return nil, false, errors.New("latest execution block is nil")
|
||||
}
|
||||
|
||||
for {
|
||||
if ctx.Err() != nil {
|
||||
return nil, false, ctx.Err()
|
||||
}
|
||||
currentTotalDifficulty, err := tDStringToUint256(blk.TotalDifficulty)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
||||
}
|
||||
blockReachedTTD := currentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
||||
|
||||
parentHash := bytesutil.ToBytes32(blk.ParentHash)
|
||||
if len(blk.ParentHash) == 0 || parentHash == params.BeaconConfig().ZeroHash {
|
||||
return nil, false, nil
|
||||
}
|
||||
parentBlk, err := s.ExecutionBlockByHash(ctx, parentHash)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not get parent execution block")
|
||||
}
|
||||
if parentBlk == nil {
|
||||
return nil, false, errors.New("parent execution block is nil")
|
||||
}
|
||||
if blockReachedTTD {
|
||||
parentTotalDifficulty, err := tDStringToUint256(parentBlk.TotalDifficulty)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
||||
}
|
||||
parentReachedTTD := parentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
||||
if !parentReachedTTD {
|
||||
log.WithFields(logrus.Fields{
|
||||
"number": blk.Number,
|
||||
"hash": fmt.Sprintf("%#x", bytesutil.Trunc(blk.Hash)),
|
||||
"td": blk.TotalDifficulty,
|
||||
"parentTd": parentBlk.TotalDifficulty,
|
||||
"ttd": terminalTotalDifficulty,
|
||||
}).Info("Retrieved terminal block hash")
|
||||
return blk.Hash, true, nil
|
||||
}
|
||||
} else {
|
||||
return nil, false, nil
|
||||
}
|
||||
blk = parentBlk
|
||||
}
|
||||
}
|
||||
|
||||
// LatestExecutionBlock fetches the latest execution engine block by calling
|
||||
// eth_blockByNumber via JSON-RPC.
|
||||
func (s *Service) LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock, error) {
|
||||
@@ -251,3 +326,15 @@ func isTimeout(e error) bool {
|
||||
t, ok := e.(httpTimeoutError)
|
||||
return ok && t.Timeout()
|
||||
}
|
||||
|
||||
func tDStringToUint256(td string) (*uint256.Int, error) {
|
||||
b, err := hexutil.DecodeBig(td)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i, overflows := uint256.FromBig(b)
|
||||
if overflows {
|
||||
return nil, errors.New("total difficulty overflowed")
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -418,6 +418,155 @@ func TestClient_HTTP(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
paramsTd string
|
||||
currentPowBlock *pb.ExecutionBlock
|
||||
parentPowBlock *pb.ExecutionBlock
|
||||
errLatestExecutionBlk error
|
||||
wantTerminalBlockHash []byte
|
||||
wantExists bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "config td overflows",
|
||||
paramsTd: "1115792089237316195423570985008687907853269984665640564039457584007913129638912",
|
||||
errString: "could not convert terminal total difficulty to uint256",
|
||||
},
|
||||
{
|
||||
name: "could not get latest execution block",
|
||||
paramsTd: "1",
|
||||
errLatestExecutionBlk: errors.New("blah"),
|
||||
errString: "could not get latest execution block",
|
||||
},
|
||||
{
|
||||
name: "nil latest execution block",
|
||||
paramsTd: "1",
|
||||
errString: "latest execution block is nil",
|
||||
},
|
||||
{
|
||||
name: "current execution block invalid TD",
|
||||
paramsTd: "1",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
TotalDifficulty: "1115792089237316195423570985008687907853269984665640564039457584007913129638912",
|
||||
},
|
||||
errString: "could not convert total difficulty to uint256",
|
||||
},
|
||||
{
|
||||
name: "current execution block has zero hash parent",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: params.BeaconConfig().ZeroHash[:],
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "could not get parent block",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: []byte{'b'},
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
errString: "could not get parent execution block",
|
||||
},
|
||||
{
|
||||
name: "parent execution block invalid TD",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: []byte{'b'},
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
parentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'b'},
|
||||
ParentHash: []byte{'c'},
|
||||
TotalDifficulty: "1",
|
||||
},
|
||||
errString: "could not convert total difficulty to uint256",
|
||||
},
|
||||
{
|
||||
name: "happy case",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: []byte{'b'},
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
parentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'b'},
|
||||
ParentHash: []byte{'c'},
|
||||
TotalDifficulty: "0x1",
|
||||
},
|
||||
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) {
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.TerminalTotalDifficulty = tt.paramsTd
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
var m map[[32]byte]*pb.ExecutionBlock
|
||||
if tt.parentPowBlock != nil {
|
||||
m = map[[32]byte]*pb.ExecutionBlock{
|
||||
bytesutil.ToBytes32(tt.parentPowBlock.Hash): tt.parentPowBlock,
|
||||
}
|
||||
}
|
||||
client := mocks.EngineClient{
|
||||
ErrLatestExecBlock: tt.errLatestExecutionBlk,
|
||||
ExecutionBlock: tt.currentPowBlock,
|
||||
BlockByHashMap: m,
|
||||
}
|
||||
b, e, err := client.GetTerminalBlockHash(context.Background())
|
||||
if tt.errString != "" {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, tt.wantExists, e)
|
||||
require.DeepEqual(t, tt.wantTerminalBlockHash, b)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_tDStringToUint256(t *testing.T) {
|
||||
i, err := tDStringToUint256("0x0")
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, uint256.NewInt(0), i)
|
||||
|
||||
i, err = tDStringToUint256("0x10000")
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, uint256.NewInt(65536), i)
|
||||
|
||||
_, err = tDStringToUint256("100")
|
||||
require.ErrorContains(t, "hex string without 0x prefix", err)
|
||||
|
||||
_, err = tDStringToUint256("0xzzzzzz")
|
||||
require.ErrorContains(t, "invalid hex string", err)
|
||||
|
||||
_, err = tDStringToUint256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
||||
require.ErrorContains(t, "hex number > 256 bits", err)
|
||||
}
|
||||
|
||||
func TestExchangeTransitionConfiguration(t *testing.T) {
|
||||
fix := fixtures()
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package powchain
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
@@ -11,11 +8,9 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/network"
|
||||
"github.com/prysmaticlabs/prysm/network/authorization"
|
||||
)
|
||||
|
||||
// DefaultRPCHTTPTimeout for HTTP requests via an RPC connection to an execution node.
|
||||
const DefaultRPCHTTPTimeout = time.Second * 6
|
||||
|
||||
type Option func(s *Service) error
|
||||
|
||||
// WithHttpEndpoints deduplicates and parses http endpoints for the powchain service to use,
|
||||
@@ -38,20 +33,29 @@ func WithHttpEndpoints(endpointStrings []string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithJWTSecret for authenticating the execution node JSON-RPC endpoint.
|
||||
func WithJWTSecret(secret []byte) Option {
|
||||
return func(c *Service) error {
|
||||
// WithHttpEndpointsAndJWTSecret for authenticating the execution node JSON-RPC endpoint.
|
||||
func WithHttpEndpointsAndJWTSecret(endpointStrings []string, secret []byte) Option {
|
||||
return func(s *Service) error {
|
||||
if len(secret) == 0 {
|
||||
return nil
|
||||
}
|
||||
authTransport := &jwtTransport{
|
||||
underlyingTransport: http.DefaultTransport,
|
||||
jwtSecret: secret,
|
||||
stringEndpoints := dedupEndpoints(endpointStrings)
|
||||
endpoints := make([]network.Endpoint, len(stringEndpoints))
|
||||
// Overwrite authorization type for all endpoints to be of a bearer
|
||||
// type.
|
||||
for i, e := range stringEndpoints {
|
||||
hEndpoint := HttpEndpoint(e)
|
||||
hEndpoint.Auth.Method = authorization.Bearer
|
||||
hEndpoint.Auth.Value = string(secret)
|
||||
endpoints[i] = hEndpoint
|
||||
}
|
||||
c.cfg.httpRPCClient = &http.Client{
|
||||
Timeout: DefaultRPCHTTPTimeout,
|
||||
Transport: authTransport,
|
||||
// Select first http endpoint in the provided list.
|
||||
var currEndpoint network.Endpoint
|
||||
if len(endpointStrings) > 0 {
|
||||
currEndpoint = endpoints[0]
|
||||
}
|
||||
s.cfg.httpEndpoints = endpoints
|
||||
s.cfg.currHttpEndpoint = currEndpoint
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
176
beacon-chain/powchain/rpc_connection.go
Normal file
176
beacon-chain/powchain/rpc_connection.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package powchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
gethRPC "github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
contracts "github.com/prysmaticlabs/prysm/contracts/deposit"
|
||||
"github.com/prysmaticlabs/prysm/io/logs"
|
||||
"github.com/prysmaticlabs/prysm/network"
|
||||
"github.com/prysmaticlabs/prysm/network/authorization"
|
||||
)
|
||||
|
||||
func (s *Service) setupExecutionClientConnections(ctx context.Context, currEndpoint network.Endpoint) error {
|
||||
client, err := s.newRPCClientWithAuth(ctx, currEndpoint)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not dial execution node")
|
||||
}
|
||||
// Attach the clients to the service struct.
|
||||
fetcher := ethclient.NewClient(client)
|
||||
s.rpcClient = client
|
||||
s.httpLogger = fetcher
|
||||
s.eth1DataFetcher = fetcher
|
||||
|
||||
depositContractCaller, err := contracts.NewDepositContractCaller(s.cfg.depositContractAddr, fetcher)
|
||||
if err != nil {
|
||||
client.Close()
|
||||
return errors.Wrap(err, "could not initialize deposit contract caller")
|
||||
}
|
||||
s.depositContractCaller = depositContractCaller
|
||||
|
||||
// Ensure we have the correct chain and deposit IDs.
|
||||
if err := ensureCorrectExecutionChain(ctx, fetcher); err != nil {
|
||||
client.Close()
|
||||
return errors.Wrap(err, "could not make initial request to verify execution chain ID")
|
||||
}
|
||||
s.updateConnectedETH1(true)
|
||||
s.runError = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Every N seconds, defined as a backoffPeriod, attempts to re-establish an execution client
|
||||
// connection and if this does not work, we fallback to the next endpoint if defined.
|
||||
func (s *Service) pollConnectionStatus(ctx context.Context) {
|
||||
// Use a custom logger to only log errors
|
||||
logCounter := 0
|
||||
errorLogger := func(err error, msg string) {
|
||||
if logCounter > logThreshold {
|
||||
log.Errorf("%s: %v", msg, err)
|
||||
logCounter = 0
|
||||
}
|
||||
logCounter++
|
||||
}
|
||||
ticker := time.NewTicker(backOffPeriod)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
log.Debugf("Trying to dial endpoint: %s", logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url))
|
||||
if err := s.setupExecutionClientConnections(ctx, s.cfg.currHttpEndpoint); err != nil {
|
||||
errorLogger(err, "Could not connect to execution client endpoint")
|
||||
s.runError = err
|
||||
s.fallbackToNextEndpoint()
|
||||
}
|
||||
case <-s.ctx.Done():
|
||||
log.Debug("Received cancelled context,closing existing powchain service")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Forces to retry an execution client connection.
|
||||
func (s *Service) retryExecutionClientConnection(ctx context.Context, err error) {
|
||||
s.runError = err
|
||||
s.updateConnectedETH1(false)
|
||||
// Back off for a while before redialing.
|
||||
time.Sleep(backOffPeriod)
|
||||
if err := s.setupExecutionClientConnections(ctx, s.cfg.currHttpEndpoint); err != nil {
|
||||
s.runError = err
|
||||
return
|
||||
}
|
||||
// Reset run error in the event of a successful connection.
|
||||
s.runError = nil
|
||||
}
|
||||
|
||||
// This performs a health check on our primary endpoint, and if it
|
||||
// is ready to serve we connect to it again. This method is only
|
||||
// relevant if we are on our backup endpoint.
|
||||
func (s *Service) checkDefaultEndpoint(ctx context.Context) {
|
||||
primaryEndpoint := s.cfg.httpEndpoints[0]
|
||||
// Return early if we are running on our primary
|
||||
// endpoint.
|
||||
if s.cfg.currHttpEndpoint.Equals(primaryEndpoint) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.setupExecutionClientConnections(ctx, primaryEndpoint); err != nil {
|
||||
log.Debugf("Primary endpoint not ready: %v", err)
|
||||
return
|
||||
}
|
||||
s.updateCurrHttpEndpoint(primaryEndpoint)
|
||||
}
|
||||
|
||||
// This is an inefficient way to search for the next endpoint, but given N is
|
||||
// expected to be small, it is fine to search this way.
|
||||
func (s *Service) fallbackToNextEndpoint() {
|
||||
currEndpoint := s.cfg.currHttpEndpoint
|
||||
currIndex := 0
|
||||
totalEndpoints := len(s.cfg.httpEndpoints)
|
||||
|
||||
for i, endpoint := range s.cfg.httpEndpoints {
|
||||
if endpoint.Equals(currEndpoint) {
|
||||
currIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
nextIndex := currIndex + 1
|
||||
if nextIndex >= totalEndpoints {
|
||||
nextIndex = 0
|
||||
}
|
||||
s.updateCurrHttpEndpoint(s.cfg.httpEndpoints[nextIndex])
|
||||
if nextIndex != currIndex {
|
||||
log.Infof("Falling back to alternative endpoint: %s", logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url))
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes an RPC connection with authentication headers.
|
||||
func (s *Service) newRPCClientWithAuth(ctx context.Context, endpoint network.Endpoint) (*gethRPC.Client, error) {
|
||||
// Need to handle ipc and http
|
||||
var client *gethRPC.Client
|
||||
u, err := url.Parse(endpoint.Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "http", "https":
|
||||
client, err = gethRPC.DialHTTPWithClient(endpoint.Url, endpoint.HttpClient())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "":
|
||||
client, err = gethRPC.DialIPC(ctx, endpoint.Url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme)
|
||||
}
|
||||
if endpoint.Auth.Method != authorization.None {
|
||||
header, err := endpoint.Auth.ToHeaderValue()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.SetHeader("Authorization", header)
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Checks the chain ID of the execution client to ensure
|
||||
// it matches local parameters of what Prysm expects.
|
||||
func ensureCorrectExecutionChain(ctx context.Context, client *ethclient.Client) error {
|
||||
cID, err := client.ChainID(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wantChainID := params.BeaconConfig().DepositChainID
|
||||
if cID.Uint64() != wantChainID {
|
||||
return fmt.Errorf("wanted chain ID %d, got %d", wantChainID, cID.Uint64())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
@@ -39,10 +38,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/container/trie"
|
||||
contracts "github.com/prysmaticlabs/prysm/contracts/deposit"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/io/logs"
|
||||
"github.com/prysmaticlabs/prysm/monitoring/clientstats"
|
||||
"github.com/prysmaticlabs/prysm/network"
|
||||
"github.com/prysmaticlabs/prysm/network/authorization"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
prysmTime "github.com/prysmaticlabs/prysm/time"
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
@@ -114,6 +111,7 @@ type Chain interface {
|
||||
// RPCDataFetcher defines a subset of methods conformed to by ETH1.0 RPC clients for
|
||||
// fetching eth1 data from the clients.
|
||||
type RPCDataFetcher interface {
|
||||
Close()
|
||||
HeaderByNumber(ctx context.Context, number *big.Int) (*gethTypes.Header, error)
|
||||
HeaderByHash(ctx context.Context, hash common.Hash) (*gethTypes.Header, error)
|
||||
SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error)
|
||||
@@ -121,6 +119,7 @@ type RPCDataFetcher interface {
|
||||
|
||||
// RPCClient defines the rpc methods required to interact with the eth1 node.
|
||||
type RPCClient interface {
|
||||
Close()
|
||||
BatchCall(b []gethRPC.BatchElem) error
|
||||
CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error
|
||||
}
|
||||
@@ -135,7 +134,6 @@ type config struct {
|
||||
eth1HeaderReqLimit uint64
|
||||
beaconNodeStatsUpdater BeaconNodeStatsUpdater
|
||||
httpEndpoints []network.Endpoint
|
||||
httpRPCClient *http.Client
|
||||
currHttpEndpoint network.Endpoint
|
||||
finalizedStateAtStartup state.BeaconState
|
||||
}
|
||||
@@ -228,14 +226,9 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
|
||||
|
||||
// Start a web3 service's main event loop.
|
||||
func (s *Service) Start() {
|
||||
|
||||
if err := s.connectToPowChain(); err != nil {
|
||||
log.WithError(err).Fatal("Could not connect to execution endpoint")
|
||||
if err := s.setupExecutionClientConnections(s.ctx, s.cfg.currHttpEndpoint); err != nil {
|
||||
log.WithError(err).Error("Could not connect to execution endpoint")
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"endpoint": logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url),
|
||||
}).Info("Connected to Ethereum execution client RPC")
|
||||
// If the chain has not started already and we don't have access to eth1 nodes, we will not be
|
||||
// able to generate the genesis state.
|
||||
if !s.chainStartData.Chainstarted && s.cfg.currHttpEndpoint.Url == "" {
|
||||
@@ -253,7 +246,7 @@ func (s *Service) Start() {
|
||||
s.isRunning = true
|
||||
|
||||
// Poll the execution client connection and fallback if errors occur.
|
||||
go s.pollConnectionStatus()
|
||||
go s.pollConnectionStatus(s.ctx)
|
||||
|
||||
// Check transition configuration for the engine API client in the background.
|
||||
go s.checkTransitionConfiguration(s.ctx, make(chan *feed.Event, 1))
|
||||
@@ -266,7 +259,12 @@ func (s *Service) Stop() error {
|
||||
if s.cancel != nil {
|
||||
defer s.cancel()
|
||||
}
|
||||
s.closeClients()
|
||||
if s.rpcClient != nil {
|
||||
s.rpcClient.Close()
|
||||
}
|
||||
if s.eth1DataFetcher != nil {
|
||||
s.eth1DataFetcher.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -338,10 +336,7 @@ func (s *Service) CurrentETH1Endpoint() string {
|
||||
|
||||
// CurrentETH1ConnectionError returns the error (if any) of the current connection.
|
||||
func (s *Service) CurrentETH1ConnectionError() error {
|
||||
httpClient, rpcClient, err := s.dialETH1Nodes(s.cfg.currHttpEndpoint)
|
||||
httpClient.Close()
|
||||
rpcClient.Close()
|
||||
return err
|
||||
return s.runError
|
||||
}
|
||||
|
||||
// ETH1Endpoints returns the slice of HTTP endpoint URLs (default is 0th element).
|
||||
@@ -358,10 +353,17 @@ func (s *Service) ETH1Endpoints() []string {
|
||||
func (s *Service) ETH1ConnectionErrors() []error {
|
||||
var errs []error
|
||||
for _, ep := range s.cfg.httpEndpoints {
|
||||
httpClient, rpcClient, err := s.dialETH1Nodes(ep)
|
||||
httpClient.Close()
|
||||
rpcClient.Close()
|
||||
errs = append(errs, err)
|
||||
client, err := s.newRPCClientWithAuth(s.ctx, ep)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
if err := ensureCorrectExecutionChain(s.ctx, ethclient.NewClient(client)); err != nil {
|
||||
client.Close()
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
client.Close()
|
||||
}
|
||||
return errs
|
||||
}
|
||||
@@ -376,146 +378,6 @@ func (s *Service) followBlockHeight(_ context.Context) (uint64, error) {
|
||||
return latestValidBlock, nil
|
||||
}
|
||||
|
||||
func (s *Service) connectToPowChain() error {
|
||||
httpClient, rpcClient, err := s.dialETH1Nodes(s.cfg.currHttpEndpoint)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not dial execution node")
|
||||
}
|
||||
|
||||
depositContractCaller, err := contracts.NewDepositContractCaller(s.cfg.depositContractAddr, httpClient)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not initialize deposit contract caller")
|
||||
}
|
||||
|
||||
if httpClient == nil || rpcClient == nil || depositContractCaller == nil {
|
||||
return errors.New("execution client RPC is nil")
|
||||
}
|
||||
s.httpLogger = httpClient
|
||||
s.eth1DataFetcher = httpClient
|
||||
s.depositContractCaller = depositContractCaller
|
||||
s.rpcClient = rpcClient
|
||||
|
||||
s.updateConnectedETH1(true)
|
||||
s.runError = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) dialETH1Nodes(endpoint network.Endpoint) (*ethclient.Client, *gethRPC.Client, error) {
|
||||
httpRPCClient, err := gethRPC.Dial(endpoint.Url)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if endpoint.Auth.Method != authorization.None {
|
||||
header, err := endpoint.Auth.ToHeaderValue()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
httpRPCClient.SetHeader("Authorization", header)
|
||||
}
|
||||
httpClient := ethclient.NewClient(httpRPCClient)
|
||||
// Add a method to clean-up and close clients in the event
|
||||
// of any connection failure.
|
||||
closeClients := func() {
|
||||
httpRPCClient.Close()
|
||||
httpClient.Close()
|
||||
}
|
||||
// Make a simple call to ensure we are actually connected to a working node.
|
||||
cID, err := httpClient.ChainID(s.ctx)
|
||||
if err != nil {
|
||||
closeClients()
|
||||
return nil, nil, err
|
||||
}
|
||||
nID, err := httpClient.NetworkID(s.ctx)
|
||||
if err != nil {
|
||||
closeClients()
|
||||
return nil, nil, err
|
||||
}
|
||||
if cID.Uint64() != params.BeaconConfig().DepositChainID {
|
||||
closeClients()
|
||||
return nil, nil, fmt.Errorf("eth1 node using incorrect chain id, %d != %d", cID.Uint64(), params.BeaconConfig().DepositChainID)
|
||||
}
|
||||
if nID.Uint64() != params.BeaconConfig().DepositNetworkID {
|
||||
closeClients()
|
||||
return nil, nil, fmt.Errorf("eth1 node using incorrect network id, %d != %d", nID.Uint64(), params.BeaconConfig().DepositNetworkID)
|
||||
}
|
||||
|
||||
return httpClient, httpRPCClient, nil
|
||||
}
|
||||
|
||||
// closes down our active eth1 clients.
|
||||
func (s *Service) closeClients() {
|
||||
gethClient, ok := s.rpcClient.(*gethRPC.Client)
|
||||
if ok {
|
||||
gethClient.Close()
|
||||
}
|
||||
httpClient, ok := s.eth1DataFetcher.(*ethclient.Client)
|
||||
if ok {
|
||||
httpClient.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) pollConnectionStatus() {
|
||||
// Use a custom logger to only log errors
|
||||
logCounter := 0
|
||||
errorLogger := func(err error, msg string) {
|
||||
if logCounter > logThreshold {
|
||||
log.Errorf("%s: %v", msg, err)
|
||||
logCounter = 0
|
||||
}
|
||||
logCounter++
|
||||
}
|
||||
ticker := time.NewTicker(backOffPeriod)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
log.Debugf("Trying to dial endpoint: %s", logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url))
|
||||
errConnect := s.connectToPowChain()
|
||||
if errConnect != nil {
|
||||
errorLogger(errConnect, "Could not connect to powchain endpoint")
|
||||
s.runError = errConnect
|
||||
s.fallbackToNextEndpoint()
|
||||
continue
|
||||
}
|
||||
case <-s.ctx.Done():
|
||||
log.Debug("Received cancelled context,closing existing powchain service")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checks if the eth1 node is healthy and ready to serve before
|
||||
// fetching data from it.
|
||||
func (s *Service) isEth1NodeSynced() (bool, error) {
|
||||
syncProg, err := s.eth1DataFetcher.SyncProgress(s.ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if syncProg != nil {
|
||||
return false, nil
|
||||
}
|
||||
head, err := s.eth1DataFetcher.HeaderByNumber(s.ctx, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return !eth1HeadIsBehind(head.Time), nil
|
||||
}
|
||||
|
||||
// Reconnect to eth1 node in case of any failure.
|
||||
func (s *Service) retryETH1Node(err error) {
|
||||
s.runError = err
|
||||
s.updateConnectedETH1(false)
|
||||
// Back off for a while before
|
||||
// resuming dialing the eth1 node.
|
||||
time.Sleep(backOffPeriod)
|
||||
if err := s.connectToPowChain(); err != nil {
|
||||
s.runError = err
|
||||
return
|
||||
}
|
||||
// Reset run error in the event of a successful connection.
|
||||
s.runError = nil
|
||||
}
|
||||
|
||||
func (s *Service) initDepositCaches(ctx context.Context, ctrs []*ethpb.DepositContainer) error {
|
||||
if len(ctrs) == 0 {
|
||||
return nil
|
||||
@@ -650,7 +512,7 @@ func (s *Service) handleETH1FollowDistance() {
|
||||
fiveMinutesTimeout := prysmTime.Now().Add(-5 * time.Minute)
|
||||
// check that web3 client is syncing
|
||||
if time.Unix(int64(s.latestEth1Data.BlockTime), 0).Before(fiveMinutesTimeout) {
|
||||
log.Warn("eth1 client is not syncing")
|
||||
log.Warn("Execution client is not syncing")
|
||||
}
|
||||
if !s.chainStartData.Chainstarted {
|
||||
if err := s.checkBlockNumberForChainStart(ctx, big.NewInt(int64(s.latestEth1Data.LastRequestedBlock))); err != nil {
|
||||
@@ -680,6 +542,15 @@ func (s *Service) handleETH1FollowDistance() {
|
||||
}
|
||||
|
||||
func (s *Service) initPOWService() {
|
||||
// Use a custom logger to only log errors
|
||||
logCounter := 0
|
||||
errorLogger := func(err error, msg string) {
|
||||
if logCounter > logThreshold {
|
||||
log.Errorf("%s: %v", msg, err)
|
||||
logCounter = 0
|
||||
}
|
||||
logCounter++
|
||||
}
|
||||
|
||||
// Run in a select loop to retry in the event of any failures.
|
||||
for {
|
||||
@@ -690,8 +561,8 @@ func (s *Service) initPOWService() {
|
||||
ctx := s.ctx
|
||||
header, err := s.eth1DataFetcher.HeaderByNumber(ctx, nil)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to retrieve latest ETH1.0 chain header: %v", err)
|
||||
s.retryETH1Node(err)
|
||||
s.retryExecutionClientConnection(ctx, err)
|
||||
errorLogger(err, "Unable to retrieve latest execution client header")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -700,14 +571,14 @@ func (s *Service) initPOWService() {
|
||||
s.latestEth1Data.BlockTime = header.Time
|
||||
|
||||
if err := s.processPastLogs(ctx); err != nil {
|
||||
log.Errorf("Unable to process past logs %v", err)
|
||||
s.retryETH1Node(err)
|
||||
s.retryExecutionClientConnection(ctx, err)
|
||||
errorLogger(err, "Unable to process past deposit contract logs")
|
||||
continue
|
||||
}
|
||||
// Cache eth1 headers from our voting period.
|
||||
if err := s.cacheHeadersForEth1DataVote(ctx); err != nil {
|
||||
log.Errorf("Unable to process past headers %v", err)
|
||||
s.retryETH1Node(err)
|
||||
s.retryExecutionClientConnection(ctx, err)
|
||||
errorLogger(err, "Unable to cache headers for execution client votes")
|
||||
continue
|
||||
}
|
||||
// Handle edge case with embedded genesis state by fetching genesis header to determine
|
||||
@@ -720,15 +591,15 @@ func (s *Service) initPOWService() {
|
||||
if genHash != [32]byte{} {
|
||||
genHeader, err := s.eth1DataFetcher.HeaderByHash(ctx, genHash)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to retrieve genesis ETH1.0 chain header: %v", err)
|
||||
s.retryETH1Node(err)
|
||||
s.retryExecutionClientConnection(ctx, err)
|
||||
errorLogger(err, "Unable to retrieve proof-of-stake genesis block data")
|
||||
continue
|
||||
}
|
||||
genBlock = genHeader.Number.Uint64()
|
||||
}
|
||||
s.chainStartData.GenesisBlock = genBlock
|
||||
if err := s.savePowchainData(ctx); err != nil {
|
||||
log.Errorf("Unable to save powchain data: %v", err)
|
||||
errorLogger(err, "Unable to save execution client data")
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -757,17 +628,16 @@ func (s *Service) run(done <-chan struct{}) {
|
||||
head, err := s.eth1DataFetcher.HeaderByNumber(s.ctx, nil)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("Could not fetch latest eth1 header")
|
||||
s.retryETH1Node(err)
|
||||
continue
|
||||
}
|
||||
if eth1HeadIsBehind(head.Time) {
|
||||
s.retryExecutionClientConnection(s.ctx, err)
|
||||
log.WithError(errFarBehind).Debug("Could not get an up to date eth1 header")
|
||||
s.retryETH1Node(errFarBehind)
|
||||
continue
|
||||
}
|
||||
s.processBlockHeader(head)
|
||||
s.handleETH1FollowDistance()
|
||||
s.checkDefaultEndpoint()
|
||||
s.checkDefaultEndpoint(s.ctx)
|
||||
case <-chainstartTicker.C:
|
||||
if s.chainStartData.Chainstarted {
|
||||
chainstartTicker.Stop()
|
||||
@@ -854,59 +724,6 @@ func (s *Service) determineEarliestVotingBlock(ctx context.Context, followBlock
|
||||
return hdr.Number.Uint64(), nil
|
||||
}
|
||||
|
||||
// This performs a health check on our primary endpoint, and if it
|
||||
// is ready to serve we connect to it again. This method is only
|
||||
// relevant if we are on our backup endpoint.
|
||||
func (s *Service) checkDefaultEndpoint() {
|
||||
primaryEndpoint := s.cfg.httpEndpoints[0]
|
||||
// Return early if we are running on our primary
|
||||
// endpoint.
|
||||
if s.cfg.currHttpEndpoint.Equals(primaryEndpoint) {
|
||||
return
|
||||
}
|
||||
|
||||
httpClient, rpcClient, err := s.dialETH1Nodes(primaryEndpoint)
|
||||
if err != nil {
|
||||
log.Debugf("Primary endpoint not ready: %v", err)
|
||||
return
|
||||
}
|
||||
log.Info("Primary endpoint ready again, switching back to it")
|
||||
// Close the clients and let our main connection routine
|
||||
// properly connect with it.
|
||||
httpClient.Close()
|
||||
rpcClient.Close()
|
||||
// Close current active clients.
|
||||
s.closeClients()
|
||||
|
||||
// Switch back to primary endpoint and try connecting
|
||||
// to it again.
|
||||
s.updateCurrHttpEndpoint(primaryEndpoint)
|
||||
s.retryETH1Node(nil)
|
||||
}
|
||||
|
||||
// This is an inefficient way to search for the next endpoint, but given N is expected to be
|
||||
// small ( < 25), it is fine to search this way.
|
||||
func (s *Service) fallbackToNextEndpoint() {
|
||||
currEndpoint := s.cfg.currHttpEndpoint
|
||||
currIndex := 0
|
||||
totalEndpoints := len(s.cfg.httpEndpoints)
|
||||
|
||||
for i, endpoint := range s.cfg.httpEndpoints {
|
||||
if endpoint.Equals(currEndpoint) {
|
||||
currIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
nextIndex := currIndex + 1
|
||||
if nextIndex >= totalEndpoints {
|
||||
nextIndex = 0
|
||||
}
|
||||
s.updateCurrHttpEndpoint(s.cfg.httpEndpoints[nextIndex])
|
||||
if nextIndex != currIndex {
|
||||
log.Infof("Falling back to alternative endpoint: %s", logs.MaskCredentialsLogging(s.cfg.currHttpEndpoint.Url))
|
||||
}
|
||||
}
|
||||
|
||||
// initializes our service from the provided eth1data object by initializing all the relevant
|
||||
// fields and data.
|
||||
func (s *Service) initializeEth1Data(ctx context.Context, eth1DataInDB *ethpb.ETH1ChainData) error {
|
||||
|
||||
@@ -42,6 +42,8 @@ type goodLogger struct {
|
||||
backend *backends.SimulatedBackend
|
||||
}
|
||||
|
||||
func (_ *goodLogger) Close() {}
|
||||
|
||||
func (g *goodLogger) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- gethTypes.Log) (ethereum.Subscription, error) {
|
||||
if g.backend == nil {
|
||||
return new(event.Feed).Subscribe(ch), nil
|
||||
@@ -80,6 +82,8 @@ type goodFetcher struct {
|
||||
backend *backends.SimulatedBackend
|
||||
}
|
||||
|
||||
func (_ *goodFetcher) Close() {}
|
||||
|
||||
func (g *goodFetcher) HeaderByHash(_ context.Context, hash common.Hash) (*gethTypes.Header, error) {
|
||||
if bytes.Equal(hash.Bytes(), common.BytesToHash([]byte{0}).Bytes()) {
|
||||
return nil, fmt.Errorf("expected block hash to be nonzero %v", hash)
|
||||
@@ -225,10 +229,6 @@ func TestService_Eth1Synced(t *testing.T) {
|
||||
now := time.Now()
|
||||
assert.NoError(t, testAcc.Backend.AdjustTime(now.Sub(time.Unix(int64(currTime), 0))))
|
||||
testAcc.Backend.Commit()
|
||||
|
||||
synced, err := web3Service.isEth1NodeSynced()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, synced, "Expected eth1 nodes to be synced")
|
||||
}
|
||||
|
||||
func TestFollowBlock_OK(t *testing.T) {
|
||||
@@ -480,8 +480,8 @@ func TestInitDepositCacheWithFinalization_OK(t *testing.T) {
|
||||
|
||||
s.chainStartData.Chainstarted = true
|
||||
require.NoError(t, s.initDepositCaches(context.Background(), ctrs))
|
||||
|
||||
deps := s.cfg.depositCache.NonFinalizedDeposits(context.Background(), nil)
|
||||
fDeposits := s.cfg.depositCache.FinalizedDeposits(ctx)
|
||||
deps := s.cfg.depositCache.NonFinalizedDeposits(context.Background(), fDeposits.MerkleTrieIndex, nil)
|
||||
assert.Equal(t, 0, len(deps))
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ go_library(
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_holiman_uint256//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -2,25 +2,32 @@ package testing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
)
|
||||
|
||||
// EngineClient --
|
||||
type EngineClient struct {
|
||||
NewPayloadResp []byte
|
||||
PayloadIDBytes *pb.PayloadIDBytes
|
||||
ForkChoiceUpdatedResp []byte
|
||||
ExecutionPayload *pb.ExecutionPayload
|
||||
ExecutionBlock *pb.ExecutionBlock
|
||||
Err error
|
||||
ErrLatestExecBlock error
|
||||
ErrExecBlockByHash error
|
||||
ErrForkchoiceUpdated error
|
||||
ErrNewPayload error
|
||||
BlockByHashMap map[[32]byte]*pb.ExecutionBlock
|
||||
NewPayloadResp []byte
|
||||
PayloadIDBytes *pb.PayloadIDBytes
|
||||
ForkChoiceUpdatedResp []byte
|
||||
ExecutionPayload *pb.ExecutionPayload
|
||||
ExecutionBlock *pb.ExecutionBlock
|
||||
Err error
|
||||
ErrLatestExecBlock error
|
||||
ErrExecBlockByHash error
|
||||
ErrForkchoiceUpdated error
|
||||
ErrNewPayload error
|
||||
BlockByHashMap map[[32]byte]*pb.ExecutionBlock
|
||||
TerminalBlockHash []byte
|
||||
TerminalBlockHashExists bool
|
||||
}
|
||||
|
||||
// NewPayload --
|
||||
@@ -58,3 +65,52 @@ func (e *EngineClient) ExecutionBlockByHash(_ context.Context, h common.Hash) (*
|
||||
}
|
||||
return b, e.ErrExecBlockByHash
|
||||
}
|
||||
|
||||
// GetTerminalBlockHash --
|
||||
func (e *EngineClient) GetTerminalBlockHash(ctx context.Context) ([]byte, bool, error) {
|
||||
ttd := new(big.Int)
|
||||
ttd.SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
|
||||
terminalTotalDifficulty, overflows := uint256.FromBig(ttd)
|
||||
if overflows {
|
||||
return nil, false, errors.New("could not convert terminal total difficulty to uint256")
|
||||
}
|
||||
blk, err := e.LatestExecutionBlock(ctx)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not get latest execution block")
|
||||
}
|
||||
if blk == nil {
|
||||
return nil, false, errors.New("latest execution block is nil")
|
||||
}
|
||||
|
||||
for {
|
||||
b, err := hexutil.DecodeBig(blk.TotalDifficulty)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
||||
}
|
||||
currentTotalDifficulty, _ := uint256.FromBig(b)
|
||||
blockReachedTTD := currentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
||||
|
||||
parentHash := bytesutil.ToBytes32(blk.ParentHash)
|
||||
if len(blk.ParentHash) == 0 || parentHash == params.BeaconConfig().ZeroHash {
|
||||
return nil, false, nil
|
||||
}
|
||||
parentBlk, err := e.ExecutionBlockByHash(ctx, parentHash)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not get parent execution block")
|
||||
}
|
||||
if blockReachedTTD {
|
||||
b, err := hexutil.DecodeBig(parentBlk.TotalDifficulty)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
||||
}
|
||||
parentTotalDifficulty, _ := uint256.FromBig(b)
|
||||
parentReachedTTD := parentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
||||
if !parentReachedTTD {
|
||||
return blk.Hash, true, nil
|
||||
}
|
||||
} else {
|
||||
return nil, false, nil
|
||||
}
|
||||
blk = parentBlk
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,8 @@ type RPCClient struct {
|
||||
Backend *backends.SimulatedBackend
|
||||
}
|
||||
|
||||
func (_ *RPCClient) Close() {}
|
||||
|
||||
func (*RPCClient) CallContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -77,7 +77,6 @@ go_library(
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_ferranbt_fastssz//:go_default_library",
|
||||
"@com_github_holiman_uint256//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
@@ -162,7 +161,6 @@ go_test(
|
||||
"@com_github_d4l3k_messagediff//:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_golang_mock//gomock:go_default_library",
|
||||
"@com_github_holiman_uint256//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
|
||||
@@ -37,17 +37,24 @@ func (vs *Server) StreamBlocksAltair(req *ethpb.StreamBlocksRequest, stream ethp
|
||||
case version.Phase0:
|
||||
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlock)
|
||||
if !ok {
|
||||
log.Warn("Mismatch between version and block type, was expecting *ethpb.SignedBeaconBlock")
|
||||
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlock")
|
||||
continue
|
||||
}
|
||||
b.Block = ðpb.StreamBlocksResponse_Phase0Block{Phase0Block: phBlk}
|
||||
case version.Altair:
|
||||
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlockAltair)
|
||||
if !ok {
|
||||
log.Warn("Mismatch between version and block type, was expecting *v2.SignedBeaconBlockAltair")
|
||||
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlockAltair")
|
||||
continue
|
||||
}
|
||||
b.Block = ðpb.StreamBlocksResponse_AltairBlock{AltairBlock: phBlk}
|
||||
case version.Bellatrix:
|
||||
phBlk, ok := data.SignedBlock.Proto().(*ethpb.SignedBeaconBlockBellatrix)
|
||||
if !ok {
|
||||
log.Warn("Mismatch between version and block type, was expecting SignedBeaconBlockBellatrix")
|
||||
continue
|
||||
}
|
||||
b.Block = ðpb.StreamBlocksResponse_BellatrixBlock{BellatrixBlock: phBlk}
|
||||
}
|
||||
|
||||
if err := stream.Send(b); err != nil {
|
||||
|
||||
@@ -161,7 +161,7 @@ func (vs *Server) depositTrie(ctx context.Context, canonicalEth1Data *ethpb.Eth1
|
||||
|
||||
finalizedDeposits := vs.DepositFetcher.FinalizedDeposits(ctx)
|
||||
depositTrie = finalizedDeposits.Deposits
|
||||
upToEth1DataDeposits := vs.DepositFetcher.NonFinalizedDeposits(ctx, canonicalEth1DataHeight)
|
||||
upToEth1DataDeposits := vs.DepositFetcher.NonFinalizedDeposits(ctx, finalizedDeposits.MerkleTrieIndex, canonicalEth1DataHeight)
|
||||
insertIndex := finalizedDeposits.MerkleTrieIndex + 1
|
||||
|
||||
for _, dep := range upToEth1DataDeposits {
|
||||
|
||||
@@ -3,11 +3,7 @@ package validator
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
@@ -181,79 +177,7 @@ func (vs *Server) getTerminalBlockHashIfExists(ctx context.Context) ([]byte, boo
|
||||
return terminalBlockHash.Bytes(), true, nil
|
||||
}
|
||||
|
||||
return vs.getPowBlockHashAtTerminalTotalDifficulty(ctx)
|
||||
}
|
||||
|
||||
// This returns the valid terminal block hash based on total difficulty.
|
||||
//
|
||||
// Spec code:
|
||||
// def get_pow_block_at_terminal_total_difficulty(pow_chain: Dict[Hash32, PowBlock]) -> Optional[PowBlock]:
|
||||
// # `pow_chain` abstractly represents all blocks in the PoW chain
|
||||
// for block in pow_chain:
|
||||
// parent = pow_chain[block.parent_hash]
|
||||
// block_reached_ttd = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
|
||||
// parent_reached_ttd = parent.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
|
||||
// if block_reached_ttd and not parent_reached_ttd:
|
||||
// return block
|
||||
//
|
||||
// return None
|
||||
func (vs *Server) getPowBlockHashAtTerminalTotalDifficulty(ctx context.Context) ([]byte, bool, error) {
|
||||
ttd := new(big.Int)
|
||||
ttd.SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
|
||||
terminalTotalDifficulty, overflows := uint256.FromBig(ttd)
|
||||
if overflows {
|
||||
return nil, false, errors.New("could not convert terminal total difficulty to uint256")
|
||||
}
|
||||
blk, err := vs.ExecutionEngineCaller.LatestExecutionBlock(ctx)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not get latest execution block")
|
||||
}
|
||||
if blk == nil {
|
||||
return nil, false, errors.New("latest execution block is nil")
|
||||
}
|
||||
|
||||
for {
|
||||
if ctx.Err() != nil {
|
||||
return nil, false, ctx.Err()
|
||||
}
|
||||
currentTotalDifficulty, err := tDStringToUint256(blk.TotalDifficulty)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
||||
}
|
||||
blockReachedTTD := currentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
||||
|
||||
parentHash := bytesutil.ToBytes32(blk.ParentHash)
|
||||
if len(blk.ParentHash) == 0 || parentHash == params.BeaconConfig().ZeroHash {
|
||||
return nil, false, nil
|
||||
}
|
||||
parentBlk, err := vs.ExecutionEngineCaller.ExecutionBlockByHash(ctx, parentHash)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not get parent execution block")
|
||||
}
|
||||
if parentBlk == nil {
|
||||
return nil, false, errors.New("parent execution block is nil")
|
||||
}
|
||||
if blockReachedTTD {
|
||||
parentTotalDifficulty, err := tDStringToUint256(parentBlk.TotalDifficulty)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "could not convert total difficulty to uint256")
|
||||
}
|
||||
parentReachedTTD := parentTotalDifficulty.Cmp(terminalTotalDifficulty) >= 0
|
||||
if !parentReachedTTD {
|
||||
log.WithFields(logrus.Fields{
|
||||
"number": blk.Number,
|
||||
"hash": fmt.Sprintf("%#x", bytesutil.Trunc(blk.Hash)),
|
||||
"td": blk.TotalDifficulty,
|
||||
"parentTd": parentBlk.TotalDifficulty,
|
||||
"ttd": terminalTotalDifficulty,
|
||||
}).Info("Retrieved terminal block hash")
|
||||
return blk.Hash, true, nil
|
||||
}
|
||||
} else {
|
||||
return nil, false, nil
|
||||
}
|
||||
blk = parentBlk
|
||||
}
|
||||
return vs.ExecutionEngineCaller.GetTerminalBlockHash(ctx)
|
||||
}
|
||||
|
||||
// activationEpochNotReached returns true if activation epoch has not been reach.
|
||||
@@ -270,18 +194,6 @@ func activationEpochNotReached(slot types.Slot) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func tDStringToUint256(td string) (*uint256.Int, error) {
|
||||
b, err := hexutil.DecodeBig(td)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i, overflows := uint256.FromBig(b)
|
||||
if overflows {
|
||||
return nil, errors.New("total difficulty overflowed")
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func emptyPayload() *enginev1.ExecutionPayload {
|
||||
return &enginev1.ExecutionPayload{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
@@ -22,26 +21,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
)
|
||||
|
||||
func Test_tDStringToUint256(t *testing.T) {
|
||||
i, err := tDStringToUint256("0x0")
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, uint256.NewInt(0), i)
|
||||
|
||||
i, err = tDStringToUint256("0x10000")
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, uint256.NewInt(65536), i)
|
||||
|
||||
_, err = tDStringToUint256("100")
|
||||
require.ErrorContains(t, "hex string without 0x prefix", err)
|
||||
|
||||
_, err = tDStringToUint256("0xzzzzzz")
|
||||
require.ErrorContains(t, "invalid hex string", err)
|
||||
|
||||
_, err = tDStringToUint256("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" +
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
||||
require.ErrorContains(t, "hex number > 256 bits", err)
|
||||
}
|
||||
|
||||
func TestServer_activationEpochNotReached(t *testing.T) {
|
||||
require.Equal(t, false, activationEpochNotReached(0))
|
||||
|
||||
@@ -154,137 +133,6 @@ func TestServer_getExecutionPayload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_getPowBlockHashAtTerminalTotalDifficulty(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
paramsTd string
|
||||
currentPowBlock *pb.ExecutionBlock
|
||||
parentPowBlock *pb.ExecutionBlock
|
||||
errLatestExecutionBlk error
|
||||
wantTerminalBlockHash []byte
|
||||
wantExists bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "config td overflows",
|
||||
paramsTd: "1115792089237316195423570985008687907853269984665640564039457584007913129638912",
|
||||
errString: "could not convert terminal total difficulty to uint256",
|
||||
},
|
||||
{
|
||||
name: "could not get latest execution block",
|
||||
paramsTd: "1",
|
||||
errLatestExecutionBlk: errors.New("blah"),
|
||||
errString: "could not get latest execution block",
|
||||
},
|
||||
{
|
||||
name: "nil latest execution block",
|
||||
paramsTd: "1",
|
||||
errString: "latest execution block is nil",
|
||||
},
|
||||
{
|
||||
name: "current execution block invalid TD",
|
||||
paramsTd: "1",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
TotalDifficulty: "1115792089237316195423570985008687907853269984665640564039457584007913129638912",
|
||||
},
|
||||
errString: "could not convert total difficulty to uint256",
|
||||
},
|
||||
{
|
||||
name: "current execution block has zero hash parent",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: params.BeaconConfig().ZeroHash[:],
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "could not get parent block",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: []byte{'b'},
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
errString: "could not get parent execution block",
|
||||
},
|
||||
{
|
||||
name: "parent execution block invalid TD",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: []byte{'b'},
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
parentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'b'},
|
||||
ParentHash: []byte{'c'},
|
||||
TotalDifficulty: "1",
|
||||
},
|
||||
errString: "could not convert total difficulty to uint256",
|
||||
},
|
||||
{
|
||||
name: "happy case",
|
||||
paramsTd: "2",
|
||||
currentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'a'},
|
||||
ParentHash: []byte{'b'},
|
||||
TotalDifficulty: "0x3",
|
||||
},
|
||||
parentPowBlock: &pb.ExecutionBlock{
|
||||
Hash: []byte{'b'},
|
||||
ParentHash: []byte{'c'},
|
||||
TotalDifficulty: "0x1",
|
||||
},
|
||||
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) {
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.TerminalTotalDifficulty = tt.paramsTd
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
var m map[[32]byte]*pb.ExecutionBlock
|
||||
if tt.parentPowBlock != nil {
|
||||
m = map[[32]byte]*pb.ExecutionBlock{
|
||||
bytesutil.ToBytes32(tt.parentPowBlock.Hash): tt.parentPowBlock,
|
||||
}
|
||||
}
|
||||
vs := &Server{
|
||||
ExecutionEngineCaller: &powtesting.EngineClient{
|
||||
ErrLatestExecBlock: tt.errLatestExecutionBlk,
|
||||
ExecutionBlock: tt.currentPowBlock,
|
||||
BlockByHashMap: m,
|
||||
},
|
||||
}
|
||||
b, e, err := vs.getPowBlockHashAtTerminalTotalDifficulty(context.Background())
|
||||
if tt.errString != "" {
|
||||
require.ErrorContains(t, tt.errString, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, tt.wantExists, e)
|
||||
require.DeepEqual(t, tt.wantTerminalBlockHash, b)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_getTerminalBlockHashIfExists(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -10,6 +10,7 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||
"//beacon-chain/state/state-native/types:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
|
||||
@@ -16,7 +16,7 @@ type FieldTrie struct {
|
||||
*sync.RWMutex
|
||||
reference *stateutil.Reference
|
||||
fieldLayers [][]*[32]byte
|
||||
field types.FieldIndex
|
||||
field types.FieldIdx
|
||||
dataType types.DataType
|
||||
length uint64
|
||||
numOfElems int
|
||||
@@ -25,7 +25,7 @@ type FieldTrie struct {
|
||||
// NewFieldTrie is the constructor for the field trie data structure. It creates the corresponding
|
||||
// trie according to the given parameters. Depending on whether the field is a basic/composite array
|
||||
// which is either fixed/variable length, it will appropriately determine the trie.
|
||||
func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
|
||||
func NewFieldTrie(field types.FieldIdx, dataType types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
|
||||
if elements == nil {
|
||||
return &FieldTrie{
|
||||
field: field,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
"github.com/prysmaticlabs/prysm/crypto/hash"
|
||||
@@ -18,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
// ProofFromMerkleLayers creates a proof starting at the leaf index of the state Merkle layers.
|
||||
func ProofFromMerkleLayers(layers [][][]byte, startingLeafIndex types.FieldIndex) [][]byte {
|
||||
func ProofFromMerkleLayers(layers [][][]byte, startingLeafIndex int) [][]byte {
|
||||
// The merkle tree structure looks as follows:
|
||||
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
|
||||
proof := make([][]byte, 0)
|
||||
@@ -49,7 +50,7 @@ func (f *FieldTrie) validateIndices(idxs []uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateElements(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) error {
|
||||
func validateElements(field types.FieldIdx, dataType types.DataType, elements interface{}, length uint64) error {
|
||||
if dataType == types.CompressedArray {
|
||||
comLength, err := field.ElemsInChunk()
|
||||
if err != nil {
|
||||
@@ -65,68 +66,117 @@ func validateElements(field types.FieldIndex, dataType types.DataType, elements
|
||||
}
|
||||
|
||||
// fieldConverters converts the corresponding field and the provided elements to the appropriate roots.
|
||||
func fieldConverters(field types.FieldIndex, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
func fieldConverters(field types.FieldIdx, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
if field.Native() {
|
||||
switch field {
|
||||
case nativetypes.BlockRoots:
|
||||
return convertBlockRoots(indices, elements, convertAll)
|
||||
case nativetypes.StateRoots:
|
||||
return convertStateRoots(indices, elements, convertAll)
|
||||
case nativetypes.RandaoMixes:
|
||||
return convertRandaoMixes(indices, elements, convertAll)
|
||||
case nativetypes.Eth1DataVotes:
|
||||
return convertEth1DataVotes(indices, elements, convertAll)
|
||||
case nativetypes.Validators:
|
||||
return convertValidators(indices, elements, convertAll)
|
||||
case nativetypes.PreviousEpochAttestations, nativetypes.CurrentEpochAttestations:
|
||||
return convertAttestations(indices, elements, convertAll)
|
||||
case nativetypes.Balances:
|
||||
return convertBalances(indices, elements, convertAll)
|
||||
default:
|
||||
return [][32]byte{}, errors.Errorf("got unsupported type of %v", reflect.TypeOf(elements).Name())
|
||||
}
|
||||
}
|
||||
|
||||
switch field {
|
||||
case types.BlockRoots:
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.BlockRoots:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for block roots")
|
||||
}
|
||||
return convertBlockRoots(indices, elements, convertAll)
|
||||
case types.StateRoots:
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.StateRoots:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for state roots")
|
||||
}
|
||||
return convertStateRoots(indices, elements, convertAll)
|
||||
case types.RandaoMixes:
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.RandaoMixes:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for randao mixes")
|
||||
}
|
||||
return convertRandaoMixes(indices, elements, convertAll)
|
||||
case types.Eth1DataVotes:
|
||||
val, ok := elements.([]*ethpb.Eth1Data)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]*ethpb.Eth1Data{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handleEth1DataSlice(val, indices, convertAll)
|
||||
return convertEth1DataVotes(indices, elements, convertAll)
|
||||
case types.Validators:
|
||||
val, ok := elements.([]*ethpb.Validator)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]*ethpb.Validator{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handleValidatorSlice(val, indices, convertAll)
|
||||
return convertValidators(indices, elements, convertAll)
|
||||
case types.PreviousEpochAttestations, types.CurrentEpochAttestations:
|
||||
val, ok := elements.([]*ethpb.PendingAttestation)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]*ethpb.PendingAttestation{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handlePendingAttestationSlice(val, indices, convertAll)
|
||||
return convertAttestations(indices, elements, convertAll)
|
||||
case types.Balances:
|
||||
val, ok := elements.([]uint64)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]uint64{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handleBalanceSlice(val, indices, convertAll)
|
||||
return convertBalances(indices, elements, convertAll)
|
||||
default:
|
||||
return [][32]byte{}, errors.Errorf("got unsupported type of %v", reflect.TypeOf(elements).Name())
|
||||
}
|
||||
}
|
||||
|
||||
func convertBlockRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.BlockRoots:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for block roots")
|
||||
}
|
||||
}
|
||||
|
||||
func convertStateRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.StateRoots:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for state roots")
|
||||
}
|
||||
}
|
||||
|
||||
func convertRandaoMixes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
switch val := elements.(type) {
|
||||
case [][]byte:
|
||||
return handleByteArrays(val, indices, convertAll)
|
||||
case *customtypes.RandaoMixes:
|
||||
return handle32ByteArrays(val[:], indices, convertAll)
|
||||
default:
|
||||
return nil, errors.Errorf("Incorrect type used for randao mixes")
|
||||
}
|
||||
}
|
||||
|
||||
func convertEth1DataVotes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
val, ok := elements.([]*ethpb.Eth1Data)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]*ethpb.Eth1Data{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handleEth1DataSlice(val, indices, convertAll)
|
||||
}
|
||||
|
||||
func convertValidators(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
val, ok := elements.([]*ethpb.Validator)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]*ethpb.Validator{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handleValidatorSlice(val, indices, convertAll)
|
||||
}
|
||||
|
||||
func convertAttestations(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
val, ok := elements.([]*ethpb.PendingAttestation)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]*ethpb.PendingAttestation{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handlePendingAttestationSlice(val, indices, convertAll)
|
||||
}
|
||||
|
||||
func convertBalances(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
|
||||
val, ok := elements.([]uint64)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("Wanted type of %v but got %v",
|
||||
reflect.TypeOf([]uint64{}).Name(), reflect.TypeOf(elements).Name())
|
||||
}
|
||||
return handleBalanceSlice(val, indices, convertAll)
|
||||
}
|
||||
|
||||
// handleByteArrays computes and returns byte arrays in a slice of root format.
|
||||
func handleByteArrays(val [][]byte, indices []uint64, convertAll bool) ([][32]byte, error) {
|
||||
length := len(indices)
|
||||
|
||||
@@ -18,7 +18,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 40)
|
||||
|
||||
// 5 represents the enum value of state roots
|
||||
trie, err := fieldtrie.NewFieldTrie(5, stateTypes.BasicArray, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(5), stateTypes.BasicArray, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
require.NoError(t, err)
|
||||
root, err := stateutil.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
|
||||
require.NoError(t, err)
|
||||
@@ -30,7 +30,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
|
||||
func TestFieldTrie_RecomputeTrie(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 32)
|
||||
// 10 represents the enum value of validators
|
||||
trie, err := fieldtrie.NewFieldTrie(11, stateTypes.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
|
||||
trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(11), stateTypes.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
|
||||
require.NoError(t, err)
|
||||
|
||||
changedIdx := []uint64{2, 29}
|
||||
@@ -58,7 +58,7 @@ func TestFieldTrie_RecomputeTrie(t *testing.T) {
|
||||
func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
|
||||
newState, _ := util.DeterministicGenesisState(t, 32)
|
||||
// 12 represents the enum value of randao mixes.
|
||||
trie, err := fieldtrie.NewFieldTrie(13, stateTypes.BasicArray, newState.RandaoMixes(), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
|
||||
trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(13), stateTypes.BasicArray, newState.RandaoMixes(), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
|
||||
require.NoError(t, err)
|
||||
|
||||
newTrie := trie.CopyTrie()
|
||||
|
||||
76
beacon-chain/state/state-native/BUILD.bazel
Normal file
76
beacon-chain/state/state-native/BUILD.bazel
Normal file
@@ -0,0 +1,76 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"getters_attestation.go",
|
||||
"getters_block.go",
|
||||
"getters_checkpoint.go",
|
||||
"getters_eth1.go",
|
||||
"getters_misc.go",
|
||||
"getters_participation.go",
|
||||
"getters_payload_header.go",
|
||||
"getters_randao.go",
|
||||
"getters_state.go",
|
||||
"getters_sync_committee.go",
|
||||
"getters_validator.go",
|
||||
"proofs.go",
|
||||
"readonly_validator.go",
|
||||
"setters_attestation.go",
|
||||
"setters_block.go",
|
||||
"setters_checkpoint.go",
|
||||
"setters_eth1.go",
|
||||
"setters_misc.go",
|
||||
"setters_participation.go",
|
||||
"setters_payload_header.go",
|
||||
"setters_randao.go",
|
||||
"setters_state.go",
|
||||
"setters_sync_committee.go",
|
||||
"setters_validator.go",
|
||||
"ssz.go",
|
||||
"state_trie.go",
|
||||
"types.go",
|
||||
] + select({
|
||||
"//config:mainnet": ["beacon_state_mainnet.go"],
|
||||
"//config:minimal": ["beacon_state_minimal.go"],
|
||||
}),
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//contracts/deposit:__subpackages__",
|
||||
"//proto/migration:__subpackages__",
|
||||
"//proto/prysm/v1alpha1:__subpackages__",
|
||||
"//proto/testing:__subpackages__",
|
||||
"//runtime/interop:__subpackages__",
|
||||
"//slasher/rpc:__subpackages__",
|
||||
"//testing/benchmark:__pkg__",
|
||||
"//testing/fuzz:__pkg__",
|
||||
"//testing/spectest:__subpackages__",
|
||||
"//testing/util:__pkg__",
|
||||
"//tools/benchmark-files-gen:__pkg__",
|
||||
"//tools/pcli:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/fieldtrie:go_default_library",
|
||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||
"//beacon-chain/state/state-native/types:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -10,14 +10,15 @@ import (
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// BeaconState defines a struct containing utilities for the eth2 chain state, defining
|
||||
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
|
||||
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
|
||||
type BeaconState struct {
|
||||
version int
|
||||
genesisTime uint64 `ssz-gen:"true"`
|
||||
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
|
||||
slot eth2types.Slot `ssz-gen:"true"`
|
||||
@@ -33,6 +34,8 @@ type BeaconState struct {
|
||||
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"65536,32"`
|
||||
slashings []uint64 `ssz-gen:"true" ssz-size:"8192"`
|
||||
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
|
||||
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
|
||||
previousEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
currentEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
|
||||
@@ -45,11 +48,12 @@ type BeaconState struct {
|
||||
latestExecutionPayloadHeader *ethpb.ExecutionPayloadHeader `ssz-gen:"true"`
|
||||
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[types.FieldIndex]bool
|
||||
dirtyIndices map[types.FieldIndex][]uint64
|
||||
stateFieldLeaves map[types.FieldIndex]*fieldtrie.FieldTrie
|
||||
rebuildTrie map[types.FieldIndex]bool
|
||||
fieldIndexesRev map[nativetypes.FieldIndex]int
|
||||
dirtyFields map[nativetypes.FieldIndex]bool
|
||||
dirtyIndices map[nativetypes.FieldIndex][]uint64
|
||||
stateFieldLeaves map[nativetypes.FieldIndex]*fieldtrie.FieldTrie
|
||||
rebuildTrie map[nativetypes.FieldIndex]bool
|
||||
valMapHandler *stateutil.ValidatorMapHandler
|
||||
merkleLayers [][][]byte
|
||||
sharedFieldReferences map[types.FieldIndex]*stateutil.Reference
|
||||
sharedFieldReferences map[nativetypes.FieldIndex]*stateutil.Reference
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"sync"
|
||||
@@ -10,14 +10,15 @@ import (
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// BeaconState defines a struct containing utilities for the eth2 chain state, defining
|
||||
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
|
||||
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
|
||||
type BeaconState struct {
|
||||
version int
|
||||
genesisTime uint64 `ssz-gen:"true"`
|
||||
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
|
||||
slot eth2types.Slot `ssz-gen:"true"`
|
||||
@@ -33,6 +34,8 @@ type BeaconState struct {
|
||||
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"64,32"`
|
||||
slashings []uint64 `ssz-gen:"true" ssz-size:"64"`
|
||||
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
|
||||
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
|
||||
previousEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
currentEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
|
||||
@@ -45,11 +48,12 @@ type BeaconState struct {
|
||||
latestExecutionPayloadHeader *ethpb.ExecutionPayloadHeader `ssz-gen:"true"`
|
||||
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[types.FieldIndex]bool
|
||||
dirtyIndices map[types.FieldIndex][]uint64
|
||||
stateFieldLeaves map[types.FieldIndex]*fieldtrie.FieldTrie
|
||||
rebuildTrie map[types.FieldIndex]bool
|
||||
fieldIndexesRev map[nativetypes.FieldIndex]int
|
||||
dirtyFields map[nativetypes.FieldIndex]bool
|
||||
dirtyIndices map[nativetypes.FieldIndex][]uint64
|
||||
stateFieldLeaves map[nativetypes.FieldIndex]*fieldtrie.FieldTrie
|
||||
rebuildTrie map[nativetypes.FieldIndex]bool
|
||||
valMapHandler *stateutil.ValidatorMapHandler
|
||||
merkleLayers [][][]byte
|
||||
sharedFieldReferences map[types.FieldIndex]*stateutil.Reference
|
||||
sharedFieldReferences map[nativetypes.FieldIndex]*stateutil.Reference
|
||||
}
|
||||
@@ -37,4 +37,4 @@
|
||||
// Although it is technically possible to remove the short-circuit conditions
|
||||
// from the external function, that would require every read to obtain a lock
|
||||
// even if the data was not present, leading to potential slowdowns.
|
||||
package v1
|
||||
package state_native
|
||||
@@ -1,4 +1,4 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -1,4 +1,4 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -1,4 +1,4 @@
|
||||
package v2
|
||||
package state_native
|
||||
|
||||
import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -1,9 +1,8 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
)
|
||||
|
||||
// GenesisTime of the beacon state as a uint64.
|
||||
@@ -25,8 +24,8 @@ func (b *BeaconState) GenesisValidatorsRoot() []byte {
|
||||
// Version of the beacon state. This method
|
||||
// is strictly meant to be used without a lock
|
||||
// internally.
|
||||
func (_ *BeaconState) Version() int {
|
||||
return version.Phase0
|
||||
func (b *BeaconState) Version() int {
|
||||
return b.version
|
||||
}
|
||||
|
||||
// Slot of the current beacon chain state.
|
||||
@@ -1,4 +1,4 @@
|
||||
package v2
|
||||
package state_native
|
||||
|
||||
// CurrentEpochParticipation corresponding to participation bits on the beacon chain.
|
||||
func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -1,4 +1,4 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -116,9 +116,9 @@ func (b *BeaconState) stateRootAtIndex(idx uint64) ([32]byte, error) {
|
||||
return b.stateRoots[idx], nil
|
||||
}
|
||||
|
||||
// ProtobufBeaconState transforms an input into beacon state in the form of protobuf.
|
||||
// ProtobufBeaconStatePhase0 transforms an input into beacon state in the form of protobuf.
|
||||
// Error is returned if the input is not type protobuf beacon state.
|
||||
func ProtobufBeaconState(s interface{}) (*ethpb.BeaconState, error) {
|
||||
func ProtobufBeaconStatePhase0(s interface{}) (*ethpb.BeaconState, error) {
|
||||
pbState, ok := s.(*ethpb.BeaconState)
|
||||
if !ok {
|
||||
return nil, errors.New("input is not type ethpb.BeaconState")
|
||||
@@ -1,4 +1,4 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
@@ -1,4 +1,4 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -111,7 +110,7 @@ func (b *BeaconState) ValidatorAtIndexReadOnly(idx types.ValidatorIndex) (state.
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return v1.NewValidator(b.validators[idx])
|
||||
return NewValidator(b.validators[idx])
|
||||
}
|
||||
|
||||
// ValidatorIndexByPubkey returns a given validator by its 48-byte public key.
|
||||
@@ -164,7 +163,7 @@ func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val state.ReadOnlyV
|
||||
b.lock.RUnlock()
|
||||
|
||||
for i, v := range validators {
|
||||
v, err := v1.NewValidator(v)
|
||||
v, err := NewValidator(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
)
|
||||
|
||||
@@ -48,7 +49,7 @@ func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error)
|
||||
epochRoot := bytesutil.ToBytes32(epochBuf)
|
||||
proof := make([][]byte, 0)
|
||||
proof = append(proof, epochRoot[:])
|
||||
branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, finalizedCheckpoint)
|
||||
branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, b.fieldIndexesRev[nativetypes.FinalizedCheckpoint])
|
||||
proof = append(proof, branch...)
|
||||
return proof, nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
@@ -1,8 +1,9 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -20,21 +21,21 @@ func (b *BeaconState) RotateAttestations() error {
|
||||
}
|
||||
|
||||
func (b *BeaconState) setPreviousEpochAttestations(val []*ethpb.PendingAttestation) {
|
||||
b.sharedFieldReferences[previousEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations] = stateutil.NewRef(1)
|
||||
|
||||
b.previousEpochAttestations = val
|
||||
b.markFieldAsDirty(previousEpochAttestations)
|
||||
b.rebuildTrie[previousEpochAttestations] = true
|
||||
b.markFieldAsDirty(nativetypes.PreviousEpochAttestations)
|
||||
b.rebuildTrie[nativetypes.PreviousEpochAttestations] = true
|
||||
}
|
||||
|
||||
func (b *BeaconState) setCurrentEpochAttestations(val []*ethpb.PendingAttestation) {
|
||||
b.sharedFieldReferences[currentEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations] = stateutil.NewRef(1)
|
||||
|
||||
b.currentEpochAttestations = val
|
||||
b.markFieldAsDirty(currentEpochAttestations)
|
||||
b.rebuildTrie[currentEpochAttestations] = true
|
||||
b.markFieldAsDirty(nativetypes.CurrentEpochAttestations)
|
||||
b.rebuildTrie[nativetypes.CurrentEpochAttestations] = true
|
||||
}
|
||||
|
||||
// AppendCurrentEpochAttestations for the beacon state. Appends the new value
|
||||
@@ -49,17 +50,17 @@ func (b *BeaconState) AppendCurrentEpochAttestations(val *ethpb.PendingAttestati
|
||||
return fmt.Errorf("current pending attestation exceeds max length %d", max)
|
||||
}
|
||||
|
||||
if b.sharedFieldReferences[currentEpochAttestations].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.CurrentEpochAttestations].Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
atts = make([]*ethpb.PendingAttestation, len(b.currentEpochAttestations))
|
||||
copy(atts, b.currentEpochAttestations)
|
||||
b.sharedFieldReferences[currentEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.currentEpochAttestations = append(atts, val)
|
||||
b.markFieldAsDirty(currentEpochAttestations)
|
||||
b.addDirtyIndices(currentEpochAttestations, []uint64{uint64(len(b.currentEpochAttestations) - 1)})
|
||||
b.markFieldAsDirty(nativetypes.CurrentEpochAttestations)
|
||||
b.addDirtyIndices(nativetypes.CurrentEpochAttestations, []uint64{uint64(len(b.currentEpochAttestations) - 1)})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -75,15 +76,15 @@ func (b *BeaconState) AppendPreviousEpochAttestations(val *ethpb.PendingAttestat
|
||||
return fmt.Errorf("previous pending attestation exceeds max length %d", max)
|
||||
}
|
||||
|
||||
if b.sharedFieldReferences[previousEpochAttestations].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.PreviousEpochAttestations].Refs() > 1 {
|
||||
atts = make([]*ethpb.PendingAttestation, len(b.previousEpochAttestations))
|
||||
copy(atts, b.previousEpochAttestations)
|
||||
b.sharedFieldReferences[previousEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.previousEpochAttestations = append(atts, val)
|
||||
b.markFieldAsDirty(previousEpochAttestations)
|
||||
b.addDirtyIndices(previousEpochAttestations, []uint64{uint64(len(b.previousEpochAttestations) - 1)})
|
||||
b.markFieldAsDirty(nativetypes.PreviousEpochAttestations)
|
||||
b.addDirtyIndices(nativetypes.PreviousEpochAttestations, []uint64{uint64(len(b.previousEpochAttestations) - 1)})
|
||||
return nil
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -15,7 +16,7 @@ func (b *BeaconState) SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.latestBlockHeader = ethpb.CopyBeaconBlockHeader(val)
|
||||
b.markFieldAsDirty(latestBlockHeader)
|
||||
b.markFieldAsDirty(nativetypes.LatestBlockHeader)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,8 +26,8 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[blockRoots].MinusRef()
|
||||
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.BlockRoots].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.BlockRoots] = stateutil.NewRef(1)
|
||||
|
||||
var rootsArr [fieldparams.BlockRootsLength][32]byte
|
||||
for i := 0; i < len(rootsArr); i++ {
|
||||
@@ -34,8 +35,8 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
|
||||
}
|
||||
roots := customtypes.BlockRoots(rootsArr)
|
||||
b.blockRoots = &roots
|
||||
b.markFieldAsDirty(blockRoots)
|
||||
b.rebuildTrie[blockRoots] = true
|
||||
b.markFieldAsDirty(nativetypes.BlockRoots)
|
||||
b.rebuildTrie[nativetypes.BlockRoots] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -49,19 +50,19 @@ func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) err
|
||||
defer b.lock.Unlock()
|
||||
|
||||
r := b.blockRoots
|
||||
if ref := b.sharedFieldReferences[blockRoots]; ref.Refs() > 1 {
|
||||
if ref := b.sharedFieldReferences[nativetypes.BlockRoots]; ref.Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
roots := *b.blockRoots
|
||||
rootsCopy := roots
|
||||
r = &rootsCopy
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.BlockRoots] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
r[idx] = blockRoot
|
||||
b.blockRoots = r
|
||||
|
||||
b.markFieldAsDirty(blockRoots)
|
||||
b.addDirtyIndices(blockRoots, []uint64{idx})
|
||||
b.markFieldAsDirty(nativetypes.BlockRoots)
|
||||
b.addDirtyIndices(nativetypes.BlockRoots, []uint64{idx})
|
||||
return nil
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package v2
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -11,7 +12,7 @@ func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.justificationBits = val
|
||||
b.markFieldAsDirty(justificationBits)
|
||||
b.markFieldAsDirty(nativetypes.JustificationBits)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,7 +22,7 @@ func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) erro
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.previousJustifiedCheckpoint = val
|
||||
b.markFieldAsDirty(previousJustifiedCheckpoint)
|
||||
b.markFieldAsDirty(nativetypes.PreviousJustifiedCheckpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -31,7 +32,7 @@ func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.currentJustifiedCheckpoint = val
|
||||
b.markFieldAsDirty(currentJustifiedCheckpoint)
|
||||
b.markFieldAsDirty(nativetypes.CurrentJustifiedCheckpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,6 +42,6 @@ func (b *BeaconState) SetFinalizedCheckpoint(val *ethpb.Checkpoint) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.finalizedCheckpoint = val
|
||||
b.markFieldAsDirty(finalizedCheckpoint)
|
||||
b.markFieldAsDirty(nativetypes.FinalizedCheckpoint)
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
@@ -11,7 +12,7 @@ func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.eth1Data = val
|
||||
b.markFieldAsDirty(eth1Data)
|
||||
b.markFieldAsDirty(nativetypes.Eth1Data)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,12 +22,12 @@ func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[eth1DataVotes].MinusRef()
|
||||
b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Eth1DataVotes].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Eth1DataVotes] = stateutil.NewRef(1)
|
||||
|
||||
b.eth1DataVotes = val
|
||||
b.markFieldAsDirty(eth1DataVotes)
|
||||
b.rebuildTrie[eth1DataVotes] = true
|
||||
b.markFieldAsDirty(nativetypes.Eth1DataVotes)
|
||||
b.rebuildTrie[nativetypes.Eth1DataVotes] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,7 +37,7 @@ func (b *BeaconState) SetEth1DepositIndex(val uint64) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.eth1DepositIndex = val
|
||||
b.markFieldAsDirty(eth1DepositIndex)
|
||||
b.markFieldAsDirty(nativetypes.Eth1DepositIndex)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -47,16 +48,16 @@ func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
votes := b.eth1DataVotes
|
||||
if b.sharedFieldReferences[eth1DataVotes].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.Eth1DataVotes].Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
votes = make([]*ethpb.Eth1Data, len(b.eth1DataVotes))
|
||||
copy(votes, b.eth1DataVotes)
|
||||
b.sharedFieldReferences[eth1DataVotes].MinusRef()
|
||||
b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Eth1DataVotes].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Eth1DataVotes] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.eth1DataVotes = append(votes, val)
|
||||
b.markFieldAsDirty(eth1DataVotes)
|
||||
b.addDirtyIndices(eth1DataVotes, []uint64{uint64(len(b.eth1DataVotes) - 1)})
|
||||
b.markFieldAsDirty(nativetypes.Eth1DataVotes)
|
||||
b.addDirtyIndices(nativetypes.Eth1DataVotes, []uint64{uint64(len(b.eth1DataVotes) - 1)})
|
||||
return nil
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
stateTypes "github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/crypto/hash"
|
||||
@@ -47,7 +47,7 @@ func (b *BeaconState) SetGenesisTime(val uint64) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.genesisTime = val
|
||||
b.markFieldAsDirty(genesisTime)
|
||||
b.markFieldAsDirty(nativetypes.GenesisTime)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func (b *BeaconState) SetGenesisValidatorsRoot(val []byte) error {
|
||||
return errors.New("incorrect validators root length")
|
||||
}
|
||||
b.genesisValidatorsRoot = bytesutil.ToBytes32(val)
|
||||
b.markFieldAsDirty(genesisValidatorsRoot)
|
||||
b.markFieldAsDirty(nativetypes.GenesisValidatorsRoot)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (b *BeaconState) SetSlot(val types.Slot) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.slot = val
|
||||
b.markFieldAsDirty(slot)
|
||||
b.markFieldAsDirty(nativetypes.Slot)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ func (b *BeaconState) SetFork(val *ethpb.Fork) error {
|
||||
return errors.New("proto.Clone did not return a fork proto")
|
||||
}
|
||||
b.fork = fk
|
||||
b.markFieldAsDirty(fork)
|
||||
b.markFieldAsDirty(nativetypes.Fork)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -94,15 +94,15 @@ func (b *BeaconState) SetHistoricalRoots(val [][]byte) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[historicalRoots].MinusRef()
|
||||
b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.HistoricalRoots].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
|
||||
|
||||
roots := make([][32]byte, len(val))
|
||||
for i, r := range val {
|
||||
copy(roots[i][:], r)
|
||||
}
|
||||
b.historicalRoots = roots
|
||||
b.markFieldAsDirty(historicalRoots)
|
||||
b.markFieldAsDirty(nativetypes.HistoricalRoots)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -113,15 +113,15 @@ func (b *BeaconState) AppendHistoricalRoots(root [32]byte) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
roots := b.historicalRoots
|
||||
if b.sharedFieldReferences[historicalRoots].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.HistoricalRoots].Refs() > 1 {
|
||||
roots = make([][32]byte, len(b.historicalRoots))
|
||||
copy(roots, b.historicalRoots)
|
||||
b.sharedFieldReferences[historicalRoots].MinusRef()
|
||||
b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.HistoricalRoots].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.historicalRoots = append(roots, root)
|
||||
b.markFieldAsDirty(historicalRoots)
|
||||
b.markFieldAsDirty(nativetypes.HistoricalRoots)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -160,18 +160,18 @@ func (b *BeaconState) recomputeRoot(idx int) {
|
||||
b.merkleLayers = layers
|
||||
}
|
||||
|
||||
func (b *BeaconState) markFieldAsDirty(field stateTypes.FieldIndex) {
|
||||
func (b *BeaconState) markFieldAsDirty(field nativetypes.FieldIndex) {
|
||||
b.dirtyFields[field] = true
|
||||
}
|
||||
|
||||
// addDirtyIndices adds the relevant dirty field indices, so that they
|
||||
// can be recomputed.
|
||||
func (b *BeaconState) addDirtyIndices(index stateTypes.FieldIndex, indices []uint64) {
|
||||
func (b *BeaconState) addDirtyIndices(index nativetypes.FieldIndex, indices []uint64) {
|
||||
if b.rebuildTrie[index] {
|
||||
return
|
||||
}
|
||||
// Exit early if balance trie computation isn't enabled.
|
||||
if !features.Get().EnableBalanceTrieComputation && index == balances {
|
||||
if !features.Get().EnableBalanceTrieComputation && index == nativetypes.Balances {
|
||||
return
|
||||
}
|
||||
totalIndicesLen := len(b.dirtyIndices[index]) + len(indices)
|
||||
@@ -1,6 +1,7 @@
|
||||
package v2
|
||||
package state_native
|
||||
|
||||
import (
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
)
|
||||
|
||||
@@ -10,12 +11,12 @@ func (b *BeaconState) SetPreviousParticipationBits(val []byte) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[previousEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[previousEpochParticipationBits] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1)
|
||||
|
||||
b.previousEpochParticipation = val
|
||||
b.markFieldAsDirty(previousEpochParticipationBits)
|
||||
b.rebuildTrie[previousEpochParticipationBits] = true
|
||||
b.markFieldAsDirty(nativetypes.PreviousEpochParticipationBits)
|
||||
b.rebuildTrie[nativetypes.PreviousEpochParticipationBits] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,12 +26,12 @@ func (b *BeaconState) SetCurrentParticipationBits(val []byte) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[currentEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[currentEpochParticipationBits] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
|
||||
|
||||
b.currentEpochParticipation = val
|
||||
b.markFieldAsDirty(currentEpochParticipationBits)
|
||||
b.rebuildTrie[currentEpochParticipationBits] = true
|
||||
b.markFieldAsDirty(nativetypes.CurrentEpochParticipationBits)
|
||||
b.rebuildTrie[nativetypes.CurrentEpochParticipationBits] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,17 +42,17 @@ func (b *BeaconState) AppendCurrentParticipationBits(val byte) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
participation := b.currentEpochParticipation
|
||||
if b.sharedFieldReferences[currentEpochParticipationBits].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
participation = make([]byte, len(b.currentEpochParticipation))
|
||||
copy(participation, b.currentEpochParticipation)
|
||||
b.sharedFieldReferences[currentEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[currentEpochParticipationBits] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.currentEpochParticipation = append(participation, val)
|
||||
b.markFieldAsDirty(currentEpochParticipationBits)
|
||||
b.addDirtyIndices(currentEpochParticipationBits, []uint64{uint64(len(b.currentEpochParticipation) - 1)})
|
||||
b.markFieldAsDirty(nativetypes.CurrentEpochParticipationBits)
|
||||
b.addDirtyIndices(nativetypes.CurrentEpochParticipationBits, []uint64{uint64(len(b.currentEpochParticipation) - 1)})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -62,16 +63,16 @@ func (b *BeaconState) AppendPreviousParticipationBits(val byte) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
bits := b.previousEpochParticipation
|
||||
if b.sharedFieldReferences[previousEpochParticipationBits].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].Refs() > 1 {
|
||||
bits = make([]byte, len(b.previousEpochParticipation))
|
||||
copy(bits, b.previousEpochParticipation)
|
||||
b.sharedFieldReferences[previousEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[previousEpochParticipationBits] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.previousEpochParticipation = append(bits, val)
|
||||
b.markFieldAsDirty(previousEpochParticipationBits)
|
||||
b.addDirtyIndices(previousEpochParticipationBits, []uint64{uint64(len(b.previousEpochParticipation) - 1)})
|
||||
b.markFieldAsDirty(nativetypes.PreviousEpochParticipationBits)
|
||||
b.addDirtyIndices(nativetypes.PreviousEpochParticipationBits, []uint64{uint64(len(b.previousEpochParticipation) - 1)})
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -82,12 +83,12 @@ func (b *BeaconState) ModifyPreviousParticipationBits(mutator func(val []byte) (
|
||||
b.lock.Lock()
|
||||
|
||||
participation := b.previousEpochParticipation
|
||||
if b.sharedFieldReferences[previousEpochParticipationBits].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
participation = make([]byte, len(b.previousEpochParticipation))
|
||||
copy(participation, b.previousEpochParticipation)
|
||||
b.sharedFieldReferences[previousEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[previousEpochParticipationBits] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1)
|
||||
}
|
||||
// Lock is released so that mutator can
|
||||
// acquire it.
|
||||
@@ -101,8 +102,8 @@ func (b *BeaconState) ModifyPreviousParticipationBits(mutator func(val []byte) (
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
b.previousEpochParticipation = participation
|
||||
b.markFieldAsDirty(previousEpochParticipationBits)
|
||||
b.rebuildTrie[previousEpochParticipationBits] = true
|
||||
b.markFieldAsDirty(nativetypes.PreviousEpochParticipationBits)
|
||||
b.rebuildTrie[nativetypes.PreviousEpochParticipationBits] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -112,12 +113,12 @@ func (b *BeaconState) ModifyCurrentParticipationBits(mutator func(val []byte) ([
|
||||
b.lock.Lock()
|
||||
|
||||
participation := b.currentEpochParticipation
|
||||
if b.sharedFieldReferences[currentEpochParticipationBits].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
participation = make([]byte, len(b.currentEpochParticipation))
|
||||
copy(participation, b.currentEpochParticipation)
|
||||
b.sharedFieldReferences[currentEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[currentEpochParticipationBits] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
|
||||
}
|
||||
// Lock is released so that mutator can
|
||||
// acquire it.
|
||||
@@ -131,7 +132,7 @@ func (b *BeaconState) ModifyCurrentParticipationBits(mutator func(val []byte) ([
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
b.currentEpochParticipation = participation
|
||||
b.markFieldAsDirty(currentEpochParticipationBits)
|
||||
b.rebuildTrie[currentEpochParticipationBits] = true
|
||||
b.markFieldAsDirty(nativetypes.CurrentEpochParticipationBits)
|
||||
b.rebuildTrie[nativetypes.CurrentEpochParticipationBits] = true
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
import (
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// SetLatestExecutionPayloadHeader for the beacon state.
|
||||
func (b *BeaconState) SetLatestExecutionPayloadHeader(val *ethpb.ExecutionPayloadHeader) error {
|
||||
@@ -8,6 +11,6 @@ func (b *BeaconState) SetLatestExecutionPayloadHeader(val *ethpb.ExecutionPayloa
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.latestExecutionPayloadHeader = val
|
||||
b.markFieldAsDirty(latestExecutionPayloadHeader)
|
||||
b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeader)
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
@@ -14,8 +15,8 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[randaoMixes].MinusRef()
|
||||
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.RandaoMixes].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.RandaoMixes] = stateutil.NewRef(1)
|
||||
|
||||
var mixesArr [fieldparams.RandaoMixesLength][32]byte
|
||||
for i := 0; i < len(mixesArr); i++ {
|
||||
@@ -23,8 +24,8 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
|
||||
}
|
||||
mixes := customtypes.RandaoMixes(mixesArr)
|
||||
b.randaoMixes = &mixes
|
||||
b.markFieldAsDirty(randaoMixes)
|
||||
b.rebuildTrie[randaoMixes] = true
|
||||
b.markFieldAsDirty(nativetypes.RandaoMixes)
|
||||
b.rebuildTrie[nativetypes.RandaoMixes] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,19 +39,19 @@ func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val []byte) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
mixes := b.randaoMixes
|
||||
if refs := b.sharedFieldReferences[randaoMixes].Refs(); refs > 1 {
|
||||
if refs := b.sharedFieldReferences[nativetypes.RandaoMixes].Refs(); refs > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
m := *b.randaoMixes
|
||||
mCopy := m
|
||||
mixes = &mCopy
|
||||
b.sharedFieldReferences[randaoMixes].MinusRef()
|
||||
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.RandaoMixes].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.RandaoMixes] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
mixes[idx] = bytesutil.ToBytes32(val)
|
||||
b.randaoMixes = mixes
|
||||
b.markFieldAsDirty(randaoMixes)
|
||||
b.addDirtyIndices(randaoMixes, []uint64{idx})
|
||||
b.markFieldAsDirty(nativetypes.RandaoMixes)
|
||||
b.addDirtyIndices(nativetypes.RandaoMixes, []uint64{idx})
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package v1
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
)
|
||||
@@ -13,8 +14,8 @@ func (b *BeaconState) SetStateRoots(val [][]byte) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[stateRoots].MinusRef()
|
||||
b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.StateRoots].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.StateRoots] = stateutil.NewRef(1)
|
||||
|
||||
var rootsArr [fieldparams.StateRootsLength][32]byte
|
||||
for i := 0; i < len(rootsArr); i++ {
|
||||
@@ -22,8 +23,8 @@ func (b *BeaconState) SetStateRoots(val [][]byte) error {
|
||||
}
|
||||
roots := customtypes.StateRoots(rootsArr)
|
||||
b.stateRoots = &roots
|
||||
b.markFieldAsDirty(stateRoots)
|
||||
b.rebuildTrie[stateRoots] = true
|
||||
b.markFieldAsDirty(nativetypes.StateRoots)
|
||||
b.rebuildTrie[nativetypes.StateRoots] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -42,19 +43,19 @@ func (b *BeaconState) UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) err
|
||||
|
||||
// Check if we hold the only reference to the shared state roots slice.
|
||||
r := b.stateRoots
|
||||
if ref := b.sharedFieldReferences[stateRoots]; ref.Refs() > 1 {
|
||||
if ref := b.sharedFieldReferences[nativetypes.StateRoots]; ref.Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
roots := *b.stateRoots
|
||||
rootsCopy := roots
|
||||
r = &rootsCopy
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.StateRoots] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
r[idx] = stateRoot
|
||||
b.stateRoots = r
|
||||
|
||||
b.markFieldAsDirty(stateRoots)
|
||||
b.addDirtyIndices(stateRoots, []uint64{idx})
|
||||
b.markFieldAsDirty(nativetypes.StateRoots)
|
||||
b.addDirtyIndices(nativetypes.StateRoots, []uint64{idx})
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
@@ -10,7 +11,7 @@ func (b *BeaconState) SetCurrentSyncCommittee(val *ethpb.SyncCommittee) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.currentSyncCommittee = val
|
||||
b.markFieldAsDirty(currentSyncCommittee)
|
||||
b.markFieldAsDirty(nativetypes.CurrentSyncCommittee)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,6 +21,6 @@ func (b *BeaconState) SetNextSyncCommittee(val *ethpb.SyncCommittee) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.nextSyncCommittee = val
|
||||
b.markFieldAsDirty(nextSyncCommittee)
|
||||
b.markFieldAsDirty(nativetypes.NextSyncCommittee)
|
||||
return nil
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package v3
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -15,10 +16,10 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.validators = val
|
||||
b.sharedFieldReferences[validators].MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
b.markFieldAsDirty(validators)
|
||||
b.rebuildTrie[validators] = true
|
||||
b.sharedFieldReferences[nativetypes.Validators].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
|
||||
b.markFieldAsDirty(nativetypes.Validators)
|
||||
b.rebuildTrie[nativetypes.Validators] = true
|
||||
b.valMapHandler = stateutil.NewValMapHandler(b.validators)
|
||||
return nil
|
||||
}
|
||||
@@ -28,10 +29,10 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
|
||||
func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error)) error {
|
||||
b.lock.Lock()
|
||||
v := b.validators
|
||||
if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 {
|
||||
if ref := b.sharedFieldReferences[nativetypes.Validators]; ref.Refs() > 1 {
|
||||
v = b.validatorsReferences()
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
|
||||
}
|
||||
b.lock.Unlock()
|
||||
var changedVals []uint64
|
||||
@@ -50,8 +51,8 @@ func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.validators = v
|
||||
b.markFieldAsDirty(validators)
|
||||
b.addDirtyIndices(validators, changedVals)
|
||||
b.markFieldAsDirty(nativetypes.Validators)
|
||||
b.addDirtyIndices(nativetypes.Validators, changedVals)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -66,16 +67,16 @@ func (b *BeaconState) UpdateValidatorAtIndex(idx types.ValidatorIndex, val *ethp
|
||||
defer b.lock.Unlock()
|
||||
|
||||
v := b.validators
|
||||
if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 {
|
||||
if ref := b.sharedFieldReferences[nativetypes.Validators]; ref.Refs() > 1 {
|
||||
v = b.validatorsReferences()
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
v[idx] = val
|
||||
b.validators = v
|
||||
b.markFieldAsDirty(validators)
|
||||
b.addDirtyIndices(validators, []uint64{uint64(idx)})
|
||||
b.markFieldAsDirty(nativetypes.Validators)
|
||||
b.addDirtyIndices(nativetypes.Validators, []uint64{uint64(idx)})
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -86,12 +87,12 @@ func (b *BeaconState) SetBalances(val []uint64) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[balances].MinusRef()
|
||||
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Balances].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
|
||||
|
||||
b.balances = val
|
||||
b.markFieldAsDirty(balances)
|
||||
b.rebuildTrie[balances] = true
|
||||
b.markFieldAsDirty(nativetypes.Balances)
|
||||
b.rebuildTrie[nativetypes.Balances] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -105,16 +106,16 @@ func (b *BeaconState) UpdateBalancesAtIndex(idx types.ValidatorIndex, val uint64
|
||||
defer b.lock.Unlock()
|
||||
|
||||
bals := b.balances
|
||||
if b.sharedFieldReferences[balances].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.Balances].Refs() > 1 {
|
||||
bals = b.balancesVal()
|
||||
b.sharedFieldReferences[balances].MinusRef()
|
||||
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Balances].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
bals[idx] = val
|
||||
b.balances = bals
|
||||
b.markFieldAsDirty(balances)
|
||||
b.addDirtyIndices(balances, []uint64{uint64(idx)})
|
||||
b.markFieldAsDirty(nativetypes.Balances)
|
||||
b.addDirtyIndices(nativetypes.Balances, []uint64{uint64(idx)})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -124,11 +125,11 @@ func (b *BeaconState) SetSlashings(val []uint64) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[slashings].MinusRef()
|
||||
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Slashings].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Slashings] = stateutil.NewRef(1)
|
||||
|
||||
b.slashings = val
|
||||
b.markFieldAsDirty(slashings)
|
||||
b.markFieldAsDirty(nativetypes.Slashings)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -142,17 +143,17 @@ func (b *BeaconState) UpdateSlashingsAtIndex(idx, val uint64) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
s := b.slashings
|
||||
if b.sharedFieldReferences[slashings].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.Slashings].Refs() > 1 {
|
||||
s = b.slashingsVal()
|
||||
b.sharedFieldReferences[slashings].MinusRef()
|
||||
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Slashings].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Slashings] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
s[idx] = val
|
||||
|
||||
b.slashings = s
|
||||
|
||||
b.markFieldAsDirty(slashings)
|
||||
b.markFieldAsDirty(nativetypes.Slashings)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -163,10 +164,10 @@ func (b *BeaconState) AppendValidator(val *ethpb.Validator) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
vals := b.validators
|
||||
if b.sharedFieldReferences[validators].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.Validators].Refs() > 1 {
|
||||
vals = b.validatorsReferences()
|
||||
b.sharedFieldReferences[validators].MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Validators].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
// append validator to slice
|
||||
@@ -175,8 +176,8 @@ func (b *BeaconState) AppendValidator(val *ethpb.Validator) error {
|
||||
|
||||
b.valMapHandler.Set(bytesutil.ToBytes48(val.PublicKey), valIdx)
|
||||
|
||||
b.markFieldAsDirty(validators)
|
||||
b.addDirtyIndices(validators, []uint64{uint64(valIdx)})
|
||||
b.markFieldAsDirty(nativetypes.Validators)
|
||||
b.addDirtyIndices(nativetypes.Validators, []uint64{uint64(valIdx)})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -187,16 +188,16 @@ func (b *BeaconState) AppendBalance(bal uint64) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
bals := b.balances
|
||||
if b.sharedFieldReferences[balances].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.Balances].Refs() > 1 {
|
||||
bals = b.balancesVal()
|
||||
b.sharedFieldReferences[balances].MinusRef()
|
||||
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.Balances].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.balances = append(bals, bal)
|
||||
balIdx := len(b.balances) - 1
|
||||
b.markFieldAsDirty(balances)
|
||||
b.addDirtyIndices(balances, []uint64{uint64(balIdx)})
|
||||
b.markFieldAsDirty(nativetypes.Balances)
|
||||
b.addDirtyIndices(nativetypes.Balances, []uint64{uint64(balIdx)})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -206,14 +207,14 @@ func (b *BeaconState) AppendInactivityScore(s uint64) error {
|
||||
defer b.lock.Unlock()
|
||||
|
||||
scores := b.inactivityScores
|
||||
if b.sharedFieldReferences[inactivityScores].Refs() > 1 {
|
||||
if b.sharedFieldReferences[nativetypes.InactivityScores].Refs() > 1 {
|
||||
scores = b.inactivityScoresVal()
|
||||
b.sharedFieldReferences[inactivityScores].MinusRef()
|
||||
b.sharedFieldReferences[inactivityScores] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.InactivityScores].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.InactivityScores] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.inactivityScores = append(scores, s)
|
||||
b.markFieldAsDirty(inactivityScores)
|
||||
b.markFieldAsDirty(nativetypes.InactivityScores)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -223,10 +224,10 @@ func (b *BeaconState) SetInactivityScores(val []uint64) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[inactivityScores].MinusRef()
|
||||
b.sharedFieldReferences[inactivityScores] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.InactivityScores].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.InactivityScores] = stateutil.NewRef(1)
|
||||
|
||||
b.inactivityScores = val
|
||||
b.markFieldAsDirty(inactivityScores)
|
||||
b.markFieldAsDirty(nativetypes.InactivityScores)
|
||||
return nil
|
||||
}
|
||||
36
beacon-chain/state/state-native/ssz.go
Normal file
36
beacon-chain/state/state-native/ssz.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
)
|
||||
|
||||
var errAssertionFailed = errors.New("failed to convert interface to proto state")
|
||||
var errUnsupportedVersion = errors.New("unsupported beacon state version")
|
||||
|
||||
func (b *BeaconState) MarshalSSZ() ([]byte, error) {
|
||||
proto := b.ToProto()
|
||||
switch b.Version() {
|
||||
case version.Phase0:
|
||||
s, ok := proto.(*ethpb.BeaconState)
|
||||
if !ok {
|
||||
return nil, errAssertionFailed
|
||||
}
|
||||
return s.MarshalSSZ()
|
||||
case version.Altair:
|
||||
s, ok := proto.(*ethpb.BeaconStateAltair)
|
||||
if !ok {
|
||||
return nil, errAssertionFailed
|
||||
}
|
||||
return s.MarshalSSZ()
|
||||
case version.Bellatrix:
|
||||
s, ok := proto.(*ethpb.BeaconStateBellatrix)
|
||||
if !ok {
|
||||
return nil, errAssertionFailed
|
||||
}
|
||||
return s.MarshalSSZ()
|
||||
default:
|
||||
return nil, errUnsupportedVersion
|
||||
}
|
||||
}
|
||||
1064
beacon-chain/state/state-native/state_trie.go
Normal file
1064
beacon-chain/state/state-native/state_trie.go
Normal file
File diff suppressed because it is too large
Load Diff
29
beacon-chain/state/state-native/types.go
Normal file
29
beacon-chain/state/state-native/types.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
)
|
||||
|
||||
// Ensure type BeaconState below implements BeaconState interface.
|
||||
var _ state.BeaconState = (*BeaconState)(nil)
|
||||
|
||||
func init() {
|
||||
fieldMap = make(map[nativetypes.FieldIndex]types.DataType)
|
||||
// Initialize the fixed sized arrays.
|
||||
fieldMap[nativetypes.BlockRoots] = types.BasicArray
|
||||
fieldMap[nativetypes.StateRoots] = types.BasicArray
|
||||
fieldMap[nativetypes.RandaoMixes] = types.BasicArray
|
||||
|
||||
// Initialize the composite arrays.
|
||||
fieldMap[nativetypes.Eth1DataVotes] = types.CompositeArray
|
||||
fieldMap[nativetypes.Validators] = types.CompositeArray
|
||||
fieldMap[nativetypes.PreviousEpochAttestations] = types.CompositeArray
|
||||
fieldMap[nativetypes.CurrentEpochAttestations] = types.CompositeArray
|
||||
fieldMap[nativetypes.Balances] = types.CompressedArray
|
||||
}
|
||||
|
||||
// fieldMap keeps track of each field
|
||||
// to its corresponding data type.
|
||||
var fieldMap map[nativetypes.FieldIndex]types.DataType
|
||||
9
beacon-chain/state/state-native/types/BUILD.bazel
Normal file
9
beacon-chain/state/state-native/types/BUILD.bazel
Normal file
@@ -0,0 +1,9 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["types.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@com_github_pkg_errors//:go_default_library"],
|
||||
)
|
||||
124
beacon-chain/state/state-native/types/types.go
Normal file
124
beacon-chain/state/state-native/types/types.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// FieldIndex represents the relevant field position in the
|
||||
// state struct for a field.
|
||||
type FieldIndex int
|
||||
|
||||
// String returns the name of the field index.
|
||||
func (f FieldIndex) String(stateVersion int) string {
|
||||
switch f {
|
||||
case GenesisTime:
|
||||
return "genesisTime"
|
||||
case GenesisValidatorsRoot:
|
||||
return "genesisValidatorsRoot"
|
||||
case Slot:
|
||||
return "slot"
|
||||
case Fork:
|
||||
return "fork"
|
||||
case LatestBlockHeader:
|
||||
return "latestBlockHeader"
|
||||
case BlockRoots:
|
||||
return "blockRoots"
|
||||
case StateRoots:
|
||||
return "stateRoots"
|
||||
case HistoricalRoots:
|
||||
return "historicalRoots"
|
||||
case Eth1Data:
|
||||
return "eth1Data"
|
||||
case Eth1DataVotes:
|
||||
return "eth1DataVotes"
|
||||
case Eth1DepositIndex:
|
||||
return "eth1DepositIndex"
|
||||
case Validators:
|
||||
return "validators"
|
||||
case Balances:
|
||||
return "balances"
|
||||
case RandaoMixes:
|
||||
return "randaoMixes"
|
||||
case Slashings:
|
||||
return "slashings"
|
||||
case PreviousEpochAttestations:
|
||||
return "previousEpochAttestations"
|
||||
case CurrentEpochAttestations:
|
||||
return "currentEpochAttestations"
|
||||
case PreviousEpochParticipationBits:
|
||||
return "previousEpochParticipationBits"
|
||||
case CurrentEpochParticipationBits:
|
||||
return "currentEpochParticipationBits"
|
||||
case JustificationBits:
|
||||
return "justificationBits"
|
||||
case PreviousJustifiedCheckpoint:
|
||||
return "previousJustifiedCheckpoint"
|
||||
case CurrentJustifiedCheckpoint:
|
||||
return "currentJustifiedCheckpoint"
|
||||
case FinalizedCheckpoint:
|
||||
return "finalizedCheckpoint"
|
||||
case InactivityScores:
|
||||
return "inactivityScores"
|
||||
case CurrentSyncCommittee:
|
||||
return "currentSyncCommittee"
|
||||
case NextSyncCommittee:
|
||||
return "nextSyncCommittee"
|
||||
case LatestExecutionPayloadHeader:
|
||||
return "latestExecutionPayloadHeader"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// ElemsInChunk returns the number of elements in the chunk (number of
|
||||
// elements that are able to be packed).
|
||||
func (f FieldIndex) ElemsInChunk() (uint64, error) {
|
||||
switch f {
|
||||
case Balances:
|
||||
return 4, nil
|
||||
default:
|
||||
return 0, errors.Errorf("field %d doesn't support element compression", f)
|
||||
}
|
||||
}
|
||||
|
||||
func (f FieldIndex) Native() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Below we define a set of useful enum values for the field
|
||||
// indices of the beacon state. For example, genesisTime is the
|
||||
// 0th field of the beacon state. This is helpful when we are
|
||||
// updating the Merkle branches up the trie representation
|
||||
// of the beacon state. The below field indexes correspond
|
||||
// to the v1 state.
|
||||
const (
|
||||
GenesisTime FieldIndex = iota
|
||||
GenesisValidatorsRoot
|
||||
Slot
|
||||
Fork
|
||||
LatestBlockHeader
|
||||
BlockRoots
|
||||
StateRoots
|
||||
HistoricalRoots
|
||||
Eth1Data
|
||||
Eth1DataVotes
|
||||
Eth1DepositIndex
|
||||
Validators
|
||||
Balances
|
||||
RandaoMixes
|
||||
Slashings
|
||||
PreviousEpochAttestations
|
||||
CurrentEpochAttestations
|
||||
PreviousEpochParticipationBits
|
||||
CurrentEpochParticipationBits
|
||||
JustificationBits
|
||||
PreviousJustifiedCheckpoint
|
||||
CurrentJustifiedCheckpoint
|
||||
FinalizedCheckpoint
|
||||
// State Fields Added in Altair.
|
||||
InactivityScores
|
||||
CurrentSyncCommittee
|
||||
NextSyncCommittee
|
||||
// State fields added in Bellatrix.
|
||||
LatestExecutionPayloadHeader
|
||||
)
|
||||
@@ -1,134 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
load("//proto:ssz_proto_library.bzl", "ssz_proto_files")
|
||||
load("//tools:ssz.bzl", "SSZ_DEPS", "ssz_gen_marshal")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"field_roots.go",
|
||||
"getters_attestation.go",
|
||||
"getters_block.go",
|
||||
"getters_checkpoint.go",
|
||||
"getters_eth1.go",
|
||||
"getters_misc.go",
|
||||
"getters_randao.go",
|
||||
"getters_state.go",
|
||||
"getters_validator.go",
|
||||
"proofs.go",
|
||||
"readonly_validator.go",
|
||||
"setters_attestation.go",
|
||||
"setters_block.go",
|
||||
"setters_checkpoint.go",
|
||||
"setters_eth1.go",
|
||||
"setters_misc.go",
|
||||
"setters_randao.go",
|
||||
"setters_state.go",
|
||||
"setters_validator.go",
|
||||
"state_trie.go",
|
||||
"types.go",
|
||||
"unsupported_getters.go",
|
||||
"unsupported_setters.go",
|
||||
":ssz_generated_files", # keep
|
||||
] + select({
|
||||
"//config:mainnet": ["beacon_state_mainnet.go"],
|
||||
"//config:minimal": ["beacon_state_minimal.go"],
|
||||
}),
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//contracts/deposit:__subpackages__",
|
||||
"//proto/migration:__subpackages__",
|
||||
"//proto/prysm/v1alpha1:__subpackages__",
|
||||
"//proto/testing:__subpackages__",
|
||||
"//runtime/interop:__subpackages__",
|
||||
"//slasher/rpc:__subpackages__",
|
||||
"//testing/benchmark:__pkg__",
|
||||
"//testing/fuzz:__pkg__",
|
||||
"//testing/spectest:__subpackages__",
|
||||
"//testing/util:__pkg__",
|
||||
"//tools/benchmark-files-gen:__pkg__",
|
||||
"//tools/pcli:__pkg__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/fieldtrie:go_default_library",
|
||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//container/slice:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_ferranbt_fastssz//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
# gazelle:exclude types_bench_test.go
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"getters_attestation_test.go",
|
||||
"getters_block_test.go",
|
||||
"getters_test.go",
|
||||
"getters_validator_test.go",
|
||||
"proofs_test.go",
|
||||
"readonly_validator_test.go",
|
||||
"references_test.go",
|
||||
"setters_attestation_test.go",
|
||||
"state_test.go",
|
||||
"state_trie_test.go",
|
||||
"types_test.go",
|
||||
] + select({
|
||||
"//config:mainnet": ["beacon_state_mainnet_test.go"],
|
||||
"//config:minimal": ["beacon_state_minimal_test.go"],
|
||||
}),
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//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",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//container/trie:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/interop:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
ssz_gen_marshal(
|
||||
name = "ssz_generated_files",
|
||||
srcs = select({
|
||||
"//config:mainnet": ["beacon_state_mainnet.go"],
|
||||
"//config:minimal": ["beacon_state_minimal.go"],
|
||||
}),
|
||||
includes = [
|
||||
"//beacon-chain/state/state-native/custom-types:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
],
|
||||
objs = [
|
||||
"BeaconState[no-htr]",
|
||||
],
|
||||
)
|
||||
@@ -1,51 +0,0 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
eth2types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
|
||||
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
|
||||
type BeaconState struct {
|
||||
genesisTime uint64 `ssz-gen:"true"`
|
||||
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
|
||||
slot eth2types.Slot `ssz-gen:"true"`
|
||||
fork *ethpb.Fork `ssz-gen:"true"`
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader `ssz-gen:"true"`
|
||||
blockRoots *customtypes.BlockRoots `ssz-gen:"true" ssz-size:"8192,32"`
|
||||
stateRoots *customtypes.StateRoots `ssz-gen:"true" ssz-size:"8192,32"`
|
||||
historicalRoots customtypes.HistoricalRoots `ssz-gen:"true" ssz-size:"?,32" ssz-max:"16777216"`
|
||||
eth1Data *ethpb.Eth1Data `ssz-gen:"true"`
|
||||
eth1DataVotes []*ethpb.Eth1Data `ssz-gen:"true" ssz-max:"2048"`
|
||||
eth1DepositIndex uint64 `ssz-gen:"true"`
|
||||
validators []*ethpb.Validator `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"65536,32"`
|
||||
slashings []uint64 `ssz-gen:"true" ssz-size:"8192"`
|
||||
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
|
||||
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
|
||||
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
|
||||
previousJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
finalizedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[types.FieldIndex]bool
|
||||
dirtyIndices map[types.FieldIndex][]uint64
|
||||
stateFieldLeaves map[types.FieldIndex]*fieldtrie.FieldTrie
|
||||
rebuildTrie map[types.FieldIndex]bool
|
||||
valMapHandler *stateutil.ValidatorMapHandler
|
||||
merkleLayers [][][]byte
|
||||
sharedFieldReferences map[types.FieldIndex]*stateutil.Reference
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
//go:build !minimal
|
||||
// +build !minimal
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestMainnetSszValuesAgainstFieldParams(t *testing.T) {
|
||||
// Casting needed to avoid lock copy analyzer issue.
|
||||
bs := (interface{})(BeaconState{})
|
||||
bsType := reflect.TypeOf(bs)
|
||||
|
||||
f, ok := bsType.FieldByName("genesisValidatorsRoot")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v := f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("blockRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.BlockRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("stateRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.StateRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("historicalRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "?,"+strconv.Itoa(fieldparams.RootLength), v)
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.HistoricalRootsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("eth1DataVotes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.Eth1DataVotesLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("validators")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("balances")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("randaoMixes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RandaoMixesLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("slashings")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.SlashingsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("previousEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.PreviousEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("currentEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.CurrentEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("justificationBits")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "1", v)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
eth2types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
|
||||
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
|
||||
type BeaconState struct {
|
||||
genesisTime uint64 `ssz-gen:"true"`
|
||||
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
|
||||
slot eth2types.Slot `ssz-gen:"true"`
|
||||
fork *ethpb.Fork `ssz-gen:"true"`
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader `ssz-gen:"true"`
|
||||
blockRoots *customtypes.BlockRoots `ssz-gen:"true" ssz-size:"64,32"`
|
||||
stateRoots *customtypes.StateRoots `ssz-gen:"true" ssz-size:"64,32"`
|
||||
historicalRoots customtypes.HistoricalRoots `ssz-gen:"true" ssz-size:"?,32" ssz-max:"16777216"`
|
||||
eth1Data *ethpb.Eth1Data `ssz-gen:"true"`
|
||||
eth1DataVotes []*ethpb.Eth1Data `ssz-gen:"true" ssz-max:"32"`
|
||||
eth1DepositIndex uint64 `ssz-gen:"true"`
|
||||
validators []*ethpb.Validator `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"64,32"`
|
||||
slashings []uint64 `ssz-gen:"true" ssz-size:"64"`
|
||||
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
|
||||
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
|
||||
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
|
||||
previousJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
finalizedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[types.FieldIndex]bool
|
||||
dirtyIndices map[types.FieldIndex][]uint64
|
||||
stateFieldLeaves map[types.FieldIndex]*fieldtrie.FieldTrie
|
||||
rebuildTrie map[types.FieldIndex]bool
|
||||
valMapHandler *stateutil.ValidatorMapHandler
|
||||
merkleLayers [][][]byte
|
||||
sharedFieldReferences map[types.FieldIndex]*stateutil.Reference
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
//go:build minimal
|
||||
// +build minimal
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestMinimalSszValuesAgainstFieldParams(t *testing.T) {
|
||||
// Casting needed to avoid lock copy analyzer issue.
|
||||
bs := (interface{})(BeaconState{})
|
||||
bsType := reflect.TypeOf(bs)
|
||||
|
||||
f, ok := bsType.FieldByName("genesisValidatorsRoot")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v := f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("blockRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.BlockRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("stateRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.StateRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("historicalRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "?,"+strconv.Itoa(fieldparams.RootLength), v)
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.HistoricalRootsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("eth1DataVotes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.Eth1DataVotesLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("validators")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("balances")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("randaoMixes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RandaoMixesLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("slashings")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.SlashingsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("previousEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.PreviousEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("currentEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.CurrentEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("justificationBits")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "1", v)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// computeFieldRoots returns the hash tree root computations of every field in
|
||||
// the beacon state as a list of 32 byte roots.
|
||||
func computeFieldRoots(ctx context.Context, state *ethpb.BeaconState) ([][]byte, error) {
|
||||
return stateutil.ComputeFieldRootsWithHasherPhase0(ctx, state)
|
||||
}
|
||||
@@ -1,493 +0,0 @@
|
||||
// Code generated by fastssz. DO NOT EDIT.
|
||||
// Hash: 2e923b42b8e4fcc278301da6506b212334a78169cb32c70e0d66a636435b8925
|
||||
package v1
|
||||
|
||||
import (
|
||||
ssz "github.com/ferranbt/fastssz"
|
||||
eth2types "github.com/prysmaticlabs/eth2-types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// MarshalSSZ ssz marshals the BeaconState object
|
||||
func (b *BeaconState) MarshalSSZ() ([]byte, error) {
|
||||
return ssz.MarshalSSZ(b)
|
||||
}
|
||||
|
||||
// MarshalSSZTo ssz marshals the BeaconState object to a target array
|
||||
func (b *BeaconState) MarshalSSZTo(buf []byte) (dst []byte, err error) {
|
||||
dst = buf
|
||||
offset := int(2687377)
|
||||
|
||||
// Field (0) 'genesisTime'
|
||||
dst = ssz.MarshalUint64(dst, b.genesisTime)
|
||||
|
||||
// Field (1) 'genesisValidatorsRoot'
|
||||
dst = append(dst, b.genesisValidatorsRoot[:]...)
|
||||
|
||||
// Field (2) 'slot'
|
||||
dst = ssz.MarshalUint64(dst, uint64(b.slot))
|
||||
|
||||
// Field (3) 'fork'
|
||||
if b.fork == nil {
|
||||
b.fork = new(ethpb.Fork)
|
||||
}
|
||||
if dst, err = b.fork.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (4) 'latestBlockHeader'
|
||||
if b.latestBlockHeader == nil {
|
||||
b.latestBlockHeader = new(ethpb.BeaconBlockHeader)
|
||||
}
|
||||
if dst, err = b.latestBlockHeader.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (5) 'blockRoots'
|
||||
for ii := 0; ii < 8192; ii++ {
|
||||
dst = append(dst, b.blockRoots[ii][:]...)
|
||||
}
|
||||
|
||||
// Field (6) 'stateRoots'
|
||||
for ii := 0; ii < 8192; ii++ {
|
||||
dst = append(dst, b.stateRoots[ii][:]...)
|
||||
}
|
||||
|
||||
// Offset (7) 'historicalRoots'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += len(b.historicalRoots) * 32
|
||||
|
||||
// Field (8) 'eth1Data'
|
||||
if b.eth1Data == nil {
|
||||
b.eth1Data = new(ethpb.Eth1Data)
|
||||
}
|
||||
if dst, err = b.eth1Data.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Offset (9) 'eth1DataVotes'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += len(b.eth1DataVotes) * 72
|
||||
|
||||
// Field (10) 'eth1DepositIndex'
|
||||
dst = ssz.MarshalUint64(dst, b.eth1DepositIndex)
|
||||
|
||||
// Offset (11) 'validators'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += len(b.validators) * 121
|
||||
|
||||
// Offset (12) 'balances'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += len(b.balances) * 8
|
||||
|
||||
// Field (13) 'randaoMixes'
|
||||
for ii := 0; ii < 65536; ii++ {
|
||||
dst = append(dst, b.randaoMixes[ii][:]...)
|
||||
}
|
||||
|
||||
// Field (14) 'slashings'
|
||||
if len(b.slashings) != 8192 {
|
||||
err = ssz.ErrVectorLength
|
||||
return
|
||||
}
|
||||
for ii := 0; ii < 8192; ii++ {
|
||||
dst = ssz.MarshalUint64(dst, b.slashings[ii])
|
||||
}
|
||||
|
||||
// Offset (15) 'previousEpochAttestations'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
for ii := 0; ii < len(b.previousEpochAttestations); ii++ {
|
||||
offset += 4
|
||||
offset += b.previousEpochAttestations[ii].SizeSSZ()
|
||||
}
|
||||
|
||||
// Offset (16) 'currentEpochAttestations'
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
for ii := 0; ii < len(b.currentEpochAttestations); ii++ {
|
||||
offset += 4
|
||||
offset += b.currentEpochAttestations[ii].SizeSSZ()
|
||||
}
|
||||
|
||||
// Field (17) 'justificationBits'
|
||||
if len(b.justificationBits) != 1 {
|
||||
err = ssz.ErrBytesLength
|
||||
return
|
||||
}
|
||||
dst = append(dst, b.justificationBits...)
|
||||
|
||||
// Field (18) 'previousJustifiedCheckpoint'
|
||||
if b.previousJustifiedCheckpoint == nil {
|
||||
b.previousJustifiedCheckpoint = new(ethpb.Checkpoint)
|
||||
}
|
||||
if dst, err = b.previousJustifiedCheckpoint.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (19) 'currentJustifiedCheckpoint'
|
||||
if b.currentJustifiedCheckpoint == nil {
|
||||
b.currentJustifiedCheckpoint = new(ethpb.Checkpoint)
|
||||
}
|
||||
if dst, err = b.currentJustifiedCheckpoint.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (20) 'finalizedCheckpoint'
|
||||
if b.finalizedCheckpoint == nil {
|
||||
b.finalizedCheckpoint = new(ethpb.Checkpoint)
|
||||
}
|
||||
if dst, err = b.finalizedCheckpoint.MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Field (7) 'historicalRoots'
|
||||
if len(b.historicalRoots) > 16777216 {
|
||||
err = ssz.ErrListTooBig
|
||||
return
|
||||
}
|
||||
for ii := 0; ii < len(b.historicalRoots); ii++ {
|
||||
dst = append(dst, b.historicalRoots[ii][:]...)
|
||||
}
|
||||
|
||||
// Field (9) 'eth1DataVotes'
|
||||
if len(b.eth1DataVotes) > 2048 {
|
||||
err = ssz.ErrListTooBig
|
||||
return
|
||||
}
|
||||
for ii := 0; ii < len(b.eth1DataVotes); ii++ {
|
||||
if dst, err = b.eth1DataVotes[ii].MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Field (11) 'validators'
|
||||
if len(b.validators) > 1099511627776 {
|
||||
err = ssz.ErrListTooBig
|
||||
return
|
||||
}
|
||||
for ii := 0; ii < len(b.validators); ii++ {
|
||||
if dst, err = b.validators[ii].MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Field (12) 'balances'
|
||||
if len(b.balances) > 1099511627776 {
|
||||
err = ssz.ErrListTooBig
|
||||
return
|
||||
}
|
||||
for ii := 0; ii < len(b.balances); ii++ {
|
||||
dst = ssz.MarshalUint64(dst, b.balances[ii])
|
||||
}
|
||||
|
||||
// Field (15) 'previousEpochAttestations'
|
||||
if len(b.previousEpochAttestations) > 4096 {
|
||||
err = ssz.ErrListTooBig
|
||||
return
|
||||
}
|
||||
{
|
||||
offset = 4 * len(b.previousEpochAttestations)
|
||||
for ii := 0; ii < len(b.previousEpochAttestations); ii++ {
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += b.previousEpochAttestations[ii].SizeSSZ()
|
||||
}
|
||||
}
|
||||
for ii := 0; ii < len(b.previousEpochAttestations); ii++ {
|
||||
if dst, err = b.previousEpochAttestations[ii].MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Field (16) 'currentEpochAttestations'
|
||||
if len(b.currentEpochAttestations) > 4096 {
|
||||
err = ssz.ErrListTooBig
|
||||
return
|
||||
}
|
||||
{
|
||||
offset = 4 * len(b.currentEpochAttestations)
|
||||
for ii := 0; ii < len(b.currentEpochAttestations); ii++ {
|
||||
dst = ssz.WriteOffset(dst, offset)
|
||||
offset += b.currentEpochAttestations[ii].SizeSSZ()
|
||||
}
|
||||
}
|
||||
for ii := 0; ii < len(b.currentEpochAttestations); ii++ {
|
||||
if dst, err = b.currentEpochAttestations[ii].MarshalSSZTo(dst); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// UnmarshalSSZ ssz unmarshals the BeaconState object
|
||||
func (b *BeaconState) UnmarshalSSZ(buf []byte) error {
|
||||
var err error
|
||||
size := uint64(len(buf))
|
||||
if size < 2687377 {
|
||||
return ssz.ErrSize
|
||||
}
|
||||
|
||||
tail := buf
|
||||
var o7, o9, o11, o12, o15, o16 uint64
|
||||
|
||||
// Field (0) 'genesisTime'
|
||||
b.genesisTime = ssz.UnmarshallUint64(buf[0:8])
|
||||
|
||||
// Field (1) 'genesisValidatorsRoot'
|
||||
copy(b.genesisValidatorsRoot[:], buf[8:40])
|
||||
|
||||
// Field (2) 'slot'
|
||||
b.slot = eth2types.Slot(ssz.UnmarshallUint64(buf[40:48]))
|
||||
|
||||
// Field (3) 'fork'
|
||||
if b.fork == nil {
|
||||
b.fork = new(ethpb.Fork)
|
||||
}
|
||||
if err = b.fork.UnmarshalSSZ(buf[48:64]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Field (4) 'latestBlockHeader'
|
||||
if b.latestBlockHeader == nil {
|
||||
b.latestBlockHeader = new(ethpb.BeaconBlockHeader)
|
||||
}
|
||||
if err = b.latestBlockHeader.UnmarshalSSZ(buf[64:176]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Field (5) 'blockRoots'
|
||||
|
||||
for ii := 0; ii < 8192; ii++ {
|
||||
copy(b.blockRoots[ii][:], buf[176:262320][ii*32:(ii+1)*32])
|
||||
}
|
||||
|
||||
// Field (6) 'stateRoots'
|
||||
|
||||
for ii := 0; ii < 8192; ii++ {
|
||||
copy(b.stateRoots[ii][:], buf[262320:524464][ii*32:(ii+1)*32])
|
||||
}
|
||||
|
||||
// Offset (7) 'historicalRoots'
|
||||
if o7 = ssz.ReadOffset(buf[524464:524468]); o7 > size {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
if o7 < 2687377 {
|
||||
return ssz.ErrInvalidVariableOffset
|
||||
}
|
||||
|
||||
// Field (8) 'eth1Data'
|
||||
if b.eth1Data == nil {
|
||||
b.eth1Data = new(ethpb.Eth1Data)
|
||||
}
|
||||
if err = b.eth1Data.UnmarshalSSZ(buf[524468:524540]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Offset (9) 'eth1DataVotes'
|
||||
if o9 = ssz.ReadOffset(buf[524540:524544]); o9 > size || o7 > o9 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Field (10) 'eth1DepositIndex'
|
||||
b.eth1DepositIndex = ssz.UnmarshallUint64(buf[524544:524552])
|
||||
|
||||
// Offset (11) 'validators'
|
||||
if o11 = ssz.ReadOffset(buf[524552:524556]); o11 > size || o9 > o11 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Offset (12) 'balances'
|
||||
if o12 = ssz.ReadOffset(buf[524556:524560]); o12 > size || o11 > o12 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Field (13) 'randaoMixes'
|
||||
|
||||
for ii := 0; ii < 65536; ii++ {
|
||||
copy(b.randaoMixes[ii][:], buf[524560:2621712][ii*32:(ii+1)*32])
|
||||
}
|
||||
|
||||
// Field (14) 'slashings'
|
||||
b.slashings = ssz.ExtendUint64(b.slashings, 8192)
|
||||
for ii := 0; ii < 8192; ii++ {
|
||||
b.slashings[ii] = ssz.UnmarshallUint64(buf[2621712:2687248][ii*8 : (ii+1)*8])
|
||||
}
|
||||
|
||||
// Offset (15) 'previousEpochAttestations'
|
||||
if o15 = ssz.ReadOffset(buf[2687248:2687252]); o15 > size || o12 > o15 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Offset (16) 'currentEpochAttestations'
|
||||
if o16 = ssz.ReadOffset(buf[2687252:2687256]); o16 > size || o15 > o16 {
|
||||
return ssz.ErrOffset
|
||||
}
|
||||
|
||||
// Field (17) 'justificationBits'
|
||||
if cap(b.justificationBits) == 0 {
|
||||
b.justificationBits = make([]byte, 0, len(buf[2687256:2687257]))
|
||||
}
|
||||
b.justificationBits = append(b.justificationBits, buf[2687256:2687257]...)
|
||||
|
||||
// Field (18) 'previousJustifiedCheckpoint'
|
||||
if b.previousJustifiedCheckpoint == nil {
|
||||
b.previousJustifiedCheckpoint = new(ethpb.Checkpoint)
|
||||
}
|
||||
if err = b.previousJustifiedCheckpoint.UnmarshalSSZ(buf[2687257:2687297]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Field (19) 'currentJustifiedCheckpoint'
|
||||
if b.currentJustifiedCheckpoint == nil {
|
||||
b.currentJustifiedCheckpoint = new(ethpb.Checkpoint)
|
||||
}
|
||||
if err = b.currentJustifiedCheckpoint.UnmarshalSSZ(buf[2687297:2687337]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Field (20) 'finalizedCheckpoint'
|
||||
if b.finalizedCheckpoint == nil {
|
||||
b.finalizedCheckpoint = new(ethpb.Checkpoint)
|
||||
}
|
||||
if err = b.finalizedCheckpoint.UnmarshalSSZ(buf[2687337:2687377]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Field (7) 'historicalRoots'
|
||||
{
|
||||
buf = tail[o7:o9]
|
||||
num, err := ssz.DivideInt2(len(buf), 32, 16777216)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.historicalRoots = make([][32]byte, num)
|
||||
for ii := 0; ii < num; ii++ {
|
||||
copy(b.historicalRoots[ii][:], buf[ii*32:(ii+1)*32])
|
||||
}
|
||||
}
|
||||
|
||||
// Field (9) 'eth1DataVotes'
|
||||
{
|
||||
buf = tail[o9:o11]
|
||||
num, err := ssz.DivideInt2(len(buf), 72, 2048)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.eth1DataVotes = make([]*ethpb.Eth1Data, num)
|
||||
for ii := 0; ii < num; ii++ {
|
||||
if b.eth1DataVotes[ii] == nil {
|
||||
b.eth1DataVotes[ii] = new(ethpb.Eth1Data)
|
||||
}
|
||||
if err = b.eth1DataVotes[ii].UnmarshalSSZ(buf[ii*72 : (ii+1)*72]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Field (11) 'validators'
|
||||
{
|
||||
buf = tail[o11:o12]
|
||||
num, err := ssz.DivideInt2(len(buf), 121, 1099511627776)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.validators = make([]*ethpb.Validator, num)
|
||||
for ii := 0; ii < num; ii++ {
|
||||
if b.validators[ii] == nil {
|
||||
b.validators[ii] = new(ethpb.Validator)
|
||||
}
|
||||
if err = b.validators[ii].UnmarshalSSZ(buf[ii*121 : (ii+1)*121]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Field (12) 'balances'
|
||||
{
|
||||
buf = tail[o12:o15]
|
||||
num, err := ssz.DivideInt2(len(buf), 8, 1099511627776)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.balances = ssz.ExtendUint64(b.balances, num)
|
||||
for ii := 0; ii < num; ii++ {
|
||||
b.balances[ii] = ssz.UnmarshallUint64(buf[ii*8 : (ii+1)*8])
|
||||
}
|
||||
}
|
||||
|
||||
// Field (15) 'previousEpochAttestations'
|
||||
{
|
||||
buf = tail[o15:o16]
|
||||
num, err := ssz.DecodeDynamicLength(buf, 4096)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.previousEpochAttestations = make([]*ethpb.PendingAttestation, num)
|
||||
err = ssz.UnmarshalDynamic(buf, num, func(indx int, buf []byte) (err error) {
|
||||
if b.previousEpochAttestations[indx] == nil {
|
||||
b.previousEpochAttestations[indx] = new(ethpb.PendingAttestation)
|
||||
}
|
||||
if err = b.previousEpochAttestations[indx].UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Field (16) 'currentEpochAttestations'
|
||||
{
|
||||
buf = tail[o16:]
|
||||
num, err := ssz.DecodeDynamicLength(buf, 4096)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.currentEpochAttestations = make([]*ethpb.PendingAttestation, num)
|
||||
err = ssz.UnmarshalDynamic(buf, num, func(indx int, buf []byte) (err error) {
|
||||
if b.currentEpochAttestations[indx] == nil {
|
||||
b.currentEpochAttestations[indx] = new(ethpb.PendingAttestation)
|
||||
}
|
||||
if err = b.currentEpochAttestations[indx].UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SizeSSZ returns the ssz encoded size in bytes for the BeaconState object
|
||||
func (b *BeaconState) SizeSSZ() (size int) {
|
||||
size = 2687377
|
||||
|
||||
// Field (7) 'historicalRoots'
|
||||
size += len(b.historicalRoots) * 32
|
||||
|
||||
// Field (9) 'eth1DataVotes'
|
||||
size += len(b.eth1DataVotes) * 72
|
||||
|
||||
// Field (11) 'validators'
|
||||
size += len(b.validators) * 121
|
||||
|
||||
// Field (12) 'balances'
|
||||
size += len(b.balances) * 8
|
||||
|
||||
// Field (15) 'previousEpochAttestations'
|
||||
for ii := 0; ii < len(b.previousEpochAttestations); ii++ {
|
||||
size += 4
|
||||
size += b.previousEpochAttestations[ii].SizeSSZ()
|
||||
}
|
||||
|
||||
// Field (16) 'currentEpochAttestations'
|
||||
for ii := 0; ii < len(b.currentEpochAttestations); ii++ {
|
||||
size += 4
|
||||
size += b.currentEpochAttestations[ii].SizeSSZ()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_PreviousEpochAttestations(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
atts, err := s.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, []*ethpb.PendingAttestation(nil), atts)
|
||||
|
||||
want := []*ethpb.PendingAttestation{{ProposerIndex: 100}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{PreviousEpochAttestations: want})
|
||||
require.NoError(t, err)
|
||||
got, err := s.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0].ProposerIndex = 101
|
||||
require.DeepNotEqual(t, want, got)
|
||||
}
|
||||
|
||||
func TestBeaconState_CurrentEpochAttestations(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
atts, err := s.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, []*ethpb.PendingAttestation(nil), atts)
|
||||
|
||||
want := []*ethpb.PendingAttestation{{ProposerIndex: 101}}
|
||||
s, err = InitializeFromProto(ðpb.BeaconState{CurrentEpochAttestations: want})
|
||||
require.NoError(t, err)
|
||||
got, err := s.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, got)
|
||||
|
||||
// Test copy does not mutate.
|
||||
got[0].ProposerIndex = 102
|
||||
require.DeepNotEqual(t, want, got)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
func TestBeaconState_LatestBlockHeader(t *testing.T) {
|
||||
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) {
|
||||
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) {
|
||||
testtmpl.VerifyBeaconStateBlockRootAtIndexNative(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
},
|
||||
func(BR [][]byte) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{BlockRoots: BR})
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// JustificationBits marking which epochs have been justified in the beacon chain.
|
||||
func (b *BeaconState) JustificationBits() bitfield.Bitvector4 {
|
||||
if b.justificationBits == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.justificationBitsVal()
|
||||
}
|
||||
|
||||
// justificationBitsVal marking which epochs have been justified in the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) justificationBitsVal() bitfield.Bitvector4 {
|
||||
if b.justificationBits == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]byte, len(b.justificationBits.Bytes()))
|
||||
copy(res, b.justificationBits.Bytes())
|
||||
return res
|
||||
}
|
||||
|
||||
// PreviousJustifiedCheckpoint denoting an epoch and block root.
|
||||
func (b *BeaconState) PreviousJustifiedCheckpoint() *ethpb.Checkpoint {
|
||||
if b.previousJustifiedCheckpoint == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.previousJustifiedCheckpointVal()
|
||||
}
|
||||
|
||||
// previousJustifiedCheckpointVal denoting an epoch and block root.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) previousJustifiedCheckpointVal() *ethpb.Checkpoint {
|
||||
return ethpb.CopyCheckpoint(b.previousJustifiedCheckpoint)
|
||||
}
|
||||
|
||||
// CurrentJustifiedCheckpoint denoting an epoch and block root.
|
||||
func (b *BeaconState) CurrentJustifiedCheckpoint() *ethpb.Checkpoint {
|
||||
if b.currentJustifiedCheckpoint == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.currentJustifiedCheckpointVal()
|
||||
}
|
||||
|
||||
// currentJustifiedCheckpointVal denoting an epoch and block root.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) currentJustifiedCheckpointVal() *ethpb.Checkpoint {
|
||||
return ethpb.CopyCheckpoint(b.currentJustifiedCheckpoint)
|
||||
}
|
||||
|
||||
// MatchCurrentJustifiedCheckpoint returns true if input justified checkpoint matches
|
||||
// the current justified checkpoint in state.
|
||||
func (b *BeaconState) MatchCurrentJustifiedCheckpoint(c *ethpb.Checkpoint) bool {
|
||||
if b.currentJustifiedCheckpoint == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if c.Epoch != b.currentJustifiedCheckpoint.Epoch {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(c.Root, b.currentJustifiedCheckpoint.Root)
|
||||
}
|
||||
|
||||
// MatchPreviousJustifiedCheckpoint returns true if the input justified checkpoint matches
|
||||
// the previous justified checkpoint in state.
|
||||
func (b *BeaconState) MatchPreviousJustifiedCheckpoint(c *ethpb.Checkpoint) bool {
|
||||
if b.previousJustifiedCheckpoint == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if c.Epoch != b.previousJustifiedCheckpoint.Epoch {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(c.Root, b.previousJustifiedCheckpoint.Root)
|
||||
}
|
||||
|
||||
// FinalizedCheckpoint denoting an epoch and block root.
|
||||
func (b *BeaconState) FinalizedCheckpoint() *ethpb.Checkpoint {
|
||||
if b.finalizedCheckpoint == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.finalizedCheckpointVal()
|
||||
}
|
||||
|
||||
// finalizedCheckpointVal denoting an epoch and block root.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) finalizedCheckpointVal() *ethpb.Checkpoint {
|
||||
return ethpb.CopyCheckpoint(b.finalizedCheckpoint)
|
||||
}
|
||||
|
||||
// FinalizedCheckpointEpoch returns the epoch value of the finalized checkpoint.
|
||||
func (b *BeaconState) FinalizedCheckpointEpoch() types.Epoch {
|
||||
if b.finalizedCheckpoint == nil {
|
||||
return 0
|
||||
}
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.finalizedCheckpoint.Epoch
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
func TestBeaconState_JustificationBitsNil(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateJustificationBitsNil(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_JustificationBits(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateJustificationBits(
|
||||
t,
|
||||
func(bits bitfield.Bitvector4) (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{JustificationBits: bits})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_PreviousJustifiedCheckpointNil(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpointNil(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_PreviousJustifiedCheckpoint(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpoint(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{PreviousJustifiedCheckpoint: cp})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_CurrentJustifiedCheckpointNil(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpointNil(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_CurrentJustifiedCheckpoint(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpoint(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{CurrentJustifiedCheckpoint: cp})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_FinalizedCheckpointNil(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateFinalizedCheckpointNil(
|
||||
t,
|
||||
func() (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_FinalizedCheckpoint(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateFinalizedCheckpoint(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(ðpb.BeaconState{FinalizedCheckpoint: cp})
|
||||
})
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// Eth1Data corresponding to the proof-of-work chain information stored in the beacon state.
|
||||
func (b *BeaconState) Eth1Data() *ethpb.Eth1Data {
|
||||
if b.eth1Data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.eth1DataVal()
|
||||
}
|
||||
|
||||
// eth1DataVal corresponding to the proof-of-work chain information stored in the beacon state.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) eth1DataVal() *ethpb.Eth1Data {
|
||||
if b.eth1Data == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ethpb.CopyETH1Data(b.eth1Data)
|
||||
}
|
||||
|
||||
// Eth1DataVotes corresponds to votes from Ethereum on the canonical proof-of-work chain
|
||||
// data retrieved from eth1.
|
||||
func (b *BeaconState) Eth1DataVotes() []*ethpb.Eth1Data {
|
||||
if b.eth1DataVotes == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.eth1DataVotesVal()
|
||||
}
|
||||
|
||||
// eth1DataVotesVal corresponds to votes from Ethereum on the canonical proof-of-work chain
|
||||
// data retrieved from eth1.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) eth1DataVotesVal() []*ethpb.Eth1Data {
|
||||
if b.eth1DataVotes == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]*ethpb.Eth1Data, len(b.eth1DataVotes))
|
||||
for i := 0; i < len(res); i++ {
|
||||
res[i] = ethpb.CopyETH1Data(b.eth1DataVotes[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Eth1DepositIndex corresponds to the index of the deposit made to the
|
||||
// validator deposit contract at the time of this state's eth1 data.
|
||||
func (b *BeaconState) Eth1DepositIndex() uint64 {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.eth1DepositIndex
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// RandaoMixes of block proposers on the beacon chain.
|
||||
func (b *BeaconState) RandaoMixes() [][]byte {
|
||||
if b.randaoMixes == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.randaoMixes.Slice()
|
||||
}
|
||||
|
||||
// RandaoMixAtIndex retrieves a specific block root based on an
|
||||
// input index value.
|
||||
func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
|
||||
if b.randaoMixes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
m, err := b.randaoMixAtIndex(idx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m[:], nil
|
||||
}
|
||||
|
||||
// randaoMixAtIndex retrieves a specific block root based on an
|
||||
// input index value.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
|
||||
if uint64(len(b.randaoMixes)) <= idx {
|
||||
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
|
||||
}
|
||||
return b.randaoMixes[idx], nil
|
||||
}
|
||||
|
||||
// RandaoMixesLength returns the length of the randao mixes slice.
|
||||
func (b *BeaconState) RandaoMixesLength() int {
|
||||
if b.randaoMixes == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.randaoMixesLength()
|
||||
}
|
||||
|
||||
// randaoMixesLength returns the length of the randao mixes slice.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) randaoMixesLength() int {
|
||||
if b.randaoMixes == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return len(b.randaoMixes)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
func TestBeaconState_SlotDataRace(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{Slot: 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{CurrentJustifiedCheckpoint: cp})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckptNative(
|
||||
t,
|
||||
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{PreviousJustifiedCheckpoint: cp})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
|
||||
return InitializeFromProto(ðpb.BeaconState{})
|
||||
})
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"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"
|
||||
)
|
||||
|
||||
// ValidatorIndexOutOfRangeError represents an error scenario where a validator does not exist
|
||||
// at a given index in the validator's array.
|
||||
type ValidatorIndexOutOfRangeError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
// NewValidatorIndexOutOfRangeError creates a new error instance.
|
||||
func NewValidatorIndexOutOfRangeError(index types.ValidatorIndex) ValidatorIndexOutOfRangeError {
|
||||
return ValidatorIndexOutOfRangeError{
|
||||
message: fmt.Sprintf("index %d out of range", index),
|
||||
}
|
||||
}
|
||||
|
||||
// Error returns the underlying error message.
|
||||
func (e *ValidatorIndexOutOfRangeError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
// Validators participating in consensus on the beacon chain.
|
||||
func (b *BeaconState) Validators() []*ethpb.Validator {
|
||||
if b.validators == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.validatorsVal()
|
||||
}
|
||||
|
||||
// validatorsVal participating in consensus on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) validatorsVal() []*ethpb.Validator {
|
||||
if b.validators == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]*ethpb.Validator, len(b.validators))
|
||||
for i := 0; i < len(res); i++ {
|
||||
val := b.validators[i]
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
res[i] = ethpb.CopyValidator(val)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// references of validators participating in consensus on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState. This does not
|
||||
// copy fully and instead just copies the reference.
|
||||
func (b *BeaconState) validatorsReferences() []*ethpb.Validator {
|
||||
if b.validators == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]*ethpb.Validator, len(b.validators))
|
||||
for i := 0; i < len(res); i++ {
|
||||
validator := b.validators[i]
|
||||
if validator == nil {
|
||||
continue
|
||||
}
|
||||
// copy validator reference instead.
|
||||
res[i] = validator
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ValidatorAtIndex is the validator at the provided index.
|
||||
func (b *BeaconState) ValidatorAtIndex(idx types.ValidatorIndex) (*ethpb.Validator, error) {
|
||||
if b.validators == nil {
|
||||
return ðpb.Validator{}, nil
|
||||
}
|
||||
if uint64(len(b.validators)) <= uint64(idx) {
|
||||
e := NewValidatorIndexOutOfRangeError(idx)
|
||||
return nil, &e
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
val := b.validators[idx]
|
||||
return ethpb.CopyValidator(val), nil
|
||||
}
|
||||
|
||||
// ValidatorAtIndexReadOnly is the validator at the provided index. This method
|
||||
// doesn't clone the validator.
|
||||
func (b *BeaconState) ValidatorAtIndexReadOnly(idx types.ValidatorIndex) (state.ReadOnlyValidator, error) {
|
||||
if b.validators == nil {
|
||||
return nil, state.ErrNilValidatorsInState
|
||||
}
|
||||
if uint64(len(b.validators)) <= uint64(idx) {
|
||||
e := NewValidatorIndexOutOfRangeError(idx)
|
||||
return nil, &e
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return NewValidator(b.validators[idx])
|
||||
}
|
||||
|
||||
// ValidatorIndexByPubkey returns a given validator by its 48-byte public key.
|
||||
func (b *BeaconState) ValidatorIndexByPubkey(key [fieldparams.BLSPubkeyLength]byte) (types.ValidatorIndex, bool) {
|
||||
if b == nil || b.valMapHandler == nil || b.valMapHandler.IsNil() {
|
||||
return 0, false
|
||||
}
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
numOfVals := len(b.validators)
|
||||
|
||||
idx, ok := b.valMapHandler.Get(key)
|
||||
if ok && types.ValidatorIndex(numOfVals) <= idx {
|
||||
return types.ValidatorIndex(0), false
|
||||
}
|
||||
return idx, ok
|
||||
}
|
||||
|
||||
// PubkeyAtIndex returns the pubkey at the given
|
||||
// validator index.
|
||||
func (b *BeaconState) PubkeyAtIndex(idx types.ValidatorIndex) [fieldparams.BLSPubkeyLength]byte {
|
||||
if uint64(idx) >= uint64(len(b.validators)) {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}
|
||||
}
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if b.validators[idx] == nil {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}
|
||||
}
|
||||
return bytesutil.ToBytes48(b.validators[idx].PublicKey)
|
||||
}
|
||||
|
||||
// NumValidators returns the size of the validator registry.
|
||||
func (b *BeaconState) NumValidators() int {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return len(b.validators)
|
||||
}
|
||||
|
||||
// ReadFromEveryValidator reads values from every validator and applies it to the provided function.
|
||||
// Warning: This method is potentially unsafe, as it exposes the actual validator registry.
|
||||
func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val state.ReadOnlyValidator) error) error {
|
||||
if b.validators == nil {
|
||||
return errors.New("nil validators in state")
|
||||
}
|
||||
b.lock.RLock()
|
||||
validators := b.validators
|
||||
b.lock.RUnlock()
|
||||
|
||||
for i, v := range validators {
|
||||
v, err := NewValidator(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f(i, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Balances of validators participating in consensus on the beacon chain.
|
||||
func (b *BeaconState) Balances() []uint64 {
|
||||
if b.balances == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.balancesVal()
|
||||
}
|
||||
|
||||
// balances of validators participating in consensus on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) balancesVal() []uint64 {
|
||||
if b.balances == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]uint64, len(b.balances))
|
||||
copy(res, b.balances)
|
||||
return res
|
||||
}
|
||||
|
||||
// BalanceAtIndex of validator with the provided index.
|
||||
func (b *BeaconState) BalanceAtIndex(idx types.ValidatorIndex) (uint64, error) {
|
||||
if b.balances == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if uint64(len(b.balances)) <= uint64(idx) {
|
||||
return 0, fmt.Errorf("index of %d does not exist", idx)
|
||||
}
|
||||
return b.balances[idx], nil
|
||||
}
|
||||
|
||||
// BalancesLength returns the length of the balances slice.
|
||||
func (b *BeaconState) BalancesLength() int {
|
||||
if b.balances == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.balancesLength()
|
||||
}
|
||||
|
||||
// Slashings of validators on the beacon chain.
|
||||
func (b *BeaconState) Slashings() []uint64 {
|
||||
if b.slashings == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.slashingsVal()
|
||||
}
|
||||
|
||||
// slashings of validators on the beacon chain.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) slashingsVal() []uint64 {
|
||||
if b.slashings == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]uint64, len(b.slashings))
|
||||
copy(res, b.slashings)
|
||||
return res
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
|
||||
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
|
||||
return v1.InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
Validators: nil,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
|
||||
"github.com/prysmaticlabs/prysm/container/trie"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
)
|
||||
|
||||
func TestBeaconStateMerkleProofs(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
st, _ := util.DeterministicGenesisState(t, 256)
|
||||
htr, err := st.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
t.Run("current sync committee", func(t *testing.T) {
|
||||
_, err := st.CurrentSyncCommitteeProof(ctx)
|
||||
require.ErrorContains(t, "unsupported", err)
|
||||
})
|
||||
t.Run("next sync committee", func(t *testing.T) {
|
||||
_, err := st.NextSyncCommitteeProof(ctx)
|
||||
require.ErrorContains(t, "unsupported", err)
|
||||
})
|
||||
t.Run("finalized root", func(t *testing.T) {
|
||||
finalizedRoot := st.FinalizedCheckpoint().Root
|
||||
proof, err := st.FinalizedRootProof(ctx)
|
||||
require.NoError(t, err)
|
||||
gIndex := v1.FinalizedRootGeneralizedIndex()
|
||||
valid := trie.VerifyMerkleProof(htr[:], finalizedRoot, gIndex, proof)
|
||||
require.Equal(t, true, valid)
|
||||
})
|
||||
t.Run("recomputes root on dirty fields", func(t *testing.T) {
|
||||
currentRoot, err := st.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
cpt := st.FinalizedCheckpoint()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Edit the checkpoint.
|
||||
cpt.Epoch = 100
|
||||
require.NoError(t, st.SetFinalizedCheckpoint(cpt))
|
||||
|
||||
// Produce a proof for the finalized root.
|
||||
proof, err := st.FinalizedRootProof(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the previous step to have triggered
|
||||
// a recomputation of dirty fields in the beacon state, resulting
|
||||
// in a new hash tree root as the finalized checkpoint had previously
|
||||
// changed and should have been marked as a dirty state field.
|
||||
// The proof validity should be false for the old root, but true for the new.
|
||||
finalizedRoot := st.FinalizedCheckpoint().Root
|
||||
gIndex := v1.FinalizedRootGeneralizedIndex()
|
||||
valid := trie.VerifyMerkleProof(currentRoot[:], finalizedRoot, gIndex, proof)
|
||||
require.Equal(t, false, valid)
|
||||
|
||||
newRoot, err := st.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
valid = trie.VerifyMerkleProof(newRoot[:], finalizedRoot, gIndex, proof)
|
||||
require.Equal(t, true, valid)
|
||||
})
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestReadOnlyValidator_ReturnsErrorOnNil(t *testing.T) {
|
||||
if _, err := v1.NewValidator(nil); err != v1.ErrNilWrappedValidator {
|
||||
t.Errorf("Wrong error returned. Got %v, wanted %v", err, v1.ErrNilWrappedValidator)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_EffectiveBalance(t *testing.T) {
|
||||
bal := uint64(234)
|
||||
v, err := v1.NewValidator(ðpb.Validator{EffectiveBalance: bal})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, bal, v.EffectiveBalance())
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_ActivationEligibilityEpoch(t *testing.T) {
|
||||
epoch := types.Epoch(234)
|
||||
v, err := v1.NewValidator(ðpb.Validator{ActivationEligibilityEpoch: epoch})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, epoch, v.ActivationEligibilityEpoch())
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_ActivationEpoch(t *testing.T) {
|
||||
epoch := types.Epoch(234)
|
||||
v, err := v1.NewValidator(ðpb.Validator{ActivationEpoch: epoch})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, epoch, v.ActivationEpoch())
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_WithdrawableEpoch(t *testing.T) {
|
||||
epoch := types.Epoch(234)
|
||||
v, err := v1.NewValidator(ðpb.Validator{WithdrawableEpoch: epoch})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, epoch, v.WithdrawableEpoch())
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_ExitEpoch(t *testing.T) {
|
||||
epoch := types.Epoch(234)
|
||||
v, err := v1.NewValidator(ðpb.Validator{ExitEpoch: epoch})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, epoch, v.ExitEpoch())
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_PublicKey(t *testing.T) {
|
||||
key := [fieldparams.BLSPubkeyLength]byte{0xFA, 0xCC}
|
||||
v, err := v1.NewValidator(ðpb.Validator{PublicKey: key[:]})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, key, v.PublicKey())
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_WithdrawalCredentials(t *testing.T) {
|
||||
creds := []byte{0xFA, 0xCC}
|
||||
v, err := v1.NewValidator(ðpb.Validator{WithdrawalCredentials: creds})
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, creds, v.WithdrawalCredentials())
|
||||
}
|
||||
|
||||
func TestReadOnlyValidator_Slashed(t *testing.T) {
|
||||
slashed := true
|
||||
v, err := v1.NewValidator(ðpb.Validator{Slashed: slashed})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, slashed, v.Slashed())
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"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.BeaconState{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.BeaconState{
|
||||
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.BeaconState{
|
||||
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 TestStateReferenceCopy_NoUnexpectedAttestationsMutation(t *testing.T) {
|
||||
assertAttFound := func(vals []*ethpb.PendingAttestation, val uint64) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i].AggregationBits, bitfield.NewBitlist(val)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Fatalf("Expected attestation not found (%v), want: %v", vals, val)
|
||||
}
|
||||
assertAttNotFound := func(vals []*ethpb.PendingAttestation, val uint64) {
|
||||
for i := range vals {
|
||||
if reflect.DeepEqual(vals[i].AggregationBits, bitfield.NewBitlist(val)) {
|
||||
t.Log(string(debug.Stack()))
|
||||
t.Fatalf("Unexpected attestation found (%v): %v", vals, val)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
s, ok := a.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, previousEpochAttestations, 1)
|
||||
assertRefCount(t, s, currentEpochAttestations, 1)
|
||||
|
||||
// Update initial state.
|
||||
atts := []*ethpb.PendingAttestation{
|
||||
{AggregationBits: bitfield.NewBitlist(1)},
|
||||
{AggregationBits: bitfield.NewBitlist(2)},
|
||||
}
|
||||
s.setPreviousEpochAttestations(atts[:1])
|
||||
s.setCurrentEpochAttestations(atts[:1])
|
||||
curAtt, err := a.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(curAtt), "Unexpected number of attestations")
|
||||
preAtt, err := a.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(preAtt), "Unexpected number of attestations")
|
||||
|
||||
// Copy, increases reference count.
|
||||
copied := a.Copy()
|
||||
b, ok := copied.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, s, previousEpochAttestations, 2)
|
||||
assertRefCount(t, s, currentEpochAttestations, 2)
|
||||
assertRefCount(t, b, previousEpochAttestations, 2)
|
||||
assertRefCount(t, b, currentEpochAttestations, 2)
|
||||
bPrevEpochAtts, err := b.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
bCurrEpochAtts, err := b.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, len(bPrevEpochAtts), "Unexpected number of attestations")
|
||||
assert.Equal(t, 1, len(bCurrEpochAtts), "Unexpected number of attestations")
|
||||
|
||||
// Assert shared state.
|
||||
aCurrEpochAtts, err := a.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
curAttsA := aCurrEpochAtts
|
||||
aPrevEpochAtts, err := a.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
prevAttsA := aPrevEpochAtts
|
||||
bCurrEpochAtts, err = b.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
curAttsB := bCurrEpochAtts
|
||||
bPrevEpochAtts, err = b.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
prevAttsB := bPrevEpochAtts
|
||||
if len(curAttsA) != len(curAttsB) || len(curAttsA) < 1 {
|
||||
t.Errorf("Unexpected number of attestations, want: %v", 1)
|
||||
}
|
||||
if len(prevAttsA) != len(prevAttsB) || len(prevAttsA) < 1 {
|
||||
t.Errorf("Unexpected number of attestations, want: %v", 1)
|
||||
}
|
||||
assertAttFound(curAttsA, 1)
|
||||
assertAttFound(prevAttsA, 1)
|
||||
assertAttFound(curAttsB, 1)
|
||||
assertAttFound(prevAttsB, 1)
|
||||
|
||||
// Extends state a attestations.
|
||||
require.NoError(t, a.AppendCurrentEpochAttestations(atts[1]))
|
||||
require.NoError(t, a.AppendPreviousEpochAttestations(atts[1]))
|
||||
curAtt, err = a.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, len(curAtt), "Unexpected number of attestations")
|
||||
preAtt, err = a.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, len(preAtt), "Unexpected number of attestations")
|
||||
aCurrEpochAtts, err = a.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
aPrevEpochAtts, err = a.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
bCurrEpochAtts, err = b.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
bPrevEpochAtts, err = b.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
assertAttFound(aCurrEpochAtts, 1)
|
||||
assertAttFound(aPrevEpochAtts, 1)
|
||||
assertAttFound(aCurrEpochAtts, 2)
|
||||
assertAttFound(aPrevEpochAtts, 2)
|
||||
assertAttFound(bCurrEpochAtts, 1)
|
||||
assertAttFound(bPrevEpochAtts, 1)
|
||||
assertAttNotFound(bCurrEpochAtts, 2)
|
||||
assertAttNotFound(bPrevEpochAtts, 2)
|
||||
|
||||
// Mutator should only affect calling state: a.
|
||||
applyToEveryAttestation := func(state *BeaconState) {
|
||||
// One MUST copy on write.
|
||||
atts = make([]*ethpb.PendingAttestation, len(state.currentEpochAttestations))
|
||||
copy(atts, state.currentEpochAttestations)
|
||||
state.currentEpochAttestations = atts
|
||||
currEpochAtts, err := state.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
for i := range currEpochAtts {
|
||||
att := ethpb.CopyPendingAttestation(state.currentEpochAttestations[i])
|
||||
att.AggregationBits = bitfield.NewBitlist(3)
|
||||
state.currentEpochAttestations[i] = att
|
||||
}
|
||||
|
||||
atts = make([]*ethpb.PendingAttestation, len(state.previousEpochAttestations))
|
||||
copy(atts, state.previousEpochAttestations)
|
||||
state.previousEpochAttestations = atts
|
||||
prevEpochAtts, err := state.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
for i := range prevEpochAtts {
|
||||
att := ethpb.CopyPendingAttestation(state.previousEpochAttestations[i])
|
||||
att.AggregationBits = bitfield.NewBitlist(3)
|
||||
state.previousEpochAttestations[i] = att
|
||||
}
|
||||
}
|
||||
applyToEveryAttestation(s)
|
||||
|
||||
aCurrEpochAtts, err = a.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
aPrevEpochAtts, err = a.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
bCurrEpochAtts, err = b.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
bPrevEpochAtts, err = b.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
// Assert no shared state mutation occurred only on state a (copy on write).
|
||||
assertAttFound(aCurrEpochAtts, 3)
|
||||
assertAttFound(aPrevEpochAtts, 3)
|
||||
assertAttNotFound(aCurrEpochAtts, 1)
|
||||
assertAttNotFound(aPrevEpochAtts, 1)
|
||||
assertAttNotFound(aCurrEpochAtts, 2)
|
||||
assertAttNotFound(aPrevEpochAtts, 2)
|
||||
// State b must be unaffected.
|
||||
assertAttNotFound(bCurrEpochAtts, 3)
|
||||
assertAttNotFound(bPrevEpochAtts, 3)
|
||||
assertAttFound(bCurrEpochAtts, 1)
|
||||
assertAttFound(bPrevEpochAtts, 1)
|
||||
assertAttNotFound(bCurrEpochAtts, 2)
|
||||
assertAttNotFound(bPrevEpochAtts, 2)
|
||||
|
||||
// Copy on write happened, reference counters are reset.
|
||||
assertRefCount(t, s, currentEpochAttestations, 1)
|
||||
assertRefCount(t, b, currentEpochAttestations, 1)
|
||||
assertRefCount(t, s, previousEpochAttestations, 1)
|
||||
assertRefCount(t, b, previousEpochAttestations, 1)
|
||||
}
|
||||
|
||||
func TestValidatorReferences_RemainsConsistent(t *testing.T) {
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_RotateAttestations(t *testing.T) {
|
||||
st, err := InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 1,
|
||||
CurrentEpochAttestations: []*ethpb.PendingAttestation{{Data: ðpb.AttestationData{Slot: 456}}},
|
||||
PreviousEpochAttestations: []*ethpb.PendingAttestation{{Data: ðpb.AttestationData{Slot: 123}}},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, st.RotateAttestations())
|
||||
currEpochAtts, err := st.CurrentEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(currEpochAtts))
|
||||
prevEpochAtts, err := st.PreviousEpochAttestations()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, types.Slot(456), prevEpochAtts[0].Data.Slot)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// SetJustificationBits for the beacon state.
|
||||
func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.justificationBits = val
|
||||
b.markFieldAsDirty(justificationBits)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPreviousJustifiedCheckpoint for the beacon state.
|
||||
func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.previousJustifiedCheckpoint = val
|
||||
b.markFieldAsDirty(previousJustifiedCheckpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetCurrentJustifiedCheckpoint for the beacon state.
|
||||
func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.currentJustifiedCheckpoint = val
|
||||
b.markFieldAsDirty(currentJustifiedCheckpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFinalizedCheckpoint for the beacon state.
|
||||
func (b *BeaconState) SetFinalizedCheckpoint(val *ethpb.Checkpoint) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.finalizedCheckpoint = val
|
||||
b.markFieldAsDirty(finalizedCheckpoint)
|
||||
return nil
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// SetEth1Data for the beacon state.
|
||||
func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.eth1Data = val
|
||||
b.markFieldAsDirty(eth1Data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetEth1DataVotes for the beacon state. Updates the entire
|
||||
// list to a new value by overwriting the previous one.
|
||||
func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[eth1DataVotes].MinusRef()
|
||||
b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1)
|
||||
|
||||
b.eth1DataVotes = val
|
||||
b.markFieldAsDirty(eth1DataVotes)
|
||||
b.rebuildTrie[eth1DataVotes] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetEth1DepositIndex for the beacon state.
|
||||
func (b *BeaconState) SetEth1DepositIndex(val uint64) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.eth1DepositIndex = val
|
||||
b.markFieldAsDirty(eth1DepositIndex)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendEth1DataVotes for the beacon state. Appends the new value
|
||||
// to the the end of list.
|
||||
func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
votes := b.eth1DataVotes
|
||||
if b.sharedFieldReferences[eth1DataVotes].Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
votes = make([]*ethpb.Eth1Data, len(b.eth1DataVotes))
|
||||
copy(votes, b.eth1DataVotes)
|
||||
b.sharedFieldReferences[eth1DataVotes].MinusRef()
|
||||
b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.eth1DataVotes = append(votes, val)
|
||||
b.markFieldAsDirty(eth1DataVotes)
|
||||
b.addDirtyIndices(eth1DataVotes, []uint64{uint64(len(b.eth1DataVotes) - 1)})
|
||||
return nil
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// SetValidators for the beacon state. Updates the entire
|
||||
// to a new value by overwriting the previous one.
|
||||
func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.validators = val
|
||||
b.sharedFieldReferences[validators].MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
b.markFieldAsDirty(validators)
|
||||
b.rebuildTrie[validators] = true
|
||||
b.valMapHandler = stateutil.NewValMapHandler(b.validators)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyToEveryValidator applies the provided callback function to each validator in the
|
||||
// validator registry.
|
||||
func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error)) error {
|
||||
b.lock.Lock()
|
||||
v := b.validators
|
||||
if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 {
|
||||
v = b.validatorsReferences()
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
}
|
||||
b.lock.Unlock()
|
||||
var changedVals []uint64
|
||||
for i, val := range v {
|
||||
changed, newVal, err := f(i, val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if changed {
|
||||
changedVals = append(changedVals, uint64(i))
|
||||
v[i] = newVal
|
||||
}
|
||||
}
|
||||
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.validators = v
|
||||
b.markFieldAsDirty(validators)
|
||||
b.addDirtyIndices(validators, changedVals)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateValidatorAtIndex for the beacon state. Updates the validator
|
||||
// at a specific index to a new value.
|
||||
func (b *BeaconState) UpdateValidatorAtIndex(idx types.ValidatorIndex, val *ethpb.Validator) error {
|
||||
if uint64(len(b.validators)) <= uint64(idx) {
|
||||
return errors.Errorf("invalid index provided %d", idx)
|
||||
}
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
v := b.validators
|
||||
if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 {
|
||||
v = b.validatorsReferences()
|
||||
ref.MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
v[idx] = val
|
||||
b.validators = v
|
||||
b.markFieldAsDirty(validators)
|
||||
b.addDirtyIndices(validators, []uint64{uint64(idx)})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetBalances for the beacon state. Updates the entire
|
||||
// list to a new value by overwriting the previous one.
|
||||
func (b *BeaconState) SetBalances(val []uint64) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[balances].MinusRef()
|
||||
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
|
||||
|
||||
b.balances = val
|
||||
b.markFieldAsDirty(balances)
|
||||
b.rebuildTrie[balances] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateBalancesAtIndex for the beacon state. This method updates the balance
|
||||
// at a specific index to a new value.
|
||||
func (b *BeaconState) UpdateBalancesAtIndex(idx types.ValidatorIndex, val uint64) error {
|
||||
if uint64(len(b.balances)) <= uint64(idx) {
|
||||
return errors.Errorf("invalid index provided %d", idx)
|
||||
}
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
bals := b.balances
|
||||
if b.sharedFieldReferences[balances].Refs() > 1 {
|
||||
bals = b.balancesVal()
|
||||
b.sharedFieldReferences[balances].MinusRef()
|
||||
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
bals[idx] = val
|
||||
b.balances = bals
|
||||
b.markFieldAsDirty(balances)
|
||||
b.addDirtyIndices(balances, []uint64{uint64(idx)})
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSlashings for the beacon state. Updates the entire
|
||||
// list to a new value by overwriting the previous one.
|
||||
func (b *BeaconState) SetSlashings(val []uint64) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.sharedFieldReferences[slashings].MinusRef()
|
||||
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
|
||||
|
||||
b.slashings = val
|
||||
b.markFieldAsDirty(slashings)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSlashingsAtIndex for the beacon state. Updates the slashings
|
||||
// at a specific index to a new value.
|
||||
func (b *BeaconState) UpdateSlashingsAtIndex(idx, val uint64) error {
|
||||
if uint64(len(b.slashings)) <= idx {
|
||||
return errors.Errorf("invalid index provided %d", idx)
|
||||
}
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
s := b.slashings
|
||||
if b.sharedFieldReferences[slashings].Refs() > 1 {
|
||||
s = b.slashingsVal()
|
||||
b.sharedFieldReferences[slashings].MinusRef()
|
||||
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
s[idx] = val
|
||||
|
||||
b.slashings = s
|
||||
|
||||
b.markFieldAsDirty(slashings)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendValidator for the beacon state. Appends the new value
|
||||
// to the the end of list.
|
||||
func (b *BeaconState) AppendValidator(val *ethpb.Validator) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
vals := b.validators
|
||||
if b.sharedFieldReferences[validators].Refs() > 1 {
|
||||
vals = b.validatorsReferences()
|
||||
b.sharedFieldReferences[validators].MinusRef()
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
// append validator to slice
|
||||
b.validators = append(vals, val)
|
||||
valIdx := types.ValidatorIndex(len(b.validators) - 1)
|
||||
|
||||
b.valMapHandler.Set(bytesutil.ToBytes48(val.PublicKey), valIdx)
|
||||
|
||||
b.markFieldAsDirty(validators)
|
||||
b.addDirtyIndices(validators, []uint64{uint64(valIdx)})
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendBalance for the beacon state. Appends the new value
|
||||
// to the the end of list.
|
||||
func (b *BeaconState) AppendBalance(bal uint64) error {
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
bals := b.balances
|
||||
if b.sharedFieldReferences[balances].Refs() > 1 {
|
||||
bals = b.balancesVal()
|
||||
b.sharedFieldReferences[balances].MinusRef()
|
||||
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.balances = append(bals, bal)
|
||||
balIdx := len(b.balances) - 1
|
||||
b.markFieldAsDirty(balances)
|
||||
b.addDirtyIndices(balances, []uint64{uint64(balIdx)})
|
||||
return nil
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"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 TestValidatorMap_DistinctCopy(t *testing.T) {
|
||||
count := uint64(100)
|
||||
vals := make([]*ethpb.Validator, 0, count)
|
||||
for i := uint64(1); i < count; i++ {
|
||||
someRoot := [32]byte{}
|
||||
someKey := [fieldparams.BLSPubkeyLength]byte{}
|
||||
copy(someRoot[:], strconv.Itoa(int(i)))
|
||||
copy(someKey[:], strconv.Itoa(int(i)))
|
||||
vals = append(vals, ðpb.Validator{
|
||||
PublicKey: someKey[:],
|
||||
WithdrawalCredentials: someRoot[:],
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
Slashed: false,
|
||||
ActivationEligibilityEpoch: 1,
|
||||
ActivationEpoch: 1,
|
||||
ExitEpoch: 1,
|
||||
WithdrawableEpoch: 1,
|
||||
})
|
||||
}
|
||||
handler := stateutil.NewValMapHandler(vals)
|
||||
newHandler := handler.Copy()
|
||||
wantedPubkey := strconv.Itoa(22)
|
||||
handler.Set(bytesutil.ToBytes48([]byte(wantedPubkey)), 27)
|
||||
val1, _ := handler.Get(bytesutil.ToBytes48([]byte(wantedPubkey)))
|
||||
val2, _ := newHandler.Get(bytesutil.ToBytes48([]byte(wantedPubkey)))
|
||||
assert.NotEqual(t, val1, val2, "Values are supposed to be unequal due to copy")
|
||||
}
|
||||
|
||||
func TestBeaconState_NoDeadlock(t *testing.T) {
|
||||
count := uint64(100)
|
||||
vals := make([]*ethpb.Validator, 0, count)
|
||||
for i := uint64(1); i < count; i++ {
|
||||
someRoot := [32]byte{}
|
||||
someKey := [fieldparams.BLSPubkeyLength]byte{}
|
||||
copy(someRoot[:], strconv.Itoa(int(i)))
|
||||
copy(someKey[:], strconv.Itoa(int(i)))
|
||||
vals = append(vals, ðpb.Validator{
|
||||
PublicKey: someKey[:],
|
||||
WithdrawalCredentials: someRoot[:],
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
Slashed: false,
|
||||
ActivationEligibilityEpoch: 1,
|
||||
ActivationEpoch: 1,
|
||||
ExitEpoch: 1,
|
||||
WithdrawableEpoch: 1,
|
||||
})
|
||||
}
|
||||
st, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
Validators: vals,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
// Continuously lock and unlock the state
|
||||
// by acquiring the lock.
|
||||
for i := 0; i < 1000; i++ {
|
||||
for _, f := range s.stateFieldLeaves {
|
||||
f.Lock()
|
||||
if f.Empty() {
|
||||
f.InsertFieldLayer(make([][]*[32]byte, 10))
|
||||
}
|
||||
f.Unlock()
|
||||
f.FieldReference().AddRef()
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
// Constantly read from the offending portion
|
||||
// of the code to ensure there is no possible
|
||||
// recursive read locking.
|
||||
for i := 0; i < 1000; i++ {
|
||||
go func() {
|
||||
_ = st.FieldReferencesCount()
|
||||
}()
|
||||
}
|
||||
// Test will not terminate in the event of a deadlock.
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestStateTrie_IsNil(t *testing.T) {
|
||||
var emptyState *BeaconState
|
||||
assert.Equal(t, true, emptyState.IsNil())
|
||||
}
|
||||
|
||||
func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
|
||||
count := uint64(100)
|
||||
vals := make([]*ethpb.Validator, 0, count)
|
||||
bals := make([]uint64, 0, count)
|
||||
for i := uint64(1); i < count; i++ {
|
||||
someRoot := [32]byte{}
|
||||
someKey := [fieldparams.BLSPubkeyLength]byte{}
|
||||
copy(someRoot[:], strconv.Itoa(int(i)))
|
||||
copy(someKey[:], strconv.Itoa(int(i)))
|
||||
vals = append(vals, ðpb.Validator{
|
||||
PublicKey: someKey[:],
|
||||
WithdrawalCredentials: someRoot[:],
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
Slashed: false,
|
||||
ActivationEligibilityEpoch: 1,
|
||||
ActivationEpoch: 1,
|
||||
ExitEpoch: 1,
|
||||
WithdrawableEpoch: 1,
|
||||
})
|
||||
bals = append(bals, params.BeaconConfig().MaxEffectiveBalance)
|
||||
}
|
||||
zeroHash := params.BeaconConfig().ZeroHash
|
||||
mockblockRoots := make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
|
||||
for i := 0; i < len(mockblockRoots); i++ {
|
||||
mockblockRoots[i] = zeroHash[:]
|
||||
}
|
||||
|
||||
mockstateRoots := make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot)
|
||||
for i := 0; i < len(mockstateRoots); i++ {
|
||||
mockstateRoots[i] = zeroHash[:]
|
||||
}
|
||||
mockrandaoMixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector)
|
||||
for i := 0; i < len(mockrandaoMixes); i++ {
|
||||
mockrandaoMixes[i] = zeroHash[:]
|
||||
}
|
||||
st, err := InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 1,
|
||||
GenesisValidatorsRoot: make([]byte, 32),
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: make([]byte, 4),
|
||||
CurrentVersion: make([]byte, 4),
|
||||
Epoch: 0,
|
||||
},
|
||||
LatestBlockHeader: ðpb.BeaconBlockHeader{
|
||||
ParentRoot: make([]byte, fieldparams.RootLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
BodyRoot: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
Validators: vals,
|
||||
Balances: bals,
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
},
|
||||
BlockRoots: mockblockRoots,
|
||||
StateRoots: mockstateRoots,
|
||||
RandaoMixes: mockrandaoMixes,
|
||||
JustificationBits: bitfield.NewBitvector4(),
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
assert.NoError(t, err)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
if i%2 == 0 {
|
||||
assert.NoError(t, st.UpdateBalancesAtIndex(types.ValidatorIndex(i), 1000))
|
||||
}
|
||||
if i%3 == 0 {
|
||||
assert.NoError(t, st.AppendBalance(1000))
|
||||
}
|
||||
}
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
assert.NoError(t, err)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
newRt := bytesutil.ToBytes32(s.merkleLayers[0][balances])
|
||||
wantedRt, err := stateutil.Uint64ListRootWithRegistryLimit(s.Balances())
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, wantedRt, newRt, "state roots are unequal")
|
||||
}
|
||||
|
||||
func TestBeaconState_ModifyPreviousParticipationBits(t *testing.T) {
|
||||
st, err := InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
assert.NoError(t, err)
|
||||
assert.ErrorContains(t, "ModifyPreviousParticipationBits is not supported for phase 0 beacon state", st.ModifyPreviousParticipationBits(func(val []byte) ([]byte, error) {
|
||||
return nil, nil
|
||||
}))
|
||||
}
|
||||
|
||||
func TestBeaconState_ModifyCurrentParticipationBits(t *testing.T) {
|
||||
st, err := InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
assert.NoError(t, err)
|
||||
assert.ErrorContains(t, "ModifyCurrentParticipationBits is not supported for phase 0 beacon state", st.ModifyCurrentParticipationBits(func(val []byte) ([]byte, error) {
|
||||
return nil, nil
|
||||
}))
|
||||
}
|
||||
@@ -1,479 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
|
||||
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/container/slice"
|
||||
"github.com/prysmaticlabs/prysm/crypto/hash"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/ssz"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"go.opencensus.io/trace"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// InitializeFromProto the beacon state from a protobuf representation.
|
||||
func InitializeFromProto(st *ethpb.BeaconState) (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(proto.Clone(st).(*ethpb.BeaconState))
|
||||
}
|
||||
|
||||
// InitializeFromProtoUnsafe directly uses the beacon state protobuf fields
|
||||
// and sets them as fields of the BeaconState type.
|
||||
func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (state.BeaconState, error) {
|
||||
if st == nil {
|
||||
return nil, errors.New("received nil state")
|
||||
}
|
||||
|
||||
var bRoots customtypes.BlockRoots
|
||||
for i, r := range st.BlockRoots {
|
||||
copy(bRoots[i][:], r)
|
||||
}
|
||||
var sRoots customtypes.StateRoots
|
||||
for i, r := range st.StateRoots {
|
||||
copy(sRoots[i][:], r)
|
||||
}
|
||||
hRoots := customtypes.HistoricalRoots(make([][32]byte, len(st.HistoricalRoots)))
|
||||
for i, r := range st.HistoricalRoots {
|
||||
copy(hRoots[i][:], r)
|
||||
}
|
||||
var mixes customtypes.RandaoMixes
|
||||
for i, m := range st.RandaoMixes {
|
||||
copy(mixes[i][:], m)
|
||||
}
|
||||
|
||||
fieldCount := params.BeaconConfig().BeaconStateFieldCount
|
||||
b := &BeaconState{
|
||||
genesisTime: st.GenesisTime,
|
||||
genesisValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot),
|
||||
slot: st.Slot,
|
||||
fork: st.Fork,
|
||||
latestBlockHeader: st.LatestBlockHeader,
|
||||
blockRoots: &bRoots,
|
||||
stateRoots: &sRoots,
|
||||
historicalRoots: hRoots,
|
||||
eth1Data: st.Eth1Data,
|
||||
eth1DataVotes: st.Eth1DataVotes,
|
||||
eth1DepositIndex: st.Eth1DepositIndex,
|
||||
validators: st.Validators,
|
||||
balances: st.Balances,
|
||||
randaoMixes: &mixes,
|
||||
slashings: st.Slashings,
|
||||
previousEpochAttestations: st.PreviousEpochAttestations,
|
||||
currentEpochAttestations: st.CurrentEpochAttestations,
|
||||
justificationBits: st.JustificationBits,
|
||||
previousJustifiedCheckpoint: st.PreviousJustifiedCheckpoint,
|
||||
currentJustifiedCheckpoint: st.CurrentJustifiedCheckpoint,
|
||||
finalizedCheckpoint: st.FinalizedCheckpoint,
|
||||
|
||||
dirtyFields: make(map[types.FieldIndex]bool, fieldCount),
|
||||
dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount),
|
||||
stateFieldLeaves: make(map[types.FieldIndex]*fieldtrie.FieldTrie, fieldCount),
|
||||
sharedFieldReferences: make(map[types.FieldIndex]*stateutil.Reference, 10),
|
||||
rebuildTrie: make(map[types.FieldIndex]bool, fieldCount),
|
||||
valMapHandler: stateutil.NewValMapHandler(st.Validators),
|
||||
}
|
||||
|
||||
var err error
|
||||
for i := 0; i < fieldCount; i++ {
|
||||
b.dirtyFields[types.FieldIndex(i)] = true
|
||||
b.rebuildTrie[types.FieldIndex(i)] = true
|
||||
b.dirtyIndices[types.FieldIndex(i)] = []uint64{}
|
||||
b.stateFieldLeaves[types.FieldIndex(i)], err = fieldtrie.NewFieldTrie(types.FieldIndex(i), types.BasicArray, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize field reference tracking for shared data.
|
||||
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1)
|
||||
|
||||
state.StateCount.Inc()
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Copy returns a deep copy of the beacon state.
|
||||
func (b *BeaconState) Copy() state.BeaconState {
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
fieldCount := params.BeaconConfig().BeaconStateFieldCount
|
||||
dst := &BeaconState{
|
||||
// Primitive types, safe to copy.
|
||||
genesisTime: b.genesisTime,
|
||||
slot: b.slot,
|
||||
eth1DepositIndex: b.eth1DepositIndex,
|
||||
|
||||
// Large arrays, infrequently changed, constant size.
|
||||
slashings: b.slashings,
|
||||
|
||||
// Large arrays, infrequently changed, constant size.
|
||||
blockRoots: b.blockRoots,
|
||||
stateRoots: b.stateRoots,
|
||||
randaoMixes: b.randaoMixes,
|
||||
previousEpochAttestations: b.previousEpochAttestations,
|
||||
currentEpochAttestations: b.currentEpochAttestations,
|
||||
eth1DataVotes: b.eth1DataVotes,
|
||||
|
||||
// Large arrays, increases over time.
|
||||
balances: b.balances,
|
||||
historicalRoots: b.historicalRoots,
|
||||
validators: b.validators,
|
||||
|
||||
// Everything else, too small to be concerned about, constant size.
|
||||
genesisValidatorsRoot: b.genesisValidatorsRoot,
|
||||
justificationBits: b.justificationBitsVal(),
|
||||
fork: b.forkVal(),
|
||||
latestBlockHeader: b.latestBlockHeaderVal(),
|
||||
eth1Data: b.eth1DataVal(),
|
||||
previousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
|
||||
currentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
|
||||
finalizedCheckpoint: b.finalizedCheckpointVal(),
|
||||
|
||||
dirtyFields: make(map[types.FieldIndex]bool, fieldCount),
|
||||
dirtyIndices: make(map[types.FieldIndex][]uint64, fieldCount),
|
||||
rebuildTrie: make(map[types.FieldIndex]bool, fieldCount),
|
||||
sharedFieldReferences: make(map[types.FieldIndex]*stateutil.Reference, 10),
|
||||
stateFieldLeaves: make(map[types.FieldIndex]*fieldtrie.FieldTrie, fieldCount),
|
||||
|
||||
// Share the reference to validator index map.
|
||||
valMapHandler: b.valMapHandler,
|
||||
}
|
||||
|
||||
for field, ref := range b.sharedFieldReferences {
|
||||
ref.AddRef()
|
||||
dst.sharedFieldReferences[field] = ref
|
||||
}
|
||||
|
||||
// Increment ref for validator map
|
||||
b.valMapHandler.AddRef()
|
||||
|
||||
for i := range b.dirtyFields {
|
||||
dst.dirtyFields[i] = true
|
||||
}
|
||||
|
||||
for i := range b.dirtyIndices {
|
||||
indices := make([]uint64, len(b.dirtyIndices[i]))
|
||||
copy(indices, b.dirtyIndices[i])
|
||||
dst.dirtyIndices[i] = indices
|
||||
}
|
||||
|
||||
for i := range b.rebuildTrie {
|
||||
dst.rebuildTrie[i] = true
|
||||
}
|
||||
|
||||
for fldIdx, fieldTrie := range b.stateFieldLeaves {
|
||||
dst.stateFieldLeaves[fldIdx] = fieldTrie
|
||||
if fieldTrie.FieldReference() != nil {
|
||||
fieldTrie.Lock()
|
||||
fieldTrie.FieldReference().AddRef()
|
||||
fieldTrie.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
if b.merkleLayers != nil {
|
||||
dst.merkleLayers = make([][][]byte, len(b.merkleLayers))
|
||||
for i, layer := range b.merkleLayers {
|
||||
dst.merkleLayers[i] = make([][]byte, len(layer))
|
||||
for j, content := range layer {
|
||||
dst.merkleLayers[i][j] = make([]byte, len(content))
|
||||
copy(dst.merkleLayers[i][j], content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.StateCount.Inc()
|
||||
// Finalizer runs when dst is being destroyed in garbage collection.
|
||||
runtime.SetFinalizer(dst, func(b *BeaconState) {
|
||||
for field, v := range b.sharedFieldReferences {
|
||||
v.MinusRef()
|
||||
if b.stateFieldLeaves[field].FieldReference() != nil {
|
||||
b.stateFieldLeaves[field].FieldReference().MinusRef()
|
||||
}
|
||||
|
||||
}
|
||||
for i := 0; i < fieldCount; i++ {
|
||||
field := types.FieldIndex(i)
|
||||
delete(b.stateFieldLeaves, field)
|
||||
delete(b.dirtyIndices, field)
|
||||
delete(b.dirtyFields, field)
|
||||
delete(b.sharedFieldReferences, field)
|
||||
delete(b.stateFieldLeaves, field)
|
||||
}
|
||||
state.StateCount.Sub(1)
|
||||
})
|
||||
return dst
|
||||
}
|
||||
|
||||
// HashTreeRoot of the beacon state retrieves the Merkle root of the trie
|
||||
// representation of the beacon state based on the Ethereum Simple Serialize specification.
|
||||
func (b *BeaconState) HashTreeRoot(ctx context.Context) ([32]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "beaconState.HashTreeRoot")
|
||||
defer span.End()
|
||||
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
if err := b.initializeMerkleLayers(ctx); err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
if err := b.recomputeDirtyFields(ctx); err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return bytesutil.ToBytes32(b.merkleLayers[len(b.merkleLayers)-1][0]), nil
|
||||
}
|
||||
|
||||
// Initializes the Merkle layers for the beacon state if they are empty.
|
||||
// WARNING: Caller must acquire the mutex before using.
|
||||
func (b *BeaconState) initializeMerkleLayers(ctx context.Context) error {
|
||||
if len(b.merkleLayers) > 0 {
|
||||
return nil
|
||||
}
|
||||
protoState, ok := b.ToProtoUnsafe().(*ethpb.BeaconState)
|
||||
if !ok {
|
||||
return errors.New("state is of the wrong type")
|
||||
}
|
||||
fieldRoots, err := computeFieldRoots(ctx, protoState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
layers := stateutil.Merkleize(fieldRoots)
|
||||
b.merkleLayers = layers
|
||||
b.dirtyFields = make(map[types.FieldIndex]bool, params.BeaconConfig().BeaconStateFieldCount)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Recomputes the Merkle layers for the dirty fields in the state.
|
||||
// WARNING: Caller must acquire the mutex before using.
|
||||
func (b *BeaconState) recomputeDirtyFields(ctx context.Context) error {
|
||||
for field := range b.dirtyFields {
|
||||
root, err := b.rootSelector(ctx, field)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.merkleLayers[0][field] = root[:]
|
||||
b.recomputeRoot(int(field))
|
||||
delete(b.dirtyFields, field)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FieldReferencesCount returns the reference count held by each field. This
|
||||
// also includes the field trie held by each field.
|
||||
func (b *BeaconState) FieldReferencesCount() map[string]uint64 {
|
||||
refMap := make(map[string]uint64)
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
for i, f := range b.sharedFieldReferences {
|
||||
refMap[i.String(b.Version())] = uint64(f.Refs())
|
||||
}
|
||||
for i, f := range b.stateFieldLeaves {
|
||||
numOfRefs := uint64(f.FieldReference().Refs())
|
||||
f.RLock()
|
||||
if !f.Empty() {
|
||||
refMap[i.String(b.Version())+"_trie"] = numOfRefs
|
||||
}
|
||||
f.RUnlock()
|
||||
}
|
||||
return refMap
|
||||
}
|
||||
|
||||
// IsNil checks if the state and the underlying proto
|
||||
// object are nil.
|
||||
func (b *BeaconState) IsNil() bool {
|
||||
return b == nil
|
||||
}
|
||||
|
||||
func (b *BeaconState) rootSelector(ctx context.Context, field types.FieldIndex) ([32]byte, error) {
|
||||
_, span := trace.StartSpan(ctx, "beaconState.rootSelector")
|
||||
defer span.End()
|
||||
span.AddAttributes(trace.StringAttribute("field", field.String(b.Version())))
|
||||
|
||||
hasher := hash.CustomSHA256Hasher()
|
||||
switch field {
|
||||
case genesisTime:
|
||||
return ssz.Uint64Root(b.genesisTime), nil
|
||||
case genesisValidatorsRoot:
|
||||
return b.genesisValidatorsRoot, nil
|
||||
case slot:
|
||||
return ssz.Uint64Root(uint64(b.slot)), nil
|
||||
case eth1DepositIndex:
|
||||
return ssz.Uint64Root(b.eth1DepositIndex), nil
|
||||
case fork:
|
||||
return ssz.ForkRoot(b.fork)
|
||||
case latestBlockHeader:
|
||||
return stateutil.BlockHeaderRoot(b.latestBlockHeader)
|
||||
case blockRoots:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(field, b.blockRoots, fieldparams.BlockRootsLength)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, field)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(blockRoots, b.blockRoots)
|
||||
case stateRoots:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(field, b.stateRoots, fieldparams.StateRootsLength)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, field)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(stateRoots, b.stateRoots)
|
||||
case historicalRoots:
|
||||
hRoots := make([][]byte, len(b.historicalRoots))
|
||||
for i := range hRoots {
|
||||
hRoots[i] = b.historicalRoots[i][:]
|
||||
}
|
||||
return ssz.ByteArrayRootWithLimit(hRoots, fieldparams.HistoricalRootsLength)
|
||||
case eth1Data:
|
||||
return stateutil.Eth1Root(hasher, b.eth1Data)
|
||||
case eth1DataVotes:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(
|
||||
field,
|
||||
b.eth1DataVotes,
|
||||
fieldparams.Eth1DataVotesLength,
|
||||
)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, field)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(field, b.eth1DataVotes)
|
||||
case validators:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(field, b.validators, fieldparams.ValidatorRegistryLimit)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, validators)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(validators, b.validators)
|
||||
case balances:
|
||||
if features.Get().EnableBalanceTrieComputation {
|
||||
if b.rebuildTrie[field] {
|
||||
maxBalCap := uint64(fieldparams.ValidatorRegistryLimit)
|
||||
elemSize := uint64(8)
|
||||
balLimit := (maxBalCap*elemSize + 31) / 32
|
||||
err := b.resetFieldTrie(field, b.balances, balLimit)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, field)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(balances, b.balances)
|
||||
}
|
||||
return stateutil.Uint64ListRootWithRegistryLimit(b.balances)
|
||||
case randaoMixes:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(field, b.randaoMixes, fieldparams.RandaoMixesLength)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, field)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(randaoMixes, b.randaoMixes)
|
||||
case slashings:
|
||||
return ssz.SlashingsRoot(b.slashings)
|
||||
case previousEpochAttestations:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(
|
||||
field,
|
||||
b.previousEpochAttestations,
|
||||
fieldparams.PreviousEpochAttestationsLength,
|
||||
)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, field)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(field, b.previousEpochAttestations)
|
||||
case currentEpochAttestations:
|
||||
if b.rebuildTrie[field] {
|
||||
err := b.resetFieldTrie(
|
||||
field,
|
||||
b.currentEpochAttestations,
|
||||
fieldparams.CurrentEpochAttestationsLength,
|
||||
)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
delete(b.rebuildTrie, field)
|
||||
return b.stateFieldLeaves[field].TrieRoot()
|
||||
}
|
||||
return b.recomputeFieldTrie(field, b.currentEpochAttestations)
|
||||
case justificationBits:
|
||||
return bytesutil.ToBytes32(b.justificationBits), nil
|
||||
case previousJustifiedCheckpoint:
|
||||
return ssz.CheckpointRoot(hasher, b.previousJustifiedCheckpoint)
|
||||
case currentJustifiedCheckpoint:
|
||||
return ssz.CheckpointRoot(hasher, b.currentJustifiedCheckpoint)
|
||||
case finalizedCheckpoint:
|
||||
return ssz.CheckpointRoot(hasher, b.finalizedCheckpoint)
|
||||
}
|
||||
return [32]byte{}, errors.New("invalid field index provided")
|
||||
}
|
||||
|
||||
func (b *BeaconState) recomputeFieldTrie(index types.FieldIndex, elements interface{}) ([32]byte, error) {
|
||||
fTrie := b.stateFieldLeaves[index]
|
||||
// We can't lock the trie directly because the trie's variable gets reassigned,
|
||||
// and therefore we would call Unlock() on a different object.
|
||||
fTrieMutex := fTrie.RWMutex
|
||||
if fTrie.FieldReference().Refs() > 1 {
|
||||
fTrieMutex.Lock()
|
||||
fTrie.FieldReference().MinusRef()
|
||||
newTrie := fTrie.CopyTrie()
|
||||
b.stateFieldLeaves[index] = newTrie
|
||||
fTrie = newTrie
|
||||
fTrieMutex.Unlock()
|
||||
}
|
||||
// remove duplicate indexes
|
||||
b.dirtyIndices[index] = slice.SetUint64(b.dirtyIndices[index])
|
||||
// sort indexes again
|
||||
sort.Slice(b.dirtyIndices[index], func(i int, j int) bool {
|
||||
return b.dirtyIndices[index][i] < b.dirtyIndices[index][j]
|
||||
})
|
||||
root, err := fTrie.RecomputeTrie(b.dirtyIndices[index], elements)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
b.dirtyIndices[index] = []uint64{}
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (b *BeaconState) resetFieldTrie(index types.FieldIndex, elements interface{}, length uint64) error {
|
||||
fTrie, err := fieldtrie.NewFieldTrie(index, fieldMap[index], elements, length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.stateFieldLeaves[index] = fTrie
|
||||
b.dirtyIndices[index] = []uint64{}
|
||||
return nil
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
package v1_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"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"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
resetCfg := features.InitWithReset(&features.Flags{EnableBalanceTrieComputation: true})
|
||||
defer resetCfg()
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func TestInitializeFromProto(t *testing.T) {
|
||||
testState, _ := util.DeterministicGenesisState(t, 64)
|
||||
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
|
||||
require.NoError(t, err)
|
||||
type test struct {
|
||||
name string
|
||||
state *ethpb.BeaconState
|
||||
error string
|
||||
}
|
||||
initTests := []test{
|
||||
{
|
||||
name: "nil state",
|
||||
state: nil,
|
||||
error: "received nil state",
|
||||
},
|
||||
{
|
||||
name: "nil validators",
|
||||
state: ðpb.BeaconState{
|
||||
Slot: 4,
|
||||
Validators: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty state",
|
||||
state: ðpb.BeaconState{},
|
||||
},
|
||||
{
|
||||
name: "full state",
|
||||
state: pbState,
|
||||
},
|
||||
}
|
||||
for _, tt := range initTests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := v1.InitializeFromProto(tt.state)
|
||||
if tt.error != "" {
|
||||
assert.ErrorContains(t, tt.error, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitializeFromProtoUnsafe(t *testing.T) {
|
||||
testState, _ := util.DeterministicGenesisState(t, 64)
|
||||
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
|
||||
require.NoError(t, err)
|
||||
type test struct {
|
||||
name string
|
||||
state *ethpb.BeaconState
|
||||
error string
|
||||
}
|
||||
initTests := []test{
|
||||
{
|
||||
name: "nil state",
|
||||
state: nil,
|
||||
error: "received nil state",
|
||||
},
|
||||
{
|
||||
name: "nil validators",
|
||||
state: ðpb.BeaconState{
|
||||
Slot: 4,
|
||||
Validators: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty state",
|
||||
state: ðpb.BeaconState{},
|
||||
},
|
||||
{
|
||||
name: "full state",
|
||||
state: pbState,
|
||||
},
|
||||
}
|
||||
for _, tt := range initTests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := v1.InitializeFromProtoUnsafe(tt.state)
|
||||
if tt.error != "" {
|
||||
assert.ErrorContains(t, tt.error, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconState_HashTreeRoot(t *testing.T) {
|
||||
testState, _ := util.DeterministicGenesisState(t, 64)
|
||||
|
||||
type test struct {
|
||||
name string
|
||||
stateModify func(beaconState state.BeaconState) (state.BeaconState, error)
|
||||
error string
|
||||
}
|
||||
initTests := []test{
|
||||
{
|
||||
name: "unchanged state",
|
||||
stateModify: func(beaconState state.BeaconState) (state.BeaconState, error) {
|
||||
return beaconState, nil
|
||||
},
|
||||
error: "",
|
||||
},
|
||||
{
|
||||
name: "different slot",
|
||||
stateModify: func(beaconState state.BeaconState) (state.BeaconState, error) {
|
||||
if err := beaconState.SetSlot(5); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
},
|
||||
error: "",
|
||||
},
|
||||
{
|
||||
name: "different validator balance",
|
||||
stateModify: func(beaconState state.BeaconState) (state.BeaconState, error) {
|
||||
val, err := beaconState.ValidatorAtIndex(5)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val.EffectiveBalance = params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement
|
||||
if err := beaconState.UpdateValidatorAtIndex(5, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
},
|
||||
error: "",
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
var oldHTR []byte
|
||||
for _, tt := range initTests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testState, err = tt.stateModify(testState)
|
||||
assert.NoError(t, err)
|
||||
root, err := testState.HashTreeRoot(context.Background())
|
||||
if err == nil && tt.error != "" {
|
||||
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
|
||||
}
|
||||
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
|
||||
require.NoError(t, err)
|
||||
genericHTR, err := pbState.HashTreeRoot()
|
||||
if err == nil && tt.error != "" {
|
||||
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
|
||||
}
|
||||
assert.DeepNotEqual(t, []byte{}, root[:], "Received empty hash tree root")
|
||||
assert.DeepEqual(t, genericHTR[:], root[:], "Expected hash tree root to match generic")
|
||||
if len(oldHTR) != 0 && bytes.Equal(root[:], oldHTR) {
|
||||
t.Errorf("Expected HTR to change, received %#x == old %#x", root, oldHTR)
|
||||
}
|
||||
oldHTR = root[:]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) {
|
||||
testState, _ := util.DeterministicGenesisState(t, 64)
|
||||
|
||||
type test struct {
|
||||
name string
|
||||
stateModify func(state.BeaconState) (state.BeaconState, error)
|
||||
error string
|
||||
}
|
||||
initTests := []test{
|
||||
{
|
||||
name: "unchanged state",
|
||||
stateModify: func(beaconState state.BeaconState) (state.BeaconState, error) {
|
||||
return beaconState, nil
|
||||
},
|
||||
error: "",
|
||||
},
|
||||
{
|
||||
name: "different slot",
|
||||
stateModify: func(beaconState state.BeaconState) (state.BeaconState, error) {
|
||||
if err := beaconState.SetSlot(5); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
},
|
||||
error: "",
|
||||
},
|
||||
{
|
||||
name: "different validator balance",
|
||||
stateModify: func(beaconState state.BeaconState) (state.BeaconState, error) {
|
||||
val, err := beaconState.ValidatorAtIndex(5)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val.EffectiveBalance = params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement
|
||||
if err := beaconState.UpdateValidatorAtIndex(5, val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
},
|
||||
error: "",
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
var oldHTR []byte
|
||||
for _, tt := range initTests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testState, err = tt.stateModify(testState)
|
||||
assert.NoError(t, err)
|
||||
root, err := testState.HashTreeRoot(context.Background())
|
||||
if err == nil && tt.error != "" {
|
||||
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
|
||||
}
|
||||
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
|
||||
require.NoError(t, err)
|
||||
genericHTR, err := pbState.HashTreeRoot()
|
||||
if err == nil && tt.error != "" {
|
||||
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
|
||||
}
|
||||
assert.DeepNotEqual(t, []byte{}, root[:], "Received empty hash tree root")
|
||||
assert.DeepEqual(t, genericHTR[:], root[:], "Expected hash tree root to match generic")
|
||||
if len(oldHTR) != 0 && bytes.Equal(root[:], oldHTR) {
|
||||
t.Errorf("Expected HTR to change, received %#x == old %#x", root, oldHTR)
|
||||
}
|
||||
oldHTR = root[:]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeaconState_AppendValidator_DoesntMutateCopy(t *testing.T) {
|
||||
st0, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
st1 := st0.Copy()
|
||||
originalCount := st1.NumValidators()
|
||||
|
||||
val := ðpb.Validator{Slashed: true}
|
||||
assert.NoError(t, st0.AppendValidator(val))
|
||||
assert.Equal(t, originalCount, st1.NumValidators(), "st1 NumValidators mutated")
|
||||
_, ok := st1.ValidatorIndexByPubkey(bytesutil.ToBytes48(val.PublicKey))
|
||||
assert.Equal(t, false, ok, "Expected no validator index to be present in st1 for the newly inserted pubkey")
|
||||
}
|
||||
|
||||
func BenchmarkBeaconState(b *testing.B) {
|
||||
testState, _ := util.DeterministicGenesisState(b, 16000)
|
||||
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
|
||||
require.NoError(b, err)
|
||||
|
||||
b.Run("Vectorized SHA256", func(b *testing.B) {
|
||||
st, err := v1.InitializeFromProtoUnsafe(pbState)
|
||||
require.NoError(b, err)
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
assert.NoError(b, err)
|
||||
})
|
||||
|
||||
b.Run("Current SHA256", func(b *testing.B) {
|
||||
_, err := pbState.HashTreeRoot()
|
||||
require.NoError(b, err)
|
||||
})
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
)
|
||||
|
||||
// Ensure type BeaconState below implements BeaconState interface.
|
||||
var _ state.BeaconState = (*BeaconState)(nil)
|
||||
|
||||
func init() {
|
||||
fieldMap = make(map[types.FieldIndex]types.DataType, params.BeaconConfig().BeaconStateFieldCount)
|
||||
// Initialize the fixed sized arrays.
|
||||
fieldMap[types.BlockRoots] = types.BasicArray
|
||||
fieldMap[types.StateRoots] = types.BasicArray
|
||||
fieldMap[types.RandaoMixes] = types.BasicArray
|
||||
|
||||
// Initialize the composite arrays.
|
||||
fieldMap[types.Eth1DataVotes] = types.CompositeArray
|
||||
fieldMap[types.Validators] = types.CompositeArray
|
||||
fieldMap[types.PreviousEpochAttestations] = types.CompositeArray
|
||||
fieldMap[types.CurrentEpochAttestations] = types.CompositeArray
|
||||
fieldMap[types.Balances] = types.CompressedArray
|
||||
}
|
||||
|
||||
// fieldMap keeps track of each field
|
||||
// to its corresponding data type.
|
||||
var fieldMap map[types.FieldIndex]types.DataType
|
||||
|
||||
// Field Aliases for values from the types package.
|
||||
const (
|
||||
genesisTime = types.GenesisTime
|
||||
genesisValidatorsRoot = types.GenesisValidatorsRoot
|
||||
slot = types.Slot
|
||||
fork = types.Fork
|
||||
latestBlockHeader = types.LatestBlockHeader
|
||||
blockRoots = types.BlockRoots
|
||||
stateRoots = types.StateRoots
|
||||
historicalRoots = types.HistoricalRoots
|
||||
eth1Data = types.Eth1Data
|
||||
eth1DataVotes = types.Eth1DataVotes
|
||||
eth1DepositIndex = types.Eth1DepositIndex
|
||||
validators = types.Validators
|
||||
balances = types.Balances
|
||||
randaoMixes = types.RandaoMixes
|
||||
slashings = types.Slashings
|
||||
previousEpochAttestations = types.PreviousEpochAttestations
|
||||
currentEpochAttestations = types.CurrentEpochAttestations
|
||||
justificationBits = types.JustificationBits
|
||||
previousJustifiedCheckpoint = types.PreviousJustifiedCheckpoint
|
||||
currentJustifiedCheckpoint = types.CurrentJustifiedCheckpoint
|
||||
finalizedCheckpoint = types.FinalizedCheckpoint
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user