diff --git a/consensus/consensus.go b/consensus/consensus.go index db2a231e3c8..25674ff312a 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -23,7 +23,6 @@ package consensus import ( "context" "github.com/erigontech/erigon-lib/kv" - "github.com/erigontech/erigon/consensus/parlia" "math/big" "github.com/holiman/uint256" @@ -226,7 +225,7 @@ type PoSA interface { AllowLightProcess(chain ChainReader, currentHeader *types.Header) bool GetJustifiedNumberAndHash(chain ChainHeaderReader, header *types.Header) (uint64, libcommon.Hash, error) GetFinalizedHeader(chain ChainHeaderReader, header *types.Header) *types.Header - Snapshot(chain ChainHeaderReader, number uint64, hash libcommon.Hash, parents []*types.Header, verify bool) (*parlia.Snapshot, error) + ResetSnapshot(chain ChainHeaderReader, header *types.Header) error } type AsyncEngine interface { diff --git a/consensus/parlia/api.go b/consensus/parlia/api.go index 5b870263f64..a62f17dff18 100644 --- a/consensus/parlia/api.go +++ b/consensus/parlia/api.go @@ -43,7 +43,7 @@ func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { if header == nil { return nil, errUnknownBlock } - return api.parlia.Snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) + return api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) } // GetSnapshotAtHash retrieves the state snapshot at a given block. @@ -52,7 +52,7 @@ func (api *API) GetSnapshotAtHash(hash libcommon.Hash) (*Snapshot, error) { if header == nil { return nil, errUnknownBlock } - return api.parlia.Snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) + return api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) } // GetValidators retrieves the list of validators at the specified block. @@ -68,7 +68,7 @@ func (api *API) GetValidators(number *rpc.BlockNumber) ([]libcommon.Address, err if header == nil { return nil, errUnknownBlock } - snap, err := api.parlia.Snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) + snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) if err != nil { return nil, err } @@ -81,7 +81,7 @@ func (api *API) GetValidatorsAtHash(hash libcommon.Hash) ([]libcommon.Address, e if header == nil { return nil, errUnknownBlock } - snap, err := api.parlia.Snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) + snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) if err != nil { return nil, err } @@ -100,7 +100,7 @@ func (api *API) GetTurnLength(number *rpc.BlockNumber) (uint8, error) { if header == nil { return 0, errUnknownBlock } - snap, err := api.parlia.Snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) + snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, false /* verify */) if err != nil || snap.TurnLength == 0 { return 0, err } diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index e6182cca2d5..ce6c31fa25f 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -467,7 +467,7 @@ func (p *Parlia) verifyVoteAttestation(chain consensus.ChainHeaderReader, header } else { parents = nil } - snap, err := p.Snapshot(chain, parent.Number.Uint64()-1, parent.ParentHash, parents, true) + snap, err := p.snapshot(chain, parent.Number.Uint64()-1, parent.ParentHash, parents, true) if err != nil { return err } @@ -637,7 +637,7 @@ func (p *Parlia) verifyCascadingFields(chain consensus.ChainHeaderReader, header return err } - snap, err := p.Snapshot(chain, number-1, header.ParentHash, parents, true /* verify */) + snap, err := p.snapshot(chain, number-1, header.ParentHash, parents, true /* verify */) if err != nil { return err } @@ -728,7 +728,7 @@ func (p *Parlia) verifySeal(header *types.Header, snap *Snapshot) error { // !!! be careful // the block with `number` and `hash` is just the last element of `parents`, // unlike other interfaces such as verifyCascadingFields, `parents` are real parents -func (p *Parlia) Snapshot(chain consensus.ChainHeaderReader, number uint64, hash libcommon.Hash, parents []*types.Header, verify bool) (*Snapshot, error) { +func (p *Parlia) snapshot(chain consensus.ChainHeaderReader, number uint64, hash libcommon.Hash, parents []*types.Header, verify bool) (*Snapshot, error) { // Search for a snapshot in memory or on disk for checkpoints var ( headers []*types.Header @@ -970,7 +970,7 @@ func (p *Parlia) finalize(header *types.Header, ibs *state.IntraBlockState, txs curIndex := userTxs.Len() // warn if not in majority fork number := header.Number.Uint64() - snap, err := p.Snapshot(chain, number-1, header.ParentHash, nil, false /* verify */) + snap, err := p.snapshot(chain, number-1, header.ParentHash, nil, false /* verify */) if err != nil { return nil, nil, nil, err } @@ -1094,7 +1094,7 @@ func (p *Parlia) distributeFinalityReward(chain consensus.ChainHeaderReader, sta continue } - snap, err := p.Snapshot(chain, justifiedBlock.Number.Uint64()-1, justifiedBlock.ParentHash, nil, true) + snap, err := p.snapshot(chain, justifiedBlock.Number.Uint64()-1, justifiedBlock.ParentHash, nil, true) if err != nil { return true, err } @@ -1218,7 +1218,7 @@ func (p *Parlia) SealHash(header *types.Header) (hash libcommon.Hash) { // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // that a new block should have. func (p *Parlia) CalcDifficulty(chain consensus.ChainHeaderReader, time, parentTime uint64, parentDifficulty *big.Int, parentNumber uint64, parentHash, parentUncleHash libcommon.Hash, _ uint64) *big.Int { - snap, err := p.Snapshot(chain, parentNumber, parentHash, nil, false /* verify */) + snap, err := p.snapshot(chain, parentNumber, parentHash, nil, false /* verify */) if err != nil { return nil } @@ -1281,7 +1281,7 @@ func (p *Parlia) IsSystemContract(to *libcommon.Address) bool { } func (p *Parlia) EnoughDistance(chain consensus.ChainReader, header *types.Header) bool { - snap, err := p.Snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil, false /* verify */) + snap, err := p.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil, false /* verify */) if err != nil { return true } @@ -1293,7 +1293,7 @@ func (p *Parlia) IsLocalBlock(header *types.Header) bool { } func (p *Parlia) AllowLightProcess(chain consensus.ChainReader, currentHeader *types.Header) bool { - snap, err := p.Snapshot(chain, currentHeader.Number.Uint64()-1, currentHeader.ParentHash, nil, false /* verify */) + snap, err := p.snapshot(chain, currentHeader.Number.Uint64()-1, currentHeader.ParentHash, nil, false /* verify */) if err != nil { return true } @@ -1558,7 +1558,7 @@ func (p *Parlia) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, he if chain == nil || header == nil { return 0, libcommon.Hash{}, fmt.Errorf("illegal chain or header") } - snap, err := p.Snapshot(chain, header.Number.Uint64(), header.Hash(), nil, true) + snap, err := p.snapshot(chain, header.Number.Uint64(), header.Hash(), nil, true) if err != nil { p.logger.Error("GetJustifiedNumberAndHash snapshot", "error", err, "blockNumber", header.Number.Uint64(), "blockHash", header.Hash()) @@ -1583,7 +1583,7 @@ func (p *Parlia) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *t return chain.GetHeaderByNumber(0) } - snap, err := p.Snapshot(chain, header.Number.Uint64(), header.Hash(), nil, true) + snap, err := p.snapshot(chain, header.Number.Uint64(), header.Hash(), nil, true) if err != nil { p.logger.Error("GetFinalizedHeader snapshot", "error", err, "blockNumber", header.Number.Uint64(), "blockHash", header.Hash()) @@ -1617,3 +1617,47 @@ func (p *Parlia) blockTimeVerifyForRamanujanFork(snap *Snapshot, header, parent } return nil } + +// ResetSnapshot Fill consensus db from snapshot +func (p *Parlia) ResetSnapshot(chain consensus.ChainHeaderReader, header *types.Header) error { + // Search for a snapshot in memory or on disk for checkpoints + var ( + headers []*types.Header + snap *Snapshot + ) + hash := header.Hash() + number := header.Number.Uint64() + + // If we're at the genesis, snapshot the initial state. + if number == 0 { + // Headers included into the snapshots have to be trusted as checkpoints get validators from headers + validators, voteAddrs, err := parseValidators(header, p.chainConfig, p.config) + if err != nil { + return err + } + // new snapshot + snap = newSnapshot(p.config, p.signatures, number, hash, validators, voteAddrs) + p.recentSnaps.Add(hash, snap) + if err := snap.store(p.db); err != nil { + return err + } + p.logger.Info("Stored checkpoint snapshot to disk", "number", number, "hash", hash) + } else { + snap, ok := p.recentSnaps.Get(header.ParentHash) + if !ok { + return fmt.Errorf("can't found parent Snap, number = %d", number) + } + headers = append(headers, header) + if _, err := snap.apply(headers, chain, nil, p.chainConfig, p.recentSnaps); err != nil { + return err + } + // If we've generated a new checkpoint snapshot, save to disk + if snap.Number%CheckpointInterval == 0 { + if err := snap.store(p.db); err != nil { + return err + } + p.logger.Trace("Stored snapshot to disk", "number", snap.Number, "hash", snap.Hash) + } + } + return nil +} diff --git a/eth/stagedsync/stage_snapshots.go b/eth/stagedsync/stage_snapshots.go index e46b733c2b6..d0dfc2c57d8 100644 --- a/eth/stagedsync/stage_snapshots.go +++ b/eth/stagedsync/stage_snapshots.go @@ -417,7 +417,7 @@ func FillDBFromSnapshots(logPrefix string, ctx context.Context, tx kv.RwTx, dirs } if isPoSa { // Fill bsc consensus snapshots may have some conditions for validators snapshots - if _, err := posa.Snapshot(chainReader, header.Number.Uint64(), header.Hash(), nil, true); err != nil { + if err := posa.ResetSnapshot(chainReader, header); err != nil { return err } }