From c822816f8ee3805c5ed620cbd098782c8fa20aac Mon Sep 17 00:00:00 2001 From: Howard Yeh Date: Sun, 14 Jun 2020 17:49:20 +0800 Subject: [PATCH] Cache tipset validation progress --- chain/store/store.go | 17 +++++++++++++++++ chain/sync.go | 25 +++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/chain/store/store.go b/chain/store/store.go index dba5995de..e3d6506e4 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -47,6 +47,7 @@ import ( var log = logging.Logger("chainstore") var chainHeadKey = dstore.NewKey("head") +var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation") type ChainStore struct { bs bstore.Blockstore @@ -215,6 +216,22 @@ func (cs *ChainStore) SubscribeHeadChanges(f func(rev, app []*types.TipSet) erro cs.headChangeNotifs = append(cs.headChangeNotifs, f) } +func (cs *ChainStore) IsBlockValidated(ctx context.Context, blkid cid.Cid) (bool, error) { + key := blockValidationCacheKeyPrefix.Instance(blkid.String()) + + return cs.ds.Has(key) +} + +func (cs *ChainStore) MarkBlockAsValidated(ctx context.Context, blkid cid.Cid) error { + key := blockValidationCacheKeyPrefix.Instance(blkid.String()) + + if err := cs.ds.Put(key, []byte{0}); err != nil { + return xerrors.Errorf("cache block validation: %w", err) + } + + return nil +} + func (cs *ChainStore) SetGenesis(b *types.BlockHeader) error { ts, err := types.NewTipSet([]*types.BlockHeader{b}) if err != nil { diff --git a/chain/sync.go b/chain/sync.go index 07d470d28..a1315d82b 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -529,7 +529,24 @@ func blockSanityChecks(h *types.BlockHeader) error { } // Should match up with 'Semantical Validation' in validation.md in the spec -func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) error { +func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (err error) { + defer func() { + // b.Cid() could panic for empty blocks that are used in tests. + if rerr := recover(); rerr != nil { + err = xerrors.Errorf("validate block panic: %w", rerr) + return + } + }() + + isValidated, err := syncer.store.IsBlockValidated(ctx, b.Cid()) + if err != nil { + return xerrors.Errorf("check block validation cache %s: %w", b.Cid(), err) + } + + if isValidated { + return nil + } + validationStart := time.Now() defer func() { dur := time.Since(validationStart) @@ -759,7 +776,11 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err } } - return merr + if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil { + return xerrors.Errorf("caching block validation %s: %w", b.Cid(), err) + } + + return nil } func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.BlockHeader, prevBeacon types.BeaconEntry, lbst cid.Cid, waddr address.Address) error {