Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add, use and test VerifyWeakSubjectivityRoot #7344

Merged
merged 16 commits into from
Sep 26, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions beacon-chain/blockchain/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ go_library(
"receive_attestation.go",
"receive_block.go",
"service.go",
"weak_subjectivity_checks.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain",
visibility = [
Expand All @@ -34,6 +35,7 @@ go_library(
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state:go_default_library",
"//beacon-chain/db:go_default_library",
"//beacon-chain/db/filters:go_default_library",
"//beacon-chain/flags:go_default_library",
"//beacon-chain/forkchoice:go_default_library",
"//beacon-chain/forkchoice/protoarray:go_default_library",
Expand Down Expand Up @@ -86,6 +88,7 @@ go_test(
"receive_attestation_test.go",
"receive_block_test.go",
"service_test.go",
"weak_subjectivity_checks_test.go",
],
embed = [":go_default_library"],
deps = [
Expand Down
5 changes: 5 additions & 0 deletions beacon-chain/blockchain/receive_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ func (s *Service) ReceiveBlockBatch(ctx context.Context, blocks []*ethpb.SignedB
reportSlotMetrics(blockCopy.Block.Slot, s.headSlot(), s.CurrentSlot(), s.finalizedCheckpt)
}

if err := s.VerifyWeakSubjectivityRoot(s.ctx); err != nil {
// Exit run time if the node failed to verify weak subjectivity checkpoint.
log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
}

return nil
}

Expand Down
13 changes: 13 additions & 0 deletions beacon-chain/blockchain/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ type Service struct {
justifiedBalances []uint64
justifiedBalancesLock sync.RWMutex
checkPtInfoCache *checkPtInfoCache
wsEpoch uint64
wsRoot []byte
wsVerified bool
}

// Config options for the service.
Expand All @@ -92,6 +95,8 @@ type Config struct {
ForkChoiceStore f.ForkChoicer
OpsService *attestations.Service
StateGen *stategen.State
WspBlockRoot []byte
WspEpoch uint64
}

// NewService instantiates a new block service instance that will
Expand Down Expand Up @@ -120,6 +125,8 @@ func NewService(ctx context.Context, cfg *Config) (*Service, error) {
recentCanonicalBlocks: make(map[[32]byte]bool),
justifiedBalances: make([]uint64, 0),
checkPtInfoCache: newCheckPointInfoCache(),
wsEpoch: cfg.WspEpoch,
wsRoot: cfg.WspBlockRoot,
}, nil
}

Expand Down Expand Up @@ -184,6 +191,12 @@ func (s *Service) Start() {
s.prevFinalizedCheckpt = stateTrie.CopyCheckpoint(finalizedCheckpoint)
s.resumeForkChoice(justifiedCheckpoint, finalizedCheckpoint)

if err := s.VerifyWeakSubjectivityRoot(s.ctx); err != nil {
// Exit run time if the node failed to verify weak subjectivity checkpoint.
log.Fatalf("Could not verify weak subjectivity checkpoint: %v", err)
return
terencechain marked this conversation as resolved.
Show resolved Hide resolved
}

s.stateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.Initialized,
Data: &statefeed.InitializedData{
Expand Down
60 changes: 60 additions & 0 deletions beacon-chain/blockchain/weak_subjectivity_checks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package blockchain

import (
"context"
"fmt"

"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
)

// VerifyWeakSubjectivityRoot verifies the weak subjectivity root in the service struct.
// Reference design: https://github.com/ethereum/eth2.0-specs/blob/master/specs/phase0/weak-subjectivity.md#weak-subjectivity-sync-procedure
func (s *Service) VerifyWeakSubjectivityRoot(ctx context.Context) error {
// TODO(7342): Remove the following to fully use weak subjectivity in production.
if len(s.wsRoot) == 0 && s.wsEpoch == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be an || ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way is fine. This is not going to be production code. I changed it to | |

return nil
}

// Do nothing if the weak subjectivity has previously been verified,
// or weak subjectivity epoch is higher than last finalized epoch.
if s.wsVerified {
return nil
}
if s.wsEpoch > s.finalizedCheckpt.Epoch {
return nil
}

r := bytesutil.ToBytes32(s.wsRoot)
log.Infof("Performing weak subjectivity check for root %#x in epoch %d", r, s.wsEpoch)
// Save initial sync cached blocks to DB.
if err := s.beaconDB.SaveBlocks(ctx, s.getInitSyncBlocks()); err != nil {
return err
}
// A node should have the weak subjectivity block in the DB.
if !s.beaconDB.HasBlock(ctx, r) {
return fmt.Errorf("node does not have root in DB: %#x", r)
}

startSlot, err := helpers.StartSlot(s.wsEpoch)
if err != nil {
return err
}
// A node should have the weak subjectivity block corresponds to the correct epoch in the DB.
filter := filters.NewFilter().SetStartSlot(startSlot).SetEndSlot(startSlot + params.BeaconConfig().SlotsPerEpoch)
roots, err := s.beaconDB.BlockRoots(ctx, filter)
if err != nil {
return err
}
for _, root := range roots {
if r == root {
log.Info("Weak subjectivity check has passed")
s.wsVerified = true
return nil
}
}

return fmt.Errorf("node does not have root in db corresponds to epoch: %#x %d", r, s.wsEpoch)
terencechain marked this conversation as resolved.
Show resolved Hide resolved
}
85 changes: 85 additions & 0 deletions beacon-chain/blockchain/weak_subjectivity_checks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package blockchain

import (
"context"
"testing"

ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
)

func TestService_VerifyWeakSubjectivityRoot(t *testing.T) {
db, _ := testDB.SetupDB(t)

b := testutil.NewBeaconBlock()
b.Block.Slot = 32
require.NoError(t, db.SaveBlock(context.Background(), b))
r, err := b.Block.HashTreeRoot()
require.NoError(t, err)
tests := []struct {
wsVerified bool
wantErr bool
wsRoot [32]byte
wsEpoch uint64
finalizedEpoch uint64
errString string
name string
}{
{
name: "nil root and epoch",
wantErr: false,
},
{
name: "already verified",
wsEpoch: 2,
finalizedEpoch: 2,
wsVerified: true,
wantErr: false,
},
{
name: "not yet to verify, ws epoch higher than finalized epoch",
wsEpoch: 2,
finalizedEpoch: 1,
wantErr: false,
},
{
name: "can't find the block in DB",
wsEpoch: 1,
wsRoot: [32]byte{'a'},
finalizedEpoch: 3,
wantErr: true,
errString: "node does not have root in DB",
},
{
name: "can't find the block corresponds to ws epoch in DB",
wsEpoch: 2,
wsRoot: r, // Root belongs in epoch 1.
finalizedEpoch: 3,
wantErr: true,
errString: "node does not have root in db corresponds to epoch",
},
{
name: "can verify and pass",
wsEpoch: 1,
wsRoot: r,
finalizedEpoch: 3,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &Service{
beaconDB: db,
wsRoot: tt.wsRoot[:],
wsEpoch: tt.wsEpoch,
wsVerified: tt.wsVerified,
finalizedCheckpt: &ethpb.Checkpoint{Epoch: tt.finalizedEpoch},
}
if err := s.VerifyWeakSubjectivityRoot(context.Background()); (err != nil) != tt.wantErr {
require.ErrorContains(t, tt.errString, err)
}
})
}
}
1 change: 1 addition & 0 deletions beacon-chain/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ var appFlags = []cli.Flag{
flags.HistoricalSlasherNode,
flags.ChainID,
flags.NetworkID,
flags.WeakSubjectivityCheckpt,
cmd.MinimalConfigFlag,
cmd.E2EConfigFlag,
cmd.RPCMaxPageSizeFlag,
Expand Down
16 changes: 8 additions & 8 deletions beacon-chain/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,12 @@ func (b *BeaconNode) registerBlockchainService() error {
return err
}

wsp := b.cliCtx.String(flags.WeakSubjectivityCheckpt.Name)
bRoot, epoch, err := convertWspInput(wsp)
if err != nil {
return err
}

maxRoutines := b.cliCtx.Int(cmd.MaxGoroutines.Name)
blockchainService, err := blockchain.NewService(b.ctx, &blockchain.Config{
BeaconDB: b.db,
Expand All @@ -449,6 +455,8 @@ func (b *BeaconNode) registerBlockchainService() error {
ForkChoiceStore: b.forkChoiceStore,
OpsService: opsService,
StateGen: b.stateGen,
WspBlockRoot: bRoot,
WspEpoch: epoch,
})
if err != nil {
return errors.Wrap(err, "could not register blockchain service")
Expand Down Expand Up @@ -535,12 +543,6 @@ func (b *BeaconNode) registerSyncService() error {
}

func (b *BeaconNode) registerInitialSyncService() error {
wsp := b.cliCtx.String(flags.WeakSubjectivityCheckpt.Name)
bRoot, epoch, err := convertWspInput(wsp)
if err != nil {
return err
}

var chainService *blockchain.Service
if err := b.services.FetchService(&chainService); err != nil {
return err
Expand All @@ -552,8 +554,6 @@ func (b *BeaconNode) registerInitialSyncService() error {
P2P: b.fetchP2P(),
StateNotifier: b,
BlockNotifier: b,
WspBlockRoot: bRoot,
WspEpoch: epoch,
})
return b.services.RegisterService(is)
}
Expand Down
2 changes: 0 additions & 2 deletions beacon-chain/sync/initial-sync/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ type Config struct {
Chain blockchainService
StateNotifier statefeed.Notifier
BlockNotifier blockfeed.Notifier
WspBlockRoot []byte
WspEpoch uint64
}

// Service service.
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ var appHelpFlagGroups = []flagGroup{
flags.HistoricalSlasherNode,
flags.ChainID,
flags.NetworkID,
flags.WeakSubjectivityCheckpt,
},
},
{
Expand Down