Compare commits

..

2 Commits

Author SHA1 Message Date
terence tsao
a6442987f9 fix: test errors 2022-04-12 14:12:37 -07:00
terence tsao
4197da13ad Add: wss payload block hash as last default 2022-04-12 14:10:29 -07:00
68 changed files with 598 additions and 1345 deletions

View File

@@ -115,19 +115,18 @@ 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/comparesame:go_default_library",
"//tools/analyzers/maligned:go_default_library",
"//tools/analyzers/cryptorand:go_default_library",
"//tools/analyzers/errcheck:go_default_library",
"//tools/analyzers/featureconfig: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/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/ineffassign: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.

View File

@@ -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.9",
go_version = "1.17.6",
nogo = "@//:nogo",
)

View File

@@ -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 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 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 been finalized, the block will always be part of the canonical chain.
return s.cfg.BeaconDB.IsFinalizedBlock(ctx, 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
}
// ChainHeads returns all possible chain heads (leaves of fork choice tree).

View File

@@ -46,31 +46,15 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, headState state.Be
if err != nil {
return nil, errors.Wrap(err, "could not get execution payload")
}
finalizedBlock, err := s.cfg.BeaconDB.Block(ctx, s.ensureRootNotZeros(finalizedRoot))
finalizedHash, err := s.getFinalizedPayloadHash(ctx, finalizedRoot)
if err != nil {
return nil, errors.Wrap(err, "could not get finalized block")
}
if finalizedBlock == nil || finalizedBlock.IsNil() {
finalizedBlock = s.getInitSyncBlock(s.ensureRootNotZeros(finalizedRoot))
if finalizedBlock == nil || finalizedBlock.IsNil() {
return nil, errors.Errorf("finalized block with root %#x does not exist in the db or our cache", s.ensureRootNotZeros(finalizedRoot))
}
}
var finalizedHash []byte
if blocks.IsPreBellatrixVersion(finalizedBlock.Block().Version()) {
finalizedHash = params.BeaconConfig().ZeroHash[:]
} else {
payload, err := finalizedBlock.Block().Body().ExecutionPayload()
if err != nil {
return nil, errors.Wrap(err, "could not get finalized block execution payload")
}
finalizedHash = payload.BlockHash
return nil, errors.Wrap(err, "could not get finalized payload hash")
}
fcs := &enginev1.ForkchoiceState{
HeadBlockHash: headPayload.BlockHash,
SafeBlockHash: headPayload.BlockHash,
FinalizedBlockHash: finalizedHash,
FinalizedBlockHash: finalizedHash[:],
}
nextSlot := s.CurrentSlot() + 1 // Cache payload ID for next slot proposer.
@@ -87,7 +71,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, headState state.Be
log.WithFields(logrus.Fields{
"headSlot": headBlk.Slot(),
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash)),
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash)),
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash[:])),
}).Info("Called fork choice updated with optimistic block")
return payloadID, nil
default:
@@ -106,6 +90,55 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, headState state.Be
return payloadID, nil
}
// getFinalizedPayloadHash returns the finalized payload hash for the given finalized block root.
// It checks the following in order:
// 1. The finalized block exists in db
// 2. The finalized block exists in initial sync block cache
// 3. The finalized block is the weak subjectivity block and exists in db
// Error is returned if the finalized block is not found from above.
func (s *Service) getFinalizedPayloadHash(ctx context.Context, finalizedRoot [32]byte) ([32]byte, error) {
b, err := s.cfg.BeaconDB.Block(ctx, s.ensureRootNotZeros(finalizedRoot))
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not get finalized block")
}
if b != nil {
return getPayloadHash(b.Block())
}
b = s.getInitSyncBlock(finalizedRoot)
if b != nil {
return getPayloadHash(b.Block())
}
r, err := s.cfg.BeaconDB.OriginCheckpointBlockRoot(ctx)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not get finalized block")
}
b, err = s.cfg.BeaconDB.Block(ctx, r)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not get finalized block")
}
if b != nil {
return getPayloadHash(b.Block())
}
return [32]byte{}, errors.Errorf("finalized block with root %#x does not exist in the db or our cache", s.ensureRootNotZeros(finalizedRoot))
}
// getPayloadHash returns the payload hash for the input given block.
// zeros are returned if the block is older than bellatrix.
func getPayloadHash(b block.BeaconBlock) ([32]byte, error) {
if blocks.IsPreBellatrixVersion(b.Version()) {
return params.BeaconConfig().ZeroHash, nil
}
payload, err := b.Body().ExecutionPayload()
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not get finalized block execution payload")
}
return bytesutil.ToBytes32(payload.BlockHash), nil
}
// notifyForkchoiceUpdate signals execution engine on a new payload.
// It returns true if the EL has returned VALID for the block
func (s *Service) notifyNewPayload(ctx context.Context, preStateVersion, postStateVersion int,

View File

@@ -792,3 +792,74 @@ func TestService_removeInvalidBlockAndState(t *testing.T) {
require.NoError(t, err)
require.Equal(t, false, has)
}
func TestService_getFinalizedPayloadHash(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB)),
}
service, err := NewService(ctx, opts...)
require.NoError(t, err)
// Use the block in DB
b := util.NewBeaconBlockBellatrix()
b.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte("hi"), 32)
blk, err := wrapper.WrappedSignedBeaconBlock(b)
require.NoError(t, err)
r, err := b.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, blk))
h, err := service.getFinalizedPayloadHash(ctx, r)
require.NoError(t, err)
require.Equal(t, bytesutil.ToBytes32(b.Block.Body.ExecutionPayload.BlockHash), h)
// Use the block in init sync cache
b = util.NewBeaconBlockBellatrix()
b.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte("hello"), 32)
blk, err = wrapper.WrappedSignedBeaconBlock(b)
require.NoError(t, err)
r, err = b.Block.HashTreeRoot()
require.NoError(t, err)
service.initSyncBlocks[r] = blk
h, err = service.getFinalizedPayloadHash(ctx, r)
require.NoError(t, err)
require.Equal(t, bytesutil.ToBytes32(b.Block.Body.ExecutionPayload.BlockHash), h)
// Use the weak subjectivity sync block
b = util.NewBeaconBlockBellatrix()
b.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte("howdy"), 32)
blk, err = wrapper.WrappedSignedBeaconBlock(b)
require.NoError(t, err)
r, err = b.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, blk))
require.NoError(t, service.cfg.BeaconDB.SaveOriginCheckpointBlockRoot(ctx, r))
h, err = service.getFinalizedPayloadHash(ctx, r)
require.NoError(t, err)
require.Equal(t, bytesutil.ToBytes32(b.Block.Body.ExecutionPayload.BlockHash), h)
// None of the above should error
require.NoError(t, service.cfg.BeaconDB.SaveOriginCheckpointBlockRoot(ctx, [32]byte{'a'}))
_, err = service.getFinalizedPayloadHash(ctx, [32]byte{'a'})
require.ErrorContains(t, "does not exist in the db or our cache", err)
}
func TestService_getPayloadHash(t *testing.T) {
// Pre-bellatrix
blk, err := wrapper.WrappedSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
h, err := getPayloadHash(blk.Block())
require.NoError(t, err)
require.Equal(t, [32]byte{}, h)
// Post bellatrix
b := util.NewBeaconBlockBellatrix()
b.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte("hi"), 32)
blk, err = wrapper.WrappedSignedBeaconBlock(b)
require.NoError(t, err)
h, err = getPayloadHash(blk.Block())
require.NoError(t, err)
require.Equal(t, bytesutil.ToBytes32(bytesutil.PadTo([]byte("hi"), 32)), h)
}

View File

