2020-09-26 08:04:07 +00:00
package blockchain
import (
"context"
"fmt"
2021-11-03 15:07:46 +00:00
"github.com/pkg/errors"
2020-09-26 08:04:07 +00:00
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
2021-09-21 19:59:25 +00:00
"github.com/prysmaticlabs/prysm/config/params"
2022-04-29 14:32:11 +00:00
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
2021-09-23 15:23:37 +00:00
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
2021-11-03 15:07:46 +00:00
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
2021-10-01 20:17:57 +00:00
"github.com/prysmaticlabs/prysm/time/slots"
2020-09-26 08:04:07 +00:00
)
2021-11-03 15:07:46 +00:00
type weakSubjectivityDB interface {
HasBlock ( ctx context . Context , blockRoot [ 32 ] byte ) bool
BlockRoots ( ctx context . Context , f * filters . QueryFilter ) ( [ ] [ 32 ] byte , error )
}
type WeakSubjectivityVerifier struct {
enabled bool
verified bool
root [ 32 ] byte
epoch types . Epoch
slot types . Slot
db weakSubjectivityDB
}
2022-05-18 16:20:35 +00:00
// NewWeakSubjectivityVerifier validates a checkpoint, and if valid, uses it to initialize a weak subjectivity verifier.
2021-11-03 15:07:46 +00:00
func NewWeakSubjectivityVerifier ( wsc * ethpb . Checkpoint , db weakSubjectivityDB ) ( * WeakSubjectivityVerifier , error ) {
if wsc == nil || len ( wsc . Root ) == 0 || wsc . Epoch == 0 {
2022-05-18 16:20:35 +00:00
log . Info ( "No checkpoint for syncing provided, node will begin syncing from genesis. Checkpoint Sync is an optional feature that allows your node to sync from a more recent checkpoint, " +
"which enhances the security of your local beacon node and the broader network. See https://docs.prylabs.network/docs/next/prysm-usage/checkpoint-sync/ to learn how to configure Checkpoint Sync." )
2021-11-03 15:07:46 +00:00
return & WeakSubjectivityVerifier {
enabled : false ,
} , nil
2020-09-26 08:04:07 +00:00
}
2021-11-03 15:07:46 +00:00
startSlot , err := slots . EpochStart ( wsc . Epoch )
if err != nil {
return nil , err
2020-09-26 08:04:07 +00:00
}
2021-11-03 15:07:46 +00:00
return & WeakSubjectivityVerifier {
enabled : true ,
verified : false ,
root : bytesutil . ToBytes32 ( wsc . Root ) ,
epoch : wsc . Epoch ,
db : db ,
slot : startSlot ,
} , nil
}
2020-09-26 08:04:07 +00:00
2021-11-03 15:07:46 +00:00
// VerifyWeakSubjectivity verifies the weak subjectivity root in the service struct.
// Reference design: https://github.com/ethereum/consensus-specs/blob/master/specs/phase0/weak-subjectivity.md#weak-subjectivity-sync-procedure
func ( v * WeakSubjectivityVerifier ) VerifyWeakSubjectivity ( ctx context . Context , finalizedEpoch types . Epoch ) error {
if v . verified || ! v . enabled {
return nil
2020-09-26 08:04:07 +00:00
}
2021-11-03 15:07:46 +00:00
// Two conditions are described in the specs:
// IF epoch_number > store.finalized_checkpoint.epoch,
// then ASSERT during block sync that block with root block_root
// is in the sync path at epoch epoch_number. Emit descriptive critical error if this assert fails,
// then exit client process.
// we do not handle this case ^, because we can only blocks that have been processed / are currently
// in line for finalization, we don't have the ability to look ahead. so we only satisfy the following:
// IF epoch_number <= store.finalized_checkpoint.epoch,
// then ASSERT that the block in the canonical chain at epoch epoch_number has root block_root.
// Emit descriptive critical error if this assert fails, then exit client process.
if v . epoch > finalizedEpoch {
return nil
2020-09-26 08:04:07 +00:00
}
2021-11-03 15:07:46 +00:00
log . Infof ( "Performing weak subjectivity check for root %#x in epoch %d" , v . root , v . epoch )
2020-09-26 08:04:07 +00:00
2021-11-03 15:07:46 +00:00
if ! v . db . HasBlock ( ctx , v . root ) {
return errors . Wrap ( errWSBlockNotFound , fmt . Sprintf ( "missing root %#x" , v . root ) )
2020-09-26 08:04:07 +00:00
}
2022-03-28 21:01:55 +00:00
endSlot := v . slot + params . BeaconConfig ( ) . SlotsPerEpoch
filter := filters . NewFilter ( ) . SetStartSlot ( v . slot ) . SetEndSlot ( endSlot )
2020-09-26 08:04:07 +00:00
// A node should have the weak subjectivity block corresponds to the correct epoch in the DB.
2022-03-28 21:01:55 +00:00
log . Infof ( "Searching block roots for weak subjectivity root=%#x, between slots %d-%d" , v . root , v . slot , endSlot )
2021-11-03 15:07:46 +00:00
roots , err := v . db . BlockRoots ( ctx , filter )
2020-09-26 08:04:07 +00:00
if err != nil {
2021-11-03 15:07:46 +00:00
return errors . Wrap ( err , "error while retrieving block roots to verify weak subjectivity" )
2020-09-26 08:04:07 +00:00
}
for _ , root := range roots {
2021-11-03 15:07:46 +00:00
if v . root == root {
2022-03-28 21:01:55 +00:00
log . Info ( "Weak subjectivity check has passed!!" )
2021-11-03 15:07:46 +00:00
v . verified = true
2020-09-26 08:04:07 +00:00
return nil
}
}
2021-11-03 15:07:46 +00:00
return errors . Wrap ( errWSBlockNotFoundInEpoch , fmt . Sprintf ( "root=%#x, epoch=%d" , v . root , v . epoch ) )
2020-09-26 08:04:07 +00:00
}