Skip to content

Commit

Permalink
Add, use and test VerifyWeakSubjectivityRoot (#7344)
Browse files Browse the repository at this point in the history
* Add, use and test `VerifyWeakSubjectivityRoot`
* Comments
* Make bazel test happy
* Merge branch 'master' into verify-ws
* Add flag to help
* Merge branch 'verify-ws' of github.com:prysmaticlabs/prysm into verify-ws
* Merge refs/heads/master into verify-ws
* Merge refs/heads/master into verify-ws
* Merge refs/heads/master into verify-ws
* Merge branch 'master' of github.com:prysmaticlabs/prysm into verify-ws
* Update beacon-chain/blockchain/service.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
* Update beacon-chain/blockchain/weak_subjectivity_checks.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
* Merge branch 'verify-ws' of github.com:prysmaticlabs/prysm into verify-ws
* s/&&/|| for VerifyWeakSubjectivityRoot circuit breaker
* Merge refs/heads/master into verify-ws
* Merge refs/heads/master into verify-ws
  • Loading branch information
terencechain committed Sep 26, 2020
1 parent 282f3ee commit 68d0c09
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 10 deletions.
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
12 changes: 12 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,11 @@ 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)
}

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 {
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 corresponding to epoch: %#x %d", r, s.wsEpoch)
}
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 corresponding 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

0 comments on commit 68d0c09

Please sign in to comment.