mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-18 16:44:12 +00:00
139 lines
3.7 KiB
Go
139 lines
3.7 KiB
Go
package persistence
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"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/cl/utils"
|
|
"github.com/ledgerwatch/erigon/cmd/sentinel/sentinel/communication/ssz_snappy"
|
|
"github.com/ledgerwatch/erigon/common/dbutils"
|
|
"github.com/spf13/afero"
|
|
)
|
|
|
|
type beaconChainDatabaseFilesystem struct {
|
|
fs afero.Fs
|
|
cfg *clparams.BeaconChainConfig
|
|
|
|
networkEncoding bool // same encoding as reqresp
|
|
|
|
// TODO(Giulio2002): actually make decoupling possible
|
|
_ execution_client.ExecutionEngine
|
|
indiciesDB *sql.DB
|
|
}
|
|
|
|
func NewbeaconChainDatabaseFilesystem(fs afero.Fs, cfg *clparams.BeaconChainConfig, indiciesDB *sql.DB) BeaconChainDatabase {
|
|
return beaconChainDatabaseFilesystem{
|
|
fs: fs,
|
|
cfg: cfg,
|
|
networkEncoding: false,
|
|
indiciesDB: indiciesDB,
|
|
}
|
|
}
|
|
|
|
func (b beaconChainDatabaseFilesystem) GetRange(ctx context.Context, from uint64, count uint64) ([]*peers.PeeredObject[*cltypes.SignedBeaconBlock], error) {
|
|
panic("not imlemented")
|
|
}
|
|
|
|
func (b beaconChainDatabaseFilesystem) PurgeRange(ctx context.Context, from uint64, count uint64) error {
|
|
panic("not imlemented")
|
|
}
|
|
|
|
func (b beaconChainDatabaseFilesystem) WriteBlock(ctx context.Context, block *cltypes.SignedBeaconBlock, canonical bool) error {
|
|
blockRoot, err := block.Block.HashSSZ()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
folderPath, path := RootToPaths(blockRoot, b.cfg)
|
|
// ignore this error... reason: windows
|
|
_ = b.fs.MkdirAll(folderPath, 0o755)
|
|
fp, err := b.fs.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fp.Close()
|
|
err = fp.Truncate(0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = fp.Seek(0, io.SeekStart)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if b.networkEncoding { // 10x bigger but less latency
|
|
err = ssz_snappy.EncodeAndWrite(fp, block)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if block.Version() >= clparams.BellatrixVersion {
|
|
// Need to reference EL somehow on read.
|
|
if _, err := fp.Write(block.Block.Body.ExecutionPayload.BlockHash[:]); err != nil {
|
|
return err
|
|
}
|
|
if _, err := fp.Write(dbutils.EncodeBlockNumber(block.Block.Body.ExecutionPayload.BlockNumber)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
encoded, err := block.EncodeForStorage(nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := fp.Write(utils.CompressSnappy(encoded)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = fp.Sync()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tx, err := b.indiciesDB.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := beacon_indicies.GenerateBlockIndicies(ctx, tx, block.Block, canonical); err != nil {
|
|
return err
|
|
}
|
|
return tx.Commit()
|
|
}
|
|
|
|
// 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}/{slot}.ssz_snappy"
|
|
func RootToPaths(root libcommon.Hash, config *clparams.BeaconChainConfig) (folderPath string, filePath string) {
|
|
folderPath = path.Clean(fmt.Sprintf("%02x/%02x", root[0], root[1]))
|
|
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
|
|
}
|