@@ -407,10 +407,6 @@ func (s *Service) insertFinalizedDeposits(ctx context.Context, fRoot [32]byte) e
if err != nil {
return errors.Wrap(err, "could not cast eth1 deposit index")
}
// The deposit index in the state is always the index of the next deposit
// to be included(rather than the last one to be processed). This was most likely
// done as the state cannot represent signed integers.
eth1DepositIndex -= 1
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, int64(eth1DepositIndex)); err != nil {

View File

@@ -1516,7 +1516,7 @@ func TestInsertFinalizedDeposits(t *testing.T) {
service.store.SetFinalizedCheckpt(&ethpb.Checkpoint{Root: gRoot[:]})
gs = gs.Copy()
assert.NoError(t, gs.SetEth1Data(&ethpb.Eth1Data{DepositCount: 10}))
assert.NoError(t, gs.SetEth1DepositIndex(8))
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++ {
@@ -1555,11 +1555,11 @@ func TestInsertFinalizedDeposits_MultipleFinalizedRoutines(t *testing.T) {
service.store.SetFinalizedCheckpt(&ethpb.Checkpoint{Root: gRoot[:]})
gs = gs.Copy()
assert.NoError(t, gs.SetEth1Data(&ethpb.Eth1Data{DepositCount: 7}))
assert.NoError(t, gs.SetEth1DepositIndex(6))
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(&ethpb.Eth1Data{DepositCount: 15}))
assert.NoError(t, gs2.SetEth1DepositIndex(13))
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++ {

View File

@@ -83,8 +83,7 @@ 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.
blockRoot := bytesutil.ToBytes32(root)
if s.cfg.ForkChoiceStore.HasNode(blockRoot) && s.cfg.ForkChoiceStore.IsCanonical(blockRoot) {
if s.cfg.ForkChoiceStore.IsCanonical(bytesutil.ToBytes32(root)) {
return nil
}

View File

@@ -137,22 +137,6 @@ 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

View File

@@ -459,7 +459,7 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
Index: 1,
},
}
newFinalizedDeposit := &ethpb.DepositContainer{
newFinalizedDeposit := ethpb.DepositContainer{
Deposit: &ethpb.Deposit{
Data: &ethpb.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(1), cachedDeposits.MerkleTrieIndex)
assert.Equal(t, int64(2), cachedDeposits.MerkleTrieIndex)
var deps [][]byte
for _, d := range oldFinalizedDeposits {
for _, d := range append(oldFinalizedDeposits, &newFinalizedDeposit) {
hash, err := d.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Could not hash deposit data")
deps = append(deps, hash[:])
@@ -491,140 +491,6 @@ 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: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{0}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: 0,
},
{
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{1}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: 1,
},
{
Deposit: &ethpb.Deposit{
Data: &ethpb.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: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{0}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: 0,
},
{
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{1}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: 1,
},
{
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{2}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: 2,
},
{
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{3}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: 3,
},
{
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{4}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: 4,
},
{
Deposit: &ethpb.Deposit{
Data: &ethpb.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)
@@ -749,85 +615,6 @@ func TestNonFinalizedDeposits_ReturnsNonFinalizedDepositsUpToBlockNumber(t *test
assert.Equal(t, 1, len(deps))
}
func TestFinalizedDeposits_ReturnsTrieCorrectly(t *testing.T) {
dc, err := New()
require.NoError(t, err)
generateCtr := func(height uint64, index int64) *ethpb.DepositContainer {
return &ethpb.DepositContainer{
Eth1BlockHeight: height,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{uint8(index)}, 48),
WithdrawalCredentials: make([]byte, 32),
Signature: make([]byte, 96),
},
},
Index: index,
}
}
finalizedDeposits := []*ethpb.DepositContainer{
generateCtr(10, 0),
generateCtr(11, 1),
generateCtr(12, 2),
generateCtr(12, 3),
generateCtr(13, 4),
generateCtr(13, 5),
generateCtr(13, 6),
generateCtr(14, 7),
}
dc.deposits = append(finalizedDeposits,
generateCtr(15, 8),
generateCtr(15, 9),
generateCtr(30, 10))
trieItems := make([][]byte, 0, len(dc.deposits))
for _, dep := range dc.allDeposits(big.NewInt(30)) {
depHash, err := dep.Data.HashTreeRoot()
assert.NoError(t, err)
trieItems = append(trieItems, depHash[:])
}
depositTrie, err := trie.GenerateTrieFromItems(trieItems, params.BeaconConfig().DepositContractTreeDepth)
assert.NoError(t, err)
// Perform this in a non-sensical ordering
dc.InsertFinalizedDeposits(context.Background(), 10)
dc.InsertFinalizedDeposits(context.Background(), 2)
dc.InsertFinalizedDeposits(context.Background(), 3)
dc.InsertFinalizedDeposits(context.Background(), 4)
// Mimick finalized deposit trie fetch.
fd := dc.FinalizedDeposits(context.Background())
deps := dc.NonFinalizedDeposits(context.Background(), fd.MerkleTrieIndex, big.NewInt(14))
insertIndex := fd.MerkleTrieIndex + 1
for _, dep := range deps {
depHash, err := dep.Data.HashTreeRoot()
assert.NoError(t, err)
if err = fd.Deposits.Insert(depHash[:], int(insertIndex)); err != nil {
assert.NoError(t, err)
}
insertIndex++
}
dc.InsertFinalizedDeposits(context.Background(), 15)
dc.InsertFinalizedDeposits(context.Background(), 15)
dc.InsertFinalizedDeposits(context.Background(), 14)
fd = dc.FinalizedDeposits(context.Background())
deps = dc.NonFinalizedDeposits(context.Background(), fd.MerkleTrieIndex, big.NewInt(30))
insertIndex = fd.MerkleTrieIndex + 1
for _, dep := range deps {
depHash, err := dep.Data.HashTreeRoot()
assert.NoError(t, err)
if err = fd.Deposits.Insert(depHash[:], int(insertIndex)); err != nil {
assert.NoError(t, err)
}
insertIndex++
}
assert.Equal(t, fd.Deposits.NumOfItems(), depositTrie.NumOfItems())
}
func TestPruneProofs_Ok(t *testing.T) {
dc, err := New()
require.NoError(t, err)

View File

@@ -105,6 +105,7 @@ type HeadAccessDatabase interface {
// initialization method needed for origin checkpoint sync
SaveOrigin(ctx context.Context, serState, serBlock []byte) error
SaveOriginCheckpointBlockRoot(ctx context.Context, blockRoot [32]byte) error
SaveBackfillBlockRoot(ctx context.Context, blockRoot [32]byte) error
}

View File

@@ -47,18 +47,14 @@ type Config struct {
// into the beacon chain database and running services at start up. This service should not be used in production
// as it does not have any value other than ease of use for testing purposes.
func NewService(ctx context.Context, cfg *Config) *Service {
log.Warn("Saving generated genesis state in database for interop testing")
ctx, cancel := context.WithCancel(ctx)
return &Service{
s := &Service{
cfg: cfg,
ctx: ctx,
cancel: cancel,
}
}
// Start initializes the genesis state from configured flags.
func (s *Service) Start() {
log.Warn("Saving generated genesis state in database for interop testing")
if s.cfg.GenesisPath != "" {
data, err := ioutil.ReadFile(s.cfg.GenesisPath)
@@ -73,14 +69,14 @@ func (s *Service) Start() {
if err != nil {
log.Fatalf("Could not get state trie: %v", err)
}
if err := s.saveGenesisState(s.ctx, genesisTrie); err != nil {
if err := s.saveGenesisState(ctx, genesisTrie); err != nil {
log.Fatalf("Could not save interop genesis state %v", err)
}
return
return s
}
// Save genesis state in db
genesisState, _, err := interop.GenerateGenesisState(s.ctx, s.cfg.GenesisTime, s.cfg.NumValidators)
genesisState, _, err := interop.GenerateGenesisState(ctx, s.cfg.GenesisTime, s.cfg.NumValidators)
if err != nil {
log.Fatalf("Could not generate interop genesis state: %v", err)
}
@@ -96,11 +92,17 @@ func (s *Service) Start() {
if err != nil {
log.Fatalf("Could not hash tree root genesis state: %v", err)
}
go slots.CountdownToGenesis(s.ctx, time.Unix(int64(s.cfg.GenesisTime), 0), s.cfg.NumValidators, gRoot)
go slots.CountdownToGenesis(ctx, time.Unix(int64(s.cfg.GenesisTime), 0), s.cfg.NumValidators, gRoot)
if err := s.saveGenesisState(s.ctx, genesisTrie); err != nil {
if err := s.saveGenesisState(ctx, genesisTrie); err != nil {
log.Fatalf("Could not save interop genesis state %v", err)
}
return s
}
// Start initializes the genesis state from configured flags.
func (_ *Service) Start() {
}
// Stop does nothing.

View File

@@ -95,7 +95,6 @@ func NewService(ctx context.Context, config *ValidatorMonitorConfig, tracked []t
latestPerformance: make(map[types.ValidatorIndex]ValidatorLatestPerformance),
aggregatedPerformance: make(map[types.ValidatorIndex]ValidatorAggregatedPerformance),
trackedSyncCommitteeIndices: make(map[types.ValidatorIndex][]types.CommitteeIndex),
isLogging: false,
}
for _, idx := range tracked {
r.TrackedValidators[idx] = true
@@ -118,6 +117,7 @@ func (s *Service) Start() {
"ValidatorIndices": tracked,
}).Info("Starting service")
s.isLogging = false
stateChannel := make(chan *feed.Event, 1)
stateSub := s.config.StateNotifier.StateFeed().Subscribe(stateChannel)

View File

@@ -906,7 +906,6 @@ func (b *BeaconNode) registerDeterminsticGenesisService() error {
DepositCache: b.depositCache,
GenesisPath: genesisStatePath,
})
svc.Start()
// Register genesis state as start-up state when interop mode.
// The start-up state gets reused across services.

View File

@@ -120,16 +120,11 @@ 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)
switch {
case errors.Is(err, hexutil.ErrEmptyString):
return false, nil
case err != nil:
if err != nil {
return false, err
case latest == nil:
}
if 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 {

View File

@@ -190,38 +190,6 @@ 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),

View File

@@ -413,14 +413,11 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*ethpb.DepositCo
// accumulates. we finalize them here before we are ready to receive a block.
// Otherwise, the first few blocks will be slower to compute as we will
// hold the lock and be busy finalizing the deposits.
// The deposit index in the state is always the index of the next deposit
// to be included(rather than the last one to be processed). This was most likely
// done as the state cannot represent signed integers.
actualIndex := int64(currIndex) - 1 // lint:ignore uintcast -- deposit index will not exceed int64 in your lifetime.
s.cfg.depositCache.InsertFinalizedDeposits(ctx, actualIndex)
s.cfg.depositCache.InsertFinalizedDeposits(ctx, int64(currIndex)) // lint:ignore uintcast -- deposit index will not exceed int64 in your lifetime.
// Deposit proofs are only used during state transition and can be safely removed to save space.
if err = s.cfg.depositCache.PruneProofs(ctx, actualIndex); err != nil {
// lint:ignore uintcast -- deposit index will not exceed int64 in your lifetime.
if err = s.cfg.depositCache.PruneProofs(ctx, int64(currIndex)); err != nil {
return errors.Wrap(err, "could not prune deposit proofs")
}
}

View File

@@ -472,7 +472,7 @@ func TestInitDepositCacheWithFinalization_OK(t *testing.T) {
require.NoError(t, s.cfg.beaconDB.SaveState(context.Background(), emptyState, headRoot))
require.NoError(t, stateGen.SaveState(context.Background(), headRoot, emptyState))
s.cfg.stateGen = stateGen
require.NoError(t, emptyState.SetEth1DepositIndex(3))
require.NoError(t, emptyState.SetEth1DepositIndex(2))
ctx := context.Background()
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Epoch: slots.ToEpoch(0), Root: headRoot[:]}))

View File

@@ -116,14 +116,21 @@ type Config struct {
// be registered into a running beacon node.
func NewService(ctx context.Context, cfg *Config) *Service {
ctx, cancel := context.WithCancel(ctx)
s := &Service{
return &Service{
cfg: cfg,
ctx: ctx,
cancel: cancel,
incomingAttestation: make(chan *ethpbv1alpha1.Attestation, params.BeaconConfig().DefaultBufferSize),
connectedRPCClients: make(map[net.Addr]bool),
}
}
// paranoid build time check to ensure ChainInfoFetcher implements required interfaces
var _ stategen.CanonicalChecker = blockchain.ChainInfoFetcher(nil)
var _ stategen.CurrentSlotter = blockchain.ChainInfoFetcher(nil)
// Start the gRPC server.
func (s *Service) Start() {
address := fmt.Sprintf("%s:%s", s.cfg.Host, s.cfg.Port)
lis, err := net.Listen("tcp", address)
if err != nil {
@@ -152,6 +159,7 @@ func NewService(ctx context.Context, cfg *Config) *Service {
)),
grpc.MaxRecvMsgSize(s.cfg.MaxMsgSize),
}
grpc_prometheus.EnableHandlingTimeHistogram()
if s.cfg.CertFlag != "" && s.cfg.KeyFlag != "" {
creds, err := credentials.NewServerTLSFromFile(s.cfg.CertFlag, s.cfg.KeyFlag)
if err != nil {
@@ -165,17 +173,6 @@ func NewService(ctx context.Context, cfg *Config) *Service {
}
s.grpcServer = grpc.NewServer(opts...)
return s
}
// paranoid build time check to ensure ChainInfoFetcher implements required interfaces
var _ stategen.CanonicalChecker = blockchain.ChainInfoFetcher(nil)
var _ stategen.CurrentSlotter = blockchain.ChainInfoFetcher(nil)
// Start the gRPC server.
func (s *Service) Start() {
grpc_prometheus.EnableHandlingTimeHistogram()
var stateCache stategen.CachedGetter
if s.cfg.StateGen != nil {
stateCache = s.cfg.StateGen.CombinedCache()

View File

@@ -56,7 +56,7 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
reference: stateutil.NewRef(1),
RWMutex: new(sync.RWMutex),
length: length,
numOfElems: retrieveLength(elements),
numOfElems: reflect.Indirect(reflect.ValueOf(elements)).Len(),
}, nil
case types.CompositeArray, types.CompressedArray:
return &FieldTrie{
@@ -66,7 +66,7 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
reference: stateutil.NewRef(1),
RWMutex: new(sync.RWMutex),
length: length,
numOfElems: retrieveLength(elements),
numOfElems: reflect.Indirect(reflect.ValueOf(elements)).Len(),
}, nil
default:
return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(dataType).Name())
@@ -97,14 +97,14 @@ func (f *FieldTrie) RecomputeTrie(indices []uint64, elements interface{}) ([32]b
if err != nil {
return [32]byte{}, err
}
f.numOfElems = retrieveLength(elements)
f.numOfElems = reflect.Indirect(reflect.ValueOf(elements)).Len()
return fieldRoot, nil
case types.CompositeArray:
fieldRoot, f.fieldLayers, err = stateutil.RecomputeFromLayerVariable(fieldRoots, indices, f.fieldLayers)
if err != nil {
return [32]byte{}, err
}
f.numOfElems = retrieveLength(elements)
f.numOfElems = reflect.Indirect(reflect.ValueOf(elements)).Len()
return stateutil.AddInMixin(fieldRoot, uint64(len(f.fieldLayers[0])))
case types.CompressedArray:
numOfElems, err := f.field.ElemsInChunk()
@@ -133,7 +133,7 @@ func (f *FieldTrie) RecomputeTrie(indices []uint64, elements interface{}) ([32]b
if err != nil {
return [32]byte{}, err
}
f.numOfElems = retrieveLength(elements)
f.numOfElems = reflect.Indirect(reflect.ValueOf(elements)).Len()
return stateutil.AddInMixin(fieldRoot, uint64(f.numOfElems))
default:
return [32]byte{}, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(f.dataType).Name())

View File

@@ -57,11 +57,9 @@ func validateElements(field types.FieldIndex, dataType types.DataType, elements
}
length *= comLength
}
elemLen := retrieveLength(elements)
castedLen := int(length) // lint:ignore uintcast- ajhdjhd
if elemLen > castedLen {
return errors.Errorf("elements length is larger than expected for field %s: %d > %d", field.String(version.Phase0), elemLen, length)
val := reflect.Indirect(reflect.ValueOf(elements))
if uint64(val.Len()) > length {
return errors.Errorf("elements length is larger than expected for field %s: %d > %d", field.String(version.Phase0), val.Len(), length)
}
return nil
}
@@ -74,7 +72,7 @@ func fieldConverters(field types.FieldIndex, indices []uint64, elements interfac
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.BlockRoots:
return handleIndexer(val, indices, convertAll)
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for block roots")
}
@@ -92,7 +90,7 @@ func fieldConverters(field types.FieldIndex, indices []uint64, elements interfac
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.RandaoMixes:
return handleIndexer(val, indices, convertAll)
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for randao mixes")
}
@@ -184,34 +182,6 @@ func handle32ByteArrays(val [][32]byte, indices []uint64, convertAll bool) ([][3
return roots, nil
}
// handle32ByteArrays computes and returns 32 byte arrays in a slice of root format.
func handleIndexer(indexer customtypes.Indexer, indices []uint64, convertAll bool) ([][32]byte, error) {
length := len(indices)
totalLength := indexer.TotalLength()
if convertAll {
length = int(totalLength) // lint:ignore uintcast- ajhdjhd
}
roots := make([][32]byte, 0, length)
rootCreator := func(input [32]byte) {
roots = append(roots, input)
}
if convertAll {
for i := uint64(0); i < uint64(length); i++ {
rootCreator(indexer.RootAtIndex(i))
}
return roots, nil
}
if totalLength > 0 {
for _, idx := range indices {
if idx > totalLength-1 {
return nil, fmt.Errorf("index %d greater than number of byte arrays %d", idx, totalLength)
}
rootCreator(indexer.RootAtIndex(idx))
}
}
return roots, nil
}
// handleValidatorSlice returns the validator indices in a slice of root format.
func handleValidatorSlice(val []*ethpb.Validator, indices []uint64, convertAll bool) ([][32]byte, error) {
length := len(indices)
@@ -378,17 +348,3 @@ func handleBalanceSlice(val, indices []uint64, convertAll bool) ([][32]byte, err
}
return [][32]byte{}, nil
}
func retrieveLength(elements interface{}) int {
elemLen := int(0)
elemVal := reflect.ValueOf(elements)
if reflect.Indirect(elemVal).Kind() == reflect.Struct {
meth := elemVal.MethodByName("TotalLength")
ret := meth.Call([]reflect.Value{})
elemLen = int(ret[0].Uint()) // lint:ignore uintcast- ajhdjhd
} else {
val := reflect.Indirect(elemVal)
elemLen = val.Len()
}
return elemLen
}

View File

@@ -12,7 +12,6 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/state/stateutil:go_default_library",
"//config/fieldparams:go_default_library",
"@com_github_ferranbt_fastssz//:go_default_library",
],

View File

@@ -2,162 +2,28 @@ package customtypes
import (
"fmt"
"reflect"
"runtime"
"sort"
"sync"
"unsafe"
fssz "github.com/ferranbt/fastssz"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
)
var _ fssz.HashRoot = (*BlockRoots)(nil)
var _ fssz.HashRoot = (BlockRoots)([fieldparams.BlockRootsLength][32]byte{})
var _ fssz.Marshaler = (*BlockRoots)(nil)
var _ fssz.Unmarshaler = (*BlockRoots)(nil)
type Indexer interface {
RootAtIndex(idx uint64) [32]byte
TotalLength() uint64
}
// BlockRoots represents block roots of the beacon state.
type BlockRoots struct {
baseArray *baseArrayBlockRoots
fieldJournal map[uint64][32]byte
generation uint64
*stateutil.Reference
}
type baseArrayBlockRoots struct {
baseArray *[fieldparams.BlockRootsLength][32]byte
descendantMap map[uint64][]uintptr
*sync.RWMutex
*stateutil.Reference
}
type sorter struct {
objs [][]uintptr
generations []uint64
}
func (s sorter) Len() int {
return len(s.generations)
}
func (s sorter) Swap(i, j int) {
s.objs[i], s.objs[j] = s.objs[j], s.objs[i]
s.generations[i], s.generations[j] = s.generations[j], s.generations[i]
}
func (s sorter) Less(i, j int) bool {
return s.generations[i] < s.generations[j]
}
func (b *baseArrayBlockRoots) RootAtIndex(idx uint64) [32]byte {
b.RWMutex.RLock()
defer b.RWMutex.RUnlock()
return b.baseArray[idx]
}
func (b *baseArrayBlockRoots) TotalLength() uint64 {
return fieldparams.BlockRootsLength
}
func (b *baseArrayBlockRoots) addGeneration(generation uint64, descendant uintptr) {
b.RWMutex.Lock()
defer b.RWMutex.Unlock()
b.descendantMap[generation] = append(b.descendantMap[generation], descendant)
}
func (b *baseArrayBlockRoots) removeGeneration(generation uint64, descendant uintptr) {
b.RWMutex.Lock()
defer b.RWMutex.Unlock()
ptrVals := b.descendantMap[generation]
newVals := []uintptr{}
for _, v := range ptrVals {
if v == descendant {
continue
}
newVals = append(newVals, v)
}
b.descendantMap[generation] = newVals
}
func (b *baseArrayBlockRoots) numOfDescendants() uint64 {
b.RWMutex.RLock()
defer b.RWMutex.RUnlock()
return uint64(len(b.descendantMap))
}
func (b *baseArrayBlockRoots) cleanUp() {
b.RWMutex.Lock()
defer b.RWMutex.Unlock()
fmt.Printf("\n cleaning up block roots %d \n ", len(b.descendantMap))
listOfObjs := [][]uintptr{}
generations := []uint64{}
for g, objs := range b.descendantMap {
generations = append(generations, g)
listOfObjs = append(listOfObjs, objs)
}
sortedObj := sorter{
objs: listOfObjs,
generations: generations,
}
sort.Sort(sortedObj)
lastReferencedGen := 0
lastRefrencedIdx := 0
lastRefPointer := 0
for i, g := range sortedObj.generations {
for j, o := range sortedObj.objs[i] {
x := (*BlockRoots)(unsafe.Pointer(o))
if x == nil {
continue
}
lastReferencedGen = int(g) // lint:ignore uintcast- ajhdjhd
lastRefrencedIdx = i
lastRefPointer = j
break
}
if lastReferencedGen != 0 {
break
}
}
fmt.Printf("\n block root map %d, %d, %d \n ", lastReferencedGen, lastRefrencedIdx, lastRefPointer)
br := (*BlockRoots)(unsafe.Pointer(sortedObj.objs[lastRefrencedIdx][lastRefPointer]))
for k, v := range br.fieldJournal {
b.baseArray[k] = v
}
sortedObj.generations = sortedObj.generations[lastRefrencedIdx:]
sortedObj.objs = sortedObj.objs[lastRefrencedIdx:]
newMap := make(map[uint64][]uintptr)
for i, g := range sortedObj.generations {
newMap[g] = sortedObj.objs[i]
}
b.descendantMap = newMap
}
type BlockRoots [fieldparams.BlockRootsLength][32]byte
// HashTreeRoot returns calculated hash root.
func (r *BlockRoots) HashTreeRoot() ([32]byte, error) {
func (r BlockRoots) HashTreeRoot() ([32]byte, error) {
return fssz.HashWithDefaultHasher(r)
}
// HashTreeRootWith hashes a BlockRoots object with a Hasher from the default HasherPool.
func (r *BlockRoots) HashTreeRootWith(hh *fssz.Hasher) error {
func (r BlockRoots) HashTreeRootWith(hh *fssz.Hasher) error {
index := hh.Index()
for i := uint64(0); i < r.baseArray.TotalLength(); i++ {
if val, ok := r.fieldJournal[i]; ok {
hh.Append(val[:])
continue
}
rt := r.baseArray.RootAtIndex(i)
hh.Append(rt[:])
for _, sRoot := range r {
hh.Append(sRoot[:])
}
hh.Merkleize(index)
return nil
@@ -168,13 +34,12 @@ func (r *BlockRoots) UnmarshalSSZ(buf []byte) error {
if len(buf) != r.SizeSSZ() {
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
}
r.baseArray.Lock()
defer r.baseArray.Unlock()
for i := range r.baseArray.baseArray {
copy(r.baseArray.baseArray[i][:], buf[i*32:(i+1)*32])
var roots BlockRoots
for i := range roots {
copy(roots[i][:], buf[i*32:(i+1)*32])
}
*r = roots
return nil
}
@@ -190,13 +55,10 @@ func (r *BlockRoots) MarshalSSZTo(dst []byte) ([]byte, error) {
// MarshalSSZ marshals BlockRoots into a serialized object.
func (r *BlockRoots) MarshalSSZ() ([]byte, error) {
marshalled := make([]byte, fieldparams.BlockRootsLength*32)
for i := uint64(0); i < r.baseArray.TotalLength(); i++ {
if val, ok := r.fieldJournal[i]; ok {
copy(marshalled[i*32:], val[:])
continue
for i, r32 := range r {
for j, rr := range r32 {
marshalled[i*32+j] = rr
}
rt := r.baseArray.RootAtIndex(i)
copy(marshalled[i*32:], rt[:])
}
return marshalled, nil
}
@@ -211,152 +73,10 @@ func (r *BlockRoots) Slice() [][]byte {
if r == nil {
return nil
}
bRoots := make([][]byte, r.baseArray.TotalLength())
for i := uint64(0); i < r.baseArray.TotalLength(); i++ {
if val, ok := r.fieldJournal[i]; ok {
bRoots[i] = val[:]
continue
}
rt := r.baseArray.RootAtIndex(i)
bRoots[i] = rt[:]
bRoots := make([][]byte, len(r))
for i, root := range r {
tmp := root
bRoots[i] = tmp[:]
}
return bRoots
}
// Slice converts a customtypes.BlockRoots object into a 2D byte slice.
func (r *BlockRoots) Array() [fieldparams.BlockRootsLength][32]byte {
if r == nil {
return [fieldparams.BlockRootsLength][32]byte{}
}
bRoots := [fieldparams.BlockRootsLength][32]byte{}
for i := uint64(0); i < r.baseArray.TotalLength(); i++ {
if val, ok := r.fieldJournal[i]; ok {
bRoots[i] = val
continue
}
rt := r.baseArray.RootAtIndex(i)
bRoots[i] = rt
}
return bRoots
}
func SetFromSlice(slice [][]byte) *BlockRoots {
br := &BlockRoots{
baseArray: &baseArrayBlockRoots{
baseArray: new([fieldparams.BlockRootsLength][32]byte),
descendantMap: map[uint64][]uintptr{},
RWMutex: new(sync.RWMutex),
Reference: stateutil.NewRef(1),
},
fieldJournal: map[uint64][32]byte{},
Reference: stateutil.NewRef(1),
}
for i, rt := range slice {
copy(br.baseArray.baseArray[i][:], rt)
}
runtime.SetFinalizer(br, blockRootsFinalizer)
return br
}
func (r *BlockRoots) SetFromBaseField(field [fieldparams.BlockRootsLength][32]byte) {
r.baseArray = &baseArrayBlockRoots{
baseArray: &field,
descendantMap: map[uint64][]uintptr{},
RWMutex: new(sync.RWMutex),
Reference: stateutil.NewRef(1),
}
r.fieldJournal = map[uint64][32]byte{}
r.Reference = stateutil.NewRef(1)
r.baseArray.addGeneration(0, reflect.ValueOf(r).Pointer())
runtime.SetFinalizer(r, blockRootsFinalizer)
}
func (r *BlockRoots) RootAtIndex(idx uint64) [32]byte {
if val, ok := r.fieldJournal[idx]; ok {
return val
}
return r.baseArray.RootAtIndex(idx)
}
func (r *BlockRoots) SetRootAtIndex(idx uint64, val [32]byte) {
if r.Refs() <= 1 && r.baseArray.Refs() <= 1 {
r.baseArray.Lock()
r.baseArray.baseArray[idx] = val
r.baseArray.Unlock()
return
}
if r.Refs() <= 1 {
r.fieldJournal[idx] = val
r.baseArray.removeGeneration(r.generation, reflect.ValueOf(r).Pointer())
r.generation++
r.baseArray.addGeneration(r.generation, reflect.ValueOf(r).Pointer())
return
}
newJournal := make(map[uint64][32]byte)
for k, val := range r.fieldJournal {
newJournal[k] = val
}
r.fieldJournal = newJournal
r.MinusRef()
r.Reference = stateutil.NewRef(1)
r.fieldJournal[idx] = val
r.baseArray.removeGeneration(r.generation, reflect.ValueOf(r).Pointer())
r.generation++
r.baseArray.addGeneration(r.generation, reflect.ValueOf(r).Pointer())
}
func (r *BlockRoots) Copy() *BlockRoots {
r.baseArray.AddRef()
r.Reference.AddRef()
br := &BlockRoots{
baseArray: r.baseArray,
fieldJournal: r.fieldJournal,
Reference: r.Reference,
generation: r.generation,
}
r.baseArray.addGeneration(r.generation, reflect.ValueOf(br).Pointer())
if r.baseArray.numOfDescendants() > 20 {
r.baseArray.cleanUp()
}
runtime.SetFinalizer(br, blockRootsFinalizer)
return br
}
func (r *BlockRoots) TotalLength() uint64 {
return fieldparams.BlockRootsLength
}
func (r *BlockRoots) IncreaseRef() {
r.Reference.AddRef()
r.baseArray.Reference.AddRef()
}
func (r *BlockRoots) DecreaseRef() {
r.Reference.MinusRef()
r.baseArray.Reference.MinusRef()
}
func blockRootsFinalizer(br *BlockRoots) {
br.baseArray.Lock()
defer br.baseArray.Unlock()
ptrVal := reflect.ValueOf(br).Pointer()
vals, ok := br.baseArray.descendantMap[br.generation]
if !ok {
return
}
exists := false
wantedVals := []uintptr{}
for _, v := range vals {
if v == ptrVal {
exists = true
continue
}
newV := v
wantedVals = append(wantedVals, newV)
}
if !exists {
return
}
br.baseArray.descendantMap[br.generation] = wantedVals
}

View File

@@ -1,25 +1,24 @@
package customtypes
import (
"bytes"
"reflect"
"testing"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/testing/assert"
)
func TestBlockRoots_Casting(t *testing.T) {
var b [fieldparams.BlockRootsLength][32]byte
f := SetFromSlice([][]byte{})
f.SetFromBaseField(b)
if !reflect.DeepEqual(f.Array(), b) {
t.Errorf("Unequal: %v = %v", f.Array(), b)
d := BlockRoots(b)
if !reflect.DeepEqual([fieldparams.BlockRootsLength][32]byte(d), b) {
t.Errorf("Unequal: %v = %v", d, b)
}
}
func TestBlockRoots_UnmarshalSSZ(t *testing.T) {
t.Run("Ok", func(t *testing.T) {
d := SetFromSlice([][]byte{})
d := BlockRoots{}
var b [fieldparams.BlockRootsLength][32]byte
b[0] = [32]byte{'f', 'o', 'o'}
b[1] = [32]byte{'b', 'a', 'r'}
@@ -33,8 +32,8 @@ func TestBlockRoots_UnmarshalSSZ(t *testing.T) {
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if !reflect.DeepEqual(b, d.Array()) {
t.Errorf("Unequal: %v = %v", b, d.Array())
if !reflect.DeepEqual(b, [fieldparams.BlockRootsLength][32]byte(d)) {
t.Errorf("Unequal: %v = %v", b, [fieldparams.BlockRootsLength][32]byte(d))
}
})
@@ -71,47 +70,28 @@ func TestBlockRoots_MarshalSSZTo(t *testing.T) {
}
func TestBlockRoots_MarshalSSZ(t *testing.T) {
d := SetFromSlice([][]byte{})
d.IncreaseRef()
d.SetRootAtIndex(0, [32]byte{'f', 'o', 'o'})
d.IncreaseRef()
d.IncreaseRef()
d.SetRootAtIndex(1, [32]byte{'b', 'a', 'r'})
d := BlockRoots{}
d[0] = [32]byte{'f', 'o', 'o'}
d[1] = [32]byte{'b', 'a', 'r'}
b, err := d.MarshalSSZ()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
rt := d.RootAtIndex(0)
if !reflect.DeepEqual(rt[:], b[0:32]) {
t.Errorf("Unequal: %v = %v", rt, b[0:32])
if !reflect.DeepEqual(d[0][:], b[0:32]) {
t.Errorf("Unequal: %v = %v", d[0], b[0:32])
}
rt = d.RootAtIndex(1)
if !reflect.DeepEqual(rt[:], b[32:64]) {
t.Errorf("Unequal: %v = %v", rt, b[32:64])
}
d2 := SetFromSlice([][]byte{})
err = d2.UnmarshalSSZ(b)
if err != nil {
t.Error(err)
}
res, err := d2.MarshalSSZ()
if err != nil {
t.Error(err)
}
if !bytes.Equal(res, b) {
t.Error("unequal")
if !reflect.DeepEqual(d[1][:], b[32:64]) {
t.Errorf("Unequal: %v = %v", d[0], b[32:64])
}
}
func TestBlockRoots_SizeSSZ(t *testing.T) {
d := SetFromSlice([][]byte{})
d := BlockRoots{}
if d.SizeSSZ() != fieldparams.BlockRootsLength*32 {
t.Errorf("Wrong SSZ size. Expected %v vs actual %v", fieldparams.BlockRootsLength*32, d.SizeSSZ())
}
}
/*
func TestBlockRoots_Slice(t *testing.T) {
a, b, c := [32]byte{'a'}, [32]byte{'b'}, [32]byte{'c'}
roots := BlockRoots{}
@@ -123,4 +103,3 @@ func TestBlockRoots_Slice(t *testing.T) {
assert.DeepEqual(t, b[:], slice[10])
assert.DeepEqual(t, c[:], slice[100])
}
*/

View File

@@ -2,77 +2,48 @@ package customtypes
import (
"fmt"
"sync"
fssz "github.com/ferranbt/fastssz"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
)
var _ fssz.HashRoot = (*RandaoMixes)(nil)
var _ fssz.HashRoot = (RandaoMixes)([fieldparams.RandaoMixesLength][32]byte{})
var _ fssz.Marshaler = (*RandaoMixes)(nil)
var _ fssz.Unmarshaler = (*RandaoMixes)(nil)
// BlockRoots represents block roots of the beacon state.
type RandaoMixes struct {
baseArray *baseArrayRandaoMixes
fieldJournal map[uint64][32]byte
*stateutil.Reference
}
type baseArrayRandaoMixes struct {
baseArray *[fieldparams.RandaoMixesLength][32]byte
*sync.RWMutex
*stateutil.Reference
}
func (b *baseArrayRandaoMixes) RootAtIndex(idx uint64) [32]byte {
b.RWMutex.RLock()
defer b.RWMutex.RUnlock()
return b.baseArray[idx]
}
func (b *baseArrayRandaoMixes) TotalLength() uint64 {
return fieldparams.RandaoMixesLength
}
// RandaoMixes represents RANDAO mixes of the beacon state.
type RandaoMixes [fieldparams.RandaoMixesLength][32]byte
// HashTreeRoot returns calculated hash root.
func (r *RandaoMixes) HashTreeRoot() ([32]byte, error) {
func (r RandaoMixes) HashTreeRoot() ([32]byte, error) {
return fssz.HashWithDefaultHasher(r)
}
// HashTreeRootWith hashes a BlockRoots object with a Hasher from the default HasherPool.
func (r *RandaoMixes) HashTreeRootWith(hh *fssz.Hasher) error {
// HashTreeRootWith hashes a RandaoMixes object with a Hasher from the default HasherPool.
func (r RandaoMixes) HashTreeRootWith(hh *fssz.Hasher) error {
index := hh.Index()
for i := uint64(0); i < r.baseArray.TotalLength(); i++ {
if val, ok := r.fieldJournal[i]; ok {
hh.Append(val[:])
continue
}
rt := r.baseArray.RootAtIndex(i)
hh.Append(rt[:])
for _, sRoot := range r {
hh.Append(sRoot[:])
}
hh.Merkleize(index)
return nil
}
// UnmarshalSSZ deserializes the provided bytes buffer into the BlockRoots object.
// UnmarshalSSZ deserializes the provided bytes buffer into the RandaoMixes object.
func (r *RandaoMixes) UnmarshalSSZ(buf []byte) error {
if len(buf) != r.SizeSSZ() {
return fmt.Errorf("expected buffer of length %d received %d", r.SizeSSZ(), len(buf))
}
r.baseArray.Lock()
defer r.baseArray.Unlock()
for i := range r.baseArray.baseArray {
copy(r.baseArray.baseArray[i][:], buf[i*32:(i+1)*32])
var roots RandaoMixes
for i := range roots {
copy(roots[i][:], buf[i*32:(i+1)*32])
}
*r = roots
return nil
}
// MarshalSSZTo marshals BlockRoots with the provided byte slice.
// MarshalSSZTo marshals RandaoMixes with the provided byte slice.
func (r *RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
marshalled, err := r.MarshalSSZ()
if err != nil {
@@ -81,16 +52,13 @@ func (r *RandaoMixes) MarshalSSZTo(dst []byte) ([]byte, error) {
return append(dst, marshalled...), nil
}
// MarshalSSZ marshals BlockRoots into a serialized object.
// MarshalSSZ marshals RandaoMixes into a serialized object.
func (r *RandaoMixes) MarshalSSZ() ([]byte, error) {
marshalled := make([]byte, fieldparams.RandaoMixesLength*32)
for i := uint64(0); i < r.baseArray.TotalLength(); i++ {
if val, ok := r.fieldJournal[i]; ok {
copy(marshalled[i*32:], val[:])
continue
for i, r32 := range r {
for j, rr := range r32 {
marshalled[i*32+j] = rr
}
rt := r.baseArray.RootAtIndex(i)
copy(marshalled[i*32:], rt[:])
}
return marshalled, nil
}
@@ -100,90 +68,15 @@ func (_ *RandaoMixes) SizeSSZ() int {
return fieldparams.RandaoMixesLength * 32
}
// Slice converts a customtypes.BlockRoots object into a 2D byte slice.
// Slice converts a customtypes.RandaoMixes object into a 2D byte slice.
func (r *RandaoMixes) Slice() [][]byte {
if r == nil {
return nil
}
bRoots := make([][]byte, r.baseArray.TotalLength())
for i := uint64(0); i < r.baseArray.TotalLength(); i++ {
if val, ok := r.fieldJournal[i]; ok {
bRoots[i] = val[:]
continue
}
rt := r.baseArray.RootAtIndex(i)
bRoots[i] = rt[:]
mixes := make([][]byte, len(r))
for i, root := range r {
tmp := root
mixes[i] = tmp[:]
}
return bRoots
}
func SetFromSliceRandao(slice [][]byte) *RandaoMixes {
br := &RandaoMixes{
baseArray: &baseArrayRandaoMixes{
baseArray: new([fieldparams.RandaoMixesLength][32]byte),
RWMutex: new(sync.RWMutex),
Reference: stateutil.NewRef(1),
},
fieldJournal: map[uint64][32]byte{},
Reference: stateutil.NewRef(1),
}
for i, rt := range slice {
copy(br.baseArray.baseArray[i][:], rt)
}
return br
}
func (r *RandaoMixes) SetFromBaseField(field [fieldparams.RandaoMixesLength][32]byte) {
r.baseArray.baseArray = &field
}
func (r *RandaoMixes) RootAtIndex(idx uint64) [32]byte {
if val, ok := r.fieldJournal[idx]; ok {
return val
}
return r.baseArray.RootAtIndex(idx)
}
func (r *RandaoMixes) SetRootAtIndex(idx uint64, val [32]byte) {
if r.Refs() <= 1 && r.baseArray.Refs() <= 1 {
r.baseArray.baseArray[idx] = val
return
}
if r.Refs() <= 1 {
r.fieldJournal[idx] = val
return
}
newJournal := make(map[uint64][32]byte)
for k, val := range r.fieldJournal {
newJournal[k] = val
}
r.fieldJournal = newJournal
r.MinusRef()
r.Reference = stateutil.NewRef(1)
r.fieldJournal[idx] = val
}
func (r *RandaoMixes) Copy() *RandaoMixes {
r.baseArray.AddRef()
r.Reference.AddRef()
rm := &RandaoMixes{
baseArray: r.baseArray,
fieldJournal: r.fieldJournal,
Reference: r.Reference,
}
return rm
}
func (r *RandaoMixes) TotalLength() uint64 {
return fieldparams.RandaoMixesLength
}
func (r *RandaoMixes) IncreaseRef() {
r.Reference.AddRef()
r.baseArray.Reference.AddRef()
}
func (r *RandaoMixes) DecreaseRef() {
r.Reference.MinusRef()
r.baseArray.Reference.MinusRef()
return mixes
}

View File

@@ -76,8 +76,8 @@ func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) blockRootAtIndex(idx uint64) ([32]byte, error) {
if b.blockRoots.TotalLength() <= idx {
if uint64(len(b.blockRoots)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
}
return b.blockRoots.RootAtIndex(idx), nil
return b.blockRoots[idx], nil
}

View File

@@ -37,10 +37,10 @@ func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
if b.randaoMixes.TotalLength() <= idx {
if uint64(len(b.randaoMixes)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
}
return b.randaoMixes.RootAtIndex(idx), nil
return b.randaoMixes[idx], nil
}
// RandaoMixesLength returns the length of the randao mixes slice.
@@ -62,5 +62,5 @@ func (b *BeaconState) randaoMixesLength() int {
return 0
}
return int(b.randaoMixes.TotalLength()) // lint:ignore uintcast- ajhdjhd
return len(b.randaoMixes)
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -24,12 +25,14 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[blockRoots].MinusRef()
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
var rootsArr [fieldparams.BlockRootsLength][32]byte
for i := 0; i < len(rootsArr); i++ {
copy(rootsArr[i][:], val[i])
}
roots := customtypes.BlockRoots{}
roots.SetFromBaseField(rootsArr)
roots := customtypes.BlockRoots(rootsArr)
b.blockRoots = &roots
b.markFieldAsDirty(blockRoots)
b.rebuildTrie[blockRoots] = true
@@ -39,13 +42,24 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
// UpdateBlockRootAtIndex for the beacon state. Updates the block root
// at a specific index to a new value.
func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error {
if b.blockRoots.TotalLength() <= idx {
if uint64(len(b.blockRoots)) <= idx {
return fmt.Errorf("invalid index provided %d", idx)
}
b.lock.Lock()
defer b.lock.Unlock()
b.blockRoots.SetRootAtIndex(idx, blockRoot)
r := b.blockRoots
if ref := b.sharedFieldReferences[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)
}
r[idx] = blockRoot
b.blockRoots = r
b.markFieldAsDirty(blockRoots)
b.addDirtyIndices(blockRoots, []uint64{idx})

View File

@@ -3,6 +3,7 @@ package v1
import (
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
)
@@ -13,12 +14,14 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[randaoMixes].MinusRef()
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
var mixesArr [fieldparams.RandaoMixesLength][32]byte
for i := 0; i < len(mixesArr); i++ {
copy(mixesArr[i][:], val[i])
}
mixes := customtypes.RandaoMixes{}
mixes.SetFromBaseField(mixesArr)
mixes := customtypes.RandaoMixes(mixesArr)
b.randaoMixes = &mixes
b.markFieldAsDirty(randaoMixes)
b.rebuildTrie[randaoMixes] = true
@@ -28,13 +31,24 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
// UpdateRandaoMixesAtIndex for the beacon state. Updates the randao mixes
// at a specific index to a new value.
func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val []byte) error {
if b.randaoMixes.TotalLength() <= idx {
if uint64(len(b.randaoMixes)) <= idx {
return errors.Errorf("invalid index provided %d", idx)
}
b.lock.Lock()
defer b.lock.Unlock()
b.randaoMixes.SetRootAtIndex(idx, bytesutil.ToBytes32(val))
mixes := b.randaoMixes
if refs := b.sharedFieldReferences[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)
}
mixes[idx] = bytesutil.ToBytes32(val)
b.randaoMixes = mixes
b.markFieldAsDirty(randaoMixes)
b.addDirtyIndices(randaoMixes, []uint64{idx})

View File

@@ -36,8 +36,10 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (state.BeaconState, error)
return nil, errors.New("received nil state")
}
bRoots := customtypes.SetFromSlice(st.BlockRoots)
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)
@@ -46,7 +48,10 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (state.BeaconState, error)
for i, r := range st.HistoricalRoots {
copy(hRoots[i][:], r)
}
mixes := customtypes.SetFromSliceRandao(st.RandaoMixes)
var mixes customtypes.RandaoMixes
for i, m := range st.RandaoMixes {
copy(mixes[i][:], m)
}
fieldCount := params.BeaconConfig().BeaconStateFieldCount
b := &BeaconState{
@@ -55,7 +60,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (state.BeaconState, error)
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
blockRoots: bRoots,
blockRoots: &bRoots,
stateRoots: &sRoots,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
@@ -63,7 +68,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (state.BeaconState, error)
eth1DepositIndex: st.Eth1DepositIndex,
validators: st.Validators,
balances: st.Balances,
randaoMixes: mixes,
randaoMixes: &mixes,
slashings: st.Slashings,
previousEpochAttestations: st.PreviousEpochAttestations,
currentEpochAttestations: st.CurrentEpochAttestations,
@@ -94,6 +99,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (state.BeaconState, error)
// 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)
@@ -121,9 +127,9 @@ func (b *BeaconState) Copy() state.BeaconState {
slashings: b.slashings,
// Large arrays, infrequently changed, constant size.
blockRoots: b.blockRoots.Copy(),
blockRoots: b.blockRoots,
stateRoots: b.stateRoots,
randaoMixes: b.randaoMixes.Copy(),
randaoMixes: b.randaoMixes,
previousEpochAttestations: b.previousEpochAttestations,
currentEpochAttestations: b.currentEpochAttestations,
eth1DataVotes: b.eth1DataVotes,
@@ -205,9 +211,6 @@ func (b *BeaconState) Copy() state.BeaconState {
}
}
b.blockRoots.MinusRef()
b.randaoMixes.MinusRef()
for i := 0; i < fieldCount; i++ {
field := types.FieldIndex(i)
delete(b.stateFieldLeaves, field)

View File

@@ -76,8 +76,9 @@ func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) blockRootAtIndex(idx uint64) ([32]byte, error) {
if b.blockRoots.TotalLength() <= idx {
if uint64(len(b.blockRoots)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
}
return b.blockRoots.RootAtIndex(idx), nil
return b.blockRoots[idx], nil
}

View File

@@ -37,10 +37,11 @@ func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
if b.randaoMixes.TotalLength() <= idx {
if uint64(len(b.randaoMixes)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
}
return b.randaoMixes.RootAtIndex(idx), nil
return b.randaoMixes[idx], nil
}
// RandaoMixesLength returns the length of the randao mixes slice.
@@ -62,5 +63,5 @@ func (b *BeaconState) randaoMixesLength() int {
return 0
}
return int(b.randaoMixes.TotalLength()) // lint:ignore uintcast- ajhdjhd
return len(b.randaoMixes)
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -24,12 +25,14 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[blockRoots].MinusRef()
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
var rootsArr [fieldparams.BlockRootsLength][32]byte
for i := 0; i < len(rootsArr); i++ {
copy(rootsArr[i][:], val[i])
}
roots := customtypes.BlockRoots{}
roots.SetFromBaseField(rootsArr)
roots := customtypes.BlockRoots(rootsArr)
b.blockRoots = &roots
b.markFieldAsDirty(blockRoots)
b.rebuildTrie[blockRoots] = true
@@ -39,13 +42,24 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
// UpdateBlockRootAtIndex for the beacon state. Updates the block root
// at a specific index to a new value.
func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error {
if b.blockRoots.TotalLength() <= idx {
if uint64(len(b.blockRoots)) <= idx {
return fmt.Errorf("invalid index provided %d", idx)
}
b.lock.Lock()
defer b.lock.Unlock()
b.blockRoots.SetRootAtIndex(idx, blockRoot)
r := b.blockRoots
if ref := b.sharedFieldReferences[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)
}
r[idx] = blockRoot
b.blockRoots = r
b.markFieldAsDirty(blockRoots)
b.addDirtyIndices(blockRoots, []uint64{idx})

View File

@@ -3,6 +3,7 @@ package v2
import (
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
)
@@ -13,12 +14,14 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[randaoMixes].MinusRef()
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
var mixesArr [fieldparams.RandaoMixesLength][32]byte
for i := 0; i < len(mixesArr); i++ {
copy(mixesArr[i][:], val[i])
}
mixes := customtypes.RandaoMixes{}
mixes.SetFromBaseField(mixesArr)
mixes := customtypes.RandaoMixes(mixesArr)
b.randaoMixes = &mixes
b.markFieldAsDirty(randaoMixes)
b.rebuildTrie[randaoMixes] = true
@@ -28,13 +31,24 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
// UpdateRandaoMixesAtIndex for the beacon state. Updates the randao mixes
// at a specific index to a new value.
func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val []byte) error {
if b.randaoMixes.TotalLength() <= idx {
if uint64(len(b.randaoMixes)) <= idx {
return errors.Errorf("invalid index provided %d", idx)
}
b.lock.Lock()
defer b.lock.Unlock()
b.randaoMixes.SetRootAtIndex(idx, bytesutil.ToBytes32(val))
mixes := b.randaoMixes
if refs := b.sharedFieldReferences[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)
}
mixes[idx] = bytesutil.ToBytes32(val)
b.randaoMixes = mixes
b.markFieldAsDirty(randaoMixes)
b.addDirtyIndices(randaoMixes, []uint64{idx})

View File

@@ -35,8 +35,10 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateAltair) (*BeaconState, error
return nil, errors.New("received nil state")
}
bRoots := customtypes.SetFromSlice(st.BlockRoots)
var bRoots customtypes.BlockRoots
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
var sRoots customtypes.StateRoots
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
@@ -45,7 +47,10 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateAltair) (*BeaconState, error
for i, r := range st.HistoricalRoots {
hRoots[i] = bytesutil.ToBytes32(r)
}
mixes := customtypes.SetFromSliceRandao(st.RandaoMixes)
var mixes customtypes.RandaoMixes
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
fieldCount := params.BeaconConfig().BeaconStateAltairFieldCount
b := &BeaconState{
@@ -54,7 +59,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateAltair) (*BeaconState, error
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
blockRoots: bRoots,
blockRoots: &bRoots,
stateRoots: &sRoots,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
@@ -62,7 +67,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateAltair) (*BeaconState, error
eth1DepositIndex: st.Eth1DepositIndex,
validators: st.Validators,
balances: st.Balances,
randaoMixes: mixes,
randaoMixes: &mixes,
slashings: st.Slashings,
previousEpochParticipation: st.PreviousEpochParticipation,
currentEpochParticipation: st.CurrentEpochParticipation,
@@ -96,6 +101,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateAltair) (*BeaconState, error
// 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[previousEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
b.sharedFieldReferences[currentEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
@@ -122,9 +128,9 @@ func (b *BeaconState) Copy() state.BeaconState {
eth1DepositIndex: b.eth1DepositIndex,
// Large arrays, infrequently changed, constant size.
blockRoots: b.blockRoots.Copy(),
blockRoots: b.blockRoots,
stateRoots: b.stateRoots,
randaoMixes: b.randaoMixes.Copy(),
randaoMixes: b.randaoMixes,
slashings: b.slashings,
eth1DataVotes: b.eth1DataVotes,
@@ -209,8 +215,6 @@ func (b *BeaconState) Copy() state.BeaconState {
b.stateFieldLeaves[field].FieldReference().MinusRef()
}
}
b.blockRoots.DecreaseRef()
b.randaoMixes.DecreaseRef()
for i := 0; i < fieldCount; i++ {
field := types.FieldIndex(i)
delete(b.stateFieldLeaves, field)

View File

@@ -76,8 +76,9 @@ func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) blockRootAtIndex(idx uint64) ([32]byte, error) {
if b.blockRoots.TotalLength() <= idx {
if uint64(len(b.blockRoots)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
}
return b.blockRoots.RootAtIndex(idx), nil
return b.blockRoots[idx], nil
}

View File

@@ -37,10 +37,11 @@ func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
if b.randaoMixes.TotalLength() <= idx {
if uint64(len(b.randaoMixes)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
}
return b.randaoMixes.RootAtIndex(idx), nil
return b.randaoMixes[idx], nil
}
// RandaoMixesLength returns the length of the randao mixes slice.
@@ -62,5 +63,5 @@ func (b *BeaconState) randaoMixesLength() int {
return 0
}
return int(b.randaoMixes.TotalLength()) // lint:ignore uintcast- ajhdjhd
return len(b.randaoMixes)
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -24,12 +25,14 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[blockRoots].MinusRef()
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
var rootsArr [fieldparams.BlockRootsLength][fieldparams.RootLength]byte
for i := 0; i < len(rootsArr); i++ {
copy(rootsArr[i][:], val[i])
}
roots := customtypes.BlockRoots{}
roots.SetFromBaseField(rootsArr)
roots := customtypes.BlockRoots(rootsArr)
b.blockRoots = &roots
b.markFieldAsDirty(blockRoots)
b.rebuildTrie[blockRoots] = true
@@ -39,13 +42,24 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
// UpdateBlockRootAtIndex for the beacon state. Updates the block root
// at a specific index to a new value.
func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error {
if b.blockRoots.TotalLength() <= idx {
if uint64(len(b.blockRoots)) <= idx {
return fmt.Errorf("invalid index provided %d", idx)
}
b.lock.Lock()
defer b.lock.Unlock()
b.blockRoots.SetRootAtIndex(idx, blockRoot)
r := b.blockRoots
if ref := b.sharedFieldReferences[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)
}
r[idx] = blockRoot
b.blockRoots = r
b.markFieldAsDirty(blockRoots)
b.addDirtyIndices(blockRoots, []uint64{idx})

View File

@@ -3,6 +3,7 @@ package v3
import (
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
)
@@ -13,12 +14,14 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
var mixesArr [fieldparams.RandaoMixesLength][32]byte
b.sharedFieldReferences[randaoMixes].MinusRef()
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
var mixesArr [fieldparams.RandaoMixesLength][fieldparams.RootLength]byte
for i := 0; i < len(mixesArr); i++ {
copy(mixesArr[i][:], val[i])
}
mixes := customtypes.RandaoMixes{}
mixes.SetFromBaseField(mixesArr)
mixes := customtypes.RandaoMixes(mixesArr)
b.randaoMixes = &mixes
b.markFieldAsDirty(randaoMixes)
b.rebuildTrie[randaoMixes] = true
@@ -28,13 +31,24 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
// UpdateRandaoMixesAtIndex for the beacon state. Updates the randao mixes
// at a specific index to a new value.
func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val []byte) error {
if b.randaoMixes.TotalLength() <= idx {
if uint64(len(b.randaoMixes)) <= idx {
return errors.Errorf("invalid index provided %d", idx)
}
b.lock.Lock()
defer b.lock.Unlock()
b.randaoMixes.SetRootAtIndex(idx, bytesutil.ToBytes32(val))
mixes := b.randaoMixes
if refs := b.sharedFieldReferences[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)
}
mixes[idx] = bytesutil.ToBytes32(val)
b.randaoMixes = mixes
b.markFieldAsDirty(randaoMixes)
b.addDirtyIndices(randaoMixes, []uint64{idx})

View File

@@ -36,8 +36,10 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateBellatrix) (state.BeaconStat
return nil, errors.New("received nil state")
}
bRoots := customtypes.SetFromSlice(st.BlockRoots)
var bRoots customtypes.BlockRoots
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
var sRoots customtypes.StateRoots
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
@@ -46,7 +48,10 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateBellatrix) (state.BeaconStat
for i, r := range st.HistoricalRoots {
hRoots[i] = bytesutil.ToBytes32(r)
}
mixes := customtypes.SetFromSliceRandao(st.RandaoMixes)
var mixes customtypes.RandaoMixes
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
fieldCount := params.BeaconConfig().BeaconStateBellatrixFieldCount
b := &BeaconState{
@@ -55,7 +60,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateBellatrix) (state.BeaconStat
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
blockRoots: bRoots,
blockRoots: &bRoots,
stateRoots: &sRoots,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
@@ -63,7 +68,7 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateBellatrix) (state.BeaconStat
eth1DepositIndex: st.Eth1DepositIndex,
validators: st.Validators,
balances: st.Balances,
randaoMixes: mixes,
randaoMixes: &mixes,
slashings: st.Slashings,
previousEpochParticipation: st.PreviousEpochParticipation,
currentEpochParticipation: st.CurrentEpochParticipation,
@@ -96,7 +101,9 @@ func InitializeFromProtoUnsafe(st *ethpb.BeaconStateBellatrix) (state.BeaconStat
}
// 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[previousEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
b.sharedFieldReferences[currentEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
@@ -123,9 +130,9 @@ func (b *BeaconState) Copy() state.BeaconState {
eth1DepositIndex: b.eth1DepositIndex,
// Large arrays, infrequently changed, constant size.
randaoMixes: b.randaoMixes.Copy(),
randaoMixes: b.randaoMixes,
stateRoots: b.stateRoots,
blockRoots: b.blockRoots.Copy(),
blockRoots: b.blockRoots,
slashings: b.slashings,
eth1DataVotes: b.eth1DataVotes,
@@ -201,7 +208,6 @@ func (b *BeaconState) Copy() state.BeaconState {
}
}
}
state.StateCount.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
runtime.SetFinalizer(dst, func(b *BeaconState) {
@@ -211,9 +217,6 @@ func (b *BeaconState) Copy() state.BeaconState {
b.stateFieldLeaves[field].FieldReference().MinusRef()
}
}
b.blockRoots.DecreaseRef()
b.randaoMixes.DecreaseRef()
for i := 0; i < fieldCount; i++ {
field := types.FieldIndex(i)
delete(b.stateFieldLeaves, field)

View File

@@ -49,29 +49,30 @@ type Service struct {
synced *abool.AtomicBool
chainStarted *abool.AtomicBool
counter *ratecounter.RateCounter
genesisChan chan time.Time
}
// NewService configures the initial sync service responsible for bringing the node up to the
// latest head of the blockchain.
func NewService(ctx context.Context, cfg *Config) *Service {
ctx, cancel := context.WithCancel(ctx)
return &Service{
s := &Service{
cfg: cfg,
ctx: ctx,
cancel: cancel,
synced: abool.New(),
chainStarted: abool.New(),
counter: ratecounter.NewRateCounter(counterSeconds * time.Second),
genesisChan: make(chan time.Time),
}
go s.waitForStateInitialization()
return s
}
// Start the initial sync service.
func (s *Service) Start() {
genesis, err := s.waitForStateInitialization()
if err != nil {
log.WithError(err).Fatal("Failed to wait for state initialization.")
return
}
// Wait for state initialized event.
genesis := <-s.genesisChan
if genesis.IsZero() {
log.Debug("Exiting Initial Sync Service")
return
@@ -179,10 +180,9 @@ func (s *Service) waitForMinimumPeers() {
}
}
// TODO: Return error
// waitForStateInitialization makes sure that beacon node is ready to be accessed: it is either
// already properly configured or system waits up until state initialized event is triggered.
func (s *Service) waitForStateInitialization() (time.Time, error) {
func (s *Service) waitForStateInitialization() {
// Wait for state to be initialized.
stateChannel := make(chan *feed.Event, 1)
stateSub := s.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
@@ -198,14 +198,19 @@ func (s *Service) waitForStateInitialization() (time.Time, error) {
continue
}
log.WithField("starttime", data.StartTime).Debug("Received state initialized event")
return data.StartTime, nil
s.genesisChan <- data.StartTime
return
}
case <-s.ctx.Done():
log.Debug("Context closed, exiting goroutine")
// Send a zero time in the event we are exiting.
return time.Time{}, errors.New("context closed, exiting goroutine")
s.genesisChan <- time.Time{}
return
case err := <-stateSub.Err():
log.WithError(err).Error("Subscription to state notifier failed")
// Send a zero time in the event we are exiting.
return time.Time{}, errors.Wrap(err, "subscription to state notifier failed")
s.genesisChan <- time.Time{}
return
}
}
}

View File

@@ -168,7 +168,11 @@ func TestService_InitStartStop(t *testing.T) {
Chain: mc,
StateNotifier: notifier,
})
time.Sleep(500 * time.Millisecond)
assert.NotNil(t, s)
if tt.methodRuns != nil {
tt.methodRuns(notifier.StateFeed())
}
wg := &sync.WaitGroup{}
wg.Add(1)
@@ -177,11 +181,6 @@ func TestService_InitStartStop(t *testing.T) {
wg.Done()
}()
time.Sleep(500 * time.Millisecond)
if tt.methodRuns != nil {
tt.methodRuns(notifier.StateFeed())
}
go func() {
// Allow to exit from test (on no head loop waiting for head is started).
// In most tests, this is redundant, as Start() already exited.
@@ -208,6 +207,7 @@ func TestService_waitForStateInitialization(t *testing.T) {
synced: abool.New(),
chainStarted: abool.New(),
counter: ratecounter.NewRateCounter(counterSeconds * time.Second),
genesisChan: make(chan time.Time),
}
return s
}
@@ -221,8 +221,9 @@ func TestService_waitForStateInitialization(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
_, err := s.waitForStateInitialization()
assert.ErrorContains(t, "context closed", err)
go s.waitForStateInitialization()
currTime := <-s.genesisChan
assert.Equal(t, true, currTime.IsZero())
wg.Done()
}()
go func() {
@@ -235,6 +236,8 @@ func TestService_waitForStateInitialization(t *testing.T) {
t.Fatalf("Test should have exited by now, timed out")
}
assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Context closed, exiting goroutine")
assert.LogsDoNotContain(t, hook, "Subscription to state notifier failed")
})
t.Run("no state and state init event received", func(t *testing.T) {
@@ -248,9 +251,8 @@ func TestService_waitForStateInitialization(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
var err error
receivedGenesisTime, err = s.waitForStateInitialization()
require.NoError(t, err)
go s.waitForStateInitialization()
receivedGenesisTime = <-s.genesisChan
assert.Equal(t, false, receivedGenesisTime.IsZero())
wg.Done()
}()
@@ -279,6 +281,7 @@ func TestService_waitForStateInitialization(t *testing.T) {
assert.LogsContain(t, hook, "Event feed data is not type *statefeed.InitializedData")
assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Received state initialized event")
assert.LogsDoNotContain(t, hook, "Context closed, exiting goroutine")
})
t.Run("no state and state init event received and service start", func(t *testing.T) {
@@ -293,8 +296,7 @@ func TestService_waitForStateInitialization(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
_, err := s.waitForStateInitialization()
require.NoError(t, err)
s.waitForStateInitialization()
wg.Done()
}()
@@ -319,6 +321,7 @@ func TestService_waitForStateInitialization(t *testing.T) {
}
assert.LogsContain(t, hook, "Waiting for state to be initialized")
assert.LogsContain(t, hook, "Received state initialized event")
assert.LogsDoNotContain(t, hook, "Context closed, exiting goroutine")
})
}

View File

@@ -154,7 +154,6 @@ func NewService(ctx context.Context, opts ...Option) *Service {
}
r.subHandler = newSubTopicHandler()
r.rateLimiter = newRateLimiter(r.cfg.p2p)
r.initCaches()
go r.registerHandlers()
go r.verifierRoutine()
@@ -164,6 +163,8 @@ func NewService(ctx context.Context, opts ...Option) *Service {
// Start the regular sync service.
func (s *Service) Start() {
s.initCaches()
s.cfg.p2p.AddConnectionHandler(s.reValidatePeer, s.sendGoodbye)
s.cfg.p2p.AddDisconnectionHandler(func(_ context.Context, _ peer.ID) error {
// no-op

View File

@@ -28,6 +28,7 @@ var Commands = &cli.Command{
flags.WalletPasswordFileFlag,
flags.DeletePublicKeysFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -61,6 +62,7 @@ var Commands = &cli.Command{
flags.GrpcRetriesFlag,
flags.GrpcRetryDelayFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -91,6 +93,7 @@ var Commands = &cli.Command{
flags.BackupPublicKeysFlag,
flags.BackupPasswordFile,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -118,6 +121,7 @@ var Commands = &cli.Command{
flags.AccountPasswordFileFlag,
flags.ImportPrivateKeyFileFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -151,6 +155,7 @@ var Commands = &cli.Command{
flags.GrpcRetryDelayFlag,
flags.ExitAllFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),

View File

@@ -22,6 +22,7 @@ var Commands = &cli.Command{
cmd.DataDirFlag,
flags.SlashingProtectionExportDirFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -46,6 +47,7 @@ var Commands = &cli.Command{
cmd.DataDirFlag,
flags.SlashingProtectionJSONFileFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),

View File

@@ -34,6 +34,7 @@ var Commands = &cli.Command{
flags.Mnemonic25thWordFileFlag,
flags.SkipMnemonic25thWordCheckFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -63,6 +64,7 @@ var Commands = &cli.Command{
flags.RemoteSignerKeyPathFlag,
flags.RemoteSignerCACertPathFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),
@@ -91,6 +93,7 @@ var Commands = &cli.Command{
flags.Mnemonic25thWordFileFlag,
flags.SkipMnemonic25thWordCheckFlag,
features.Mainnet,
features.PyrmontTestnet,
features.PraterTestnet,
cmd.AcceptTosFlag,
}),

View File

@@ -35,6 +35,9 @@ const disabledFeatureFlag = "Disabled feature flag"
// Flags is a struct to represent which features the client will perform on runtime.
type Flags struct {
// Testnet Flags.
PyrmontTestnet bool // PyrmontTestnet defines the flag through which we can enable the node to run on the Pyrmont testnet.
// Feature related flags.
RemoteSlasherProtection bool // RemoteSlasherProtection utilizes a beacon node with --slasher mode for validator slashing protection.
WriteSSZStateTransitions bool // WriteSSZStateTransitions to tmp directory.
@@ -118,8 +121,13 @@ func InitWithReset(c *Flags) func() {
}
// configureTestnet sets the config according to specified testnet flag
func configureTestnet(ctx *cli.Context) {
if ctx.Bool(PraterTestnet.Name) {
func configureTestnet(ctx *cli.Context, cfg *Flags) {
if ctx.Bool(PyrmontTestnet.Name) {
log.Warn("Running on Pyrmont Testnet")
params.UsePyrmontConfig()
params.UsePyrmontNetworkConfig()
cfg.PyrmontTestnet = true
} else if ctx.Bool(PraterTestnet.Name) {
log.Warn("Running on the Prater Testnet")
params.UsePraterConfig()
params.UsePraterNetworkConfig()
@@ -137,7 +145,7 @@ func ConfigureBeaconChain(ctx *cli.Context) {
if ctx.Bool(devModeFlag.Name) {
enableDevModeFlags(ctx)
}
configureTestnet(ctx)
configureTestnet(ctx, cfg)
if ctx.Bool(writeSSZStateTransitionsFlag.Name) {
logEnabled(writeSSZStateTransitionsFlag)
@@ -232,7 +240,7 @@ func ConfigureBeaconChain(ctx *cli.Context) {
func ConfigureValidator(ctx *cli.Context) {
complainOnDeprecatedFlags(ctx)
cfg := &Flags{}
configureTestnet(ctx)
configureTestnet(ctx, cfg)
if ctx.Bool(enableExternalSlasherProtectionFlag.Name) {
log.Fatal(
"Remote slashing protection has currently been disabled in Prysm due to safety concerns. " +

View File

@@ -11,41 +11,41 @@ import (
func TestInitFeatureConfig(t *testing.T) {
defer Init(&Flags{})
cfg := &Flags{
EnablePeerScorer: true,
PyrmontTestnet: true,
}
Init(cfg)
c := Get()
assert.Equal(t, true, c.EnablePeerScorer)
assert.Equal(t, true, c.PyrmontTestnet)
// Reset back to false for the follow up tests.
cfg = &Flags{RemoteSlasherProtection: false}
cfg = &Flags{PyrmontTestnet: false}
Init(cfg)
}
func TestInitWithReset(t *testing.T) {
defer Init(&Flags{})
Init(&Flags{
EnablePeerScorer: true,
PyrmontTestnet: true,
})
assert.Equal(t, true, Get().EnablePeerScorer)
assert.Equal(t, true, Get().PyrmontTestnet)
// Overwrite previously set value (value that didn't come by default).
resetCfg := InitWithReset(&Flags{
EnablePeerScorer: false,
PyrmontTestnet: false,
})
assert.Equal(t, false, Get().EnablePeerScorer)
assert.Equal(t, false, Get().PyrmontTestnet)
// Reset must get to previously set configuration (not to default config values).
resetCfg()
assert.Equal(t, true, Get().EnablePeerScorer)
assert.Equal(t, true, Get().PyrmontTestnet)
}
func TestConfigureBeaconConfig(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.Bool(enablePeerScorer.Name, true, "test")
set.Bool(PyrmontTestnet.Name, true, "test")
context := cli.NewContext(&app, set, nil)
ConfigureBeaconChain(context)
c := Get()
assert.Equal(t, true, c.EnablePeerScorer)
assert.Equal(t, true, c.PyrmontTestnet)
}

View File

@@ -70,11 +70,6 @@ var (
Usage: deprecatedUsage,
Hidden: true,
}
deprecatedPyrmontTestnet = &cli.BoolFlag{
Name: "pyrmont",
Usage: deprecatedUsage,
Hidden: true,
}
)
var deprecatedFlags = []cli.Flag{
@@ -89,5 +84,4 @@ var deprecatedFlags = []cli.Flag{
deprecatedDisableNextSlotStateCache,
deprecatedAttestationAggregationStrategy,
deprecatedForceOptMaxCoverAggregationStategy,
deprecatedPyrmontTestnet,
}

View File

@@ -7,6 +7,11 @@ import (
)
var (
// PyrmontTestnet flag for the multiclient Ethereum consensus testnet.
PyrmontTestnet = &cli.BoolFlag{
Name: "pyrmont",
Usage: "This defines the flag through which we can run on the Pyrmont Multiclient Testnet",
}
// PraterTestnet flag for the multiclient Ethereum consensus testnet.
PraterTestnet = &cli.BoolFlag{
Name: "prater",
@@ -144,7 +149,6 @@ var devModeFlags = []cli.Flag{
enablePeerScorer,
enableVecHTR,
enableForkChoiceDoublyLinkedTree,
enableNativeState,
}
// ValidatorFlags contains a list of all the feature flags that apply to the validator client.
@@ -152,6 +156,7 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
writeWalletPasswordOnWebOnboarding,
enableExternalSlasherProtectionFlag,
disableAttestingHistoryDBCache,
PyrmontTestnet,
PraterTestnet,
Mainnet,
dynamicKeyReloadDebounceInterval,
@@ -170,6 +175,7 @@ var BeaconChainFlags = append(deprecatedFlags, []cli.Flag{
devModeFlag,
writeSSZStateTransitionsFlag,
disableGRPCConnectionLogging,
PyrmontTestnet,
PraterTestnet,
Mainnet,
enablePeerScorer,

View File

@@ -13,6 +13,7 @@ go_library(
"network_config.go",
"testnet_e2e_config.go",
"testnet_prater_config.go",
"testnet_pyrmont_config.go",
"testutils.go",
"values.go",
],

View File

@@ -0,0 +1,43 @@
package params
import "math"
// UsePyrmontNetworkConfig uses the Pyrmont specific
// network config.
func UsePyrmontNetworkConfig() {
cfg := BeaconNetworkConfig().Copy()
cfg.ContractDeploymentBlock = 3743587
cfg.BootstrapNodes = []string{
"enr:-Ku4QOA5OGWObY8ep_x35NlGBEj7IuQULTjkgxC_0G1AszqGEA0Wn2RNlyLFx9zGTNB1gdFBA6ZDYxCgIza1uJUUOj4Dh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDVTPWXAAAgCf__________gmlkgnY0gmlwhDQPSjiJc2VjcDI1NmsxoQM6yTQB6XGWYJbI7NZFBjp4Yb9AYKQPBhVrfUclQUobb4N1ZHCCIyg",
"enr:-Ku4QOksdA2tabOGrfOOr6NynThMoio6Ggka2oDPqUuFeWCqcRM2alNb8778O_5bK95p3EFt0cngTUXm2H7o1jkSJ_8Dh2F0dG5ldHOIAAAAAAAAAACEZXRoMpDVTPWXAAAgCf__________gmlkgnY0gmlwhDaa13aJc2VjcDI1NmsxoQKdNQJvnohpf0VO0ZYCAJxGjT0uwJoAHbAiBMujGjK0SoN1ZHCCIyg",
}
OverrideBeaconNetworkConfig(cfg)
}
// UsePyrmontConfig sets the main beacon chain
// config for Pyrmont.
func UsePyrmontConfig() {
beaconConfig = PyrmontConfig()
}
// PyrmontConfig defines the config for the
// Pyrmont testnet.
func PyrmontConfig() *BeaconChainConfig {
cfg := MainnetConfig().Copy()
cfg.MinGenesisTime = 1605700800
cfg.GenesisDelay = 432000
cfg.ConfigName = ConfigNames[Pyrmont]
cfg.GenesisForkVersion = []byte{0x00, 0x00, 0x20, 0x09}
cfg.AltairForkVersion = []byte{0x01, 0x00, 0x20, 0x09}
cfg.AltairForkEpoch = 61650
cfg.BellatrixForkVersion = []byte{0x02, 0x00, 0x20, 0x09}
cfg.BellatrixForkEpoch = math.MaxUint64
cfg.ShardingForkVersion = []byte{0x03, 0x00, 0x20, 0x09}
cfg.ShardingForkEpoch = math.MaxUint64
cfg.SecondsPerETH1Block = 14
cfg.DepositChainID = 5
cfg.DepositNetworkID = 5
cfg.DepositContractAddress = "0x8c5fecdC472E27Bc447696F431E425D02dd46a8c"
cfg.InitializeForkSchedule()
return cfg
}

View File

@@ -12,6 +12,7 @@ const (
Mainnet ConfigName = iota
Minimal
EndToEnd
Pyrmont
Prater
EndToEndMainnet
)
@@ -32,6 +33,7 @@ var ConfigNames = map[ConfigName]string{
Mainnet: "mainnet",
Minimal: "minimal",
EndToEnd: "end-to-end",
Pyrmont: "pyrmont",
Prater: "prater",
EndToEndMainnet: "end-to-end-mainnet",
}
@@ -40,6 +42,7 @@ var ConfigNames = map[ConfigName]string{
var KnownConfigs = map[ConfigName]func() *BeaconChainConfig{
Mainnet: MainnetConfig,
Prater: PraterConfig,
Pyrmont: PyrmontConfig,
Minimal: MinimalSpecConfig,
EndToEnd: E2ETestConfig,
EndToEndMainnet: E2EMainnetTestConfig,

View File

@@ -3756,13 +3756,6 @@ def prysm_deps():
sum = "h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=",
version = "v2.3.0",
)
go_repository(
name = "com_github_uudashr_gocognit",
importpath = "github.com/uudashr/gocognit",
sum = "h1:rrSex7oHr3/pPLQ0xoWq108XMU8s678FJcQ+aSfOHa4=",
version = "v1.0.5",
)
go_repository(
name = "com_github_valyala_bytebufferpool",
importpath = "github.com/valyala/bytebufferpool",

1
go.mod
View File

@@ -77,7 +77,6 @@ require (
github.com/trailofbits/go-mutexasserts v0.0.0-20200708152505-19999e7d3cef
github.com/tyler-smith/go-bip39 v1.1.0
github.com/urfave/cli/v2 v2.3.0
github.com/uudashr/gocognit v1.0.5
github.com/wealdtech/go-bytesutil v1.1.1
github.com/wealdtech/go-eth2-util v1.6.3
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3

3
go.sum
View File

@@ -1358,8 +1358,6 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/uudashr/gocognit v1.0.5 h1:rrSex7oHr3/pPLQ0xoWq108XMU8s678FJcQ+aSfOHa4=
github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
@@ -1806,7 +1804,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -1,7 +1,6 @@
{
"unsafeptr": {
"exclude_files": {
"beacon-chain/state/state-native/custom-types/block_roots.go": "Needed for field management operations",
"external/.*": "Unsafe third party code",
"rules_go_work-.*": "Third party code"
}
@@ -171,13 +170,5 @@
"rules_go_work-.*": "Third party code",
".*_test\\.go": "Tests are ok"
}
},
"gocognit": {
"exclude_files": {
"external/.*": "Third party code",
"rules_go_work-.*": "Third party code",
".*\\.pb.*.go": "Generated code is ok",
".*generated\\.ssz\\.go": "Generated code is ok"
}
}
}

View File

@@ -5,7 +5,6 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -174,13 +173,6 @@ func TestJsonMarshalUnmarshal(t *testing.T) {
require.DeepEqual(t, [][]byte{[]byte("hi")}, payloadPb.Transactions)
require.DeepEqual(t, [][]byte{[]byte("bye")}, payloadPb.Uncles)
})
t.Run("nil execution block", func(t *testing.T) {
jsonPayload := (*enginev1.ExecutionBlock)(nil)
enc, err := json.Marshal(jsonPayload)
require.NoError(t, err)
payloadPb := &enginev1.ExecutionBlock{}
require.ErrorIs(t, hexutil.ErrEmptyString, json.Unmarshal(enc, payloadPb))
})
}
func TestPayloadIDBytes_MarshalUnmarshalJSON(t *testing.T) {

View File

@@ -1,14 +0,0 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["analyzer.go"],
importpath = "github.com/prysmaticlabs/prysm/tools/analyzers/gocognit",
visibility = ["//visibility:public"],
deps = [
"@com_github_uudashr_gocognit//:go_default_library",
"@org_golang_x_tools//go/analysis:go_default_library",
"@org_golang_x_tools//go/analysis/passes/inspect:go_default_library",
"@org_golang_x_tools//go/ast/inspector:go_default_library",
],
)

View File

@@ -1,195 +0,0 @@
> Copied from https://github.com/uudashr/gocognit/blob/5bf67146515e79acd2a8d5728deafa9d91ad48db/README.md
> License: MIT
[![GoDoc](https://godoc.org/github.com/uudashr/gocognit?status.svg)](https://godoc.org/github.com/uudashr/gocognit)
# Gocognit
Gocognit calculates cognitive complexities of functions in Go source code. A measurement of how hard does the code is intuitively to understand.
## Understanding the complexity
Given code using `if` statement,
```go
func GetWords(number int) string {
if number == 1 { // +1
return "one"
} else if number == 2 { // +1
return "a couple"
} else if number == 3 { // +1
return "a few"
} else { // +1
return "lots"
}
} // Cognitive complexity = 4
```
Above code can be refactored using `switch` statement,
```go
func GetWords(number int) string {
switch number { // +1
case 1:
return "one"
case 2:
return "a couple"
case 3:
return "a few"
default:
return "lots"
}
} // Cognitive complexity = 1
```
As you see above codes are the same, but the second code are easier to understand, that is why the cognitive complexity score are lower compare to the first one.
## Comparison with cyclometic complexity
### Example 1
#### Cyclometic complexity
```go
func GetWords(number int) string { // +1
switch number {
case 1: // +1
return "one"
case 2: // +1
return "a couple"
case 3: // +1
return "a few"
default:
return "lots"
}
} // Cyclomatic complexity = 4
```
#### Cognitive complexity
```go
func GetWords(number int) string {
switch number { // +1
case 1:
return "one"
case 2:
return "a couple"
case 3:
return "a few"
default:
return "lots"
}
} // Cognitive complexity = 1
```
Cognitive complexity give lower score compare to cyclomatic complexity.
### Example 2
#### Cyclomatic complexity
```go
func SumOfPrimes(max int) int { // +1
var total int
OUT:
for i := 1; i < max; i++ { // +1
for j := 2; j < i; j++ { // +1
if i%j == 0 { // +1
continue OUT
}
}
total += i
}
return total
} // Cyclomatic complexity = 4
```
#### Cognitive complexity
```go
func SumOfPrimes(max int) int {
var total int
OUT:
for i := 1; i < max; i++ { // +1
for j := 2; j < i; j++ { // +2 (nesting = 1)
if i%j == 0 { // +3 (nesting = 2)
continue OUT // +1
}
}
total += i
}
return total
} // Cognitive complexity = 7
```
Cognitive complexity give higher score compare to cyclomatic complexity.
## Rules
The cognitive complexity of a function is calculated according to the
following rules:
> Note: these rules are specific for Go, please see the [original whitepaper](./CognitiveComplexity.pdf) for more complete reference.
### Increments
There is an increment for each of the following:
1. `if`, `else if`, `else`
2. `switch`, `select`
3. `for`
4. `goto` LABEL, `break` LABEL, `continue` LABEL
5. sequence of binary logical operators
6. each method in a recursion cycle
### Nesting level
The following structures increment the nesting level:
1. `if`, `else if`, `else`
2. `switch`, `select`
3. `for`
4. function literal or lambda
### Nesting increments
The following structures receive a nesting increment commensurate with their nested depth inside nesting structures:
1. `if`
2. `switch`, `select`
3. `for`
## Installation
```
$ go install github.com/uudashr/gocognit/cmd/gocognit@latest
```
or
```
$ go get github.com/uudashr/gocognit/cmd/gocognit
```
## Usage
```
$ gocognit
Calculate cognitive complexities of Go functions.
Usage:
gocognit [flags] <Go file or directory> ...
Flags:
-over N show functions with complexity > N only and
return exit code 1 if the set is non-empty
-top N show the top N most complex functions only
-avg show the average complexity over all functions,
not depending on whether -over or -top are set
The output fields for each line are:
<complexity> <package> <function> <file:row:column>
```
Examples:
```
$ gocognit .
$ gocognit main.go
$ gocognit -top 10 src/
$ gocognit -over 25 docker
$ gocognit -avg .
```
The output fields for each line are:
```
<complexity> <package> <function> <file:row:column>
```
## Related project
- [Gocyclo](https://github.com/fzipp/gocyclo) where the code are based on.
- [Cognitive Complexity: A new way of measuring understandability](./CognitiveComplexity.pdf) white paper by G. Ann Campbell.

View File

@@ -1,90 +0,0 @@
package gocognit
import (
"errors"
"fmt"
"go/ast"
"github.com/uudashr/gocognit"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
)
// Doc explaining the tool.
const Doc = "Tool to ensure go code does not have high cognitive complexity."
// Analyzer runs static analysis.
var Analyzer = &analysis.Analyzer{
Name: "gocognit",
Doc: Doc,
Requires: []*analysis.Analyzer{inspect.Analyzer},
Run: run,
}
// Recommended thresholds according to the 2008 presentation titled
// "Software Quality Metrics to Identify Risk" by Thomas McCabe Jr.
//
// 1 - 10 Simple procedure, little risk
// 11 - 20 More complex, moderate risk
// 21 - 50 Complex, high risk
// > 50 Untestable code, very high risk
//
// This threshold should be lowered to 50 over time.
const over = 130
func run(pass *analysis.Pass) (interface{}, error) {
inspect, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
if !ok {
return nil, errors.New("analyzer is not type *inspector.Inspector")
}
nodeFilter := []ast.Node{
(*ast.FuncDecl)(nil),
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
fnDecl, ok := n.(*ast.FuncDecl)
if !ok {
return
}
fnName := funcName(fnDecl)
fnComplexity := gocognit.Complexity(fnDecl)
if fnComplexity > over {
pass.Reportf(fnDecl.Pos(), "cognitive complexity %d of func %s is high (> %d)", fnComplexity, fnName, over)
}
})
return nil, nil
}
// funcName returns the name representation of a function or method:
// "(Type).Name" for methods or simply "Name" for functions.
//
// Copied from https://github.com/uudashr/gocognit/blob/5bf67146515e79acd2a8d5728deafa9d91ad48db/gocognit.go
// License: MIT
func funcName(fn *ast.FuncDecl) string {
if fn.Recv != nil {
if fn.Recv.NumFields() > 0 {
typ := fn.Recv.List[0].Type
return fmt.Sprintf("(%s).%s", recvString(typ), fn.Name)
}
}
return fn.Name.Name
}
// recvString returns a string representation of recv of the
// form "T", "*T", or "BADRECV" (if not a proper receiver type).
//
// Copied from https://github.com/uudashr/gocognit/blob/5bf67146515e79acd2a8d5728deafa9d91ad48db/gocognit.go
// License: MIT
func recvString(recv ast.Expr) string {
switch t := recv.(type) {
case *ast.Ident:
return t.Name
case *ast.StarExpr:
return "*" + recvString(t.X)
}
return "BADRECV"
}

View File

@@ -7,7 +7,7 @@ Flags:
-beacon string
gRPC address of the Prysm beacon node (default "127.0.0.1:4000")
-genesis uint
Genesis time. mainnet=1606824023, prater=1616508000 (default 1606824023)
Genesis time. mainnet=1606824023, prater=1616508000, pyrmont=1605722407 (default 1606824023)
```
Usage:

View File

@@ -18,7 +18,7 @@ import (
var (
beacon = flag.String("beacon", "127.0.0.1:4000", "gRPC address of the Prysm beacon node")
genesis = flag.Uint64("genesis", 1606824023, "Genesis time. mainnet=1606824023, prater=1616508000")
genesis = flag.Uint64("genesis", 1606824023, "Genesis time. mainnet=1606824023, prater=1616508000, pyrmont=1605722407")
)
func main() {

View File

@@ -276,7 +276,9 @@ func displayExitInfo(rawExitedKeys [][]byte, trimmedExitedKeys []string) {
urlFormattedPubKeys := make([]string, len(rawExitedKeys))
for i, key := range rawExitedKeys {
var baseUrl string
if params.BeaconConfig().ConfigName == params.ConfigNames[params.Prater] {
if params.BeaconConfig().ConfigName == params.ConfigNames[params.Pyrmont] {
baseUrl = "https://pyrmont.beaconcha.in/validator/"
} else if params.BeaconConfig().ConfigName == params.ConfigNames[params.Prater] {
baseUrl = "https://prater.beaconcha.in/validator/"
} else {
baseUrl = "https://beaconcha.in/validator/"

View File

@@ -101,7 +101,7 @@ type Config struct {
// registry.
func NewValidatorService(ctx context.Context, cfg *Config) (*ValidatorService, error) {
ctx, cancel := context.WithCancel(ctx)
s := &ValidatorService{
return &ValidatorService{
ctx: ctx,
cancel: cancel,
endpoint: cfg.Endpoint,
@@ -124,35 +124,34 @@ func NewValidatorService(ctx context.Context, cfg *Config) (*ValidatorService, e
logDutyCountDown: cfg.LogDutyCountDown,
Web3SignerConfig: cfg.Web3SignerConfig,
feeRecipientConfig: cfg.FeeRecipientConfig,
}
dialOpts := ConstructDialOptions(
s.maxCallRecvMsgSize,
s.withCert,
s.grpcRetries,
s.grpcRetryDelay,
)
if dialOpts == nil {
return s, nil
}
s.ctx = grpcutil.AppendHeaders(ctx, s.grpcHeaders)
conn, err := grpc.DialContext(ctx, s.endpoint, dialOpts...)
if err != nil {
return s, err
}
if s.withCert != "" {
log.Info("Established secure gRPC connection")
}
s.conn = conn
return s, nil
}, nil
}
// Start the validator service. Launches the main go routine for the validator
// client.
func (v *ValidatorService) Start() {
dialOpts := ConstructDialOptions(
v.maxCallRecvMsgSize,
v.withCert,
v.grpcRetries,
v.grpcRetryDelay,
)
if dialOpts == nil {
return
}
v.ctx = grpcutil.AppendHeaders(v.ctx, v.grpcHeaders)
conn, err := grpc.DialContext(v.ctx, v.endpoint, dialOpts...)
if err != nil {
log.Errorf("Could not dial endpoint: %s, %v", v.endpoint, err)
return
}
if v.withCert != "" {
log.Info("Established secure gRPC connection")
}
v.conn = conn
cache, err := ristretto.NewCache(&ristretto.Config{
NumCounters: 1920, // number of keys to track.
MaxCost: 192, // maximum cost of cache, 1 item = 1 cost.

View File

@@ -2,6 +2,7 @@ package client
import (
"context"
"strings"
"testing"
"time"
@@ -32,11 +33,36 @@ func TestStop_CancelsContext(t *testing.T) {
}
}
func TestNew_Insecure(t *testing.T) {
func TestLifecycle(t *testing.T) {
hook := logTest.NewGlobal()
_, err := NewValidatorService(context.Background(), &Config{})
require.NoError(t, err)
// Use canceled context so that the run function exits immediately..
ctx, cancel := context.WithCancel(context.Background())
cancel()
validatorService := &ValidatorService{
ctx: ctx,
cancel: cancel,
endpoint: "merkle tries",
withCert: "alice.crt",
}
validatorService.Start()
require.NoError(t, validatorService.Stop(), "Could not stop service")
require.LogsContain(t, hook, "Stopping service")
}
func TestLifecycle_Insecure(t *testing.T) {
hook := logTest.NewGlobal()
// Use canceled context so that the run function exits immediately.
ctx, cancel := context.WithCancel(context.Background())
cancel()
validatorService := &ValidatorService{
ctx: ctx,
cancel: cancel,
endpoint: "merkle tries",
}
validatorService.Start()
require.LogsContain(t, hook, "You are using an insecure gRPC connection")
require.NoError(t, validatorService.Stop(), "Could not stop service")
require.LogsContain(t, hook, "Stopping service")
}
func TestStatus_NoConnectionError(t *testing.T) {
@@ -46,7 +72,9 @@ func TestStatus_NoConnectionError(t *testing.T) {
func TestStart_GrpcHeaders(t *testing.T) {
hook := logTest.NewGlobal()
ctx := context.Background()
// Use canceled context so that the run function exits immediately.
ctx, cancel := context.WithCancel(context.Background())
cancel()
for input, output := range map[string][]string{
"should-break": {},
"key=value": {"key", "value"},
@@ -59,9 +87,13 @@ func TestStart_GrpcHeaders(t *testing.T) {
"Authorization", "this is a valid value",
},
} {
cfg := &Config{GrpcHeadersFlag: input}
validatorService, err := NewValidatorService(ctx, cfg)
require.NoError(t, err)
validatorService := &ValidatorService{
ctx: ctx,
cancel: cancel,
endpoint: "merkle tries",
grpcHeaders: strings.Split(input, ","),
}
validatorService.Start()
md, _ := metadata.FromOutgoingContext(validatorService.ctx)
if input == "should-break" {
require.LogsContain(t, hook, "Incorrect gRPC header flag format. Skipping should-break")

View File

@@ -46,7 +46,7 @@ func TestServer_GetBeaconNodeConnection(t *testing.T) {
require.NoError(t, err)
want := &pb.NodeConnectionResponse{
BeaconNodeEndpoint: endpoint,
Connected: true,
Connected: false,
Syncing: false,
GenesisTime: uint64(time.Unix(0, 0).Unix()),
}