mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-09 04:21:20 +00:00
162 lines
5.3 KiB
Go
162 lines
5.3 KiB
Go
package blockio
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon-lib/common/hexutility"
|
|
"github.com/ledgerwatch/erigon-lib/etl"
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
|
"github.com/ledgerwatch/erigon-lib/kv/rawdbv3"
|
|
"github.com/ledgerwatch/erigon/common/dbutils"
|
|
"github.com/ledgerwatch/erigon/core/rawdb"
|
|
"github.com/ledgerwatch/erigon/core/types"
|
|
"github.com/ledgerwatch/erigon/turbo/backup"
|
|
"github.com/ledgerwatch/log/v3"
|
|
)
|
|
|
|
// BlockReader can read blocks from db and snapshots
|
|
type BlockWriter struct {
|
|
historyV3 bool
|
|
|
|
// adding Auto-Increment BlockID
|
|
// allow store non-canonical Txs/Senders
|
|
txsV3 bool
|
|
}
|
|
|
|
func NewBlockWriter(historyV3, txsV3 bool) *BlockWriter {
|
|
return &BlockWriter{historyV3: historyV3, txsV3: txsV3}
|
|
}
|
|
|
|
func (w *BlockWriter) TxsV3Enabled() bool { return w.txsV3 }
|
|
func (w *BlockWriter) WriteBlock(tx kv.RwTx, block *types.Block) error {
|
|
if err := rawdb.WriteHeader(tx, block.HeaderNoCopy()); err != nil {
|
|
return err
|
|
}
|
|
if err := rawdb.WriteBody(tx, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
func (w *BlockWriter) WriteHeader(tx kv.RwTx, header *types.Header) error {
|
|
return rawdb.WriteHeader(tx, header)
|
|
}
|
|
func (w *BlockWriter) WriteHeaderRaw(tx kv.StatelessRwTx, number uint64, hash common.Hash, headerRlp []byte, skipIndexing bool) error {
|
|
return rawdb.WriteHeaderRaw(tx, number, hash, headerRlp, skipIndexing)
|
|
}
|
|
func (w *BlockWriter) WriteCanonicalHash(tx kv.RwTx, hash common.Hash, number uint64) error {
|
|
return rawdb.WriteCanonicalHash(tx, hash, number)
|
|
}
|
|
func (w *BlockWriter) WriteTd(db kv.Putter, hash common.Hash, number uint64, td *big.Int) error {
|
|
return rawdb.WriteTd(db, hash, number, td)
|
|
}
|
|
|
|
func (w *BlockWriter) FillHeaderNumberIndex(logPrefix string, tx kv.RwTx, tmpDir string, from, to uint64, ctx context.Context, logger log.Logger) error {
|
|
startKey := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(startKey, from)
|
|
endKey := dbutils.HeaderKey(to, common.Hash{}) // etl.Tranform uses ExractEndKey as exclusive bound, therefore +1
|
|
|
|
return etl.Transform(
|
|
logPrefix,
|
|
tx,
|
|
kv.Headers,
|
|
kv.HeaderNumber,
|
|
tmpDir,
|
|
extractHeaders,
|
|
etl.IdentityLoadFunc,
|
|
etl.TransformArgs{
|
|
ExtractStartKey: startKey,
|
|
ExtractEndKey: endKey,
|
|
Quit: ctx.Done(),
|
|
},
|
|
logger,
|
|
)
|
|
}
|
|
|
|
func (w *BlockWriter) MakeBodiesCanonical(tx kv.RwTx, from uint64, ctx context.Context, logPrefix string, logEvery *time.Ticker) error {
|
|
// Property of blockchain: same block in different forks will have different hashes.
|
|
// Means - can mark all canonical blocks as non-canonical on unwind, and
|
|
// do opposite here - without storing any meta-info.
|
|
if err := rawdb.MakeBodiesCanonical(tx, from, ctx, logPrefix, logEvery, w.txsV3, func(blockNum, lastTxnNum uint64) error {
|
|
if w.historyV3 {
|
|
if err := rawdbv3.TxNums.Append(tx, blockNum, lastTxnNum); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return fmt.Errorf("make block canonical: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
func (w *BlockWriter) MakeBodiesNonCanonical(tx kv.RwTx, from uint64, deleteBodies bool, ctx context.Context, logPrefix string, logEvery *time.Ticker) error {
|
|
if err := rawdb.MakeBodiesNonCanonical(tx, from, deleteBodies, ctx, logPrefix, logEvery); err != nil {
|
|
return err
|
|
}
|
|
if w.historyV3 {
|
|
if err := rawdbv3.TxNums.Truncate(tx, from); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func extractHeaders(k []byte, v []byte, next etl.ExtractNextFunc) error {
|
|
// We only want to extract entries composed by Block Number + Header Hash
|
|
if len(k) != 40 {
|
|
return nil
|
|
}
|
|
return next(k, common.Copy(k[8:]), common.Copy(k[:8]))
|
|
}
|
|
|
|
func (w *BlockWriter) WriteRawBodyIfNotExists(tx kv.RwTx, hash common.Hash, number uint64, body *types.RawBody) (ok bool, lastTxnNum uint64, err error) {
|
|
return rawdb.WriteRawBodyIfNotExists(tx, hash, number, body)
|
|
}
|
|
func (w *BlockWriter) WriteBody(tx kv.RwTx, hash common.Hash, number uint64, body *types.Body) error {
|
|
return rawdb.WriteBody(tx, hash, number, body)
|
|
}
|
|
func (w *BlockWriter) TruncateBodies(db kv.RoDB, tx kv.RwTx, from uint64) error {
|
|
fromB := hexutility.EncodeTs(from)
|
|
if err := tx.ForEach(kv.BlockBody, fromB, func(k, _ []byte) error { return tx.Delete(kv.BlockBody, k) }); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := backup.ClearTables(context.Background(), db, tx,
|
|
kv.NonCanonicalTxs,
|
|
kv.EthTx,
|
|
kv.MaxTxNum,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
if err := rawdb.ResetSequence(tx, kv.EthTx, 0); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := rawdb.ResetSequence(tx, kv.NonCanonicalTxs, 0); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *BlockWriter) TruncateBlocks(ctx context.Context, tx kv.RwTx, blockFrom uint64) error {
|
|
return rawdb.TruncateBlocks(ctx, tx, blockFrom)
|
|
}
|
|
func (w *BlockWriter) TruncateTd(tx kv.RwTx, blockFrom uint64) error {
|
|
return rawdb.TruncateTd(tx, blockFrom)
|
|
}
|
|
func (w *BlockWriter) ResetSenders(ctx context.Context, db kv.RoDB, tx kv.RwTx) error {
|
|
return backup.ClearTables(ctx, db, tx, kv.Senders)
|
|
}
|
|
|
|
// Prune - [1, to) old blocks after moving it to snapshots.
|
|
// keeps genesis in db
|
|
// doesn't change sequences of kv.EthTx and kv.NonCanonicalTxs
|
|
// doesn't delete Receipts, Senders, Canonical markers, TotalDifficulty
|
|
func (w *BlockWriter) Prune(ctx context.Context, tx kv.RwTx, blockTo uint64, blocksDeleteLimit int) error {
|
|
return rawdb.DeleteAncientBlocks(tx, blockTo, blocksDeleteLimit)
|
|
}
|