mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-11 06:18:05 -05:00
Compare commits
31 Commits
save-sync-
...
dankshardi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9abc24243b | ||
|
|
eae50b180c | ||
|
|
b295514900 | ||
|
|
9f419bee7d | ||
|
|
d04eaf8fa0 | ||
|
|
82ceb51548 | ||
|
|
6a2ef13b87 | ||
|
|
72a2dd004b | ||
|
|
1a0e16a48b | ||
|
|
bff5c1e1a9 | ||
|
|
3f5ce0cdca | ||
|
|
d51b52d432 | ||
|
|
7b5a821c81 | ||
|
|
f89265f2f7 | ||
|
|
c731b715ed | ||
|
|
2a68c69d8f | ||
|
|
a82fd7bf68 | ||
|
|
9c540627ab | ||
|
|
11f50453fc | ||
|
|
5f8b01ccda | ||
|
|
d800107927 | ||
|
|
d3d5cfca0b | ||
|
|
18ef760ee5 | ||
|
|
14e3e80df3 | ||
|
|
3bea0e7896 | ||
|
|
8455656597 | ||
|
|
af8bafd895 | ||
|
|
c538a6c068 | ||
|
|
d5eb8392b6 | ||
|
|
4906a0e6de | ||
|
|
168e06e607 |
10
WORKSPACE
10
WORKSPACE
@@ -222,7 +222,7 @@ filegroup(
|
||||
url = "https://github.com/eth-clients/slashing-protection-interchange-tests/archive/b8413ca42dc92308019d0d4db52c87e9e125c4e9.tar.gz",
|
||||
)
|
||||
|
||||
consensus_spec_version = "v1.1.8"
|
||||
consensus_spec_version = "v1.1.9"
|
||||
|
||||
bls_test_version = "v0.1.1"
|
||||
|
||||
@@ -238,7 +238,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "e4d2b7830e85734442d7172887dcd4edc0985d6256bafedb3353ab477a1433c0",
|
||||
sha256 = "207d9c326ba4fa1f34bab7b6169201c32f2611755db030909a3405873445e0ba",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/general.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -254,7 +254,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "4a88d01ad12260220ab5c8efdeec6534bac48a47f29ba4f7977ea14c9d07b0fe",
|
||||
sha256 = "a3995b39f412db236b2f1db909f288218da53cb53b9923b71dda9d144d68f40a",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/minimal.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -270,7 +270,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "0033fe107d9d2adb8d4fcb60dfb1c43fc5a54f0af970525c962124221757c266",
|
||||
sha256 = "76cea7a4c8e32d458ad456b54bfbb30bc772481a91954a4cd97e229aa3023b1d",
|
||||
url = "https://github.com/ethereum/consensus-spec-tests/releases/download/%s/mainnet.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -285,7 +285,7 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "3fc3b8809d140a1ab61350fbd410f33add2851a63829d874dcb620babba603de",
|
||||
sha256 = "0fc429684775f943250dce1f9c485ac25e26c6395d7f585c8d1317becec2ace7",
|
||||
strip_prefix = "consensus-specs-" + consensus_spec_version[1:],
|
||||
url = "https://github.com/ethereum/consensus-specs/archive/refs/tags/%s.tar.gz" % consensus_spec_version,
|
||||
)
|
||||
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
"log.go",
|
||||
"metrics.go",
|
||||
"new_slot.go",
|
||||
"optimistic_sync.go",
|
||||
"options.go",
|
||||
"pow_block.go",
|
||||
"process_attestation.go",
|
||||
@@ -38,6 +39,7 @@ go_library(
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/cache/depositcache:go_default_library",
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/feed:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
@@ -103,6 +105,7 @@ go_test(
|
||||
"log_test.go",
|
||||
"metrics_test.go",
|
||||
"mock_test.go",
|
||||
"optimistic_sync_test.go",
|
||||
"pow_block_test.go",
|
||||
"process_attestation_test.go",
|
||||
"process_block_test.go",
|
||||
|
||||
@@ -55,6 +55,7 @@ type HeadFetcher interface {
|
||||
ProtoArrayStore() *protoarray.Store
|
||||
ChainHeads() ([][32]byte, []types.Slot)
|
||||
IsOptimistic(ctx context.Context) (bool, error)
|
||||
IsOptimisticForRoot(ctx context.Context, root [32]byte, slot types.Slot) (bool, error)
|
||||
HeadSyncCommitteeFetcher
|
||||
HeadDomainFetcher
|
||||
}
|
||||
@@ -336,6 +337,12 @@ func (s *Service) IsOptimistic(ctx context.Context) (bool, error) {
|
||||
return s.cfg.ForkChoiceStore.Optimistic(ctx, s.head.root, s.head.slot)
|
||||
}
|
||||
|
||||
// IsOptimisticForRoot takes the root and slot as aguments instead of the current head
|
||||
// and returns true if it is optimistic.
|
||||
func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte, slot types.Slot) (bool, error) {
|
||||
return s.cfg.ForkChoiceStore.Optimistic(ctx, root, slot)
|
||||
}
|
||||
|
||||
// SetGenesisTime sets the genesis time of beacon chain.
|
||||
func (s *Service) SetGenesisTime(t time.Time) {
|
||||
s.genesisTime = t
|
||||
|
||||
@@ -366,3 +366,14 @@ func TestService_IsOptimistic(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, opt)
|
||||
}
|
||||
|
||||
func TestService_IsOptimisticForRoot(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{ForkChoiceStore: protoarray.New(0, 0, [32]byte{})}, head: &head{slot: 101, root: [32]byte{'b'}}}
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.ProcessBlock(ctx, 100, [32]byte{'a'}, [32]byte{}, [32]byte{}, 0, 0))
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.ProcessBlock(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{}, 0, 0))
|
||||
|
||||
opt, err := c.IsOptimisticForRoot(ctx, [32]byte{'a'}, 100)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, opt)
|
||||
}
|
||||
|
||||
53
beacon-chain/blockchain/optimistic_sync.go
Normal file
53
beacon-chain/blockchain/optimistic_sync.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
)
|
||||
|
||||
// optimisticCandidateBlock returns true if this block can be optimistically synced.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def is_optimistic_candidate_block(opt_store: OptimisticStore, current_slot: Slot, block: BeaconBlock) -> bool:
|
||||
// justified_root = opt_store.block_states[opt_store.head_block_root].current_justified_checkpoint.root
|
||||
// justified_is_execution_block = is_execution_block(opt_store.blocks[justified_root])
|
||||
// block_is_deep = block.slot + SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY <= current_slot
|
||||
// return justified_is_execution_block or block_is_deep
|
||||
func (s *Service) optimisticCandidateBlock(ctx context.Context, blk block.BeaconBlock) (bool, error) {
|
||||
if blk.Slot()+params.BeaconConfig().SafeSlotsToImportOptimistically <= s.CurrentSlot() {
|
||||
return true, nil
|
||||
}
|
||||
j := s.store.JustifiedCheckpt()
|
||||
if j == nil {
|
||||
return false, errNilJustifiedInStore
|
||||
}
|
||||
jBlock, err := s.cfg.BeaconDB.Block(ctx, bytesutil.ToBytes32(j.Root))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return blocks.ExecutionBlock(jBlock.Block().Body())
|
||||
}
|
||||
|
||||
// loadSyncedTips loads a previously saved synced Tips from DB
|
||||
// if no synced tips are saved, then it creates one from the given
|
||||
// root and slot number.
|
||||
func (s *Service) loadSyncedTips(root [32]byte, slot types.Slot) error {
|
||||
// Initialize synced tips
|
||||
tips, err := s.cfg.BeaconDB.ValidatedTips(s.ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get synced tips")
|
||||
}
|
||||
if len(tips) == 0 {
|
||||
tips[root] = slot
|
||||
}
|
||||
if err := s.cfg.ForkChoiceStore.SetSyncedTips(tips); err != nil {
|
||||
return errors.Wrap(err, "could not set synced tips")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
141
beacon-chain/blockchain/optimistic_sync_test.go
Normal file
141
beacon-chain/blockchain/optimistic_sync_test.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
)
|
||||
|
||||
func Test_IsOptimisticCandidateBlock(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
fcs := protoarray.New(0, 0, [32]byte{'a'})
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithStateGen(stategen.New(beaconDB)),
|
||||
WithForkChoiceStore(fcs),
|
||||
}
|
||||
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
params.BeaconConfig().SafeSlotsToImportOptimistically = 128
|
||||
service.genesisTime = time.Now().Add(-time.Second * 12 * 2 * 128)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
blk block.BeaconBlock
|
||||
justified block.SignedBeaconBlock
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "deep block",
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 1
|
||||
wr, err := wrapper.WrappedBellatrixBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
wr, err := wrapper.WrappedBellatrixSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "shallow block, Altair justified chkpt",
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockAltair()
|
||||
blk.Block.Slot = 200
|
||||
wr, err := wrapper.WrappedAltairBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockAltair()
|
||||
blk.Block.Slot = 32
|
||||
wr, err := wrapper.WrappedAltairSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "shallow block, Bellatrix justified chkpt without execution",
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 200
|
||||
wr, err := wrapper.WrappedBellatrixBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
wr, err := wrapper.WrappedBellatrixSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "shallow block, execution enabled justified chkpt",
|
||||
blk: func(tt *testing.T) block.BeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 200
|
||||
wr, err := wrapper.WrappedBellatrixBeaconBlock(blk.Block)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
justified: func(tt *testing.T) block.SignedBeaconBlock {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Slot = 32
|
||||
blk.Block.Body.ExecutionPayload.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
blk.Block.Body.ExecutionPayload.FeeRecipient = bytesutil.PadTo([]byte{'a'}, fieldparams.FeeRecipientLength)
|
||||
blk.Block.Body.ExecutionPayload.StateRoot = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
blk.Block.Body.ExecutionPayload.ReceiptsRoot = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
blk.Block.Body.ExecutionPayload.LogsBloom = bytesutil.PadTo([]byte{'a'}, fieldparams.LogsBloomLength)
|
||||
blk.Block.Body.ExecutionPayload.Random = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
blk.Block.Body.ExecutionPayload.BaseFeePerGas = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
blk.Block.Body.ExecutionPayload.BlockHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
wr, err := wrapper.WrappedBellatrixSignedBeaconBlock(blk)
|
||||
require.NoError(tt, err)
|
||||
return wr
|
||||
}(t),
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
jroot, err := tt.justified.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, tt.justified))
|
||||
service.store.SetJustifiedCheckpt(
|
||||
ðpb.Checkpoint{
|
||||
Root: jroot[:],
|
||||
Epoch: slots.ToEpoch(tt.justified.Block().Slot()),
|
||||
})
|
||||
candidate, err := service.optimisticCandidateBlock(ctx, tt.blk)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.want, candidate, tt.name)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
)
|
||||
|
||||
@@ -11,9 +14,16 @@ import (
|
||||
// is_total_difficulty_reached = block.total_difficulty >= TERMINAL_TOTAL_DIFFICULTY
|
||||
// is_parent_total_difficulty_valid = parent.total_difficulty < TERMINAL_TOTAL_DIFFICULTY
|
||||
// return is_total_difficulty_reached and is_parent_total_difficulty_valid
|
||||
func validTerminalPowBlock(currentDifficulty *uint256.Int, parentDifficulty *uint256.Int) bool {
|
||||
ttd := uint256.NewInt(params.BeaconConfig().TerminalTotalDifficulty)
|
||||
func validTerminalPowBlock(currentDifficulty *uint256.Int, parentDifficulty *uint256.Int) (bool, error) {
|
||||
b, ok := new(big.Int).SetString(params.BeaconConfig().TerminalTotalDifficulty, 10)
|
||||
if !ok {
|
||||
return false, errors.New("failed to parse terminal total difficulty")
|
||||
}
|
||||
ttd, of := uint256.FromBig(b)
|
||||
if of {
|
||||
return false, errors.New("overflow terminal total difficulty")
|
||||
}
|
||||
totalDifficultyReached := currentDifficulty.Cmp(ttd) >= 0
|
||||
parentTotalDifficultyValid := ttd.Cmp(parentDifficulty) > 0
|
||||
return totalDifficultyReached && parentTotalDifficultyValid
|
||||
return totalDifficultyReached && parentTotalDifficultyValid, nil
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func Test_validTerminalPowBlock(t *testing.T) {
|
||||
@@ -61,11 +64,30 @@ func Test_validTerminalPowBlock(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.TerminalTotalDifficulty = tt.ttd
|
||||
cfg.TerminalTotalDifficulty = fmt.Sprint(tt.ttd)
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
if got := validTerminalPowBlock(tt.currentDifficulty, tt.parentDifficulty); got != tt.want {
|
||||
got, err := validTerminalPowBlock(tt.currentDifficulty, tt.parentDifficulty)
|
||||
require.NoError(t, err)
|
||||
if got != tt.want {
|
||||
t.Errorf("validTerminalPowBlock() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_validTerminalPowBlockSpecConfig(t *testing.T) {
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.TerminalTotalDifficulty = "115792089237316195423570985008687907853269984665640564039457584007913129638912"
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
i, _ := new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007913129638912", 10)
|
||||
current, of := uint256.FromBig(i)
|
||||
require.Equal(t, of, false)
|
||||
i, _ = new(big.Int).SetString("115792089237316195423570985008687907853269984665640564039457584007913129638911", 10)
|
||||
parent, of := uint256.FromBig(i)
|
||||
require.Equal(t, of, false)
|
||||
|
||||
got, err := validTerminalPowBlock(current, parent)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, got)
|
||||
}
|
||||
|
||||
@@ -175,6 +175,10 @@ func (s *Service) onBlock(ctx context.Context, signed block.SignedBeaconBlock, b
|
||||
log.WithError(err).Warn("Could not update head")
|
||||
}
|
||||
|
||||
if err := s.saveSyncedTipsDB(ctx); err != nil {
|
||||
return errors.Wrap(err, "could not save synced tips")
|
||||
}
|
||||
|
||||
if err := s.pruneCanonicalAttsFromPool(ctx, blockRoot, signed); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -330,6 +334,10 @@ func (s *Service) handleBlockAfterBatchVerify(ctx context.Context, signed block.
|
||||
if err := s.insertBlockToForkChoiceStore(ctx, b, blockRoot, fCheckpoint, jCheckpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.saveSyncedTipsDB(ctx); err != nil {
|
||||
return errors.Wrap(err, "could not save synced tips")
|
||||
}
|
||||
|
||||
if err := s.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{
|
||||
Slot: signed.Block().Slot(),
|
||||
Root: blockRoot[:],
|
||||
@@ -501,3 +509,12 @@ func (s *Service) pruneCanonicalAttsFromPool(ctx context.Context, r [32]byte, b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Saves synced and validated tips to DB.
|
||||
func (s *Service) saveSyncedTipsDB(ctx context.Context) error {
|
||||
tips := s.cfg.ForkChoiceStore.SyncedTips()
|
||||
if len(tips) == 0 {
|
||||
return nil
|
||||
}
|
||||
return s.cfg.BeaconDB.UpdateValidatedTips(ctx, tips)
|
||||
}
|
||||
|
||||
@@ -996,3 +996,49 @@ func TestRemoveBlockAttestationsInPool_NonCanonical(t *testing.T) {
|
||||
require.NoError(t, service.pruneCanonicalAttsFromPool(ctx, r, wrapper.WrappedPhase0SignedBeaconBlock(b)))
|
||||
require.Equal(t, 1, service.cfg.AttPool.AggregatedAttestationCount())
|
||||
}
|
||||
|
||||
func TestService_saveSyncedTipsDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
service := setupBeaconChain(t, beaconDB)
|
||||
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b100 := util.NewBeaconBlock()
|
||||
b100.Block.Slot = 100
|
||||
b100.Block.ParentRoot = r1[:]
|
||||
r100, err := b100.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b200 := util.NewBeaconBlock()
|
||||
b200.Block.Slot = 200
|
||||
b200.Block.ParentRoot = r1[:]
|
||||
r200, err := b200.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
for _, b := range []*ethpb.SignedBeaconBlock{b1, b100, b200} {
|
||||
beaconBlock := util.NewBeaconBlock()
|
||||
beaconBlock.Block.Slot = b.Block.Slot
|
||||
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.Block.ParentRoot, 32)
|
||||
r, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.ProcessBlock(context.Background(), b.Block.Slot, r, bytesutil.ToBytes32(b.Block.ParentRoot), [32]byte{}, 0, 0))
|
||||
}
|
||||
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.UpdateSyncedTipsWithValidRoot(ctx, r100))
|
||||
require.NoError(t, service.saveSyncedTipsDB(ctx))
|
||||
savedTips, err := service.cfg.BeaconDB.ValidatedTips(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(savedTips))
|
||||
require.Equal(t, types.Slot(1), savedTips[r1])
|
||||
require.Equal(t, types.Slot(100), savedTips[r100])
|
||||
|
||||
// Delete invalid root
|
||||
require.NoError(t, service.cfg.ForkChoiceStore.UpdateSyncedTipsWithInvalidRoot(ctx, r200))
|
||||
require.NoError(t, service.saveSyncedTipsDB(ctx))
|
||||
savedTips, err = service.cfg.BeaconDB.ValidatedTips(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(savedTips))
|
||||
require.Equal(t, types.Slot(100), savedTips[r100])
|
||||
}
|
||||
|
||||
@@ -187,6 +187,10 @@ func (s *Service) startFromSavedState(saved state.BeaconState) error {
|
||||
store := protoarray.New(justified.Epoch, finalized.Epoch, bytesutil.ToBytes32(finalized.Root))
|
||||
s.cfg.ForkChoiceStore = store
|
||||
|
||||
if err := s.loadSyncedTips(originRoot, saved.Slot()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ss, err := slots.EpochStart(finalized.Epoch)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get start slot of finalized epoch")
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/async/event"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain/store"
|
||||
mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
||||
@@ -163,6 +164,74 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
require.LogsContain(t, hook, "data already exists")
|
||||
}
|
||||
|
||||
func TestChainStart_SyncedTipsInDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, beaconDB)
|
||||
|
||||
genesisBlk := util.NewBeaconBlock()
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesisBlk)))
|
||||
s, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.SetSlot(1))
|
||||
require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot))
|
||||
require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, beaconDB.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
chainService.cfg.FinalizedStateAtStartUp = s
|
||||
|
||||
tips := make(map[[32]byte]types.Slot)
|
||||
tips[bytesutil.ToBytes32([]byte{'a'})] = 1
|
||||
tips[bytesutil.ToBytes32([]byte{'b'})] = 2
|
||||
require.NoError(t, beaconDB.UpdateValidatedTips(ctx, tips))
|
||||
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
|
||||
// Test synced Tips in DB
|
||||
tips2 := chainService.cfg.ForkChoiceStore.SyncedTips()
|
||||
require.Equal(t, len(tips2), len(tips))
|
||||
for k, v := range tips {
|
||||
v2, ok := tips2[k]
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, v, v2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainStart_SyncedTipsNotInDB(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
chainService := setupBeaconChain(t, beaconDB)
|
||||
|
||||
genesisBlk := util.NewBeaconBlock()
|
||||
blkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesisBlk)))
|
||||
s, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.SetSlot(1))
|
||||
require.NoError(t, beaconDB.SaveState(ctx, s, blkRoot))
|
||||
require.NoError(t, beaconDB.SaveHeadBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, blkRoot))
|
||||
require.NoError(t, beaconDB.SaveJustifiedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
require.NoError(t, beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: blkRoot[:]}))
|
||||
chainService.cfg.FinalizedStateAtStartUp = s
|
||||
// Test the start function.
|
||||
chainService.Start()
|
||||
|
||||
// Test synced Tips in DB
|
||||
tips := chainService.cfg.ForkChoiceStore.SyncedTips()
|
||||
require.Equal(t, 1, len(tips))
|
||||
slot, ok := tips[blkRoot]
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, types.Slot(1), slot)
|
||||
}
|
||||
|
||||
func TestChainStartStop_GenesisZeroHashes(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -20,7 +20,6 @@ go_library(
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/forkchoice/protoarray:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/protoarray"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
@@ -29,6 +28,8 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var ErrNilState = errors.New("nil state")
|
||||
|
||||
// ChainService defines the mock interface for testing
|
||||
type ChainService struct {
|
||||
State state.BeaconState
|
||||
@@ -159,7 +160,7 @@ func (mon *MockOperationNotifier) OperationFeed() *event.Feed {
|
||||
// ReceiveBlockInitialSync mocks ReceiveBlockInitialSync method in chain service.
|
||||
func (s *ChainService) ReceiveBlockInitialSync(ctx context.Context, block block.SignedBeaconBlock, _ [32]byte) error {
|
||||
if s.State == nil {
|
||||
s.State = &v1.BeaconState{}
|
||||
return ErrNilState
|
||||
}
|
||||
if !bytes.Equal(s.Root, block.Block().ParentRoot()) {
|
||||
return errors.Errorf("wanted %#x but got %#x", s.Root, block.Block().ParentRoot())
|
||||
@@ -186,7 +187,7 @@ func (s *ChainService) ReceiveBlockInitialSync(ctx context.Context, block block.
|
||||
// ReceiveBlockBatch processes blocks in batches from initial-sync.
|
||||
func (s *ChainService) ReceiveBlockBatch(ctx context.Context, blks []block.SignedBeaconBlock, _ [][32]byte) error {
|
||||
if s.State == nil {
|
||||
s.State = &v1.BeaconState{}
|
||||
return ErrNilState
|
||||
}
|
||||
for _, block := range blks {
|
||||
if !bytes.Equal(s.Root, block.Block().ParentRoot()) {
|
||||
@@ -215,7 +216,7 @@ func (s *ChainService) ReceiveBlockBatch(ctx context.Context, blks []block.Signe
|
||||
// ReceiveBlock mocks ReceiveBlock method in chain service.
|
||||
func (s *ChainService) ReceiveBlock(ctx context.Context, block block.SignedBeaconBlock, _ [32]byte) error {
|
||||
if s.State == nil {
|
||||
s.State = &v1.BeaconState{}
|
||||
return ErrNilState
|
||||
}
|
||||
if !bytes.Equal(s.Root, block.Block().ParentRoot()) {
|
||||
return errors.Errorf("wanted %#x but got %#x", s.Root, block.Block().ParentRoot())
|
||||
@@ -443,3 +444,8 @@ func (s *ChainService) HeadSyncContributionProofDomain(_ context.Context, _ type
|
||||
func (s *ChainService) IsOptimistic(_ context.Context) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// IsOptimisticForRoot mocks the same method in the chain service.
|
||||
func (s *ChainService) IsOptimisticForRoot(_ context.Context, _ [32]byte, _ types.Slot) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
1
beacon-chain/cache/BUILD.bazel
vendored
1
beacon-chain/cache/BUILD.bazel
vendored
@@ -30,7 +30,6 @@ go_library(
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//cache/lru:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
lruwrpr "github.com/prysmaticlabs/prysm/cache/lru"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
)
|
||||
@@ -33,8 +32,7 @@ func (c *SyncCommitteeHeadStateCache) Put(slot types.Slot, st state.BeaconState)
|
||||
return ErrNilValueProvided
|
||||
}
|
||||
|
||||
_, ok := st.(*v1.BeaconState)
|
||||
if ok {
|
||||
if st.Version() == version.Phase0 {
|
||||
return ErrIncorrectType
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/crypto/bls"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -18,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
func TestSyncCommitteeIndices_CanGet(t *testing.T) {
|
||||
getState := func(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
getState := func(t *testing.T, count uint64) state.BeaconStateAltair {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
@@ -35,7 +37,7 @@ func TestSyncCommitteeIndices_CanGet(t *testing.T) {
|
||||
}
|
||||
|
||||
type args struct {
|
||||
state *stateAltair.BeaconState
|
||||
state state.BeaconStateAltair
|
||||
epoch types.Epoch
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -45,9 +47,9 @@ func TestSyncCommitteeIndices_CanGet(t *testing.T) {
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "nil state",
|
||||
name: "nil inner state",
|
||||
args: args{
|
||||
state: nil,
|
||||
state: &v2.BeaconState{},
|
||||
},
|
||||
wantErr: true,
|
||||
errString: "nil inner state",
|
||||
@@ -93,7 +95,7 @@ func TestSyncCommitteeIndices_CanGet(t *testing.T) {
|
||||
|
||||
func TestSyncCommitteeIndices_DifferentPeriods(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
getState := func(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
getState := func(t *testing.T, count uint64) state.BeaconStateAltair {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
@@ -127,7 +129,7 @@ func TestSyncCommitteeIndices_DifferentPeriods(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncCommittee_CanGet(t *testing.T) {
|
||||
getState := func(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
getState := func(t *testing.T, count uint64) state.BeaconStateAltair {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
blsKey, err := bls.RandKey()
|
||||
@@ -147,7 +149,7 @@ func TestSyncCommittee_CanGet(t *testing.T) {
|
||||
}
|
||||
|
||||
type args struct {
|
||||
state *stateAltair.BeaconState
|
||||
state state.BeaconStateAltair
|
||||
epoch types.Epoch
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -157,9 +159,9 @@ func TestSyncCommittee_CanGet(t *testing.T) {
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
name: "nil state",
|
||||
name: "nil inner state",
|
||||
args: args{
|
||||
state: nil,
|
||||
state: &v2.BeaconState{},
|
||||
},
|
||||
wantErr: true,
|
||||
errString: "nil inner state",
|
||||
@@ -382,7 +384,7 @@ func Test_ValidateSyncMessageTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getState(t *testing.T, count uint64) *stateAltair.BeaconState {
|
||||
func getState(t *testing.T, count uint64) state.BeaconStateAltair {
|
||||
validators := make([]*ethpb.Validator, count)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
blsKey, err := bls.RandKey()
|
||||
|
||||
@@ -137,7 +137,7 @@ func UpgradeToAltair(ctx context.Context, state state.BeaconState) (state.Beacon
|
||||
// for index in get_attesting_indices(state, data, attestation.aggregation_bits):
|
||||
// for flag_index in participation_flag_indices:
|
||||
// epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
||||
func TranslateParticipation(ctx context.Context, state *statealtair.BeaconState, atts []*ethpb.PendingAttestation) (*statealtair.BeaconState, error) {
|
||||
func TranslateParticipation(ctx context.Context, state state.BeaconStateAltair, atts []*ethpb.PendingAttestation) (state.BeaconStateAltair, error) {
|
||||
epochParticipation, err := state.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
stateAltair "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
|
||||
@@ -20,12 +19,10 @@ import (
|
||||
func TestTranslateParticipation(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s, _ := util.DeterministicGenesisStateAltair(t, 64)
|
||||
st, ok := s.(*stateAltair.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, st.SetSlot(st.Slot()+params.BeaconConfig().MinAttestationInclusionDelay))
|
||||
require.NoError(t, s.SetSlot(s.Slot()+params.BeaconConfig().MinAttestationInclusionDelay))
|
||||
|
||||
var err error
|
||||
newState, err := altair.TranslateParticipation(ctx, st, nil)
|
||||
newState, err := altair.TranslateParticipation(ctx, s, nil)
|
||||
require.NoError(t, err)
|
||||
participation, err := newState.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
@@ -56,7 +53,7 @@ func TestTranslateParticipation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.DeepNotSSZEqual(t, make([]byte, 64), participation)
|
||||
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, st, pendingAtts[0].Data.Slot, pendingAtts[0].Data.CommitteeIndex)
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, s, pendingAtts[0].Data.Slot, pendingAtts[0].Data.CommitteeIndex)
|
||||
require.NoError(t, err)
|
||||
indices, err := attestation.AttestingIndices(pendingAtts[0].AggregationBits, committee)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -98,6 +98,7 @@ go_test(
|
||||
"//proto/prysm/v1alpha1/attestation/aggregation:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation/aggregation/attestations:go_default_library",
|
||||
"//proto/prysm/v1alpha1/wrapper:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
|
||||
@@ -337,7 +337,9 @@ func TestValidateIndexedAttestation_AboveMaxLength(t *testing.T) {
|
||||
}
|
||||
|
||||
want := "validator indices count exceeds MAX_VALIDATORS_PER_COMMITTEE"
|
||||
err := blocks.VerifyIndexedAttestation(context.Background(), &v1.BeaconState{}, indexedAtt1)
|
||||
st, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
err = blocks.VerifyIndexedAttestation(context.Background(), st, indexedAtt1)
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@ func TestFuzzverifyDepositDataSigningRoot_10000(_ *testing.T) {
|
||||
func TestFuzzProcessEth1DataInBlock_10000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
e := ðpb.Eth1Data{}
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < 10000; i++ {
|
||||
fuzzer.Fuzz(state)
|
||||
fuzzer.Fuzz(e)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
@@ -175,12 +176,10 @@ func TestProcessEth1Data_SetsCorrectly(t *testing.T) {
|
||||
}
|
||||
|
||||
period := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod)))
|
||||
var ok bool
|
||||
for i := uint64(0); i < period; i++ {
|
||||
processedState, err := blocks.ProcessEth1DataInBlock(context.Background(), beaconState, b.Block.Body.Eth1Data)
|
||||
require.NoError(t, err)
|
||||
beaconState, ok = processedState.(*v1.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, true, processedState.Version() == version.Phase0)
|
||||
}
|
||||
|
||||
newETH1DataVotes := beaconState.Eth1DataVotes()
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
@@ -100,12 +101,14 @@ func ProcessBlockHeaderNoVerify(
|
||||
if beaconState.Slot() != slot {
|
||||
return nil, fmt.Errorf("state slot: %d is different than block slot: %d", beaconState.Slot(), slot)
|
||||
}
|
||||
idx, err := helpers.BeaconProposerIndex(ctx, beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if proposerIndex != idx {
|
||||
return nil, fmt.Errorf("proposer index: %d is different than calculated: %d", proposerIndex, idx)
|
||||
if !time.IsIntermediateBlockSlot(slot) {
|
||||
idx, err := helpers.BeaconProposerIndex(ctx, beaconState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if proposerIndex != idx {
|
||||
return nil, fmt.Errorf("proposer index: %d is different than calculated: %d", proposerIndex, idx)
|
||||
}
|
||||
}
|
||||
parentHeader := beaconState.LatestBlockHeader()
|
||||
if parentHeader.Slot >= slot {
|
||||
@@ -122,12 +125,12 @@ func ProcessBlockHeaderNoVerify(
|
||||
parentRoot, parentHeaderRoot[:])
|
||||
}
|
||||
|
||||
proposer, err := beaconState.ValidatorAtIndexReadOnly(idx)
|
||||
proposer, err := beaconState.ValidatorAtIndexReadOnly(proposerIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if proposer.Slashed() {
|
||||
return nil, fmt.Errorf("proposer at index %d was previously slashed", idx)
|
||||
return nil, fmt.Errorf("proposer at index %d was previously slashed", proposerIndex)
|
||||
}
|
||||
|
||||
if err := beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
|
||||
@@ -2,6 +2,7 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
@@ -16,13 +17,13 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
)
|
||||
|
||||
// MergeComplete returns true if the transition to Bellatrix has completed.
|
||||
// MergeTransitionComplete returns true if the transition to Bellatrix has completed.
|
||||
// Meaning the payload header in beacon state is not `ExecutionPayloadHeader()` (i.e. not empty).
|
||||
//
|
||||
// Spec code:
|
||||
// def is_merge_complete(state: BeaconState) -> bool:
|
||||
// def is_merge_transition_complete(state: BeaconState) -> bool:
|
||||
// return state.latest_execution_payload_header != ExecutionPayloadHeader()
|
||||
func MergeComplete(st state.BeaconState) (bool, error) {
|
||||
func MergeTransitionComplete(st state.BeaconState) (bool, error) {
|
||||
h, err := st.LatestExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -31,15 +32,15 @@ func MergeComplete(st state.BeaconState) (bool, error) {
|
||||
return !isEmptyHeader(h), nil
|
||||
}
|
||||
|
||||
// IsMergeBlock returns true if the input block is the terminal merge block.
|
||||
// MergeTransitionBlock returns true if the input block is the terminal merge block.
|
||||
// Meaning the header in beacon state is `ExecutionPayloadHeader()` (i.e. empty).
|
||||
// And the input block has a non-empty header.
|
||||
//
|
||||
// Spec code:
|
||||
// def is_merge_block(state: BeaconState, body: BeaconBlockBody) -> bool:
|
||||
// return not is_merge_complete(state) and body.execution_payload != ExecutionPayload()
|
||||
func IsMergeBlock(st state.BeaconState, blk block.BeaconBlockBody) (bool, error) {
|
||||
mergeComplete, err := MergeComplete(st)
|
||||
// def is_merge_transition_block(state: BeaconState, body: BeaconBlockBody) -> bool:
|
||||
// return not is_merge_transition_complete(state) and body.execution_payload != ExecutionPayload()
|
||||
func MergeTransitionBlock(st state.BeaconState, body block.BeaconBlockBody) (bool, error) {
|
||||
mergeComplete, err := MergeTransitionComplete(st)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -47,8 +48,20 @@ func IsMergeBlock(st state.BeaconState, blk block.BeaconBlockBody) (bool, error)
|
||||
return false, err
|
||||
}
|
||||
|
||||
payload, err := blk.ExecutionPayload()
|
||||
return ExecutionBlock(body)
|
||||
}
|
||||
|
||||
// ExecutionBlock returns whether the block has a non-empty ExecutionPayload.
|
||||
//
|
||||
// Spec code:
|
||||
// def is_execution_block(block: BeaconBlock) -> bool:
|
||||
// return block.body.execution_payload != ExecutionPayload()
|
||||
func ExecutionBlock(body block.BeaconBlockBody) (bool, error) {
|
||||
payload, err := body.ExecutionPayload()
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "ExecutionPayload is not supported in") {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return !isEmptyPayload(payload), nil
|
||||
@@ -60,15 +73,15 @@ func IsMergeBlock(st state.BeaconState, blk block.BeaconBlockBody) (bool, error)
|
||||
// Spec code:
|
||||
// def is_execution_enabled(state: BeaconState, body: BeaconBlockBody) -> bool:
|
||||
// return is_merge_block(state, body) or is_merge_complete(state)
|
||||
func ExecutionEnabled(st state.BeaconState, blk block.BeaconBlockBody) (bool, error) {
|
||||
mergeBlock, err := IsMergeBlock(st, blk)
|
||||
func ExecutionEnabled(st state.BeaconState, body block.BeaconBlockBody) (bool, error) {
|
||||
mergeBlock, err := MergeTransitionBlock(st, body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if mergeBlock {
|
||||
return true, nil
|
||||
}
|
||||
return MergeComplete(st)
|
||||
return MergeTransitionComplete(st)
|
||||
}
|
||||
|
||||
// ValidatePayloadWhenMergeCompletes validates if payload is valid versus input beacon state.
|
||||
@@ -79,7 +92,7 @@ func ExecutionEnabled(st state.BeaconState, blk block.BeaconBlockBody) (bool, er
|
||||
// if is_merge_complete(state):
|
||||
// assert payload.parent_hash == state.latest_execution_payload_header.block_hash
|
||||
func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload *enginev1.ExecutionPayload) error {
|
||||
complete, err := MergeComplete(st)
|
||||
complete, err := MergeTransitionComplete(st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ func Test_MergeComplete(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(tt.payload))
|
||||
got, err := blocks.MergeComplete(st)
|
||||
got, err := blocks.MergeTransitionComplete(st)
|
||||
require.NoError(t, err)
|
||||
if got != tt.want {
|
||||
t.Errorf("mergeComplete() got = %v, want %v", got, tt.want)
|
||||
@@ -341,15 +341,49 @@ func Test_MergeBlock(t *testing.T) {
|
||||
blk.Block.Body.ExecutionPayload = tt.payload
|
||||
body, err := wrapper.WrappedBellatrixBeaconBlockBody(blk.Block.Body)
|
||||
require.NoError(t, err)
|
||||
got, err := blocks.IsMergeBlock(st, body)
|
||||
got, err := blocks.MergeTransitionBlock(st, body)
|
||||
require.NoError(t, err)
|
||||
if got != tt.want {
|
||||
t.Errorf("IsMergeBlock() got = %v, want %v", got, tt.want)
|
||||
t.Errorf("MergeTransitionBlock() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_IsExecutionBlock(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
payload *enginev1.ExecutionPayload
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "empty payload",
|
||||
payload: emptyPayload(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "non-empty payload",
|
||||
payload: func() *enginev1.ExecutionPayload {
|
||||
p := emptyPayload()
|
||||
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
||||
return p
|
||||
}(),
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
blk := util.NewBeaconBlockBellatrix()
|
||||
blk.Block.Body.ExecutionPayload = tt.payload
|
||||
wrappedBlock, err := wrapper.WrappedBellatrixBeaconBlock(blk.Block)
|
||||
require.NoError(t, err)
|
||||
got, err := blocks.ExecutionBlock(wrappedBlock.Body())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ExecutionEnabled(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -617,7 +651,7 @@ func BenchmarkBellatrixComplete(b *testing.B) {
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := blocks.MergeComplete(st)
|
||||
_, err := blocks.MergeTransitionComplete(st)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/math"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
@@ -47,8 +48,7 @@ func TestProcessRewardsAndPenaltiesPrecompute(t *testing.T) {
|
||||
|
||||
processedState, err := ProcessRewardsAndPenaltiesPrecompute(beaconState, bp, vp, AttestationsDelta, ProposersDelta)
|
||||
require.NoError(t, err)
|
||||
beaconState, ok := processedState.(*v1.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, true, processedState.Version() == version.Phase0)
|
||||
|
||||
// Indices that voted everything except for head, lost a bit money
|
||||
wanted := uint64(31999810265)
|
||||
|
||||
19
beacon-chain/core/sharding/BUILD.bazel
Normal file
19
beacon-chain/core/sharding/BUILD.bazel
Normal file
@@ -0,0 +1,19 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"processor.go",
|
||||
"verifier.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/sharding",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/block:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
],
|
||||
)
|
||||
24
beacon-chain/core/sharding/processor.go
Normal file
24
beacon-chain/core/sharding/processor.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package sharding
|
||||
|
||||
import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
)
|
||||
|
||||
func getActiveShardCount(st state.BeaconState, epoch types.Epoch) uint64 {
|
||||
return 256
|
||||
}
|
||||
|
||||
func appendIntermediateBlock(st state.BeaconState, blk block.BeaconBlock) {
|
||||
// Check state version
|
||||
if time.IsIntermediateBlockSlot(blk.Slot()) {
|
||||
// state.blocks_since_intermediate_block = []
|
||||
}
|
||||
// state.blocks_since_intermediate_block.append(block)
|
||||
}
|
||||
|
||||
func processShardedData(st state.BeaconState, blk block.BeaconBlock) (state.BeaconState, error) {
|
||||
return nil, nil
|
||||
}
|
||||
68
beacon-chain/core/sharding/verifier.go
Normal file
68
beacon-chain/core/sharding/verifier.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package sharding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
)
|
||||
|
||||
func verifyIntermediateBlockBid(st state.BeaconState, blk block.BeaconBlock) error {
|
||||
if time.IsIntermediateBlockSlot(blk.Slot()) {
|
||||
return verifyIntermediateBlockBid(st, blk)
|
||||
}
|
||||
return verifyBidAtNormalBlockSlot(st, blk)
|
||||
}
|
||||
|
||||
func verifyBidAtIntermediateBlockSlot(st state.BeaconState, blk block.BeaconBlock) error {
|
||||
// get last intermediate block from beacon state
|
||||
b := ðpb.BeaconBlockDankSharding{}
|
||||
blockBid := b.Body.PayloadData.GetBlockBid()
|
||||
// Verify block in state contains bid (selector should be 0)
|
||||
if b.Slot+1 != blk.Slot() {
|
||||
return fmt.Errorf("intermediate block slot %d +1 does not match slot %d", b.Slot+1, blk.Slot())
|
||||
}
|
||||
// Verify intermediate block does not contain bid (selector should be 1)
|
||||
blockData := ðpb.IntermediateBlockData{}
|
||||
|
||||
blockDataPayloadRoot, err := blockData.ExecutionPayload.HashTreeRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if blockDataPayloadRoot != bytesutil.ToBytes32(blockBid.ExecutionPayloadRoot) {
|
||||
return fmt.Errorf("intermediate block data root %#x does not match block data root %#x", blockDataPayloadRoot, bytesutil.ToBytes32(blockBid.ExecutionPayloadRoot))
|
||||
}
|
||||
if blockBid.ShardedDataCommitmentCount != blockData.ShardedCommitmentsContainer.IncludedShardedDataCommitments {
|
||||
return fmt.Errorf("intermediate block sharded data commitment count %d does not match block sharded data commitment count %d", blockBid.ShardedDataCommitmentCount, blockData.ShardedCommitmentsContainer.IncludedShardedDataCommitments)
|
||||
}
|
||||
cr := blockBid.ShardedDataCommitmentRoot
|
||||
l := uint64(len(blockData.ShardedCommitmentsContainer.ShardedCommitments)) - blockData.ShardedCommitmentsContainer.IncludedShardedDataCommitments
|
||||
_ = blockData.ShardedCommitmentsContainer.ShardedCommitments[l:]
|
||||
// HTR of sharded commitments HTR(shardedCommitments)
|
||||
if bytesutil.ToBytes32(cr) != [32]byte{} {
|
||||
return fmt.Errorf("intermediate block sharded data commitment root %#x does not match block sharded data commitment root %#x", cr, [32]byte{})
|
||||
}
|
||||
if blockBid.ValidatorIndex != blk.ProposerIndex() {
|
||||
return fmt.Errorf("intermediate block proposer index %d does not match block proposer index %d", blockBid.ValidatorIndex, blk.ProposerIndex())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyBidAtNormalBlockSlot(st state.BeaconState, blk block.BeaconBlock) error {
|
||||
// Verify payload data contains bid (selector should be 0)
|
||||
blockBid := ðpb.IntermediateBlockBid{}
|
||||
if blockBid.Slot != blk.Slot() {
|
||||
return fmt.Errorf("intermediate block slot %d does not match slot %d", blockBid.Slot, blk.Slot())
|
||||
}
|
||||
if bytes.Equal(blockBid.ParentBlockRoot, blk.ParentRoot()) {
|
||||
return fmt.Errorf("intermediate block parent block root %#x does not match block parent block root %#x", blockBid.ParentBlockRoot, blk.ParentRoot())
|
||||
}
|
||||
// We do not check that the builder address exists or has sufficient balance here.
|
||||
// # If it does not have sufficient balance, the block proposer loses out, so it is their
|
||||
// # responsibility to check.
|
||||
return nil
|
||||
}
|
||||
@@ -78,3 +78,8 @@ func CanUpgradeToBellatrix(slot types.Slot) bool {
|
||||
func CanProcessEpoch(state state.ReadOnlyBeaconState) bool {
|
||||
return (state.Slot()+1)%params.BeaconConfig().SlotsPerEpoch == 0
|
||||
}
|
||||
|
||||
// IsIntermediateBlockSlot returns true of input slot is an intermediate block slot.
|
||||
func IsIntermediateBlockSlot(s types.Slot) bool {
|
||||
return s%2 == 1
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
@@ -33,8 +34,7 @@ func TestSkipSlotCache_OK(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
executedState, err := transition.ExecuteStateTransition(context.Background(), originalState, wrapper.WrappedPhase0SignedBeaconBlock(blk))
|
||||
require.NoError(t, err, "Could not run state transition")
|
||||
originalState, ok := executedState.(*v1.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, true, executedState.Version() == version.Phase0)
|
||||
bState, err = transition.ExecuteStateTransition(context.Background(), bState, wrapper.WrappedPhase0SignedBeaconBlock(blk))
|
||||
require.NoError(t, err, "Could not process state transition")
|
||||
|
||||
@@ -59,8 +59,7 @@ func TestSkipSlotCache_ConcurrentMixup(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
executedState, err := transition.ExecuteStateTransition(context.Background(), originalState, wrapper.WrappedPhase0SignedBeaconBlock(blk))
|
||||
require.NoError(t, err, "Could not run state transition")
|
||||
originalState, ok := executedState.(*v1.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, true, executedState.Version() == version.Phase0)
|
||||
|
||||
// Create two shallow but different forks
|
||||
var s1, s0 state.BeaconState
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
fuzz "github.com/google/gofuzz"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestGenesisBeaconState_1000(t *testing.T) {
|
||||
@@ -37,7 +38,8 @@ func TestOptimizedGenesisBeaconState_1000(t *testing.T) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
var genesisTime uint64
|
||||
preState := &v1.BeaconState{}
|
||||
preState, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
eth1Data := ðpb.Eth1Data{}
|
||||
for i := 0; i < 1000; i++ {
|
||||
fuzzer.Fuzz(&genesisTime)
|
||||
|
||||
@@ -10,13 +10,15 @@ import (
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestFuzzExecuteStateTransition_1000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
ctx := context.Background()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
sb := ðpb.SignedBeaconBlock{}
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
@@ -34,7 +36,8 @@ func TestFuzzCalculateStateRoot_1000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
ctx := context.Background()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
sb := ðpb.SignedBeaconBlock{}
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
@@ -52,7 +55,8 @@ func TestFuzzProcessSlot_1000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
ctx := context.Background()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
for i := 0; i < 1000; i++ {
|
||||
@@ -68,7 +72,8 @@ func TestFuzzProcessSlots_1000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
ctx := context.Background()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
slot := types.Slot(0)
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
@@ -86,7 +91,8 @@ func TestFuzzprocessOperationsNoVerify_1000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
ctx := context.Background()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
bb := ðpb.SignedBeaconBlock{}
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
@@ -100,10 +106,11 @@ func TestFuzzprocessOperationsNoVerify_1000(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzverifyOperationLengths_10000(_ *testing.T) {
|
||||
func TestFuzzverifyOperationLengths_10000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
bb := ðpb.SignedBeaconBlock{}
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
@@ -115,10 +122,11 @@ func TestFuzzverifyOperationLengths_10000(_ *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzCanProcessEpoch_10000(_ *testing.T) {
|
||||
func TestFuzzCanProcessEpoch_10000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
for i := 0; i < 10000; i++ {
|
||||
@@ -131,7 +139,8 @@ func TestFuzzProcessEpochPrecompute_1000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
ctx := context.Background()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
for i := 0; i < 1000; i++ {
|
||||
@@ -147,7 +156,8 @@ func TestFuzzProcessBlockForStateRoot_1000(t *testing.T) {
|
||||
SkipSlotCache.Disable()
|
||||
defer SkipSlotCache.Enable()
|
||||
ctx := context.Background()
|
||||
state := &v1.BeaconState{}
|
||||
state, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
sb := ðpb.SignedBeaconBlock{}
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
fuzzer.NilChance(0.1)
|
||||
|
||||
@@ -394,7 +394,9 @@ func TestProcessBlock_OverMaxProposerSlashings(t *testing.T) {
|
||||
}
|
||||
want := fmt.Sprintf("number of proposer slashings (%d) in block body exceeds allowed threshold of %d",
|
||||
len(b.Block.Body.ProposerSlashings), params.BeaconConfig().MaxProposerSlashings)
|
||||
_, err := transition.VerifyOperationLengths(context.Background(), &v1.BeaconState{}, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
s, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
_, err = transition.VerifyOperationLengths(context.Background(), s, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -409,7 +411,9 @@ func TestProcessBlock_OverMaxAttesterSlashings(t *testing.T) {
|
||||
}
|
||||
want := fmt.Sprintf("number of attester slashings (%d) in block body exceeds allowed threshold of %d",
|
||||
len(b.Block.Body.AttesterSlashings), params.BeaconConfig().MaxAttesterSlashings)
|
||||
_, err := transition.VerifyOperationLengths(context.Background(), &v1.BeaconState{}, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
s, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
_, err = transition.VerifyOperationLengths(context.Background(), s, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -423,7 +427,9 @@ func TestProcessBlock_OverMaxAttestations(t *testing.T) {
|
||||
}
|
||||
want := fmt.Sprintf("number of attestations (%d) in block body exceeds allowed threshold of %d",
|
||||
len(b.Block.Body.Attestations), params.BeaconConfig().MaxAttestations)
|
||||
_, err := transition.VerifyOperationLengths(context.Background(), &v1.BeaconState{}, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
s, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
_, err = transition.VerifyOperationLengths(context.Background(), s, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
@@ -438,7 +444,9 @@ func TestProcessBlock_OverMaxVoluntaryExits(t *testing.T) {
|
||||
}
|
||||
want := fmt.Sprintf("number of voluntary exits (%d) in block body exceeds allowed threshold of %d",
|
||||
len(b.Block.Body.VoluntaryExits), maxExits)
|
||||
_, err := transition.VerifyOperationLengths(context.Background(), &v1.BeaconState{}, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
s, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
_, err = transition.VerifyOperationLengths(context.Background(), s, wrapper.WrappedPhase0SignedBeaconBlock(b))
|
||||
assert.ErrorContains(t, want, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ go_test(
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
@@ -129,8 +130,7 @@ func TestSlashValidator_OK(t *testing.T) {
|
||||
cfg := params.BeaconConfig()
|
||||
slashedState, err := SlashValidator(context.Background(), state, slashedIdx, cfg.MinSlashingPenaltyQuotient, cfg.ProposerRewardQuotient)
|
||||
require.NoError(t, err, "Could not slash validator")
|
||||
state, ok := slashedState.(*v1.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, true, slashedState.Version() == version.Phase0)
|
||||
|
||||
v, err := state.ValidatorAtIndex(slashedIdx)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -30,6 +30,7 @@ type ReadOnlyDatabase interface {
|
||||
IsFinalizedBlock(ctx context.Context, blockRoot [32]byte) bool
|
||||
FinalizedChildBlock(ctx context.Context, blockRoot [32]byte) (block.SignedBeaconBlock, error)
|
||||
HighestSlotBlocksBelow(ctx context.Context, slot types.Slot) ([]block.SignedBeaconBlock, error)
|
||||
ValidatedTips(ctx context.Context) (map[[32]byte]types.Slot, error)
|
||||
// State related methods.
|
||||
State(ctx context.Context, blockRoot [32]byte) (state.BeaconState, error)
|
||||
GenesisState(ctx context.Context) (state.BeaconState, error)
|
||||
@@ -58,9 +59,11 @@ type NoHeadAccessDatabase interface {
|
||||
ReadOnlyDatabase
|
||||
|
||||
// Block related methods.
|
||||
DeleteBlock(ctx context.Context, root [32]byte) error
|
||||
SaveBlock(ctx context.Context, block block.SignedBeaconBlock) error
|
||||
SaveBlocks(ctx context.Context, blocks []block.SignedBeaconBlock) error
|
||||
SaveGenesisBlockRoot(ctx context.Context, blockRoot [32]byte) error
|
||||
UpdateValidatedTips(ctx context.Context, newVals map[[32]byte]types.Slot) error
|
||||
// State related methods.
|
||||
SaveState(ctx context.Context, state state.ReadOnlyBeaconState, blockRoot [32]byte) error
|
||||
SaveStates(ctx context.Context, states []state.ReadOnlyBeaconState, blockRoots [][32]byte) error
|
||||
|
||||
@@ -204,6 +204,34 @@ func (s *Store) BlockRootsBySlot(ctx context.Context, slot types.Slot) (bool, []
|
||||
return len(blockRoots) > 0, blockRoots, nil
|
||||
}
|
||||
|
||||
// DeleteBlock from the db
|
||||
// This deletes the root entry from all buckets in the blocks DB
|
||||
// If the block is finalized this function returns an error
|
||||
func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.DeleteBlock")
|
||||
defer span.End()
|
||||
|
||||
if err := s.DeleteState(ctx, root); err != nil {
|
||||
return errDeleteFinalized
|
||||
}
|
||||
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
if b := bkt.Get(root[:]); b != nil {
|
||||
return errDeleteFinalized
|
||||
}
|
||||
|
||||
if err := tx.Bucket(blocksBucket).Delete(root[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Bucket(blockParentRootIndicesBucket).Delete(root[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
s.blockCache.Del(string(root[:]))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// SaveBlock to the db.
|
||||
func (s *Store) SaveBlock(ctx context.Context, signed block.SignedBeaconBlock) error {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveBlock")
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
@@ -163,6 +164,44 @@ func TestStore_BlocksHandleInvalidEndSlot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_DeleteBlock(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*4, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
root2, err := blks[4*slotsPerEpoch-2].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
b, err := db.Block(ctx, root2)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, b)
|
||||
require.NoError(t, db.DeleteBlock(ctx, root2))
|
||||
st, err = db.State(ctx, root2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, st, nil)
|
||||
|
||||
b, err = db.Block(ctx, root2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, b, nil)
|
||||
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), errDeleteFinalized)
|
||||
|
||||
}
|
||||
|
||||
func TestStore_GenesisBlock(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -2,6 +2,9 @@ package kv
|
||||
|
||||
import "errors"
|
||||
|
||||
// errDeleteFinalized is raised when we attempt to delete a finalized block/state
|
||||
var errDeleteFinalized = errors.New("cannot delete finalized block or state")
|
||||
|
||||
// ErrNotFound can be used directly, or as a wrapped DBError, whenever a db method needs to
|
||||
// indicate that a value couldn't be found.
|
||||
var ErrNotFound = errors.New("not found in db")
|
||||
|
||||
@@ -105,6 +105,8 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
|
||||
}
|
||||
}
|
||||
datafile := KVStoreDatafilePath(dirPath)
|
||||
start := time.Now()
|
||||
log.Infof("Opening Bolt DB at %s", datafile)
|
||||
boltDB, err := bolt.Open(
|
||||
datafile,
|
||||
params.BeaconIoConfig().ReadWritePermissions,
|
||||
@@ -114,29 +116,40 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.WithField("elapsed", time.Since(start)).Error("Failed to open Bolt DB")
|
||||
if errors.Is(err, bolt.ErrTimeout) {
|
||||
return nil, errors.New("cannot obtain database lock, database may be in use by another process")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
log.WithField("elapsed", time.Since(start)).Info("Opened Bolt DB")
|
||||
|
||||
boltDB.AllocSize = boltAllocSize
|
||||
start = time.Now()
|
||||
log.Infof("Creating block cache...")
|
||||
blockCache, err := ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: 1000, // number of keys to track frequency of (1000).
|
||||
MaxCost: BlockCacheSize, // maximum cost of cache (1000 Blocks).
|
||||
BufferItems: 64, // number of keys per Get buffer.
|
||||
})
|
||||
if err != nil {
|
||||
log.WithField("elapsed", time.Since(start)).Error("Failed to create block cache")
|
||||
return nil, err
|
||||
}
|
||||
log.WithField("elapsed", time.Since(start)).Info("Created block cache")
|
||||
|
||||
start = time.Now()
|
||||
log.Infof("Creating validator cache...")
|
||||
validatorCache, err := ristretto.NewCache(&ristretto.Config{
|
||||
NumCounters: NumOfValidatorEntries, // number of entries in cache (2 Million).
|
||||
MaxCost: ValidatorEntryMaxCost, // maximum size of the cache (64Mb)
|
||||
BufferItems: 64, // number of keys per Get buffer.
|
||||
})
|
||||
if err != nil {
|
||||
log.WithField("elapsed", time.Since(start)).Error("Failed to to create validator cache")
|
||||
return nil, err
|
||||
}
|
||||
log.WithField("elapsed", time.Since(start)).Info("Created validator cache")
|
||||
|
||||
kv := &Store{
|
||||
db: boltDB,
|
||||
@@ -146,7 +159,8 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
|
||||
stateSummaryCache: newStateSummaryCache(),
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
start = time.Now()
|
||||
log.Infof("Updating DB and creating buckets...")
|
||||
if err := kv.db.Update(func(tx *bolt.Tx) error {
|
||||
return createBuckets(
|
||||
tx,
|
||||
@@ -179,8 +193,10 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
|
||||
migrationsBucket,
|
||||
)
|
||||
}); err != nil {
|
||||
log.WithField("elapsed", time.Since(start)).Error("Failed to update db and create buckets")
|
||||
return nil, err
|
||||
}
|
||||
log.WithField("elapsed", time.Since(start)).Info("Updated db and created buckets")
|
||||
|
||||
err = prometheus.Register(createBoltCollector(kv.db))
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
@@ -19,12 +20,12 @@ import (
|
||||
func Test_migrateStateValidators(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator)
|
||||
eval func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator)
|
||||
setup func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
|
||||
eval func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator)
|
||||
}{
|
||||
{
|
||||
name: "only runs once",
|
||||
setup: func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator) {
|
||||
setup: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
|
||||
// create some new buckets that should be present for this migration
|
||||
err := dbStore.db.Update(func(tx *bbolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(stateValidatorsBucket)
|
||||
@@ -35,7 +36,7 @@ func Test_migrateStateValidators(t *testing.T) {
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
eval: func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator) {
|
||||
eval: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
|
||||
// check if the migration is completed, per migration table.
|
||||
err := dbStore.db.View(func(tx *bbolt.Tx) error {
|
||||
migrationCompleteOrNot := tx.Bucket(migrationsBucket).Get(migrationStateValidatorsKey)
|
||||
@@ -47,7 +48,7 @@ func Test_migrateStateValidators(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "once migrated, always enable flag",
|
||||
setup: func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator) {
|
||||
setup: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
|
||||
// create some new buckets that should be present for this migration
|
||||
err := dbStore.db.Update(func(tx *bbolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(stateValidatorsBucket)
|
||||
@@ -58,7 +59,7 @@ func Test_migrateStateValidators(t *testing.T) {
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
eval: func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator) {
|
||||
eval: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
|
||||
// disable the flag and see if the code mandates that flag.
|
||||
resetCfg := features.InitWithReset(&features.Flags{
|
||||
EnableHistoricalSpaceRepresentation: false,
|
||||
@@ -111,7 +112,7 @@ func Test_migrateStateValidators(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "migrates validators and adds them to new buckets",
|
||||
setup: func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator) {
|
||||
setup: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
|
||||
// create some new buckets that should be present for this migration
|
||||
err := dbStore.db.Update(func(tx *bbolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(stateValidatorsBucket)
|
||||
@@ -122,7 +123,7 @@ func Test_migrateStateValidators(t *testing.T) {
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
eval: func(t *testing.T, dbStore *Store, state *v1.BeaconState, vals []*v1alpha1.Validator) {
|
||||
eval: func(t *testing.T, dbStore *Store, state state.BeaconState, vals []*v1alpha1.Validator) {
|
||||
// check whether the new buckets are present
|
||||
err := dbStore.db.View(func(tx *bbolt.Tx) error {
|
||||
valBkt := tx.Bucket(stateValidatorsBucket)
|
||||
@@ -209,12 +210,12 @@ func Test_migrateStateValidators(t *testing.T) {
|
||||
func Test_migrateAltairStateValidators(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func(t *testing.T, dbStore *Store, state *v2.BeaconState, vals []*v1alpha1.Validator)
|
||||
eval func(t *testing.T, dbStore *Store, state *v2.BeaconState, vals []*v1alpha1.Validator)
|
||||
setup func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator)
|
||||
eval func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator)
|
||||
}{
|
||||
{
|
||||
name: "migrates validators and adds them to new buckets",
|
||||
setup: func(t *testing.T, dbStore *Store, state *v2.BeaconState, vals []*v1alpha1.Validator) {
|
||||
setup: func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator) {
|
||||
// create some new buckets that should be present for this migration
|
||||
err := dbStore.db.Update(func(tx *bbolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists(stateValidatorsBucket)
|
||||
@@ -225,7 +226,7 @@ func Test_migrateAltairStateValidators(t *testing.T) {
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
eval: func(t *testing.T, dbStore *Store, state *v2.BeaconState, vals []*v1alpha1.Validator) {
|
||||
eval: func(t *testing.T, dbStore *Store, state state.BeaconStateAltair, vals []*v1alpha1.Validator) {
|
||||
// check whether the new buckets are present
|
||||
err := dbStore.db.View(func(tx *bbolt.Tx) error {
|
||||
valBkt := tx.Bucket(stateValidatorsBucket)
|
||||
@@ -300,9 +301,9 @@ func Test_migrateAltairStateValidators(t *testing.T) {
|
||||
})
|
||||
defer resetCfg()
|
||||
|
||||
tt.setup(t, dbStore, st.(*v2.BeaconState), vals)
|
||||
tt.setup(t, dbStore, st, vals)
|
||||
assert.NoError(t, migrateStateValidators(context.Background(), dbStore.db), "migrateArchivedIndex(tx) error")
|
||||
tt.eval(t, dbStore, st.(*v2.BeaconState), vals)
|
||||
tt.eval(t, dbStore, st, vals)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,11 @@ func (_ *Service) ChainStartEth1Data() *ethpb.Eth1Data {
|
||||
|
||||
// PreGenesisState returns an empty beacon state.
|
||||
func (_ *Service) PreGenesisState() state.BeaconState {
|
||||
return &v1.BeaconState{}
|
||||
s, err := v1.InitializeFromProto(ðpb.BeaconState{})
|
||||
if err != nil {
|
||||
panic("could not initialize state")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ClearPreGenesisData --
|
||||
|
||||
@@ -16,6 +16,7 @@ type ForkChoicer interface {
|
||||
Pruner // to clean old data for fork choice.
|
||||
Getter // to retrieve fork choice information.
|
||||
ProposerBooster // ability to boost timely-proposed block roots.
|
||||
SyncTipper // to update and retrieve validated sync tips.
|
||||
}
|
||||
|
||||
// HeadRetriever retrieves head root and optimistic info of the current chain.
|
||||
@@ -55,3 +56,11 @@ type Getter interface {
|
||||
AncestorRoot(ctx context.Context, root [32]byte, slot types.Slot) ([]byte, error)
|
||||
IsCanonical(root [32]byte) bool
|
||||
}
|
||||
|
||||
// SyncTipper returns sync tips related information.
|
||||
type SyncTipper interface {
|
||||
SyncedTips() map[[32]byte]types.Slot
|
||||
SetSyncedTips(tips map[[32]byte]types.Slot) error
|
||||
UpdateSyncedTipsWithValidRoot(ctx context.Context, root [32]byte) error
|
||||
UpdateSyncedTipsWithInvalidRoot(ctx context.Context, root [32]byte) error
|
||||
}
|
||||
|
||||
@@ -11,3 +11,4 @@ var errInvalidBestDescendantIndex = errors.New("best descendant index is invalid
|
||||
var errInvalidParentDelta = errors.New("parent delta is invalid")
|
||||
var errInvalidNodeDelta = errors.New("node delta is invalid")
|
||||
var errInvalidDeltaLength = errors.New("delta length is invalid")
|
||||
var errInvalidSyncedTips = errors.New("invalid synced tips")
|
||||
|
||||
@@ -48,4 +48,16 @@ var (
|
||||
Help: "The number of times pruning happened.",
|
||||
},
|
||||
)
|
||||
lastSyncedTipSlot = promauto.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "proto_array_last_synced_tip_slot",
|
||||
Help: "The slot of the last fully validated block added to the proto array.",
|
||||
},
|
||||
)
|
||||
syncedTipsCount = promauto.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "proto_array_synced_tips_count",
|
||||
Help: "The number of elements in the syncedTips structure.",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
@@ -107,7 +107,9 @@ func (s *Store) findSyncedTip(ctx context.Context, node *Node, syncedTips *optim
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateSyncedTipsWithValidRoot updates the synced_tips map when the block with the given root becomes VALID
|
||||
// UpdateSyncedTipsWithValidRoot is called with the root of a block that was returned as
|
||||
// VALID by the EL. This routine recomputes and updates the synced_tips map to
|
||||
// account for this new tip.
|
||||
func (f *ForkChoice) UpdateSyncedTipsWithValidRoot(ctx context.Context, root [32]byte) error {
|
||||
f.store.nodesLock.RLock()
|
||||
defer f.store.nodesLock.RUnlock()
|
||||
@@ -132,7 +134,9 @@ func (f *ForkChoice) UpdateSyncedTipsWithValidRoot(ctx context.Context, root [32
|
||||
}
|
||||
|
||||
// Cache root and slot to validated tips
|
||||
f.syncedTips.validatedTips[root] = node.slot
|
||||
newTips := make(map[[32]byte]types.Slot)
|
||||
newValidSlot := node.slot
|
||||
newTips[root] = newValidSlot
|
||||
|
||||
// Compute the full valid path from the given node to its previous synced tip
|
||||
// This path will now consist of fully validated blocks. Notice that
|
||||
@@ -140,6 +144,7 @@ func (f *ForkChoice) UpdateSyncedTipsWithValidRoot(ctx context.Context, root [32
|
||||
// In this case, only one block can be in syncedTips as the whole
|
||||
// Fork Choice would be a descendant of this block.
|
||||
validPath := make(map[uint64]bool)
|
||||
validPath[index] = true
|
||||
for {
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
@@ -168,7 +173,6 @@ func (f *ForkChoice) UpdateSyncedTipsWithValidRoot(ctx context.Context, root [32
|
||||
}
|
||||
|
||||
// For each leaf, recompute the new tip.
|
||||
newTips := make(map[[32]byte]types.Slot)
|
||||
for _, i := range leaves {
|
||||
node = f.store.nodes[i]
|
||||
j := i
|
||||
@@ -202,6 +206,8 @@ func (f *ForkChoice) UpdateSyncedTipsWithValidRoot(ctx context.Context, root [32
|
||||
}
|
||||
|
||||
f.syncedTips.validatedTips = newTips
|
||||
lastSyncedTipSlot.Set(float64(newValidSlot))
|
||||
syncedTipsCount.Set(float64(len(newTips)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -311,5 +317,6 @@ func (f *ForkChoice) UpdateSyncedTipsWithInvalidRoot(ctx context.Context, root [
|
||||
}
|
||||
}
|
||||
delete(f.syncedTips.validatedTips, parentRoot)
|
||||
syncedTipsCount.Set(float64(len(f.syncedTips.validatedTips)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -40,6 +40,33 @@ func New(justifiedEpoch, finalizedEpoch types.Epoch, finalizedRoot [32]byte) *Fo
|
||||
return &ForkChoice{store: s, balances: b, votes: v, syncedTips: st}
|
||||
}
|
||||
|
||||
// SetSyncedTips sets the synced and validated tips from the passed map
|
||||
func (f *ForkChoice) SetSyncedTips(tips map[[32]byte]types.Slot) error {
|
||||
if len(tips) == 0 {
|
||||
return errInvalidSyncedTips
|
||||
}
|
||||
newTips := make(map[[32]byte]types.Slot, len(tips))
|
||||
for k, v := range tips {
|
||||
newTips[k] = v
|
||||
}
|
||||
f.syncedTips.Lock()
|
||||
defer f.syncedTips.Unlock()
|
||||
f.syncedTips.validatedTips = newTips
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncedTips returns the synced and validated tips from the fork choice store.
|
||||
func (f *ForkChoice) SyncedTips() map[[32]byte]types.Slot {
|
||||
f.syncedTips.RLock()
|
||||
defer f.syncedTips.RUnlock()
|
||||
|
||||
m := make(map[[32]byte]types.Slot)
|
||||
for k, v := range f.syncedTips.validatedTips {
|
||||
m[k] = v
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Head returns the head root from fork choice store.
|
||||
// It firsts computes validator's balance changes then recalculates block tree from leaves to root.
|
||||
func (f *ForkChoice) Head(
|
||||
@@ -439,26 +466,18 @@ func (s *Store) applyWeightChanges(
|
||||
}
|
||||
s.proposerBoostLock.Unlock()
|
||||
|
||||
// A node's weight can not be negative but the delta can be negative.
|
||||
if nodeDelta < 0 {
|
||||
// A node's weight can not be negative but the delta can be negative.
|
||||
if int(n.weight)+nodeDelta < 0 {
|
||||
d := uint64(-nodeDelta)
|
||||
if n.weight < d {
|
||||
n.weight = 0
|
||||
} else {
|
||||
// Absolute value of node delta.
|
||||
d := nodeDelta
|
||||
if nodeDelta < 0 {
|
||||
d *= -1
|
||||
}
|
||||
// Subtract node's weight.
|
||||
n.weight -= uint64(d)
|
||||
n.weight -= d
|
||||
}
|
||||
} else {
|
||||
// Add node's weight.
|
||||
n.weight += uint64(nodeDelta)
|
||||
}
|
||||
|
||||
s.nodes[i] = n
|
||||
|
||||
// Update parent's best child and descendent if the node has a known parent.
|
||||
if n.parent != NonExistentNode {
|
||||
// Protection against node parent index out of bound. This should not happen.
|
||||
@@ -663,7 +682,7 @@ func (s *Store) prune(ctx context.Context, finalizedRoot [32]byte, syncedTips *o
|
||||
|
||||
s.nodes = canonicalNodes
|
||||
prunedCount.Inc()
|
||||
|
||||
syncedTipsCount.Set(float64(len(syncedTips.validatedTips)))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -600,6 +600,20 @@ func TestStore_LeadsToViableHead(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_SetSyncedTips(t *testing.T) {
|
||||
f := setup(1, 1)
|
||||
tips := make(map[[32]byte]types.Slot)
|
||||
require.ErrorIs(t, errInvalidSyncedTips, f.SetSyncedTips(tips))
|
||||
tips[bytesutil.ToBytes32([]byte{'a'})] = 1
|
||||
require.NoError(t, f.SetSyncedTips(tips))
|
||||
f.syncedTips.RLock()
|
||||
defer f.syncedTips.RUnlock()
|
||||
require.Equal(t, 1, len(f.syncedTips.validatedTips))
|
||||
slot, ok := f.syncedTips.validatedTips[bytesutil.ToBytes32([]byte{'a'})]
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, types.Slot(1), slot)
|
||||
}
|
||||
|
||||
func TestStore_ViableForHead(t *testing.T) {
|
||||
tests := []struct {
|
||||
n *Node
|
||||
|
||||
@@ -154,65 +154,80 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debugln("Starting DB")
|
||||
if err := beacon.startDB(cliCtx, depositAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Starting Slashing DB")
|
||||
if err := beacon.startSlasherDB(cliCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Starting State Gen")
|
||||
if err := beacon.startStateGen(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering P2P Service")
|
||||
if err := beacon.registerP2P(cliCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering POW Chain Service")
|
||||
if err := beacon.registerPOWChainService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering Attestation Pool Service")
|
||||
if err := beacon.registerAttestationPool(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering Determinstic Genesis Service")
|
||||
if err := beacon.registerDeterminsticGenesisService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Starting Fork Choice")
|
||||
beacon.startForkChoice()
|
||||
|
||||
log.Debugln("Registering Blockchain Service")
|
||||
if err := beacon.registerBlockchainService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering Intial Sync Service")
|
||||
if err := beacon.registerInitialSyncService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering Sync Service")
|
||||
if err := beacon.registerSyncService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering Slasher Service")
|
||||
if err := beacon.registerSlasherService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering RPC Service")
|
||||
if err := beacon.registerRPCService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering GRPC Gateway Service")
|
||||
if err := beacon.registerGRPCGateway(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugln("Registering Validator Monitoring Service")
|
||||
if err := beacon.registerValidatorMonitorService(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cliCtx.Bool(cmd.DisableMonitoringFlag.Name) {
|
||||
log.Debugln("Registering Prometheus Service")
|
||||
if err := beacon.registerPrometheusService(cliCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/powchain/engine-api-client/v1:go_default_library",
|
||||
"//beacon-chain/powchain/types:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -11,6 +11,21 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["client_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/pkg/errors"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
@@ -20,6 +21,10 @@ const (
|
||||
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
||||
// GetPayloadMethod v1 request string for JSON-RPC.
|
||||
GetPayloadMethod = "engine_getPayloadV1"
|
||||
// ExecutionBlockByHashMethod request string for JSON-RPC.
|
||||
ExecutionBlockByHashMethod = "eth_blockByHash"
|
||||
// LatestExecutionBlockMethod request string for JSON-RPC.
|
||||
LatestExecutionBlockMethod = "eth_blockByNumber"
|
||||
// DefaultTimeout for HTTP.
|
||||
DefaultTimeout = time.Second * 5
|
||||
)
|
||||
@@ -27,8 +32,20 @@ const (
|
||||
// ForkchoiceUpdatedResponse is the response kind received by the
|
||||
// engine_forkchoiceUpdatedV1 endpoint.
|
||||
type ForkchoiceUpdatedResponse struct {
|
||||
Status *pb.PayloadStatus `json:"status"`
|
||||
PayloadId [8]byte `json:"payloadId"`
|
||||
Status *pb.PayloadStatus `json:"status"`
|
||||
PayloadId *pb.PayloadIDBytes `json:"payloadId"`
|
||||
}
|
||||
|
||||
// EngineCaller defines a client that can interact with an Ethereum
|
||||
// execution node's engine service via JSON-RPC.
|
||||
type EngineCaller interface {
|
||||
NewPayload(ctx context.Context, payload *pb.ExecutionPayload) (*pb.PayloadStatus, error)
|
||||
ForkchoiceUpdated(
|
||||
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error)
|
||||
GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error)
|
||||
LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock, error)
|
||||
ExecutionBlockByHash(ctx context.Context, hash common.Hash) (*pb.ExecutionBlock, error)
|
||||
}
|
||||
|
||||
// Client defines a new engine API client for the Prysm consensus node
|
||||
@@ -67,19 +84,81 @@ func New(ctx context.Context, endpoint string, opts ...Option) (*Client, error)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewPayload --
|
||||
func (*Client) NewPayload(_ context.Context, _ *pb.ExecutionPayload) (*pb.PayloadStatus, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
// NewPayload calls the engine_newPayloadV1 method via JSON-RPC.
|
||||
func (c *Client) NewPayload(ctx context.Context, payload *pb.ExecutionPayload) (*pb.PayloadStatus, error) {
|
||||
result := &pb.PayloadStatus{}
|
||||
err := c.rpc.CallContext(ctx, result, NewPayloadMethod, payload)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// ForkchoiceUpdated --
|
||||
func (*Client) ForkchoiceUpdated(
|
||||
_ context.Context, _ *pb.ForkchoiceState, _ *pb.PayloadAttributes,
|
||||
// ForkchoiceUpdated calls the engine_forkchoiceUpdatedV1 method via JSON-RPC.
|
||||
func (c *Client) ForkchoiceUpdated(
|
||||
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
result := &ForkchoiceUpdatedResponse{}
|
||||
err := c.rpc.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, attrs)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// GetPayload --
|
||||
func (*Client) GetPayload(_ context.Context, _ [8]byte) (*pb.ExecutionPayload, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
// GetPayload calls the engine_getPayloadV1 method via JSON-RPC.
|
||||
func (c *Client) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error) {
|
||||
result := &pb.ExecutionPayload{}
|
||||
err := c.rpc.CallContext(ctx, result, GetPayloadMethod, pb.PayloadIDBytes(payloadId))
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// LatestExecutionBlock fetches the latest execution engine block by calling
|
||||
// eth_blockByNumber via JSON-RPC.
|
||||
func (c *Client) LatestExecutionBlock(ctx context.Context) (*pb.ExecutionBlock, error) {
|
||||
result := &pb.ExecutionBlock{}
|
||||
err := c.rpc.CallContext(
|
||||
ctx,
|
||||
result,
|
||||
LatestExecutionBlockMethod,
|
||||
"latest",
|
||||
false, /* no full transaction objects */
|
||||
)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// ExecutionBlockByHash fetches an execution engine block by hash by calling
|
||||
// eth_blockByHash via JSON-RPC.
|
||||
func (c *Client) ExecutionBlockByHash(ctx context.Context, hash common.Hash) (*pb.ExecutionBlock, error) {
|
||||
result := &pb.ExecutionBlock{}
|
||||
err := c.rpc.CallContext(ctx, result, ExecutionBlockByHashMethod, hash)
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// Handles errors received from the RPC server according to the specification.
|
||||
func handleRPCError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
e, ok := err.(rpc.Error)
|
||||
if !ok {
|
||||
return errors.Wrap(err, "got an unexpected error")
|
||||
}
|
||||
switch e.ErrorCode() {
|
||||
case -32700:
|
||||
return ErrParse
|
||||
case -32600:
|
||||
return ErrInvalidRequest
|
||||
case -32601:
|
||||
return ErrMethodNotFound
|
||||
case -32602:
|
||||
return ErrInvalidParams
|
||||
case -32603:
|
||||
return ErrInternal
|
||||
case -32001:
|
||||
return ErrUnknownPayload
|
||||
case -32000:
|
||||
// Only -32000 status codes are data errors in the RPC specification.
|
||||
errWithData, ok := err.(rpc.DataError)
|
||||
if !ok {
|
||||
return errors.Wrap(err, "got an unexpected error")
|
||||
}
|
||||
return errors.Wrapf(ErrServer, "%v", errWithData.ErrorData())
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
512
beacon-chain/powchain/engine-api-client/v1/client_test.go
Normal file
512
beacon-chain/powchain/engine-api-client/v1/client_test.go
Normal file
@@ -0,0 +1,512 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
var _ = EngineCaller(&Client{})
|
||||
|
||||
func TestClient_IPC(t *testing.T) {
|
||||
server := newTestIPCServer(t)
|
||||
defer server.Stop()
|
||||
rpcClient := rpc.DialInProc(server)
|
||||
defer rpcClient.Close()
|
||||
client := &Client{}
|
||||
client.rpc = rpcClient
|
||||
ctx := context.Background()
|
||||
fix := fixtures()
|
||||
|
||||
t.Run(GetPayloadMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
payloadId := [8]byte{1}
|
||||
resp, err := client.GetPayload(ctx, payloadId)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
|
||||
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
||||
require.Equal(t, true, ok)
|
||||
resp, err := client.ForkchoiceUpdated(ctx, &pb.ForkchoiceState{}, &pb.PayloadAttributes{})
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want.Status, resp.Status)
|
||||
require.DeepEqual(t, want.PayloadId, resp.PayloadId)
|
||||
})
|
||||
t.Run(NewPayloadMethod, func(t *testing.T) {
|
||||
want, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
|
||||
require.Equal(t, true, ok)
|
||||
req, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
resp, err := client.NewPayload(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(LatestExecutionBlockMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
require.Equal(t, true, ok)
|
||||
resp, err := client.LatestExecutionBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ExecutionBlockByHashMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
require.Equal(t, true, ok)
|
||||
arg := common.BytesToHash([]byte("foo"))
|
||||
resp, err := client.ExecutionBlockByHash(ctx, arg)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_HTTP(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
fix := fixtures()
|
||||
|
||||
t.Run(GetPayloadMethod, func(t *testing.T) {
|
||||
payloadId := [8]byte{1}
|
||||
want, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
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())
|
||||
}()
|
||||
enc, err := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
|
||||
reqArg, err := json.Marshal(pb.PayloadIDBytes(payloadId))
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the JSON string RPC request contains the right arguments.
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, string(reqArg),
|
||||
))
|
||||
resp := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": want,
|
||||
}
|
||||
err = json.NewEncoder(w).Encode(resp)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||
require.NoError(t, err)
|
||||
defer rpcClient.Close()
|
||||
|
||||
client := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.GetPayload(ctx, payloadId)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ForkchoiceUpdatedMethod, func(t *testing.T) {
|
||||
forkChoiceState := &pb.ForkchoiceState{
|
||||
HeadBlockHash: []byte("head"),
|
||||
SafeBlockHash: []byte("safe"),
|
||||
FinalizedBlockHash: []byte("finalized"),
|
||||
}
|
||||
payloadAttributes := &pb.PayloadAttributes{
|
||||
Timestamp: 1,
|
||||
Random: []byte("random"),
|
||||
SuggestedFeeRecipient: []byte("suggestedFeeRecipient"),
|
||||
}
|
||||
want, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
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())
|
||||
}()
|
||||
enc, err := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
|
||||
forkChoiceStateReq, err := json.Marshal(forkChoiceState)
|
||||
require.NoError(t, err)
|
||||
payloadAttrsReq, err := json.Marshal(payloadAttributes)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the JSON string RPC request contains the right arguments.
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, string(forkChoiceStateReq),
|
||||
))
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, string(payloadAttrsReq),
|
||||
))
|
||||
resp := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": want,
|
||||
}
|
||||
err = json.NewEncoder(w).Encode(resp)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||
require.NoError(t, err)
|
||||
defer rpcClient.Close()
|
||||
|
||||
client := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.ForkchoiceUpdated(ctx, forkChoiceState, payloadAttributes)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want.Status, resp.Status)
|
||||
require.DeepEqual(t, want.PayloadId, resp.PayloadId)
|
||||
})
|
||||
t.Run(NewPayloadMethod, func(t *testing.T) {
|
||||
execPayload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
require.Equal(t, true, ok)
|
||||
want, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
|
||||
require.Equal(t, true, ok)
|
||||
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())
|
||||
}()
|
||||
enc, err := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
|
||||
reqArg, err := json.Marshal(execPayload)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the JSON string RPC request contains the right arguments.
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, string(reqArg),
|
||||
))
|
||||
resp := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": want,
|
||||
}
|
||||
err = json.NewEncoder(w).Encode(resp)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||
require.NoError(t, err)
|
||||
defer rpcClient.Close()
|
||||
|
||||
client := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.NewPayload(ctx, execPayload)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(LatestExecutionBlockMethod, func(t *testing.T) {
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
require.Equal(t, true, ok)
|
||||
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 := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": want,
|
||||
}
|
||||
err := json.NewEncoder(w).Encode(resp)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||
require.NoError(t, err)
|
||||
defer rpcClient.Close()
|
||||
|
||||
client := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.LatestExecutionBlock(ctx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
t.Run(ExecutionBlockByHashMethod, func(t *testing.T) {
|
||||
arg := common.BytesToHash([]byte("foo"))
|
||||
want, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
require.Equal(t, true, ok)
|
||||
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())
|
||||
}()
|
||||
enc, err := ioutil.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
jsonRequestString := string(enc)
|
||||
// We expect the JSON string RPC request contains the right arguments.
|
||||
require.Equal(t, true, strings.Contains(
|
||||
jsonRequestString, fmt.Sprintf("%#x", arg),
|
||||
))
|
||||
resp := map[string]interface{}{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": want,
|
||||
}
|
||||
err = json.NewEncoder(w).Encode(resp)
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
rpcClient, err := rpc.DialHTTP(srv.URL)
|
||||
require.NoError(t, err)
|
||||
defer rpcClient.Close()
|
||||
|
||||
client := &Client{}
|
||||
client.rpc = rpcClient
|
||||
|
||||
// We call the RPC method via HTTP and expect a proper result.
|
||||
resp, err := client.ExecutionBlockByHash(ctx, arg)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, want, resp)
|
||||
})
|
||||
}
|
||||
|
||||
type customError struct {
|
||||
code int
|
||||
}
|
||||
|
||||
func (c *customError) ErrorCode() int {
|
||||
return c.code
|
||||
}
|
||||
|
||||
func (*customError) Error() string {
|
||||
return "something went wrong"
|
||||
}
|
||||
|
||||
type dataError struct {
|
||||
code int
|
||||
data interface{}
|
||||
}
|
||||
|
||||
func (c *dataError) ErrorCode() int {
|
||||
return c.code
|
||||
}
|
||||
|
||||
func (*dataError) Error() string {
|
||||
return "something went wrong"
|
||||
}
|
||||
|
||||
func (c *dataError) ErrorData() interface{} {
|
||||
return c.data
|
||||
}
|
||||
|
||||
func Test_handleRPCError(t *testing.T) {
|
||||
got := handleRPCError(nil)
|
||||
require.Equal(t, true, got == nil)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
expected error
|
||||
expectedContains string
|
||||
given error
|
||||
}{
|
||||
{
|
||||
name: "not an rpc error",
|
||||
expectedContains: "got an unexpected error",
|
||||
given: errors.New("foo"),
|
||||
},
|
||||
{
|
||||
name: "ErrParse",
|
||||
expectedContains: ErrParse.Error(),
|
||||
given: &customError{code: -32700},
|
||||
},
|
||||
{
|
||||
name: "ErrInvalidRequest",
|
||||
expectedContains: ErrInvalidRequest.Error(),
|
||||
given: &customError{code: -32600},
|
||||
},
|
||||
{
|
||||
name: "ErrMethodNotFound",
|
||||
expectedContains: ErrMethodNotFound.Error(),
|
||||
given: &customError{code: -32601},
|
||||
},
|
||||
{
|
||||
name: "ErrInvalidParams",
|
||||
expectedContains: ErrInvalidParams.Error(),
|
||||
given: &customError{code: -32602},
|
||||
},
|
||||
{
|
||||
name: "ErrInternal",
|
||||
expectedContains: ErrInternal.Error(),
|
||||
given: &customError{code: -32603},
|
||||
},
|
||||
{
|
||||
name: "ErrUnknownPayload",
|
||||
expectedContains: ErrUnknownPayload.Error(),
|
||||
given: &customError{code: -32001},
|
||||
},
|
||||
{
|
||||
name: "ErrServer unexpected no data",
|
||||
expectedContains: "got an unexpected error",
|
||||
given: &customError{code: -32000},
|
||||
},
|
||||
{
|
||||
name: "ErrServer with data",
|
||||
expectedContains: ErrServer.Error(),
|
||||
given: &dataError{code: -32000, data: 5},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := handleRPCError(tt.given)
|
||||
require.ErrorContains(t, tt.expectedContains, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newTestIPCServer(t *testing.T) *rpc.Server {
|
||||
server := rpc.NewServer()
|
||||
err := server.RegisterName("engine", new(testEngineService))
|
||||
require.NoError(t, err)
|
||||
err = server.RegisterName("eth", new(testEngineService))
|
||||
require.NoError(t, err)
|
||||
return server
|
||||
}
|
||||
|
||||
func fixtures() map[string]interface{} {
|
||||
foo := bytesutil.ToBytes32([]byte("foo"))
|
||||
bar := bytesutil.PadTo([]byte("bar"), 20)
|
||||
baz := bytesutil.PadTo([]byte("baz"), 256)
|
||||
baseFeePerGas := big.NewInt(6)
|
||||
executionPayloadFixture := &pb.ExecutionPayload{
|
||||
ParentHash: foo[:],
|
||||
FeeRecipient: bar,
|
||||
StateRoot: foo[:],
|
||||
ReceiptsRoot: foo[:],
|
||||
LogsBloom: baz,
|
||||
Random: foo[:],
|
||||
BlockNumber: 1,
|
||||
GasLimit: 1,
|
||||
GasUsed: 1,
|
||||
Timestamp: 1,
|
||||
ExtraData: foo[:],
|
||||
BaseFeePerGas: baseFeePerGas.Bytes(),
|
||||
BlockHash: foo[:],
|
||||
Transactions: [][]byte{foo[:]},
|
||||
}
|
||||
executionBlock := &pb.ExecutionBlock{
|
||||
Number: []byte("100"),
|
||||
Hash: []byte("hash"),
|
||||
ParentHash: []byte("parentHash"),
|
||||
Sha3Uncles: []byte("sha3Uncles"),
|
||||
Miner: []byte("miner"),
|
||||
StateRoot: []byte("sha3Uncles"),
|
||||
TransactionsRoot: []byte("transactionsRoot"),
|
||||
ReceiptsRoot: []byte("receiptsRoot"),
|
||||
LogsBloom: []byte("logsBloom"),
|
||||
Difficulty: []byte("1"),
|
||||
TotalDifficulty: []byte("2"),
|
||||
GasLimit: 3,
|
||||
GasUsed: 4,
|
||||
Timestamp: 5,
|
||||
Size: []byte("6"),
|
||||
ExtraData: []byte("extraData"),
|
||||
BaseFeePerGas: []byte("baseFeePerGas"),
|
||||
Transactions: [][]byte{foo[:]},
|
||||
Uncles: [][]byte{foo[:]},
|
||||
}
|
||||
status := &pb.PayloadStatus{
|
||||
Status: pb.PayloadStatus_ACCEPTED,
|
||||
LatestValidHash: foo[:],
|
||||
ValidationError: "",
|
||||
}
|
||||
id := pb.PayloadIDBytes([8]byte{1, 0, 0, 0, 0, 0, 0, 0})
|
||||
forkChoiceResp := &ForkchoiceUpdatedResponse{
|
||||
Status: status,
|
||||
PayloadId: &id,
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"ExecutionBlock": executionBlock,
|
||||
"ExecutionPayload": executionPayloadFixture,
|
||||
"PayloadStatus": status,
|
||||
"ForkchoiceUpdatedResponse": forkChoiceResp,
|
||||
}
|
||||
}
|
||||
|
||||
type testEngineService struct{}
|
||||
|
||||
func (*testEngineService) NoArgsRets() {}
|
||||
|
||||
func (*testEngineService) BlockByHash(
|
||||
_ context.Context, _ common.Hash,
|
||||
) *pb.ExecutionBlock {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) BlockByNumber(
|
||||
_ context.Context, _ string, _ bool,
|
||||
) *pb.ExecutionBlock {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ExecutionBlock"].(*pb.ExecutionBlock)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) GetPayloadV1(
|
||||
_ context.Context, _ pb.PayloadIDBytes,
|
||||
) *pb.ExecutionPayload {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) ForkchoiceUpdatedV1(
|
||||
_ context.Context, _ *pb.ForkchoiceState, _ *pb.PayloadAttributes,
|
||||
) *ForkchoiceUpdatedResponse {
|
||||
fix := fixtures()
|
||||
item, ok := fix["ForkchoiceUpdatedResponse"].(*ForkchoiceUpdatedResponse)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func (*testEngineService) NewPayloadV1(
|
||||
_ context.Context, _ *pb.ExecutionPayload,
|
||||
) *pb.PayloadStatus {
|
||||
fix := fixtures()
|
||||
item, ok := fix["PayloadStatus"].(*pb.PayloadStatus)
|
||||
if !ok {
|
||||
panic("not found")
|
||||
}
|
||||
return item
|
||||
}
|
||||
@@ -32,6 +32,14 @@ func WithHttpEndpoints(endpointStrings []string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithExecutionEndpoint for the execution node JSON-RPC endpoint.
|
||||
func WithExecutionEndpoint(endpoint string) Option {
|
||||
return func(s *Service) error {
|
||||
s.cfg.executionEndpoint = endpoint
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithDepositContractAddress for the deposit contract.
|
||||
func WithDepositContractAddress(addr common.Address) Option {
|
||||
return func(s *Service) error {
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
engine "github.com/prysmaticlabs/prysm/beacon-chain/powchain/engine-api-client/v1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
@@ -133,6 +134,7 @@ type config struct {
|
||||
eth1HeaderReqLimit uint64
|
||||
beaconNodeStatsUpdater BeaconNodeStatsUpdater
|
||||
httpEndpoints []network.Endpoint
|
||||
executionEndpoint string
|
||||
currHttpEndpoint network.Endpoint
|
||||
finalizedStateAtStartup state.BeaconState
|
||||
}
|
||||
@@ -153,6 +155,7 @@ type Service struct {
|
||||
headTicker *time.Ticker
|
||||
httpLogger bind.ContractFilterer
|
||||
eth1DataFetcher RPCDataFetcher
|
||||
engineAPIClient *engine.Client
|
||||
rpcClient RPCClient
|
||||
headerCache *headerCache // cache to store block hash/block height.
|
||||
latestEth1Data *ethpb.LatestETH1Data
|
||||
@@ -208,6 +211,10 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.initializeEngineAPIClient(ctx); err != nil {
|
||||
return nil, errors.Wrap(err, "unable to initialize engine API client")
|
||||
}
|
||||
|
||||
if err := s.ensureValidPowchainData(ctx); err != nil {
|
||||
return nil, errors.Wrap(err, "unable to validate powchain data")
|
||||
}
|
||||
@@ -298,6 +305,12 @@ func (s *Service) Status() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// EngineAPIClient returns the associated engine API client to interact
|
||||
// with an execution node via JSON-RPC.
|
||||
func (s *Service) EngineAPIClient() *engine.Client {
|
||||
return s.engineAPIClient
|
||||
}
|
||||
|
||||
func (s *Service) updateBeaconNodeStats() {
|
||||
bs := clientstats.BeaconNodeStats{}
|
||||
if len(s.cfg.httpEndpoints) > 1 {
|
||||
@@ -798,13 +811,20 @@ func (s *Service) initPOWService() {
|
||||
// Handle edge case with embedded genesis state by fetching genesis header to determine
|
||||
// its height.
|
||||
if s.chainStartData.Chainstarted && s.chainStartData.GenesisBlock == 0 {
|
||||
genHeader, err := s.eth1DataFetcher.HeaderByHash(ctx, common.BytesToHash(s.chainStartData.Eth1Data.BlockHash))
|
||||
if err != nil {
|
||||
log.Errorf("Unable to retrieve genesis ETH1.0 chain header: %v", err)
|
||||
s.retryETH1Node(err)
|
||||
continue
|
||||
genHash := common.BytesToHash(s.chainStartData.Eth1Data.BlockHash)
|
||||
genBlock := s.chainStartData.GenesisBlock
|
||||
// In the event our provided chainstart data references a non-existent blockhash
|
||||
// we assume the genesis block to be 0.
|
||||
if genHash != [32]byte{} {
|
||||
genHeader, err := s.eth1DataFetcher.HeaderByHash(ctx, genHash)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to retrieve genesis ETH1.0 chain header: %v", err)
|
||||
s.retryETH1Node(err)
|
||||
continue
|
||||
}
|
||||
genBlock = genHeader.Number.Uint64()
|
||||
}
|
||||
s.chainStartData.GenesisBlock = genHeader.Number.Uint64()
|
||||
s.chainStartData.GenesisBlock = genBlock
|
||||
if err := s.savePowchainData(ctx); err != nil {
|
||||
log.Errorf("Unable to save powchain data: %v", err)
|
||||
}
|
||||
@@ -1073,6 +1093,19 @@ func (s *Service) ensureValidPowchainData(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Initializes a connection to the engine API if an execution provider endpoint is set.
|
||||
func (s *Service) initializeEngineAPIClient(ctx context.Context) error {
|
||||
if s.cfg.executionEndpoint == "" {
|
||||
return nil
|
||||
}
|
||||
client, err := engine.New(ctx, s.cfg.executionEndpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.engineAPIClient = client
|
||||
return nil
|
||||
}
|
||||
|
||||
func dedupEndpoints(endpoints []string) []string {
|
||||
selectionMap := make(map[string]bool)
|
||||
newEndpoints := make([]string, 0, len(endpoints))
|
||||
|
||||
@@ -24,5 +24,6 @@ go_library(
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//rpc:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -2,10 +2,10 @@ package testing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/async/event"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
@@ -76,7 +76,11 @@ func (_ *FaultyMockPOWChain) ChainStartEth1Data() *ethpb.Eth1Data {
|
||||
|
||||
// PreGenesisState --
|
||||
func (_ *FaultyMockPOWChain) PreGenesisState() state.BeaconState {
|
||||
return &v1.BeaconState{}
|
||||
s, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
if err != nil {
|
||||
panic("could not initialize state")
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ClearPreGenesisData --
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestGetSpec(t *testing.T) {
|
||||
config.MinSyncCommitteeParticipants = 71
|
||||
config.TerminalBlockHash = common.HexToHash("TerminalBlockHash")
|
||||
config.TerminalBlockHashActivationEpoch = 72
|
||||
config.TerminalTotalDifficulty = 73
|
||||
config.TerminalTotalDifficulty = "73"
|
||||
config.FeeRecipient = common.HexToAddress("FeeRecipient")
|
||||
|
||||
var dbp [4]byte
|
||||
|
||||
@@ -13,8 +13,7 @@ go_library(
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/rpc/eth/helpers:go_default_library",
|
||||
"//beacon-chain/rpc/statefetcher:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//beacon-chain/state/v2:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//proto/eth/v2:go_default_library",
|
||||
"//proto/migration:go_default_library",
|
||||
|
||||
@@ -4,8 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/rpc/eth/helpers"
|
||||
statev1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
statev2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
ethpbv1 "github.com/prysmaticlabs/prysm/proto/eth/v1"
|
||||
ethpbv2 "github.com/prysmaticlabs/prysm/proto/eth/v2"
|
||||
"github.com/prysmaticlabs/prysm/proto/migration"
|
||||
@@ -26,11 +25,10 @@ func (ds *Server) GetBeaconState(ctx context.Context, req *ethpbv1.StateRequest)
|
||||
return nil, helpers.PrepareStateFetchGRPCError(err)
|
||||
}
|
||||
|
||||
st, ok := beaconSt.(*statev1.BeaconState)
|
||||
if !ok {
|
||||
return nil, status.Error(codes.Internal, "State type assertion failed")
|
||||
if beaconSt.Version() != version.Phase0 {
|
||||
return nil, status.Error(codes.Internal, "State has incorrect type")
|
||||
}
|
||||
protoSt, err := migration.BeaconStateToV1(st)
|
||||
protoSt, err := migration.BeaconStateToV1(beaconSt)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
|
||||
}
|
||||
@@ -69,11 +67,7 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.StateReques
|
||||
}
|
||||
switch beaconSt.Version() {
|
||||
case version.Phase0:
|
||||
st, ok := beaconSt.(*statev1.BeaconState)
|
||||
if !ok {
|
||||
return nil, status.Error(codes.Internal, "State type assertion failed")
|
||||
}
|
||||
protoSt, err := migration.BeaconStateToV1(st)
|
||||
protoSt, err := migration.BeaconStateToV1(beaconSt)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not convert state to proto: %v", err)
|
||||
}
|
||||
@@ -84,7 +78,7 @@ func (ds *Server) GetBeaconStateV2(ctx context.Context, req *ethpbv2.StateReques
|
||||
},
|
||||
}, nil
|
||||
case version.Altair:
|
||||
altairState, ok := beaconSt.(*statev2.BeaconState)
|
||||
altairState, ok := beaconSt.(state.BeaconStateAltair)
|
||||
if !ok {
|
||||
return nil, status.Error(codes.Internal, "Altair state type assertion failed")
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
"proposer.go",
|
||||
"proposer_altair.go",
|
||||
"proposer_attestations.go",
|
||||
"proposer_bellatrix.go",
|
||||
"proposer_deposits.go",
|
||||
"proposer_eth1data.go",
|
||||
"proposer_phase0.go",
|
||||
@@ -59,6 +60,7 @@ go_library(
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//monitoring/tracing:go_default_library",
|
||||
"//network/forks:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation/aggregation:go_default_library",
|
||||
@@ -134,6 +136,7 @@ go_test(
|
||||
"//container/trie:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/eth/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
||||
|
||||
@@ -30,7 +30,8 @@ import (
|
||||
func TestSubmitAggregateAndProof_Syncing(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
s := &v1.BeaconState{}
|
||||
s, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
|
||||
aggregatorServer := &Server{
|
||||
HeadFetcher: &mock.ChainService{State: s},
|
||||
@@ -39,7 +40,7 @@ func TestSubmitAggregateAndProof_Syncing(t *testing.T) {
|
||||
|
||||
req := ðpb.AggregateSelectionRequest{CommitteeIndex: 1}
|
||||
wanted := "Syncing to latest head, not ready to respond"
|
||||
_, err := aggregatorServer.SubmitAggregateSelectionProof(ctx, req)
|
||||
_, err = aggregatorServer.SubmitAggregateSelectionProof(ctx, req)
|
||||
assert.ErrorContains(t, wanted, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,12 +40,20 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
||||
return nil, status.Errorf(codes.Internal, "Could not fetch phase0 beacon block: %v", err)
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Phase0{Phase0: blk}}, nil
|
||||
} else if slots.ToEpoch(req.Slot) < params.BeaconConfig().BellatrixForkEpoch {
|
||||
blk, err := vs.getAltairBeaconBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err)
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
|
||||
}
|
||||
blk, err := vs.getAltairBeaconBlock(ctx, req)
|
||||
|
||||
blk, err := vs.getBellatrixBeaconBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not fetch Altair beacon block: %v", err)
|
||||
return nil, status.Errorf(codes.Internal, "Could not fetch Bellatrix beacon block: %v", err)
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: blk}}, nil
|
||||
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Bellatrix{Bellatrix: blk}}, nil
|
||||
}
|
||||
|
||||
// GetBlock is called by a proposer during its assigned slot to request a block to sign
|
||||
@@ -75,6 +83,11 @@ func (vs *Server) ProposeBeaconBlock(ctx context.Context, req *ethpb.GenericSign
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "could not wrap altair beacon block")
|
||||
}
|
||||
case *ethpb.GenericSignedBeaconBlock_Bellatrix:
|
||||
blk, err = wrapper.WrappedBellatrixSignedBeaconBlock(b.Bellatrix)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "could not wrap Bellatrix beacon block")
|
||||
}
|
||||
default:
|
||||
return nil, status.Error(codes.Internal, "block version not supported")
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.getAltairBeaconBlock")
|
||||
func (vs *Server) buildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.buildAltairBeaconBlock")
|
||||
defer span.End()
|
||||
blkData, err := vs.buildPhase0BlockData(ctx, req)
|
||||
if err != nil {
|
||||
@@ -33,7 +33,7 @@ func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequ
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blk := ðpb.BeaconBlockAltair{
|
||||
return ðpb.BeaconBlockAltair{
|
||||
Slot: req.Slot,
|
||||
ParentRoot: blkData.ParentRoot,
|
||||
StateRoot: stateRoot,
|
||||
@@ -49,6 +49,15 @@ func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequ
|
||||
Graffiti: blkData.Graffiti[:],
|
||||
SyncAggregate: syncAggregate,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.getAltairBeaconBlock")
|
||||
defer span.End()
|
||||
blk, err := vs.buildAltairBeaconBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not build block data: %v", err)
|
||||
}
|
||||
// Compute state root with the newly constructed block.
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(
|
||||
@@ -57,7 +66,7 @@ func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequ
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stateRoot, err = vs.computeStateRoot(ctx, wsb)
|
||||
stateRoot, err := vs.computeStateRoot(ctx, wsb)
|
||||
if err != nil {
|
||||
interop.WriteBlockToDisk(wsb, true /*failed*/)
|
||||
return nil, fmt.Errorf("could not compute state root: %v", err)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/transition/interop"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
)
|
||||
|
||||
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockBellatrix, error) {
|
||||
altairBlk, err := vs.buildAltairBeaconBlock(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blk := ðpb.BeaconBlockBellatrix{
|
||||
Slot: altairBlk.Slot,
|
||||
ProposerIndex: altairBlk.ProposerIndex,
|
||||
ParentRoot: altairBlk.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: altairBlk.Body.RandaoReveal,
|
||||
Eth1Data: altairBlk.Body.Eth1Data,
|
||||
Graffiti: altairBlk.Body.Graffiti,
|
||||
ProposerSlashings: altairBlk.Body.ProposerSlashings,
|
||||
AttesterSlashings: altairBlk.Body.AttesterSlashings,
|
||||
Attestations: altairBlk.Body.Attestations,
|
||||
Deposits: altairBlk.Body.Deposits,
|
||||
VoluntaryExits: altairBlk.Body.VoluntaryExits,
|
||||
SyncAggregate: altairBlk.Body.SyncAggregate,
|
||||
ExecutionPayload: &enginev1.ExecutionPayload{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
||||
Random: make([]byte, fieldparams.RootLength),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
}, // TODO(9853) Insert real execution payload.
|
||||
},
|
||||
}
|
||||
// Compute state root with the newly constructed block.
|
||||
wsb, err := wrapper.WrappedBellatrixSignedBeaconBlock(
|
||||
ðpb.SignedBeaconBlockBellatrix{Block: blk, Signature: make([]byte, 96)},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stateRoot, err := vs.computeStateRoot(ctx, wsb)
|
||||
if err != nil {
|
||||
interop.WriteBlockToDisk(wsb, true /*failed*/)
|
||||
return nil, fmt.Errorf("could not compute state root: %v", err)
|
||||
}
|
||||
blk.StateRoot = stateRoot
|
||||
return blk, nil
|
||||
}
|
||||
@@ -25,10 +25,12 @@ import (
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/container/trie"
|
||||
"github.com/prysmaticlabs/prysm/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation"
|
||||
attaggregation "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/attestation/aggregation/attestations"
|
||||
@@ -281,6 +283,44 @@ func TestProposer_ProposeBlock_Altair_OK(t *testing.T) {
|
||||
assert.NoError(t, err, "Could not propose block correctly")
|
||||
}
|
||||
|
||||
func TestProposer_ProposeBlock_Bellatrix_OK(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
|
||||
genesis := util.NewBeaconBlock()
|
||||
require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genesis)), "Could not save genesis block")
|
||||
|
||||
numDeposits := uint64(64)
|
||||
beaconState, _ := util.DeterministicGenesisStateBellatrix(t, numDeposits)
|
||||
bsRoot, err := beaconState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
|
||||
|
||||
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
|
||||
proposerServer := &Server{
|
||||
ChainStartFetcher: &mockPOW.POWChain{},
|
||||
Eth1InfoFetcher: &mockPOW.POWChain{},
|
||||
Eth1BlockFetcher: &mockPOW.POWChain{},
|
||||
BlockReceiver: c,
|
||||
HeadFetcher: c,
|
||||
BlockNotifier: c.BlockNotifier(),
|
||||
P2P: mockp2p.NewTestP2P(t),
|
||||
}
|
||||
blockToPropose := util.NewBeaconBlockBellatrix()
|
||||
blockToPropose.Block.Slot = 5
|
||||
blockToPropose.Block.ParentRoot = bsRoot[:]
|
||||
blk := ðpb.GenericSignedBeaconBlock_Bellatrix{Bellatrix: blockToPropose}
|
||||
wrapped, err := wrapper.WrappedSignedBeaconBlock(blockToPropose)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, wrapped))
|
||||
_, err = proposerServer.ProposeBeaconBlock(context.Background(), ðpb.GenericSignedBeaconBlock{Block: blk})
|
||||
assert.NoError(t, err, "Could not propose block correctly")
|
||||
}
|
||||
|
||||
func TestProposer_ComputeStateRoot_OK(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
@@ -2222,6 +2262,101 @@ func TestProposer_GetBeaconBlock_PostForkEpoch(t *testing.T) {
|
||||
assert.DeepEqual(t, attSlashings, altairBlk.Altair.Body.AttesterSlashings)
|
||||
}
|
||||
|
||||
func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.MainnetConfig().Copy()
|
||||
cfg.BellatrixForkEpoch = 2
|
||||
cfg.AltairForkEpoch = 1
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
beaconState, privKeys := util.DeterministicGenesisState(t, 64)
|
||||
|
||||
stateRoot, err := beaconState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err, "Could not hash genesis state")
|
||||
|
||||
genesis := b.NewGenesisBlock(stateRoot[:])
|
||||
wsb := wrapper.WrappedPhase0SignedBeaconBlock(genesis)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, wsb), "Could not save genesis block")
|
||||
|
||||
parentRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not get signing root")
|
||||
require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state")
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
|
||||
|
||||
bellatrixSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
|
||||
require.NoError(t, err)
|
||||
|
||||
blk := ðpb.SignedBeaconBlockBellatrix{
|
||||
Block: ðpb.BeaconBlockBellatrix{
|
||||
Slot: bellatrixSlot + 1,
|
||||
ParentRoot: parentRoot[:],
|
||||
StateRoot: genesis.Block.StateRoot,
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: genesis.Block.Body.RandaoReveal,
|
||||
Graffiti: genesis.Block.Body.Graffiti,
|
||||
Eth1Data: genesis.Block.Body.Eth1Data,
|
||||
SyncAggregate: ðpb.SyncAggregate{SyncCommitteeBits: bitfield.NewBitvector512(), SyncCommitteeSignature: make([]byte, 96)},
|
||||
ExecutionPayload: &enginev1.ExecutionPayload{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
||||
Random: make([]byte, fieldparams.RootLength),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
},
|
||||
},
|
||||
},
|
||||
Signature: genesis.Signature,
|
||||
}
|
||||
|
||||
blkRoot, err := blk.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, err, "Could not get signing root")
|
||||
require.NoError(t, db.SaveState(ctx, beaconState, blkRoot), "Could not save genesis state")
|
||||
require.NoError(t, db.SaveHeadBlockRoot(ctx, blkRoot), "Could not save genesis state")
|
||||
|
||||
proposerServer := &Server{
|
||||
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
BlockReceiver: &mock.ChainService{},
|
||||
ChainStartFetcher: &mockPOW.POWChain{},
|
||||
Eth1InfoFetcher: &mockPOW.POWChain{},
|
||||
Eth1BlockFetcher: &mockPOW.POWChain{},
|
||||
MockEth1Votes: true,
|
||||
AttPool: attestations.NewPool(),
|
||||
SlashingsPool: slashings.NewPool(),
|
||||
ExitPool: voluntaryexits.NewPool(),
|
||||
StateGen: stategen.New(db),
|
||||
SyncCommitteePool: synccommittee.NewStore(),
|
||||
}
|
||||
|
||||
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
|
||||
require.NoError(t, err)
|
||||
|
||||
graffiti := bytesutil.ToBytes32([]byte("eth2"))
|
||||
require.NoError(t, err)
|
||||
req := ðpb.BlockRequest{
|
||||
Slot: bellatrixSlot + 1,
|
||||
RandaoReveal: randaoReveal,
|
||||
Graffiti: graffiti[:],
|
||||
}
|
||||
|
||||
block, err := proposerServer.GetBeaconBlock(ctx, req)
|
||||
require.NoError(t, err)
|
||||
bellatrixBlk, ok := block.GetBlock().(*ethpb.GenericBeaconBlock_Bellatrix)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
assert.Equal(t, req.Slot, bellatrixBlk.Bellatrix.Slot)
|
||||
assert.DeepEqual(t, parentRoot[:], bellatrixBlk.Bellatrix.ParentRoot, "Expected block to have correct parent root")
|
||||
assert.DeepEqual(t, randaoReveal, bellatrixBlk.Bellatrix.Body.RandaoReveal, "Expected block to have correct randao reveal")
|
||||
assert.DeepEqual(t, req.Graffiti, bellatrixBlk.Bellatrix.Body.Graffiti, "Expected block to have correct Graffiti")
|
||||
}
|
||||
|
||||
func TestProposer_GetSyncAggregate_OK(t *testing.T) {
|
||||
proposerServer := &Server{
|
||||
SyncChecker: &mockSync.Sync{IsSyncing: false},
|
||||
|
||||
@@ -4,6 +4,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"altair.go",
|
||||
"bellatrix.go",
|
||||
"error.go",
|
||||
"phase0.go",
|
||||
"prometheus.go",
|
||||
@@ -12,6 +13,7 @@ go_library(
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//contracts/deposit:__subpackages__",
|
||||
"//proto/migration:__pkg__",
|
||||
"//proto/prysm/v1alpha1:__subpackages__",
|
||||
"//proto/testing:__subpackages__",
|
||||
"//slasher/rpc:__subpackages__",
|
||||
|
||||
6
beacon-chain/state/bellatrix.go
Normal file
6
beacon-chain/state/bellatrix.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package state
|
||||
|
||||
// BeaconStateBellatrix has read and write access to beacon state methods.
|
||||
type BeaconStateBellatrix interface {
|
||||
BeaconStateAltair
|
||||
}
|
||||
@@ -7,6 +7,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/genesis",
|
||||
visibility = ["//beacon-chain/db:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
|
||||
@@ -4,7 +4,8 @@ import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
state "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
@@ -15,7 +16,7 @@ var (
|
||||
)
|
||||
|
||||
// State returns a copy of the genesis state from a hardcoded value.
|
||||
func State(name string) (*state.BeaconState, error) {
|
||||
func State(name string) (state.BeaconState, error) {
|
||||
switch name {
|
||||
case params.ConfigNames[params.Mainnet]:
|
||||
return load(mainnetRawSSZCompressed)
|
||||
@@ -26,7 +27,7 @@ func State(name string) (*state.BeaconState, error) {
|
||||
}
|
||||
|
||||
// load a compressed ssz state file into a beacon state struct.
|
||||
func load(b []byte) (*state.BeaconState, error) {
|
||||
func load(b []byte) (state.BeaconState, error) {
|
||||
st := ðpb.BeaconState{}
|
||||
b, err := snappy.Decode(nil /*dst*/, b)
|
||||
if err != nil {
|
||||
@@ -35,5 +36,5 @@ func load(b []byte) (*state.BeaconState, error) {
|
||||
if err := st.UnmarshalSSZ(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state.InitializeFromProtoUnsafe(st)
|
||||
return v1.InitializeFromProtoUnsafe(st)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
@@ -87,7 +88,9 @@ func TestBeaconState_MatchCurrentJustifiedCheckpt(t *testing.T) {
|
||||
require.Equal(t, false, beaconState.MatchCurrentJustifiedCheckpoint(c2))
|
||||
require.Equal(t, false, beaconState.MatchPreviousJustifiedCheckpoint(c1))
|
||||
require.Equal(t, false, beaconState.MatchPreviousJustifiedCheckpoint(c2))
|
||||
beaconState.state = nil
|
||||
s, ok := beaconState.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
s.state = nil
|
||||
require.Equal(t, false, beaconState.MatchCurrentJustifiedCheckpoint(c1))
|
||||
}
|
||||
|
||||
@@ -101,13 +104,17 @@ func TestBeaconState_MatchPreviousJustifiedCheckpt(t *testing.T) {
|
||||
require.Equal(t, false, beaconState.MatchCurrentJustifiedCheckpoint(c2))
|
||||
require.Equal(t, true, beaconState.MatchPreviousJustifiedCheckpoint(c1))
|
||||
require.Equal(t, false, beaconState.MatchPreviousJustifiedCheckpoint(c2))
|
||||
beaconState.state = nil
|
||||
s, ok := beaconState.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
s.state = nil
|
||||
require.Equal(t, false, beaconState.MatchPreviousJustifiedCheckpoint(c1))
|
||||
}
|
||||
|
||||
func TestBeaconState_MarshalSSZ_NilState(t *testing.T) {
|
||||
s, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
beaconState, err := InitializeFromProto(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
s, ok := beaconState.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
s.state = nil
|
||||
_, err = s.MarshalSSZ()
|
||||
require.ErrorContains(t, "nil beacon state", err)
|
||||
@@ -122,14 +129,14 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
modifyFunc func(b *BeaconState, k [fieldparams.BLSPubkeyLength]byte)
|
||||
modifyFunc func(b state.BeaconState, k [fieldparams.BLSPubkeyLength]byte)
|
||||
exists bool
|
||||
expectedIdx types.ValidatorIndex
|
||||
largestIdxInSet types.ValidatorIndex
|
||||
}{
|
||||
{
|
||||
name: "retrieve validator",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
},
|
||||
exists: true,
|
||||
@@ -137,7 +144,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators from the start",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
@@ -149,7 +156,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
@@ -161,7 +168,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators from the start with shared state",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
@@ -174,7 +181,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators with shared state",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
@@ -189,7 +196,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators with shared state at boundary",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
n := b.Copy()
|
||||
|
||||
@@ -18,8 +18,10 @@ import (
|
||||
func TestStateReferenceSharing_Finalizer(t *testing.T) {
|
||||
// This test showcases the logic on a the RandaoMixes field with the GC finalizer.
|
||||
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconState{RandaoMixes: [][]byte{[]byte("foo")}})
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconState{RandaoMixes: [][]byte{[]byte("foo")}})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, uint(1), a.sharedFieldReferences[randaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
|
||||
|
||||
func() {
|
||||
@@ -44,7 +46,7 @@ func TestStateReferenceSharing_Finalizer(t *testing.T) {
|
||||
|
||||
func TestStateReferenceCopy_NoUnexpectedRootsMutation(t *testing.T) {
|
||||
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
BlockRoots: [][]byte{
|
||||
root1[:],
|
||||
},
|
||||
@@ -53,6 +55,9 @@ func TestStateReferenceCopy_NoUnexpectedRootsMutation(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, err)
|
||||
assertRefCount(t, a, blockRoots, 1)
|
||||
assertRefCount(t, a, stateRoots, 1)
|
||||
|
||||
@@ -115,12 +120,15 @@ func TestStateReferenceCopy_NoUnexpectedRootsMutation(t *testing.T) {
|
||||
func TestStateReferenceCopy_NoUnexpectedRandaoMutation(t *testing.T) {
|
||||
|
||||
val1, val2 := []byte("foo"), []byte("bar")
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
RandaoMixes: [][]byte{
|
||||
val1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, err)
|
||||
assertRefCount(t, a, randaoMixes, 1)
|
||||
|
||||
// Copy, increases reference count.
|
||||
@@ -181,8 +189,10 @@ func TestStateReferenceCopy_NoUnexpectedAttestationsMutation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconState{})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
assertRefCount(t, a, previousEpochAttestations, 1)
|
||||
assertRefCount(t, a, currentEpochAttestations, 1)
|
||||
|
||||
@@ -291,7 +301,7 @@ func TestStateReferenceCopy_NoUnexpectedAttestationsMutation(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestValidatorReferences_RemainsConsistent(t *testing.T) {
|
||||
a, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
Validators: []*ethpb.Validator{
|
||||
{PublicKey: []byte{'A'}},
|
||||
{PublicKey: []byte{'B'}},
|
||||
@@ -301,6 +311,8 @@ func TestValidatorReferences_RemainsConsistent(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
a, ok := s.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
// Create a second state.
|
||||
copied := a.Copy()
|
||||
|
||||
@@ -21,8 +21,10 @@ func TestBeaconState_RotateAttestations(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, st.RotateAttestations())
|
||||
require.Equal(t, 0, len(st.currentEpochAttestations()))
|
||||
require.Equal(t, types.Slot(456), st.previousEpochAttestations()[0].Data.Slot)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, 0, len(s.currentEpochAttestations()))
|
||||
require.Equal(t, types.Slot(456), s.previousEpochAttestations()[0].Data.Slot)
|
||||
}
|
||||
|
||||
func TestAppendBeyondIndicesLimit(t *testing.T) {
|
||||
@@ -40,7 +42,7 @@ func TestAppendBeyondIndicesLimit(t *testing.T) {
|
||||
for i := 0; i < len(mockrandaoMixes); i++ {
|
||||
mockrandaoMixes[i] = zeroHash[:]
|
||||
}
|
||||
st, err := InitializeFromProto(ðpb.BeaconState{
|
||||
newState, err := InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 1,
|
||||
CurrentEpochAttestations: []*ethpb.PendingAttestation{{Data: ðpb.AttestationData{Slot: 456}}},
|
||||
PreviousEpochAttestations: []*ethpb.PendingAttestation{{Data: ðpb.AttestationData{Slot: 123}}},
|
||||
@@ -51,8 +53,10 @@ func TestAppendBeyondIndicesLimit(t *testing.T) {
|
||||
RandaoMixes: mockrandaoMixes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
_, err = newState.HashTreeRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
st, ok := newState.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
for i := stateTypes.FieldIndex(0); i < stateTypes.FieldIndex(params.BeaconConfig().BeaconStateFieldCount); i++ {
|
||||
st.dirtyFields[i] = true
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestValidatorMap_DistinctCopy(t *testing.T) {
|
||||
@@ -63,10 +64,12 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
|
||||
WithdrawableEpoch: 1,
|
||||
})
|
||||
}
|
||||
st, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
newState, err := InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
Validators: vals,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
st, ok := newState.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
@@ -144,7 +147,7 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
|
||||
for i := 0; i < len(mockrandaoMixes); i++ {
|
||||
mockrandaoMixes[i] = zeroHash[:]
|
||||
}
|
||||
st, err := InitializeFromProto(ðpb.BeaconState{
|
||||
newState, err := InitializeFromProto(ðpb.BeaconState{
|
||||
Slot: 1,
|
||||
GenesisValidatorsRoot: make([]byte, 32),
|
||||
Fork: ðpb.Fork{
|
||||
@@ -173,6 +176,8 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
|
||||
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
st, ok := newState.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -23,13 +23,13 @@ import (
|
||||
)
|
||||
|
||||
// InitializeFromProto the beacon state from a protobuf representation.
|
||||
func InitializeFromProto(st *ethpb.BeaconState) (*BeaconState, error) {
|
||||
func InitializeFromProto(st *ethpb.BeaconState) (state.BeaconState, error) {
|
||||
return InitializeFromProtoUnsafe(proto.Clone(st).(*ethpb.BeaconState))
|
||||
}
|
||||
|
||||
// InitializeFromProtoUnsafe directly uses the beacon state protobuf pointer
|
||||
// and sets it as the inner state of the BeaconState type.
|
||||
func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (*BeaconState, error) {
|
||||
func InitializeFromProtoUnsafe(st *ethpb.BeaconState) (state.BeaconState, error) {
|
||||
if st == nil {
|
||||
return nil, errors.New("received nil state")
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
|
||||
@@ -3,17 +3,20 @@ package v2
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_CurrentEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
_, err := s.CurrentEpochAttestations()
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
_, err = s.CurrentEpochAttestations()
|
||||
require.ErrorContains(t, "CurrentEpochAttestations is not supported for hard fork 1 beacon state", err)
|
||||
}
|
||||
|
||||
func TestBeaconState_PreviousEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
_, err := s.PreviousEpochAttestations()
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
_, err = s.PreviousEpochAttestations()
|
||||
require.ErrorContains(t, "PreviousEpochAttestations is not supported for hard fork 1 beacon state", err)
|
||||
}
|
||||
|
||||
@@ -5,16 +5,6 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// SetPreviousEpochAttestations is not supported for HF1 beacon state.
|
||||
func (*BeaconState) SetPreviousEpochAttestations(_ []*ethpb.PendingAttestation) error {
|
||||
return errors.New("SetPreviousEpochAttestations is not supported for hard fork 1 beacon state")
|
||||
}
|
||||
|
||||
// SetCurrentEpochAttestations is not supported for HF1 beacon state.
|
||||
func (*BeaconState) SetCurrentEpochAttestations(_ []*ethpb.PendingAttestation) error {
|
||||
return errors.New("SetCurrentEpochAttestations is not supported for hard fork 1 beacon state")
|
||||
}
|
||||
|
||||
// AppendCurrentEpochAttestations is not supported for HF1 beacon state.
|
||||
func (*BeaconState) AppendCurrentEpochAttestations(_ *ethpb.PendingAttestation) error {
|
||||
return errors.New("AppendCurrentEpochAttestations is not supported for hard fork 1 beacon state")
|
||||
|
||||
@@ -3,25 +3,18 @@ package v2
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_AppendCurrentEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
require.ErrorContains(t, "AppendCurrentEpochAttestations is not supported for hard fork 1 beacon state", s.AppendCurrentEpochAttestations(nil))
|
||||
}
|
||||
|
||||
func TestBeaconState_AppendPreviousEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{})
|
||||
require.NoError(t, err)
|
||||
require.ErrorContains(t, "AppendPreviousEpochAttestations is not supported for hard fork 1 beacon state", s.AppendPreviousEpochAttestations(nil))
|
||||
}
|
||||
|
||||
func TestBeaconState_SetCurrentEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
require.ErrorContains(t, "SetCurrentEpochAttestations is not supported for hard fork 1 beacon state", s.SetCurrentEpochAttestations(nil))
|
||||
}
|
||||
|
||||
func TestBeaconState_SetPreviousEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
require.ErrorContains(t, "SetPreviousEpochAttestations is not supported for hard fork 1 beacon state", s.SetPreviousEpochAttestations(nil))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
@@ -63,52 +61,6 @@ func (b *BeaconState) genesisValidatorRoot() []byte {
|
||||
return root
|
||||
}
|
||||
|
||||
// GenesisUnixTime returns the genesis time as time.Time.
|
||||
func (b *BeaconState) GenesisUnixTime() time.Time {
|
||||
if !b.hasInnerState() {
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.genesisUnixTime()
|
||||
}
|
||||
|
||||
// genesisUnixTime returns the genesis time as time.Time.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) genesisUnixTime() time.Time {
|
||||
if !b.hasInnerState() {
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
|
||||
return time.Unix(int64(b.state.GenesisTime), 0)
|
||||
}
|
||||
|
||||
// ParentRoot is a convenience method to access state.LatestBlockRoot.ParentRoot.
|
||||
func (b *BeaconState) ParentRoot() [32]byte {
|
||||
if !b.hasInnerState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.parentRoot()
|
||||
}
|
||||
|
||||
// parentRoot is a convenience method to access state.LatestBlockRoot.ParentRoot.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) parentRoot() [32]byte {
|
||||
if !b.hasInnerState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
|
||||
parentRoot := [32]byte{}
|
||||
copy(parentRoot[:], b.state.LatestBlockHeader.ParentRoot)
|
||||
return parentRoot
|
||||
}
|
||||
|
||||
// Version of the beacon state. This method
|
||||
// is strictly meant to be used without a lock
|
||||
// internally.
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
@@ -40,12 +41,10 @@ func TestNilState_NoPanic(t *testing.T) {
|
||||
// retrieve elements from nil state
|
||||
_ = st.GenesisTime()
|
||||
_ = st.GenesisValidatorRoot()
|
||||
_ = st.GenesisUnixTime()
|
||||
_ = st.GenesisValidatorRoot()
|
||||
_ = st.Slot()
|
||||
_ = st.Fork()
|
||||
_ = st.LatestBlockHeader()
|
||||
_ = st.ParentRoot()
|
||||
_ = st.BlockRoots()
|
||||
_, err := st.BlockRootAtIndex(0)
|
||||
_ = err
|
||||
@@ -99,14 +98,14 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
modifyFunc func(b *BeaconState, k [fieldparams.BLSPubkeyLength]byte)
|
||||
modifyFunc func(b state.BeaconStateAltair, k [fieldparams.BLSPubkeyLength]byte)
|
||||
exists bool
|
||||
expectedIdx types.ValidatorIndex
|
||||
largestIdxInSet types.ValidatorIndex
|
||||
}{
|
||||
{
|
||||
name: "retrieve validator",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateAltair, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
},
|
||||
exists: true,
|
||||
@@ -114,7 +113,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators from the start",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateAltair, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
@@ -126,7 +125,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateAltair, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
@@ -138,7 +137,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators from the start with shared state",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateAltair, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
@@ -151,7 +150,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators with shared state",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateAltair, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
@@ -166,7 +165,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators with shared state at boundary",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateAltair, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
n := b.Copy()
|
||||
|
||||
@@ -4,14 +4,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
st, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
st, err := v2.InitializeFromProtoUnsafe(ðpb.BeaconStateAltair{
|
||||
Validators: nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -45,22 +45,24 @@ func TestAppendBeyondIndicesLimit(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
for i := stateTypes.FieldIndex(0); i < stateTypes.FieldIndex(params.BeaconConfig().BeaconStateAltairFieldCount); i++ {
|
||||
st.dirtyFields[i] = true
|
||||
s.dirtyFields[i] = true
|
||||
}
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < 10; i++ {
|
||||
assert.NoError(t, st.AppendValidator(ðpb.Validator{}))
|
||||
}
|
||||
assert.Equal(t, false, st.rebuildTrie[validators])
|
||||
assert.NotEqual(t, len(st.dirtyIndices[validators]), 0)
|
||||
assert.Equal(t, false, s.rebuildTrie[validators])
|
||||
assert.NotEqual(t, len(s.dirtyIndices[validators]), 0)
|
||||
|
||||
for i := 0; i < indicesLimit; i++ {
|
||||
assert.NoError(t, st.AppendValidator(ðpb.Validator{}))
|
||||
}
|
||||
assert.Equal(t, true, st.rebuildTrie[validators])
|
||||
assert.Equal(t, len(st.dirtyIndices[validators]), 0)
|
||||
assert.Equal(t, true, s.rebuildTrie[validators])
|
||||
assert.Equal(t, len(s.dirtyIndices[validators]), 0)
|
||||
}
|
||||
|
||||
func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
|
||||
@@ -154,8 +156,10 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
|
||||
}
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
assert.NoError(t, err)
|
||||
newRt := bytesutil.ToBytes32(st.merkleLayers[0][balances])
|
||||
wantedRt, err := stateutil.Uint64ListRootWithRegistryLimit(st.state.Balances)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
newRt := bytesutil.ToBytes32(s.merkleLayers[0][balances])
|
||||
wantedRt, err := stateutil.Uint64ListRootWithRegistryLimit(s.state.Balances)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, wantedRt, newRt, "state roots are unequal")
|
||||
}
|
||||
|
||||
@@ -25,14 +25,14 @@ import (
|
||||
)
|
||||
|
||||
// InitializeFromProto the beacon state from a protobuf representation.
|
||||
func InitializeFromProto(st *ethpb.BeaconStateAltair) (*BeaconState, error) {
|
||||
func InitializeFromProto(st *ethpb.BeaconStateAltair) (state.BeaconStateAltair, error) {
|
||||
return InitializeFromProtoUnsafe(proto.Clone(st).(*ethpb.BeaconStateAltair))
|
||||
}
|
||||
|
||||
// InitializeFromSSZReader can be used when the source for a serialized BeaconState object
|
||||
// is an io.Reader. This allows client code to remain agnostic about whether the data comes
|
||||
// from the network or a file without needing to read the entire state into mem as a large byte slice.
|
||||
func InitializeFromSSZReader(r io.Reader) (*BeaconState, error) {
|
||||
func InitializeFromSSZReader(r io.Reader) (state.BeaconStateAltair, error) {
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -42,7 +42,7 @@ func InitializeFromSSZReader(r io.Reader) (*BeaconState, error) {
|
||||
|
||||
// InitializeFromSSZBytes is a convenience method to obtain a BeaconState by unmarshaling
|
||||
// a slice of bytes containing the ssz-serialized representation of the state.
|
||||
func InitializeFromSSZBytes(marshaled []byte) (*BeaconState, error) {
|
||||
func InitializeFromSSZBytes(marshaled []byte) (state.BeaconStateAltair, error) {
|
||||
st := ðpb.BeaconStateAltair{}
|
||||
if err := st.UnmarshalSSZ(marshaled); err != nil {
|
||||
return nil, err
|
||||
@@ -52,7 +52,7 @@ func InitializeFromSSZBytes(marshaled []byte) (*BeaconState, error) {
|
||||
|
||||
// InitializeFromProtoUnsafe directly uses the beacon state protobuf pointer
|
||||
// and sets it as the inner state of the BeaconState type.
|
||||
func InitializeFromProtoUnsafe(st *ethpb.BeaconStateAltair) (*BeaconState, error) {
|
||||
func InitializeFromProtoUnsafe(st *ethpb.BeaconStateAltair) (state.BeaconStateAltair, error) {
|
||||
if st == nil {
|
||||
return nil, errors.New("received nil state")
|
||||
}
|
||||
|
||||
@@ -109,6 +109,8 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
|
||||
Validators: vals,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
@@ -117,7 +119,7 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
|
||||
// Continuously lock and unlock the state
|
||||
// by acquiring the lock.
|
||||
for i := 0; i < 1000; i++ {
|
||||
for _, f := range st.stateFieldLeaves {
|
||||
for _, f := range s.stateFieldLeaves {
|
||||
f.Lock()
|
||||
if f.Empty() {
|
||||
f.InsertFieldLayer(make([][]*[32]byte, 10))
|
||||
|
||||
@@ -76,7 +76,6 @@ go_test(
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//beacon-chain/state/types:go_default_library",
|
||||
"//beacon-chain/state/v1:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
|
||||
@@ -3,17 +3,20 @@ package v3
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_CurrentEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
_, err := s.CurrentEpochAttestations()
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
_, err = s.CurrentEpochAttestations()
|
||||
require.ErrorContains(t, "CurrentEpochAttestations is not supported for version Bellatrix beacon state", err)
|
||||
}
|
||||
|
||||
func TestBeaconState_PreviousEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
_, err := s.PreviousEpochAttestations()
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
_, err = s.PreviousEpochAttestations()
|
||||
require.ErrorContains(t, "PreviousEpochAttestations is not supported for version Bellatrix beacon state", err)
|
||||
}
|
||||
|
||||
@@ -5,16 +5,6 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// SetPreviousEpochAttestations is not supported for HF1 beacon state.
|
||||
func (*BeaconState) SetPreviousEpochAttestations(_ []*ethpb.PendingAttestation) error {
|
||||
return errors.New("SetPreviousEpochAttestations is not supported for version Bellatrix beacon state")
|
||||
}
|
||||
|
||||
// SetCurrentEpochAttestations is not supported for HF1 beacon state.
|
||||
func (*BeaconState) SetCurrentEpochAttestations(_ []*ethpb.PendingAttestation) error {
|
||||
return errors.New("SetCurrentEpochAttestations is not supported for version Bellatrix beacon state")
|
||||
}
|
||||
|
||||
// AppendCurrentEpochAttestations is not supported for HF1 beacon state.
|
||||
func (*BeaconState) AppendCurrentEpochAttestations(_ *ethpb.PendingAttestation) error {
|
||||
return errors.New("AppendCurrentEpochAttestations is not supported for version Bellatrix beacon state")
|
||||
|
||||
@@ -3,25 +3,18 @@ package v3
|
||||
import (
|
||||
"testing"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_AppendCurrentEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
require.ErrorContains(t, "AppendCurrentEpochAttestations is not supported for version Bellatrix beacon state", s.AppendCurrentEpochAttestations(nil))
|
||||
}
|
||||
|
||||
func TestBeaconState_AppendPreviousEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
s, err := InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{})
|
||||
require.NoError(t, err)
|
||||
require.ErrorContains(t, "AppendPreviousEpochAttestations is not supported for version Bellatrix beacon state", s.AppendPreviousEpochAttestations(nil))
|
||||
}
|
||||
|
||||
func TestBeaconState_SetCurrentEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
require.ErrorContains(t, "SetCurrentEpochAttestations is not supported for version Bellatrix beacon state", s.SetCurrentEpochAttestations(nil))
|
||||
}
|
||||
|
||||
func TestBeaconState_SetPreviousEpochAttestations(t *testing.T) {
|
||||
s := &BeaconState{}
|
||||
require.ErrorContains(t, "SetPreviousEpochAttestations is not supported for version Bellatrix beacon state", s.SetPreviousEpochAttestations(nil))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package v3
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
@@ -62,52 +60,6 @@ func (b *BeaconState) genesisValidatorRoot() []byte {
|
||||
return root
|
||||
}
|
||||
|
||||
// GenesisUnixTime returns the genesis time as time.Time.
|
||||
func (b *BeaconState) GenesisUnixTime() time.Time {
|
||||
if !b.hasInnerState() {
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.genesisUnixTime()
|
||||
}
|
||||
|
||||
// genesisUnixTime returns the genesis time as time.Time.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) genesisUnixTime() time.Time {
|
||||
if !b.hasInnerState() {
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
|
||||
return time.Unix(int64(b.state.GenesisTime), 0)
|
||||
}
|
||||
|
||||
// ParentRoot is a convenience method to access state.LatestBlockRoot.ParentRoot.
|
||||
func (b *BeaconState) ParentRoot() [32]byte {
|
||||
if !b.hasInnerState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.parentRoot()
|
||||
}
|
||||
|
||||
// parentRoot is a convenience method to access state.LatestBlockRoot.ParentRoot.
|
||||
// This assumes that a lock is already held on BeaconState.
|
||||
func (b *BeaconState) parentRoot() [32]byte {
|
||||
if !b.hasInnerState() {
|
||||
return [32]byte{}
|
||||
}
|
||||
|
||||
parentRoot := [32]byte{}
|
||||
copy(parentRoot[:], b.state.LatestBlockHeader.ParentRoot)
|
||||
return parentRoot
|
||||
}
|
||||
|
||||
// Version of the beacon state. This method
|
||||
// is strictly meant to be used without a lock
|
||||
// internally.
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
@@ -40,12 +41,10 @@ func TestNilState_NoPanic(t *testing.T) {
|
||||
// retrieve elements from nil state
|
||||
_ = st.GenesisTime()
|
||||
_ = st.GenesisValidatorRoot()
|
||||
_ = st.GenesisUnixTime()
|
||||
_ = st.GenesisValidatorRoot()
|
||||
_ = st.Slot()
|
||||
_ = st.Fork()
|
||||
_ = st.LatestBlockHeader()
|
||||
_ = st.ParentRoot()
|
||||
_ = st.BlockRoots()
|
||||
_, err := st.BlockRootAtIndex(0)
|
||||
_ = err
|
||||
@@ -99,14 +98,14 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
modifyFunc func(b *BeaconState, k [fieldparams.BLSPubkeyLength]byte)
|
||||
modifyFunc func(b state.BeaconStateBellatrix, k [fieldparams.BLSPubkeyLength]byte)
|
||||
exists bool
|
||||
expectedIdx types.ValidatorIndex
|
||||
largestIdxInSet types.ValidatorIndex
|
||||
}{
|
||||
{
|
||||
name: "retrieve validator",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateBellatrix, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
},
|
||||
exists: true,
|
||||
@@ -114,7 +113,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators from the start",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateBellatrix, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
@@ -126,7 +125,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateBellatrix, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
@@ -138,7 +137,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators from the start with shared state",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateBellatrix, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key[:]}))
|
||||
@@ -151,7 +150,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators with shared state",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateBellatrix, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
key2 := keyCreator([]byte{'D'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
@@ -166,7 +165,7 @@ func TestBeaconState_ValidatorByPubkey(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "retrieve validator with multiple validators with shared state at boundary",
|
||||
modifyFunc: func(b *BeaconState, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
modifyFunc: func(b state.BeaconStateBellatrix, key [fieldparams.BLSPubkeyLength]byte) {
|
||||
key1 := keyCreator([]byte{'C'})
|
||||
assert.NoError(t, b.AppendValidator(ðpb.Validator{PublicKey: key1[:]}))
|
||||
n := b.Copy()
|
||||
|
||||
@@ -4,14 +4,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
||||
v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
)
|
||||
|
||||
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice(t *testing.T) {
|
||||
st, err := v1.InitializeFromProtoUnsafe(ðpb.BeaconState{
|
||||
st, err := v3.InitializeFromProtoUnsafe(ðpb.BeaconStateBellatrix{
|
||||
Validators: nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -56,23 +56,25 @@ func TestAppendBeyondIndicesLimit(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
require.NoError(t, err)
|
||||
for i := stateTypes.FieldIndex(0); i < stateTypes.FieldIndex(params.BeaconConfig().BeaconStateBellatrixFieldCount); i++ {
|
||||
st.dirtyFields[i] = true
|
||||
s.dirtyFields[i] = true
|
||||
}
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < 10; i++ {
|
||||
assert.NoError(t, st.AppendValidator(ðpb.Validator{}))
|
||||
}
|
||||
assert.Equal(t, false, st.rebuildTrie[validators])
|
||||
assert.NotEqual(t, len(st.dirtyIndices[validators]), 0)
|
||||
assert.Equal(t, false, s.rebuildTrie[validators])
|
||||
assert.NotEqual(t, len(s.dirtyIndices[validators]), 0)
|
||||
|
||||
for i := 0; i < indicesLimit; i++ {
|
||||
assert.NoError(t, st.AppendValidator(ðpb.Validator{}))
|
||||
}
|
||||
assert.Equal(t, true, st.rebuildTrie[validators])
|
||||
assert.Equal(t, len(st.dirtyIndices[validators]), 0)
|
||||
assert.Equal(t, true, s.rebuildTrie[validators])
|
||||
assert.Equal(t, len(s.dirtyIndices[validators]), 0)
|
||||
}
|
||||
|
||||
func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
|
||||
@@ -178,8 +180,10 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
|
||||
}
|
||||
_, err = st.HashTreeRoot(context.Background())
|
||||
assert.NoError(t, err)
|
||||
newRt := bytesutil.ToBytes32(st.merkleLayers[0][balances])
|
||||
wantedRt, err := stateutil.Uint64ListRootWithRegistryLimit(st.state.Balances)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
newRt := bytesutil.ToBytes32(s.merkleLayers[0][balances])
|
||||
wantedRt, err := stateutil.Uint64ListRootWithRegistryLimit(s.state.Balances)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, wantedRt, newRt, "state roots are unequal")
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ import (
|
||||
)
|
||||
|
||||
// InitializeFromProto the beacon state from a protobuf representation.
|
||||
func InitializeFromProto(st *ethpb.BeaconStateBellatrix) (*BeaconState, error) {
|
||||
func InitializeFromProto(st *ethpb.BeaconStateBellatrix) (state.BeaconStateBellatrix, error) {
|
||||
return InitializeFromProtoUnsafe(proto.Clone(st).(*ethpb.BeaconStateBellatrix))
|
||||
}
|
||||
|
||||
// InitializeFromProtoUnsafe directly uses the beacon state protobuf pointer
|
||||
// and sets it as the inner state of the BeaconState type.
|
||||
func InitializeFromProtoUnsafe(st *ethpb.BeaconStateBellatrix) (*BeaconState, error) {
|
||||
func InitializeFromProtoUnsafe(st *ethpb.BeaconStateBellatrix) (state.BeaconStateBellatrix, error) {
|
||||
if st == nil {
|
||||
return nil, errors.New("received nil state")
|
||||
}
|
||||
|
||||
@@ -108,6 +108,8 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
|
||||
Validators: vals,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
s, ok := st.(*BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
@@ -116,7 +118,7 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
|
||||
// Continuously lock and unlock the state
|
||||
// by acquiring the lock.
|
||||
for i := 0; i < 1000; i++ {
|
||||
for _, f := range st.stateFieldLeaves {
|
||||
for _, f := range s.stateFieldLeaves {
|
||||
f.Lock()
|
||||
if f.Empty() {
|
||||
f.InsertFieldLayer(make([][]*[32]byte, 10))
|
||||
|
||||
@@ -49,7 +49,8 @@ func (s *Service) registerForUpcomingFork(currEpoch types.Epoch) error {
|
||||
// will subscribe the new topics in advance.
|
||||
if isNextForkEpoch {
|
||||
nextEpoch := currEpoch + 1
|
||||
if nextEpoch == params.BeaconConfig().AltairForkEpoch {
|
||||
switch nextEpoch {
|
||||
case params.BeaconConfig().AltairForkEpoch:
|
||||
digest, err := forks.ForkDigestFromEpoch(nextEpoch, genRoot[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not retrieve fork digest")
|
||||
@@ -59,6 +60,15 @@ func (s *Service) registerForUpcomingFork(currEpoch types.Epoch) error {
|
||||
}
|
||||
s.registerSubscribers(nextEpoch, digest)
|
||||
s.registerRPCHandlersAltair()
|
||||
case params.BeaconConfig().BellatrixForkEpoch:
|
||||
digest, err := forks.ForkDigestFromEpoch(nextEpoch, genRoot[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not retrieve fork digest")
|
||||
}
|
||||
if s.subHandler.digestExists(digest) {
|
||||
return nil
|
||||
}
|
||||
s.registerSubscribers(nextEpoch, digest)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -95,7 +105,15 @@ func (s *Service) deregisterFromPastFork(currEpoch types.Epoch) error {
|
||||
if !s.subHandler.digestExists(prevDigest) {
|
||||
return nil
|
||||
}
|
||||
s.unregisterPhase0Handlers()
|
||||
prevFork, err := forks.Fork(epochBeforeFork)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to determine previous epoch fork data")
|
||||
}
|
||||
|
||||
switch prevFork.Epoch {
|
||||
case params.BeaconConfig().GenesisEpoch:
|
||||
s.unregisterPhase0Handlers()
|
||||
}
|
||||
// Run through all our current active topics and see
|
||||
// if there are any subscriptions to be removed.
|
||||
for _, t := range s.subHandler.allTopics() {
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fork in the next epoch",
|
||||
name: "altair fork in the next epoch",
|
||||
svcCreator: func(t *testing.T) *Service {
|
||||
p2p := p2ptest.NewTestP2P(t)
|
||||
chainService := &mockChain.ChainService{
|
||||
@@ -97,6 +97,47 @@ func TestService_CheckForNextEpochFork(t *testing.T) {
|
||||
assert.Equal(t, true, rpcMap[p2p.RPCMetaDataTopicV2+s.cfg.p2p.Encoding().ProtocolSuffix()], "topic doesn't exist")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bellatrix fork in the next epoch",
|
||||
svcCreator: func(t *testing.T) *Service {
|
||||
p2p := p2ptest.NewTestP2P(t)
|
||||
chainService := &mockChain.ChainService{
|
||||
Genesis: time.Now().Add(-4 * oneEpoch()),
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
}
|
||||
bCfg := params.BeaconConfig()
|
||||
bCfg.AltairForkEpoch = 3
|
||||
bCfg.BellatrixForkEpoch = 5
|
||||
params.OverrideBeaconConfig(bCfg)
|
||||
params.BeaconConfig().InitializeForkSchedule()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
r := &Service{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
cfg: &config{
|
||||
p2p: p2p,
|
||||
chain: chainService,
|
||||
stateNotifier: chainService.StateNotifier(),
|
||||
initialSync: &mockSync.Sync{IsSyncing: false},
|
||||
},
|
||||
chainStarted: abool.New(),
|
||||
subHandler: newSubTopicHandler(),
|
||||
}
|
||||
return r
|
||||
},
|
||||
currEpoch: 4,
|
||||
wantErr: false,
|
||||
postSvcCheck: func(t *testing.T, s *Service) {
|
||||
genRoot := s.cfg.chain.GenesisValidatorRoot()
|
||||
digest, err := forks.ForkDigestFromEpoch(5, genRoot[:])
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, s.subHandler.digestExists(digest))
|
||||
rpcMap := make(map[string]bool)
|
||||
for _, p := range s.cfg.p2p.Host().Mux().Protocols() {
|
||||
rpcMap[p] = true
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -159,7 +200,7 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fork in the previous epoch",
|
||||
name: "altair fork in the previous epoch",
|
||||
svcCreator: func(t *testing.T) *Service {
|
||||
p2p := p2ptest.NewTestP2P(t)
|
||||
chainService := &mockChain.ChainService{
|
||||
@@ -232,6 +273,57 @@ func TestService_CheckForPreviousEpochFork(t *testing.T) {
|
||||
assert.Equal(t, false, pMap[p2p.RPCBlocksByRootTopicV1+s.cfg.p2p.Encoding().ProtocolSuffix()])
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bellatrix fork in the previous epoch",
|
||||
svcCreator: func(t *testing.T) *Service {
|
||||
p2p := p2ptest.NewTestP2P(t)
|
||||
chainService := &mockChain.ChainService{
|
||||
Genesis: time.Now().Add(-4 * oneEpoch()),
|
||||
ValidatorsRoot: [32]byte{'A'},
|
||||
}
|
||||
bCfg := params.BeaconConfig()
|
||||
bCfg.AltairForkEpoch = 1
|
||||
bCfg.BellatrixForkEpoch = 3
|
||||
params.OverrideBeaconConfig(bCfg)
|
||||
params.BeaconConfig().InitializeForkSchedule()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
r := &Service{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
cfg: &config{
|
||||
p2p: p2p,
|
||||
chain: chainService,
|
||||
stateNotifier: chainService.StateNotifier(),
|
||||
initialSync: &mockSync.Sync{IsSyncing: false},
|
||||
},
|
||||
chainStarted: abool.New(),
|
||||
subHandler: newSubTopicHandler(),
|
||||
}
|
||||
genRoot := r.cfg.chain.GenesisValidatorRoot()
|
||||
digest, err := forks.ForkDigestFromEpoch(1, genRoot[:])
|
||||
assert.NoError(t, err)
|
||||
r.registerSubscribers(1, digest)
|
||||
assert.Equal(t, true, r.subHandler.digestExists(digest))
|
||||
|
||||
digest, err = forks.ForkDigestFromEpoch(3, genRoot[:])
|
||||
assert.NoError(t, err)
|
||||
r.registerSubscribers(3, digest)
|
||||
assert.Equal(t, true, r.subHandler.digestExists(digest))
|
||||
|
||||
return r
|
||||
},
|
||||
currEpoch: 4,
|
||||
wantErr: false,
|
||||
postSvcCheck: func(t *testing.T, s *Service) {
|
||||
genRoot := s.cfg.chain.GenesisValidatorRoot()
|
||||
digest, err := forks.ForkDigestFromEpoch(1, genRoot[:])
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, s.subHandler.digestExists(digest))
|
||||
digest, err = forks.ForkDigestFromEpoch(3, genRoot[:])
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, s.subHandler.digestExists(digest))
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestService_beaconBlockSubscriber(t *testing.T) {
|
||||
return b
|
||||
}(),
|
||||
},
|
||||
wantedErr: "nil inner state",
|
||||
wantedErr: chainMock.ErrNilState.Error(),
|
||||
check: func(t *testing.T, s *Service) {
|
||||
if s.cfg.attPool.AggregatedAttestationCount() == 0 {
|
||||
t.Error("Expected at least 1 aggregated attestation in the pool")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user