mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 11:41:19 +00:00
159 lines
4.4 KiB
Go
159 lines
4.4 KiB
Go
package persistence
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"path"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
|
"github.com/ledgerwatch/erigon/cl/clparams"
|
|
"github.com/ledgerwatch/erigon/cl/cltypes"
|
|
"github.com/ledgerwatch/erigon/cl/persistence/beacon_indicies"
|
|
"github.com/ledgerwatch/erigon/cl/phase1/execution_client"
|
|
"github.com/ledgerwatch/erigon/cl/sentinel/peers"
|
|
"github.com/ledgerwatch/erigon/cmd/sentinel/sentinel/communication/ssz_snappy"
|
|
"github.com/spf13/afero"
|
|
)
|
|
|
|
type beaconChainDatabaseFilesystem struct {
|
|
rawDB RawBeaconBlockChain
|
|
cfg *clparams.BeaconChainConfig
|
|
|
|
executionEngine execution_client.ExecutionEngine
|
|
}
|
|
|
|
func NewBeaconChainDatabaseFilesystem(rawDB RawBeaconBlockChain, executionEngine execution_client.ExecutionEngine, cfg *clparams.BeaconChainConfig) BeaconChainDatabase {
|
|
return beaconChainDatabaseFilesystem{
|
|
rawDB: rawDB,
|
|
cfg: cfg,
|
|
executionEngine: executionEngine,
|
|
}
|
|
}
|
|
|
|
func (b beaconChainDatabaseFilesystem) GetRange(tx kv.Tx, ctx context.Context, from uint64, count uint64) ([]*peers.PeeredObject[*cltypes.SignedBeaconBlock], error) {
|
|
// Retrieve block roots for each ranged slot
|
|
beaconBlockRooots, slots, err := beacon_indicies.ReadBeaconBlockRootsInSlotRange(ctx, tx, from, count)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(beaconBlockRooots) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
blocks := []*peers.PeeredObject[*cltypes.SignedBeaconBlock]{}
|
|
for idx, blockRoot := range beaconBlockRooots {
|
|
slot := slots[idx]
|
|
|
|
r, err := b.rawDB.BlockReader(ctx, slot, blockRoot)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer r.Close()
|
|
|
|
block := cltypes.NewSignedBeaconBlock(b.cfg)
|
|
version := b.cfg.GetCurrentStateVersion(slot / b.cfg.SlotsPerEpoch)
|
|
if err := ssz_snappy.DecodeAndReadNoForkDigest(r, block, version); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
blocks = append(blocks, &peers.PeeredObject[*cltypes.SignedBeaconBlock]{Data: block})
|
|
}
|
|
return blocks, nil
|
|
|
|
}
|
|
|
|
func (b beaconChainDatabaseFilesystem) PurgeRange(tx kv.RwTx, ctx context.Context, from uint64, count uint64) error {
|
|
if err := beacon_indicies.RangeBlockRoots(ctx, tx, from, from+count, func(slot uint64, beaconBlockRoot libcommon.Hash) bool {
|
|
b.rawDB.DeleteBlock(ctx, slot, beaconBlockRoot)
|
|
return true
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return beacon_indicies.PruneBlockRoots(ctx, tx, from, from+count)
|
|
}
|
|
|
|
func (b beaconChainDatabaseFilesystem) WriteBlock(tx kv.RwTx, ctx context.Context, block *cltypes.SignedBeaconBlock, canonical bool) error {
|
|
blockRoot, err := block.Block.HashSSZ()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
w, err := b.rawDB.BlockWriter(ctx, block.Block.Slot, blockRoot)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer w.Close()
|
|
|
|
if fp, ok := w.(afero.File); ok {
|
|
err = fp.Truncate(0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = fp.Seek(0, io.SeekStart)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = ssz_snappy.EncodeAndWrite(w, block)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if fp, ok := w.(afero.File); ok {
|
|
err = fp.Sync()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
bodyRoot, err := block.Block.Body.HashSSZ()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := beacon_indicies.WriteBeaconBlockHeaderAndIndicies(ctx, tx, &cltypes.SignedBeaconBlockHeader{
|
|
Signature: block.Signature,
|
|
Header: &cltypes.BeaconBlockHeader{
|
|
Slot: block.Block.Slot,
|
|
ParentRoot: block.Block.ParentRoot,
|
|
ProposerIndex: block.Block.ProposerIndex,
|
|
Root: block.Block.StateRoot,
|
|
BodyRoot: bodyRoot,
|
|
},
|
|
}, canonical); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SlotToPaths define the file structure to store a block
|
|
//
|
|
// superEpoch = floor(slot / (epochSize ^ 2))
|
|
// epoch = floot(slot / epochSize)
|
|
// file is to be stored at
|
|
// "/signedBeaconBlock/{superEpoch}/{epoch}/{root}.ssz_snappy"
|
|
func RootToPaths(slot uint64, root libcommon.Hash, config *clparams.BeaconChainConfig) (folderPath string, filePath string) {
|
|
folderPath = path.Clean(fmt.Sprintf("%d/%d", slot/(config.SlotsPerEpoch*config.SlotsPerEpoch), slot/config.SlotsPerEpoch))
|
|
filePath = path.Clean(fmt.Sprintf("%s/%x.sz", folderPath, root))
|
|
return
|
|
}
|
|
|
|
func ValidateEpoch(fs afero.Fs, epoch uint64, config *clparams.BeaconChainConfig) error {
|
|
superEpoch := epoch / (config.SlotsPerEpoch)
|
|
|
|
// the folder path is superEpoch/epoch
|
|
folderPath := path.Clean(fmt.Sprintf("%d/%d", superEpoch, epoch))
|
|
|
|
fi, err := afero.ReadDir(fs, folderPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, fn := range fi {
|
|
fn.Name()
|
|
}
|
|
return nil
|
|
}
|