@@ -12,6 +12,7 @@ import (
1212 "time"
1313
1414 "github.com/oasisprotocol/oasis-core/go/p2p/rpc"
15+ "github.com/oasisprotocol/oasis-core/go/roothash/api/block"
1516 storageApi "github.com/oasisprotocol/oasis-core/go/storage/api"
1617 "github.com/oasisprotocol/oasis-core/go/storage/mkvs/checkpoint"
1718 "github.com/oasisprotocol/oasis-core/go/worker/storage/p2p/checkpointsync"
@@ -367,40 +368,30 @@ func sortCheckpoints(s []*checkpointsync.Checkpoint) {
367368 })
368369}
369370
370- func (w * Worker ) checkCheckpointUsable (ctx context.Context , cp * checkpointsync.Checkpoint , remainingMask outstandingMask , genesisRound uint64 ) bool {
371- namespace := w .commonNode .Runtime .ID ()
372- if ! namespace .Equal (& cp .Root .Namespace ) {
373- // Not for the right runtime.
374- return false
375- }
376- if cp .Root .Version == genesisRound && cp .Root .Type == storageApi .RootTypeIO {
377- // Never fetch i/o root for genesis round.
378- return false
371+ func validateCheckpoint (cp * checkpointsync.Checkpoint , blk * block.Block ) error {
372+ if ! blk .Header .Namespace .Equal ((& cp .Root .Namespace )) {
373+ return fmt .Errorf ("namespace mismatch: got %s, want %s" , cp .Root .Namespace , blk .Header .Namespace )
379374 }
380375
381- blk , err := w . commonNode . Runtime . History (). GetCommittedBlock ( ctx , cp . Root . Version )
382- if err != nil {
383- w . logger . Error ( "can't get block information for checkpoint, skipping" , "err" , err , "root" , cp . Root )
384- return false
376+ for _ , root := range blk . Header . StorageRoots () {
377+ if cp . Root . Equal ( & root ) {
378+ return nil
379+ }
385380 }
381+ return fmt .Errorf ("checkpoint metadata with unexpected root %s" , cp .Root )
382+ }
383+
384+ func (w * Worker ) checkCheckpointUsable (cp * checkpointsync.Checkpoint , remainingMask outstandingMask , genesisRound uint64 ) bool {
386385 _ , lastIORoot , lastStateRoot := w .GetLastSynced ()
387- lastVersions := map [storageApi.RootType ]uint64 {
388- storageApi .RootTypeIO : lastIORoot .Version ,
389- storageApi .RootTypeState : lastStateRoot .Version ,
390- }
391- if namespace .Equal (& blk .Header .Namespace ) {
392- for _ , root := range blk .Header .StorageRoots () {
393- if cp .Root .Type == root .Type && root .Hash .Equal (& cp .Root .Hash ) {
394- // Do we already have this root?
395- if lastVersions [cp .Root .Type ] < cp .Root .Version && remainingMask .contains (cp .Root .Type ) {
396- return true
397- }
398- return false
399- }
400- }
386+ var lastVersion uint64
387+ switch cp .Root .Type {
388+ case storageApi .RootTypeIO :
389+ lastVersion = lastIORoot .Version
390+ case storageApi .RootTypeState :
391+ lastVersion = lastStateRoot .Version
401392 }
402- w . logger . Info ( "checkpoint for unknown root skipped" , "root" , cp . Root )
403- return false
393+
394+ return lastVersion < cp . Root . Version && remainingMask . contains ( cp . Root . Type )
404395}
405396
406397func (w * Worker ) syncCheckpoints (ctx context.Context , genesisRound uint64 , wantOnlyGenesis bool ) (* blockSummary , error ) {
@@ -447,7 +438,32 @@ func (w *Worker) syncCheckpoints(ctx context.Context, genesisRound uint64, wantO
447438
448439 for _ , check := range cps {
449440
450- if check .Root .Version < genesisRound || ! w .checkCheckpointUsable (ctx , check , remainingRoots , genesisRound ) {
441+ if check .Root .Version < genesisRound {
442+ continue
443+ }
444+
445+ if check .Root .Version == genesisRound && check .Root .Type == storageApi .RootTypeIO {
446+ // Genesis round has no i/o root. Some peers may still advertise one after
447+ // dump-restore upgrades; ignore it without penalizing.
448+ continue
449+ }
450+
451+ blk , err := w .commonNode .Runtime .History ().GetCommittedBlock (ctx , check .Root .Version )
452+ if err != nil {
453+ w .logger .Error ("can't get block information for checkpoint, skipping" , "err" , err , "root" , check .Root )
454+ continue
455+ }
456+
457+ if err := validateCheckpoint (check , blk ); err != nil {
458+ w .logger .Error ("invalid checkpoint received, penalizing bad peers" , "checkpoint" , check )
459+ for _ , peer := range check .Peers {
460+ peer .RecordBadPeer ()
461+ }
462+ continue
463+ }
464+
465+ if ! w .checkCheckpointUsable (check , remainingRoots , genesisRound ) {
466+ w .logger .Info ("checkpoint not usable" , "checkpoint" , check )
451467 continue
452468 }
453469
0 commit comments