More careful handle of sequences in stage_headers --reset (#4023)

* save

* save

* save

* save
This commit is contained in:
Alex Sharov 2022-04-29 14:37:02 +07:00 committed by GitHub
parent 38e8706c91
commit 77560b6732
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 230 additions and 167 deletions

View File

@ -17,7 +17,6 @@ import (
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/interfaces"
"github.com/ledgerwatch/erigon/cmd/sentry/sentry"
"github.com/ledgerwatch/erigon/common/dbutils"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/ethash"
"github.com/ledgerwatch/erigon/core"
@ -483,7 +482,7 @@ func stageHeaders(db kv.RwDB, ctx context.Context) error {
return fmt.Errorf("re-read Bodies progress: %w", err)
}
{ // hard-unwind stage_body also
if err := rawdb.DeleteNewBlocks(tx, progress+1); err != nil {
if err := rawdb.TruncateBlocks(tx, progress+1); err != nil {
return err
}
progressBodies, err := stages.GetStageProgress(tx, stages.Bodies)
@ -497,14 +496,10 @@ func stageHeaders(db kv.RwDB, ctx context.Context) error {
}
}
// remove all canonical markers from this point
if err := tx.ForEach(kv.HeaderCanonical, dbutils.EncodeBlockNumber(progress+1), func(k, v []byte) error {
return tx.Delete(kv.HeaderCanonical, k, nil)
}); err != nil {
if err = rawdb.TruncateCanonicalHash(tx, progress+1); err != nil {
return err
}
if err := tx.ForEach(kv.HeaderTD, dbutils.EncodeBlockNumber(progress+1), func(k, v []byte) error {
return tx.Delete(kv.HeaderTD, k, nil)
}); err != nil {
if err = rawdb.TruncateTd(tx, progress+1); err != nil {
return err
}
hash, err := rawdb.ReadCanonicalHash(tx, progress-1)

View File

@ -1,16 +1,48 @@
package core
import (
"context"
"testing"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon-lib/kv/memdb"
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/params/networkname"
"github.com/stretchr/testify/require"
"testing"
)
func TestDefaultBSCGenesisBlock(t *testing.T) {
genesis := DefaultBSCGenesisBlock()
db := memdb.New()
_, block, err := CommitGenesisBlock(db, genesis)
require.NoError(t, err)
require.Equal(t, block.Hash(), params.BSCGenesisHash)
db := memdb.NewTestDB(t)
check := func(network string) {
genesis := DefaultGenesisBlockByChainName(network)
tx, err := db.BeginRw(context.Background())
if err != nil {
t.Fatal(err)
}
defer tx.Rollback()
_, block, err := WriteGenesisBlock(tx, genesis)
require.NoError(t, err)
expect := params.GenesisHashByChainName(network)
require.NotNil(t, expect, network)
require.Equal(t, block.Hash().Bytes(), expect.Bytes(), network)
}
for _, network := range networkname.All {
check(network)
}
}
func TestCommitGenesisIdempotency(t *testing.T) {
_, tx := memdb.NewTestTx(t)
genesis := DefaultGenesisBlockByChainName(networkname.MainnetChainName)
_, _, err := WriteGenesisBlock(tx, genesis)
require.NoError(t, err)
seq, err := tx.ReadSequence(kv.EthTx)
require.NoError(t, err)
require.Equal(t, uint64(2), seq)
_, _, err = WriteGenesisBlock(tx, genesis)
require.NoError(t, err)
seq, err = tx.ReadSequence(kv.EthTx)
require.NoError(t, err)
require.Equal(t, uint64(2), seq)
}

View File

@ -26,8 +26,6 @@ import (
"time"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/log/v3"
"github.com/ledgerwatch/erigon/cmd/rpcdaemon/interfaces"
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/dbutils"
@ -35,6 +33,7 @@ import (
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/ethdb/cbor"
"github.com/ledgerwatch/erigon/rlp"
"github.com/ledgerwatch/log/v3"
)
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
@ -57,10 +56,12 @@ func WriteCanonicalHash(db kv.Putter, hash common.Hash, number uint64) error {
return nil
}
// DeleteCanonicalHash removes the number to hash canonical mapping.
func DeleteCanonicalHash(db kv.Deleter, number uint64) error {
if err := db.Delete(kv.HeaderCanonical, dbutils.EncodeBlockNumber(number), nil); err != nil {
return fmt.Errorf("failed to delete number to hash mapping: %w", err)
// TruncateCanonicalHash removes all the number to hash canonical mapping from block number N
func TruncateCanonicalHash(tx kv.RwTx, blockFrom uint64) error {
if err := tx.ForEach(kv.HeaderCanonical, dbutils.EncodeBlockNumber(blockFrom), func(k, _ []byte) error {
return tx.Delete(kv.HeaderCanonical, k, nil)
}); err != nil {
return fmt.Errorf("TruncateCanonicalHash: %w", err)
}
return nil
}
@ -254,8 +255,8 @@ func WriteHeader(db kv.Putter, header *types.Header) {
}
}
// DeleteHeader removes all block header data associated with a hash.
func DeleteHeader(db kv.Deleter, hash common.Hash, number uint64) {
// deleteHeader - dangerous, use DeleteAncientBlocks/TruncateBlocks methods
func deleteHeader(db kv.Deleter, hash common.Hash, number uint64) {
if err := db.Delete(kv.Headers, dbutils.HeaderKey(number, hash), nil); err != nil {
log.Crit("Failed to delete header", "err", err)
}
@ -617,8 +618,8 @@ func WriteSenders(db kv.Putter, hash common.Hash, number uint64, senders []commo
return nil
}
// DeleteBody removes all block body data associated with a hash.
func DeleteBody(db kv.Deleter, hash common.Hash, number uint64) {
// deleteBody removes all block body data associated with a hash.
func deleteBody(db kv.Deleter, hash common.Hash, number uint64) {
if err := db.Delete(kv.BlockBody, dbutils.BlockBodyKey(number, hash), nil); err != nil {
log.Crit("Failed to delete block body", "err", err)
}
@ -797,10 +798,12 @@ func WriteTd(db kv.Putter, hash common.Hash, number uint64, td *big.Int) error {
return nil
}
// DeleteTd removes all block total difficulty data associated with a hash.
func DeleteTd(db kv.Deleter, hash common.Hash, number uint64) error {
if err := db.Delete(kv.HeaderTD, dbutils.HeaderKey(number, hash), nil); err != nil {
return fmt.Errorf("failed to delete block total difficulty: %w", err)
// TruncateTd removes all block total difficulty from block number N
func TruncateTd(tx kv.RwTx, blockFrom uint64) error {
if err := tx.ForEach(kv.HeaderTD, dbutils.EncodeBlockNumber(blockFrom), func(k, _ []byte) error {
return tx.Delete(kv.HeaderTD, k, nil)
}); err != nil {
return fmt.Errorf("TruncateTd: %w", err)
}
return nil
}
@ -960,25 +963,9 @@ func AppendReceipts(tx kv.StatelessWriteTx, blockNumber uint64, receipts types.R
return nil
}
// DeleteReceipts removes all receipt data associated with a block hash.
func DeleteReceipts(db kv.RwTx, number uint64) error {
if err := db.Delete(kv.Receipts, dbutils.EncodeBlockNumber(number), nil); err != nil {
return fmt.Errorf("receipts delete failed: %d, %w", number, err)
}
prefix := make([]byte, 8)
binary.BigEndian.PutUint64(prefix, number)
if err := db.ForPrefix(kv.Log, prefix, func(k, v []byte) error {
return db.Delete(kv.Log, k, nil)
}); err != nil {
return err
}
return nil
}
// DeleteNewerReceipts removes all receipt for given block number or newer
func DeleteNewerReceipts(db kv.RwTx, number uint64) error {
if err := db.ForEach(kv.Receipts, dbutils.EncodeBlockNumber(number), func(k, v []byte) error {
// TruncateReceipts removes all receipt for given block number or newer
func TruncateReceipts(db kv.RwTx, number uint64) error {
if err := db.ForEach(kv.Receipts, dbutils.EncodeBlockNumber(number), func(k, _ []byte) error {
return db.Delete(kv.Receipts, k, nil)
}); err != nil {
return err
@ -986,7 +973,7 @@ func DeleteNewerReceipts(db kv.RwTx, number uint64) error {
from := make([]byte, 8)
binary.BigEndian.PutUint64(from, number)
if err := db.ForEach(kv.Log, from, func(k, v []byte) error {
if err := db.ForEach(kv.Log, from, func(k, _ []byte) error {
return db.Delete(kv.Log, k, nil)
}); err != nil {
return err
@ -1099,22 +1086,17 @@ func DeleteAncientBlocks(db kv.RwTx, blockTo uint64, blocksDeleteLimit int) erro
}
defer c.Close()
var stopAtBlock, firstNonGenesisInDB uint64
{
k, _, err := c.First()
if err != nil {
return err
}
firstNonGenesisInDB = binary.BigEndian.Uint64(k)
if firstNonGenesisInDB == 0 { // keep genesis in DB
k, _, err := c.Next()
if err != nil {
return err
}
firstNonGenesisInDB = binary.BigEndian.Uint64(k)
}
stopAtBlock = min(blockTo, firstNonGenesisInDB+uint64(blocksDeleteLimit))
// find first non-genesis block
k, _, err := c.Seek(dbutils.EncodeBlockNumber(1))
if err != nil {
return err
}
if k == nil { //nothing to delete
return nil
}
blockFrom := binary.BigEndian.Uint64(k)
stopAtBlock := min(blockTo, blockFrom+uint64(blocksDeleteLimit))
for k, _, err := c.Current(); k != nil; k, _, err = c.Next() {
if err != nil {
return err
@ -1124,38 +1106,7 @@ func DeleteAncientBlocks(db kv.RwTx, blockTo uint64, blocksDeleteLimit int) erro
if n >= stopAtBlock { // [from, to)
break
}
canonicalHash, err := ReadCanonicalHash(db, n)
if err != nil {
return err
}
isCanonical := bytes.Equal(k[8:], canonicalHash[:])
b, err := ReadBodyForStorageByKey(db, k)
if err != nil {
return err
}
if b == nil {
return fmt.Errorf("DeleteAncientBlocks: block body not found for block %d", n)
}
txIDBytes := make([]byte, 8)
for txID := b.BaseTxId; txID < b.BaseTxId+uint64(b.TxAmount); txID++ {
binary.BigEndian.PutUint64(txIDBytes, txID)
bucket := kv.EthTx
if !isCanonical {
bucket = kv.NonCanonicalTxs
}
if err := db.Delete(bucket, txIDBytes, nil); err != nil {
return err
}
}
if err := db.Delete(kv.Headers, k, nil); err != nil {
return err
}
if err := db.Delete(kv.BlockBody, k, nil); err != nil {
return err
}
if err := db.Delete(kv.Senders, k, nil); err != nil {
if err := delBlock(db, k, true); err != nil {
return err
}
}
@ -1163,65 +1114,125 @@ func DeleteAncientBlocks(db kv.RwTx, blockTo uint64, blocksDeleteLimit int) erro
return nil
}
func DeleteNewBlocks(db kv.RwTx, blockFrom uint64) error {
c, err := db.Cursor(kv.Headers)
func lastKey(tx kv.Tx, table string) ([]byte, error) {
c, err := tx.Cursor(table)
if err != nil {
return nil, err
}
defer c.Close()
k, _, err := c.Last()
if err != nil {
return nil, err
}
return k, nil
}
// delBlock - low-level method to delete 1 block by key
// keeps genesis in db: [1, to)
// doesn't delete Reciepts
// doesn't delete Canonical markers
// doesn't delete TotalDifficulty
// keepSequence - can track decrement sequnces of Canonical and Non-Canonical txs
func delBlock(tx kv.RwTx, k []byte, keepSequence bool) error {
n := binary.BigEndian.Uint64(k)
canonicalHash, err := ReadCanonicalHash(tx, n)
if err != nil {
return err
}
isCanonical := bytes.Equal(k[8:], canonicalHash[:])
b, err := ReadBodyForStorageByKey(tx, k)
if err != nil {
return err
}
if b == nil {
return fmt.Errorf("DeleteAncientBlocks: block body not found for block %d", n)
}
txIDBytes := make([]byte, 8)
for txID := b.BaseTxId; txID < b.BaseTxId+uint64(b.TxAmount); txID++ {
binary.BigEndian.PutUint64(txIDBytes, txID)
bucket := kv.EthTx
if !isCanonical {
bucket = kv.NonCanonicalTxs
}
if !keepSequence {
lastK, err := lastKey(tx, bucket)
if err != nil {
return err
}
seq, err := tx.ReadSequence(bucket)
if err != nil {
return err
}
if lastK != nil && binary.BigEndian.Uint64(lastK) > seq {
return fmt.Errorf("please delete blocks from newest to older. txnId: %d > %d", binary.BigEndian.Uint64(lastK), seq)
}
if seq > b.BaseTxId+uint64(b.TxAmount) {
return fmt.Errorf("please delete blocks from newest to older. seq: %d > %d+%d", seq, b.BaseTxId, uint64(b.TxAmount))
}
if err := ResetSequence(tx, bucket, b.BaseTxId); err != nil {
return err
}
}
if err := tx.Delete(bucket, txIDBytes, nil); err != nil {
return err
}
}
if err := tx.Delete(kv.Headers, k, nil); err != nil {
return err
}
if err := tx.Delete(kv.BlockBody, k, nil); err != nil {
return err
}
if err := tx.Delete(kv.Senders, k, nil); err != nil {
return err
}
if !keepSequence {
bucket := kv.EthTx
if !isCanonical {
bucket = kv.NonCanonicalTxs
}
lastK, err := lastKey(tx, bucket)
if err != nil {
return err
}
seq, err := tx.ReadSequence(bucket)
if err != nil {
return err
}
if lastK != nil && binary.BigEndian.Uint64(lastK) > seq {
return fmt.Errorf("end: please delete blocks from newest to older. txnId: %d > %d", binary.BigEndian.Uint64(lastK), seq)
}
if seq > b.BaseTxId+uint64(b.TxAmount) {
return fmt.Errorf("end: please delete blocks from newest to older. seq: %d > %d+%d", seq, b.BaseTxId, uint64(b.TxAmount))
}
}
return nil
}
// TruncateBlocks - delete block >= blockFrom
func TruncateBlocks(tx kv.RwTx, blockFrom uint64) error {
c, err := tx.Cursor(kv.Headers)
if err != nil {
return err
}
defer c.Close()
for k, _, err := c.Seek(dbutils.EncodeBlockNumber(blockFrom)); k != nil; k, _, err = c.Next() {
if blockFrom < 1 { //protect genesis
blockFrom = 1
}
for k, _, err := c.Last(); k != nil; k, _, err = c.Prev() {
if err != nil {
return err
}
n := binary.BigEndian.Uint64(k)
canonicalHash, err := ReadCanonicalHash(db, n)
if err != nil {
if n < blockFrom { // [from, to)
break
}
if err := delBlock(tx, k, false); err != nil {
return err
}
isCanonical := bytes.Equal(k[8:], canonicalHash[:])
b, err := ReadBodyForStorageByKey(db, k)
if err != nil {
return err
}
if b != nil { // b == nil means body were marked as non-canonical already
txIDBytes := make([]byte, 8)
for txID := b.BaseTxId; txID < b.BaseTxId+uint64(b.TxAmount); txID++ {
binary.BigEndian.PutUint64(txIDBytes, txID)
bucket := kv.EthTx
if !isCanonical {
bucket = kv.NonCanonicalTxs
}
if err := db.Delete(bucket, txIDBytes, nil); err != nil {
return err
}
}
}
if err := db.Delete(kv.Headers, k, nil); err != nil {
return err
}
if err := db.Delete(kv.BlockBody, k, nil); err != nil {
return err
}
if err := db.Delete(kv.Senders, k, nil); err != nil {
return err
}
}
return nil
}
// DeleteBlock removes all block data associated with a hash.
func DeleteBlock(db kv.RwTx, hash common.Hash, number uint64) error {
if err := DeleteReceipts(db, number); err != nil {
return err
}
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
if err := DeleteTd(db, hash, number); err != nil {
return err
}
return nil
}

View File

@ -61,7 +61,7 @@ func TestHeaderStorage(t *testing.T) {
}
}
// Delete the header and verify the execution
DeleteHeader(tx, header.Hash(), header.Number.Uint64())
deleteHeader(tx, header.Hash(), header.Number.Uint64())
if entry := ReadHeader(tx, header.Hash(), header.Number.Uint64()); entry != nil {
t.Fatalf("Deleted header returned: %v", entry)
}
@ -116,7 +116,7 @@ func TestBodyStorage(t *testing.T) {
}
}
// Delete the body and verify the execution
DeleteBody(tx, hash, 0)
deleteBody(tx, hash, 0)
if entry := ReadCanonicalBodyWithTransactions(tx, hash, 0); entry != nil {
t.Fatalf("Deleted body returned: %v", entry)
}
@ -128,6 +128,7 @@ func TestBlockStorage(t *testing.T) {
// Create a test block to move around the database and make sure it's really new
block := types.NewBlockWithHeader(&types.Header{
Number: big.NewInt(1),
Extra: []byte("test block"),
UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyRootHash,
@ -157,15 +158,21 @@ func TestBlockStorage(t *testing.T) {
} else if entry.Hash() != block.Hash() {
t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header())
}
if err := TruncateBlocks(tx, 2); err != nil {
t.Fatal(err)
}
if entry := ReadCanonicalBodyWithTransactions(tx, block.Hash(), block.NumberU64()); entry == nil {
t.Fatalf("Stored body not found")
} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) {
t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body())
}
// Delete the block and verify the execution
if err := DeleteBlock(tx, block.Hash(), block.NumberU64()); err != nil {
t.Fatalf("Could not delete block: %v", err)
if err := TruncateBlocks(tx, block.NumberU64()); err != nil {
t.Fatal(err)
}
//if err := DeleteBlock(tx, block.Hash(), block.NumberU64()); err != nil {
// t.Fatalf("Could not delete block: %v", err)
//}
if entry := ReadBlock(tx, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Deleted block returned: %v", entry)
}
@ -175,6 +182,14 @@ func TestBlockStorage(t *testing.T) {
if entry := ReadCanonicalBodyWithTransactions(tx, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Deleted body returned: %v", entry)
}
// write again and delete it as old one
if err := WriteBlock(tx, block); err != nil {
t.Fatalf("Could not write block: %v", err)
}
if err := DeleteAncientBlocks(tx, 0, 1); err != nil {
t.Fatal(err)
}
}
// Tests that partial block contents don't get reassembled into full blocks.
@ -193,7 +208,7 @@ func TestPartialBlockStorage(t *testing.T) {
if entry := ReadBlock(tx, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Non existent block returned: %v", entry)
}
DeleteHeader(tx, block.Hash(), block.NumberU64())
deleteHeader(tx, block.Hash(), block.NumberU64())
// Store a body and check that it's not recognized as a block
if err := WriteBody(tx, block.Hash(), block.NumberU64(), block.Body()); err != nil {
@ -202,7 +217,7 @@ func TestPartialBlockStorage(t *testing.T) {
if entry := ReadBlock(tx, block.Hash(), block.NumberU64()); entry != nil {
t.Fatalf("Non existent block returned: %v", entry)
}
DeleteBody(tx, block.Hash(), block.NumberU64())
deleteBody(tx, block.Hash(), block.NumberU64())
// Store a header and a body separately and check reassembly
WriteHeader(tx, header)
@ -245,7 +260,7 @@ func TestTdStorage(t *testing.T) {
t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td)
}
// Delete the TD and verify the execution
err = DeleteTd(tx, hash, 0)
err = TruncateTd(tx, 0)
if err != nil {
t.Fatalf("DeleteTd failed: %v", err)
}
@ -286,7 +301,7 @@ func TestCanonicalMappingStorage(t *testing.T) {
t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash)
}
// Delete the TD and verify the execution
err = DeleteCanonicalHash(tx, number)
err = TruncateCanonicalHash(tx, number)
if err != nil {
t.Fatalf("DeleteCanonicalHash failed: %v", err)
}
@ -394,8 +409,8 @@ func TestBlockReceiptStorage(t *testing.T) {
}
}
// Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed)
DeleteHeader(tx, hash, 0)
DeleteBody(tx, hash, 0)
deleteHeader(tx, hash, 0)
deleteBody(tx, hash, 0)
b, senders, err = ReadBlockWithSenders(tx, hash, 0)
require.NoError(err)
require.Nil(b)
@ -409,7 +424,7 @@ func TestBlockReceiptStorage(t *testing.T) {
WriteHeader(tx, header)
// Sanity check that body alone without the receipt is a full purge
require.NoError(WriteBody(tx, hash, 0, body))
require.NoError(DeleteReceipts(tx, 0))
require.NoError(TruncateReceipts(tx, 0))
b, senders, err = ReadBlockWithSenders(tx, hash, 0)
require.NoError(err)
require.NotNil(b)

View File

@ -519,7 +519,7 @@ func unwindExecutionStage(u *UnwindState, s *StageState, tx kv.RwTx, quit <-chan
return err
}
if err := rawdb.DeleteNewerReceipts(tx, u.UnwindPoint+1); err != nil {
if err := rawdb.TruncateReceipts(tx, u.UnwindPoint+1); err != nil {
return fmt.Errorf("walking receipts: %w", err)
}
if err := rawdb.DeleteNewerEpochs(tx, u.UnwindPoint+1); err != nil {

View File

@ -23,7 +23,6 @@ import (
"github.com/ledgerwatch/erigon/common/dbutils"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
"github.com/ledgerwatch/erigon/ethdb/privateapi"
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/rlp"
@ -871,11 +870,6 @@ func HeadersUnwind(u *UnwindState, s *StageState, tx kv.RwTx, cfg HeadersCfg, te
defer tx.Rollback()
}
// Delete canonical hashes that are being unwound
var headerProgress uint64
headerProgress, err = stages.GetStageProgress(tx, stages.Headers)
if err != nil {
return err
}
badBlock := u.BadBlock != (common.Hash{})
if badBlock {
cfg.hd.ReportBadHeader(u.BadBlock)
@ -899,10 +893,8 @@ func HeadersUnwind(u *UnwindState, s *StageState, tx kv.RwTx, cfg HeadersCfg, te
return fmt.Errorf("iterate over headers to mark bad headers: %w", err)
}
}
for blockHeight := headerProgress; blockHeight > u.UnwindPoint; blockHeight-- {
if err = rawdb.DeleteCanonicalHash(tx, blockHeight); err != nil {
return err
}
if err := rawdb.TruncateCanonicalHash(tx, u.UnwindPoint+1); err != nil {
return err
}
if badBlock {
var maxTd big.Int

View File

@ -41,8 +41,8 @@ func TestTxsBeginEnd(t *testing.T) {
return err
}
err = rawdb.TruncateCanonicalHash(tx, 7)
for i := uint64(7); i < 10; i++ {
err = rawdb.DeleteCanonicalHash(tx, i)
require.NoError(err)
hash := common.Hash{0xa, byte(i)}
err = writeRawBodyDeprecated(tx, hash, i, b)

View File

@ -17,3 +17,21 @@ const (
MumbaiChainName = "mumbai"
BorMainnetChainName = "bor-mainnet"
)
var All = []string{
MainnetChainName,
SepoliaChainName,
RopstenChainName,
RinkebyChainName,
GoerliChainName,
KilnDevnetChainName,
//DevChainName,
ErigonMineName,
SokolChainName,
FermionChainName,
BSCChainName,
ChapelChainName,
//RialtoChainName,
MumbaiChainName,
BorMainnetChainName,
}