mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 03:30:37 +00:00
borheimdall: add tests for validator set and selected proposers validation (#9089)
Adds unit tests for: - Bor Heimdall Stage - `checkHeaderExtraData` - at end of each sprint verifies that the validators in the header extra data matches the selected proposers from the heimdall span - 1 test for selected proposers length mismatch - 1 test for selected proposers bytes mismatch - BorHeimdall Stage - `persistValidatorSets` - verifies that each header is created by a validator in the validator set - in such situation we set the unwind point
This commit is contained in:
parent
ab27531fa7
commit
67704871c0
@ -26,7 +26,6 @@ import (
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon-lib/common/length"
|
||||
"github.com/ledgerwatch/erigon-lib/kv"
|
||||
|
||||
"github.com/ledgerwatch/erigon/common"
|
||||
"github.com/ledgerwatch/erigon/consensus"
|
||||
"github.com/ledgerwatch/erigon/consensus/bor/finality"
|
||||
@ -112,7 +111,7 @@ var (
|
||||
|
||||
// errInvalidSpanValidators is returned if a block contains an
|
||||
// invalid list of validators (i.e. non divisible by 40 bytes).
|
||||
ErrInvalidSpanValidators = errors.New("invalid validator list on sprint end block")
|
||||
errInvalidSpanValidators = errors.New("invalid validator list on sprint end block")
|
||||
|
||||
// errInvalidMixDigest is returned if a block's mix digest is non-zero.
|
||||
errInvalidMixDigest = errors.New("non-zero mix digest")
|
||||
@ -543,7 +542,7 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
|
||||
}
|
||||
|
||||
if isSprintEnd && signersBytes%validatorHeaderBytesLength != 0 {
|
||||
return ErrInvalidSpanValidators
|
||||
return errInvalidSpanValidators
|
||||
}
|
||||
|
||||
// Ensure that the mix digest is zero as we don't have fork protection currently
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
@ -45,6 +46,11 @@ const (
|
||||
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||
)
|
||||
|
||||
var (
|
||||
ErrHeaderValidatorsLengthMismatch = errors.New("header validators length mismatch")
|
||||
ErrHeaderValidatorsBytesMismatch = errors.New("header validators bytes mismatch")
|
||||
)
|
||||
|
||||
type BorHeimdallCfg struct {
|
||||
db kv.RwDB
|
||||
snapDb kv.RwDB // Database to store and retrieve snapshot checkpoints
|
||||
@ -280,6 +286,14 @@ func BorHeimdallForward(
|
||||
return fmt.Errorf("verification failed for header %d: %x", blockNum, header.Hash())
|
||||
}
|
||||
}
|
||||
|
||||
sprintLength := cfg.chainConfig.Bor.CalculateSprint(blockNum)
|
||||
spanID := bor.SpanIDAt(blockNum)
|
||||
if (spanID > 0) && ((blockNum+1)%sprintLength == 0) {
|
||||
if err = checkHeaderExtraData(u, ctx, chain, blockNum, header, cfg.chainConfig.Bor); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if blockNum > 0 && blockNum%cfg.chainConfig.Bor.CalculateSprint(blockNum) == 0 {
|
||||
@ -312,16 +326,6 @@ func BorHeimdallForward(
|
||||
return fmt.Errorf("can't persist validator sets: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !mine {
|
||||
sprintLength := cfg.chainConfig.Bor.CalculateSprint(blockNum)
|
||||
spanID := bor.SpanIDAt(blockNum)
|
||||
if (spanID > 0) && ((blockNum+1)%sprintLength == 0) {
|
||||
if err = checkHeaderExtraData(u, ctx, chain, blockNum, header, cfg.chainConfig.Bor); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.loopBreakCheck != nil && cfg.loopBreakCheck(int(blockNum-lastBlockNum)) {
|
||||
@ -372,12 +376,12 @@ func checkHeaderExtraData(
|
||||
}
|
||||
|
||||
if len(producerSet) != len(headerVals) {
|
||||
return bor.ErrInvalidSpanValidators
|
||||
return ErrHeaderValidatorsLengthMismatch
|
||||
}
|
||||
|
||||
for i, val := range producerSet {
|
||||
if !bytes.Equal(val.HeaderBytes(), headerVals[i].HeaderBytes()) {
|
||||
return bor.ErrInvalidSpanValidators
|
||||
return ErrHeaderValidatorsBytesMismatch
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -1,26 +1,35 @@
|
||||
package stagedsync_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ledgerwatch/erigon/consensus/bor"
|
||||
"github.com/ledgerwatch/erigon/consensus/bor/valset"
|
||||
"github.com/ledgerwatch/erigon/core"
|
||||
"github.com/ledgerwatch/erigon/core/types"
|
||||
"github.com/ledgerwatch/erigon/crypto"
|
||||
"github.com/ledgerwatch/erigon/eth/stagedsync"
|
||||
"github.com/ledgerwatch/erigon/eth/stagedsync/stagedsynctest"
|
||||
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
|
||||
"github.com/ledgerwatch/erigon/eth/stagedsync/test"
|
||||
"github.com/ledgerwatch/erigon/turbo/testlog"
|
||||
)
|
||||
|
||||
func TestBorHeimdallForwardPersistsSpans(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
logger := testlog.Logger(t, log.LvlInfo)
|
||||
numBlocks := 6640
|
||||
testHarness := test.InitHarness(ctx, t, logger, test.HarnessCfg{
|
||||
ChainConfig: test.BorDevnetChainConfigWithNoBlockSealDelays(),
|
||||
testHarness := stagedsynctest.InitHarness(ctx, t, stagedsynctest.HarnessCfg{
|
||||
ChainConfig: stagedsynctest.BorDevnetChainConfigWithNoBlockSealDelays(),
|
||||
GenerateChainNumBlocks: numBlocks,
|
||||
LogLvl: log.LvlInfo,
|
||||
})
|
||||
// pretend-update previous stage progress
|
||||
testHarness.SaveStageProgress(ctx, t, stages.Headers, uint64(numBlocks))
|
||||
@ -29,7 +38,7 @@ func TestBorHeimdallForwardPersistsSpans(t *testing.T) {
|
||||
testHarness.RunStageForward(t, stages.BorHeimdall)
|
||||
|
||||
// asserts
|
||||
spans, err := testHarness.ReadSpansFromDb(ctx)
|
||||
spans, err := testHarness.ReadSpansFromDB(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, spans, 3)
|
||||
require.Equal(t, uint64(0), spans[0].ID)
|
||||
@ -47,11 +56,11 @@ func TestBorHeimdallForwardPersistsStateSyncEvents(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
logger := testlog.Logger(t, log.LvlInfo)
|
||||
numBlocks := 96
|
||||
testHarness := test.InitHarness(ctx, t, logger, test.HarnessCfg{
|
||||
ChainConfig: test.BorDevnetChainConfigWithNoBlockSealDelays(),
|
||||
testHarness := stagedsynctest.InitHarness(ctx, t, stagedsynctest.HarnessCfg{
|
||||
ChainConfig: stagedsynctest.BorDevnetChainConfigWithNoBlockSealDelays(),
|
||||
GenerateChainNumBlocks: numBlocks,
|
||||
LogLvl: log.LvlInfo,
|
||||
})
|
||||
// pretend-update previous stage progress
|
||||
testHarness.SaveStageProgress(ctx, t, stages.Headers, uint64(numBlocks))
|
||||
@ -61,11 +70,11 @@ func TestBorHeimdallForwardPersistsStateSyncEvents(t *testing.T) {
|
||||
|
||||
// asserts
|
||||
// 1 event per sprint expected
|
||||
events, err := testHarness.ReadStateSyncEventsFromDb(ctx)
|
||||
events, err := testHarness.ReadStateSyncEventsFromDB(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, events, 6)
|
||||
|
||||
firstEventNumPerBlock, err := testHarness.ReadFirstStateSyncEventNumPerBlockFromDb(ctx)
|
||||
firstEventNumPerBlock, err := testHarness.ReadFirstStateSyncEventNumPerBlockFromDB(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, firstEventNumPerBlock, 6)
|
||||
require.Equal(t, uint64(1), firstEventNumPerBlock[16])
|
||||
@ -75,3 +84,99 @@ func TestBorHeimdallForwardPersistsStateSyncEvents(t *testing.T) {
|
||||
require.Equal(t, uint64(5), firstEventNumPerBlock[80])
|
||||
require.Equal(t, uint64(6), firstEventNumPerBlock[96])
|
||||
}
|
||||
|
||||
func TestBorHeimdallForwardErrHeaderValidatorsLengthMismatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
numBlocks := 271
|
||||
validatorKey1, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
validatorKey2, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
testHarness := stagedsynctest.InitHarness(ctx, t, stagedsynctest.HarnessCfg{
|
||||
ChainConfig: stagedsynctest.BorDevnetChainConfigWithNoBlockSealDelays(),
|
||||
GenerateChainNumBlocks: numBlocks,
|
||||
LogLvl: log.LvlInfo,
|
||||
HeimdallProducersOverride: map[uint64][]valset.Validator{
|
||||
1: {
|
||||
*valset.NewValidator(crypto.PubkeyToAddress(validatorKey1.PublicKey), 1),
|
||||
*valset.NewValidator(crypto.PubkeyToAddress(validatorKey2.PublicKey), 1),
|
||||
},
|
||||
},
|
||||
})
|
||||
// pretend-update previous stage progress
|
||||
testHarness.SaveStageProgress(ctx, t, stages.Headers, uint64(numBlocks))
|
||||
|
||||
// run stage under test
|
||||
testHarness.RunStageForwardWithErrorIs(t, stages.BorHeimdall, stagedsync.ErrHeaderValidatorsLengthMismatch)
|
||||
}
|
||||
|
||||
func TestBorHeimdallForwardErrHeaderValidatorsBytesMismatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
numBlocks := 271
|
||||
validatorKey1, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
testHarness := stagedsynctest.InitHarness(ctx, t, stagedsynctest.HarnessCfg{
|
||||
ChainConfig: stagedsynctest.BorDevnetChainConfigWithNoBlockSealDelays(),
|
||||
GenerateChainNumBlocks: numBlocks,
|
||||
LogLvl: log.LvlInfo,
|
||||
HeimdallProducersOverride: map[uint64][]valset.Validator{
|
||||
1: {
|
||||
*valset.NewValidator(crypto.PubkeyToAddress(validatorKey1.PublicKey), 1),
|
||||
},
|
||||
},
|
||||
})
|
||||
// pretend-update previous stage progress
|
||||
testHarness.SaveStageProgress(ctx, t, stages.Headers, uint64(numBlocks))
|
||||
|
||||
// run stage under test
|
||||
testHarness.RunStageForwardWithErrorIs(t, stages.BorHeimdall, stagedsync.ErrHeaderValidatorsBytesMismatch)
|
||||
}
|
||||
|
||||
func TestBorHeimdallForwardDetectsUnauthorizedSignerError(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
numBlocks := 312
|
||||
chainConfig := stagedsynctest.BorDevnetChainConfigWithNoBlockSealDelays()
|
||||
testHarness := stagedsynctest.InitHarness(ctx, t, stagedsynctest.HarnessCfg{
|
||||
ChainConfig: chainConfig,
|
||||
GenerateChainNumBlocks: numBlocks,
|
||||
LogLvl: log.LvlInfo,
|
||||
})
|
||||
|
||||
// prepare invalid header and insert it in the db
|
||||
latestHeader, err := testHarness.ReadHeaderByNumber(ctx, uint64(numBlocks))
|
||||
require.NoError(t, err)
|
||||
gasLimit := uint64(15500)
|
||||
invalidHeader := core.MakeEmptyHeader(latestHeader, chainConfig, uint64(time.Now().Unix()), &gasLimit)
|
||||
invalidHeader.Number = new(big.Int).Add(latestHeader.Number, big.NewInt(1))
|
||||
invalidHeader.Extra = bytes.Repeat([]byte{0x00}, types.ExtraVanityLength+types.ExtraSealLength)
|
||||
validatorKey1, err := crypto.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
sighash, err := crypto.Sign(crypto.Keccak256(bor.BorRLP(invalidHeader, chainConfig.Bor)), validatorKey1)
|
||||
require.NoError(t, err)
|
||||
copy(invalidHeader.Extra[len(invalidHeader.Extra)-types.ExtraSealLength:], sighash)
|
||||
testHarness.SaveHeader(ctx, t, invalidHeader)
|
||||
// pretend-update previous stage progress
|
||||
testHarness.SaveStageProgress(ctx, t, stages.Headers, invalidHeader.Number.Uint64())
|
||||
require.Equal(t, uint64(numBlocks+1), testHarness.GetStageProgress(ctx, t, stages.Headers))
|
||||
require.Equal(t, uint64(0), testHarness.GetStageProgress(ctx, t, stages.BorHeimdall))
|
||||
|
||||
// run stage under test
|
||||
testHarness.RunStageForward(t, stages.BorHeimdall)
|
||||
|
||||
// asserts
|
||||
require.Equal(t, uint64(numBlocks+1), testHarness.GetStageProgress(ctx, t, stages.BorHeimdall))
|
||||
require.Equal(t, invalidHeader.Number.Uint64()-1, testHarness.StateSyncUnwindPoint())
|
||||
unwindReason := testHarness.StateSyncUnwindReason()
|
||||
require.Equal(t, invalidHeader.Hash(), *unwindReason.Block)
|
||||
var unauthorizedSignerErr *bor.UnauthorizedSignerError
|
||||
ok := errors.As(unwindReason.Err, &unauthorizedSignerErr)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, invalidHeader.Number.Uint64(), unauthorizedSignerErr.Number)
|
||||
require.Equal(t, crypto.PubkeyToAddress(validatorKey1.PublicKey).Bytes(), unauthorizedSignerErr.Signer)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package test
|
||||
package stagedsynctest
|
||||
|
||||
import (
|
||||
"github.com/ledgerwatch/erigon-lib/chain"
|
@ -1,10 +1,11 @@
|
||||
package test
|
||||
package stagedsynctest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
@ -12,8 +13,6 @@ import (
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/ledgerwatch/erigon/turbo/services"
|
||||
"github.com/ledgerwatch/erigon/turbo/stages/mock"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -37,19 +36,23 @@ import (
|
||||
"github.com/ledgerwatch/erigon/eth/ethconfig"
|
||||
"github.com/ledgerwatch/erigon/eth/stagedsync"
|
||||
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
|
||||
"github.com/ledgerwatch/erigon/turbo/services"
|
||||
"github.com/ledgerwatch/erigon/turbo/stages/mock"
|
||||
"github.com/ledgerwatch/erigon/turbo/testlog"
|
||||
)
|
||||
|
||||
func InitHarness(ctx context.Context, t *testing.T, logger log.Logger, cfg HarnessCfg) Harness {
|
||||
func InitHarness(ctx context.Context, t *testing.T, cfg HarnessCfg) Harness {
|
||||
logger := testlog.Logger(t, cfg.LogLvl)
|
||||
genesisInit := createGenesisInitData(t, cfg.ChainConfig)
|
||||
m := mock.MockWithGenesis(t, genesisInit.genesis, genesisInit.genesisAllocPrivateKey, false)
|
||||
chainDataDb := m.DB
|
||||
chainDataDB := m.DB
|
||||
blockReader := m.BlockReader
|
||||
borConsensusDb := memdb.NewTestDB(t)
|
||||
borConsensusDB := memdb.NewTestDB(t)
|
||||
ctrl := gomock.NewController(t)
|
||||
heimdallClient := heimdallmock.NewMockIHeimdallClient(ctrl)
|
||||
bhCfg := stagedsync.StageBorHeimdallCfg(
|
||||
chainDataDb,
|
||||
borConsensusDb,
|
||||
chainDataDB,
|
||||
borConsensusDB,
|
||||
stagedsync.NewProposingState(ðconfig.Defaults.Miner),
|
||||
*cfg.ChainConfig,
|
||||
heimdallClient,
|
||||
@ -83,20 +86,21 @@ func InitHarness(ctx context.Context, t *testing.T, logger log.Logger, cfg Harne
|
||||
require.NoError(t, err)
|
||||
validatorAddress := crypto.PubkeyToAddress(validatorKey.PublicKey)
|
||||
h := Harness{
|
||||
logger: logger,
|
||||
chainDataDb: chainDataDb,
|
||||
borConsensusDb: borConsensusDb,
|
||||
chainConfig: cfg.ChainConfig,
|
||||
blockReader: blockReader,
|
||||
stateSyncStages: stateSyncStages,
|
||||
stateSync: stateSync,
|
||||
bhCfg: bhCfg,
|
||||
heimdallClient: heimdallClient,
|
||||
sealedHeaders: make(map[uint64]*types.Header),
|
||||
borSpanner: bormock.NewMockSpanner(ctrl),
|
||||
validatorAddress: validatorAddress,
|
||||
validatorKey: validatorKey,
|
||||
genesisInitData: genesisInit,
|
||||
logger: logger,
|
||||
chainDataDB: chainDataDB,
|
||||
borConsensusDB: borConsensusDB,
|
||||
chainConfig: cfg.ChainConfig,
|
||||
blockReader: blockReader,
|
||||
stateSyncStages: stateSyncStages,
|
||||
stateSync: stateSync,
|
||||
bhCfg: bhCfg,
|
||||
heimdallClient: heimdallClient,
|
||||
heimdallProducersOverride: cfg.GetOrCreateDefaultHeimdallProducersOverride(),
|
||||
sealedHeaders: make(map[uint64]*types.Header),
|
||||
borSpanner: bormock.NewMockSpanner(ctrl),
|
||||
validatorAddress: validatorAddress,
|
||||
validatorKey: validatorKey,
|
||||
genesisInitData: genesisInit,
|
||||
}
|
||||
|
||||
if cfg.ChainConfig.Bor != nil {
|
||||
@ -118,14 +122,24 @@ type genesisInitData struct {
|
||||
}
|
||||
|
||||
type HarnessCfg struct {
|
||||
ChainConfig *chain.Config
|
||||
GenerateChainNumBlocks int
|
||||
ChainConfig *chain.Config
|
||||
GenerateChainNumBlocks int
|
||||
LogLvl log.Lvl
|
||||
HeimdallProducersOverride map[uint64][]valset.Validator
|
||||
}
|
||||
|
||||
func (hc *HarnessCfg) GetOrCreateDefaultHeimdallProducersOverride() map[uint64][]valset.Validator {
|
||||
if hc.HeimdallProducersOverride == nil {
|
||||
hc.HeimdallProducersOverride = map[uint64][]valset.Validator{}
|
||||
}
|
||||
|
||||
return hc.HeimdallProducersOverride
|
||||
}
|
||||
|
||||
type Harness struct {
|
||||
logger log.Logger
|
||||
chainDataDb kv.RwDB
|
||||
borConsensusDb kv.RwDB
|
||||
chainDataDB kv.RwDB
|
||||
borConsensusDB kv.RwDB
|
||||
chainConfig *chain.Config
|
||||
blockReader services.BlockReader
|
||||
stateSyncStages []*stagedsync.Stage
|
||||
@ -133,8 +147,9 @@ type Harness struct {
|
||||
bhCfg stagedsync.BorHeimdallCfg
|
||||
heimdallClient *heimdallmock.MockIHeimdallClient
|
||||
heimdallNextMockSpan *span.HeimdallSpan
|
||||
heimdallLastEventId uint64
|
||||
heimdallLastEventID uint64
|
||||
heimdallLastEventHeaderNum uint64
|
||||
heimdallProducersOverride map[uint64][]valset.Validator // spanID -> selected producers override
|
||||
sealedHeaders map[uint64]*types.Header
|
||||
borSpanner *bormock.MockSpanner
|
||||
validatorAddress libcommon.Address
|
||||
@ -142,33 +157,63 @@ type Harness struct {
|
||||
genesisInitData *genesisInitData
|
||||
}
|
||||
|
||||
func (h *Harness) SaveStageProgress(ctx context.Context, t *testing.T, stageId stages.SyncStage, progress uint64) {
|
||||
rwTx, err := h.chainDataDb.BeginRw(ctx)
|
||||
func (h *Harness) Logger() log.Logger {
|
||||
return h.logger
|
||||
}
|
||||
|
||||
func (h *Harness) SaveStageProgress(ctx context.Context, t *testing.T, stageID stages.SyncStage, progress uint64) {
|
||||
rwTx, err := h.chainDataDB.BeginRw(ctx)
|
||||
require.NoError(t, err)
|
||||
defer rwTx.Rollback()
|
||||
|
||||
err = stages.SaveStageProgress(rwTx, stageId, progress)
|
||||
err = stages.SaveStageProgress(rwTx, stageID, progress)
|
||||
require.NoError(t, err)
|
||||
err = rwTx.Commit()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func (h *Harness) GetStageProgress(ctx context.Context, t *testing.T, stageID stages.SyncStage) uint64 {
|
||||
roTx, err := h.chainDataDB.BeginRo(ctx)
|
||||
require.NoError(t, err)
|
||||
defer roTx.Rollback()
|
||||
|
||||
progress, err := stages.GetStageProgress(roTx, stageID)
|
||||
require.NoError(t, err)
|
||||
return progress
|
||||
}
|
||||
|
||||
func (h *Harness) StateSyncUnwindPoint() uint64 {
|
||||
return h.stateSync.UnwindPoint()
|
||||
}
|
||||
|
||||
func (h *Harness) StateSyncUnwindReason() stagedsync.UnwindReason {
|
||||
return h.stateSync.UnwindReason()
|
||||
}
|
||||
|
||||
func (h *Harness) RunStageForward(t *testing.T, id stages.SyncStage) {
|
||||
h.RunStageForwardWithErrorIs(t, id, nil)
|
||||
}
|
||||
|
||||
func (h *Harness) RunStageForwardWithErrorIs(t *testing.T, id stages.SyncStage, wantErr error) {
|
||||
err := h.RunStageForwardWithReturnError(t, id)
|
||||
require.ErrorIs(t, err, wantErr)
|
||||
}
|
||||
|
||||
func (h *Harness) RunStageForwardWithReturnError(t *testing.T, id stages.SyncStage) error {
|
||||
err := h.stateSync.SetCurrentStage(id)
|
||||
require.NoError(t, err)
|
||||
|
||||
stage, found := h.findStateSyncStageById(id)
|
||||
stage, found := h.findStateSyncStageByID(id)
|
||||
require.True(t, found)
|
||||
|
||||
stageState, err := h.stateSync.StageState(id, nil, h.chainDataDb)
|
||||
stageState, err := h.stateSync.StageState(id, nil, h.chainDataDB)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = stage.Forward(true, false, stageState, h.stateSync, nil, h.logger)
|
||||
require.NoError(t, err)
|
||||
return stage.Forward(true, false, stageState, h.stateSync, nil, h.logger)
|
||||
}
|
||||
|
||||
func (h *Harness) ReadSpansFromDb(ctx context.Context) (spans []*span.HeimdallSpan, err error) {
|
||||
err = h.chainDataDb.View(ctx, func(tx kv.Tx) error {
|
||||
func (h *Harness) ReadSpansFromDB(ctx context.Context) (spans []*span.HeimdallSpan, err error) {
|
||||
err = h.chainDataDB.View(ctx, func(tx kv.Tx) error {
|
||||
spanIter, err := tx.Range(kv.BorSpans, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -202,8 +247,8 @@ func (h *Harness) ReadSpansFromDb(ctx context.Context) (spans []*span.HeimdallSp
|
||||
return spans, nil
|
||||
}
|
||||
|
||||
func (h *Harness) ReadStateSyncEventsFromDb(ctx context.Context) (eventIds []uint64, err error) {
|
||||
err = h.chainDataDb.View(ctx, func(tx kv.Tx) error {
|
||||
func (h *Harness) ReadStateSyncEventsFromDB(ctx context.Context) (eventIDs []uint64, err error) {
|
||||
err = h.chainDataDB.View(ctx, func(tx kv.Tx) error {
|
||||
eventsIter, err := tx.Range(kv.BorEvents, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -215,7 +260,7 @@ func (h *Harness) ReadStateSyncEventsFromDb(ctx context.Context) (eventIds []uin
|
||||
return err
|
||||
}
|
||||
|
||||
eventIds = append(eventIds, binary.BigEndian.Uint64(keyBytes))
|
||||
eventIDs = append(eventIDs, binary.BigEndian.Uint64(keyBytes))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -224,12 +269,12 @@ func (h *Harness) ReadStateSyncEventsFromDb(ctx context.Context) (eventIds []uin
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return eventIds, nil
|
||||
return eventIDs, nil
|
||||
}
|
||||
|
||||
func (h *Harness) ReadFirstStateSyncEventNumPerBlockFromDb(ctx context.Context) (nums map[uint64]uint64, err error) {
|
||||
func (h *Harness) ReadFirstStateSyncEventNumPerBlockFromDB(ctx context.Context) (nums map[uint64]uint64, err error) {
|
||||
nums = map[uint64]uint64{}
|
||||
err = h.chainDataDb.View(ctx, func(tx kv.Tx) error {
|
||||
err = h.chainDataDB.View(ctx, func(tx kv.Tx) error {
|
||||
eventNumsIter, err := tx.Range(kv.BorEventNums, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -255,6 +300,19 @@ func (h *Harness) ReadFirstStateSyncEventNumPerBlockFromDb(ctx context.Context)
|
||||
return nums, nil
|
||||
}
|
||||
|
||||
func (h *Harness) ReadHeaderByNumber(ctx context.Context, number uint64) (header *types.Header, err error) {
|
||||
err = h.chainDataDB.View(ctx, func(tx kv.Tx) error {
|
||||
header = rawdb.ReadHeaderByNumber(tx, number)
|
||||
if header == nil {
|
||||
return errors.New("header not found by harness")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func createGenesisInitData(t *testing.T, chainConfig *chain.Config) *genesisInitData {
|
||||
t.Helper()
|
||||
accountPrivateKey, err := crypto.GenerateKey()
|
||||
@ -283,7 +341,7 @@ func createGenesisInitData(t *testing.T, chainConfig *chain.Config) *genesisInit
|
||||
func (h *Harness) generateChain(ctx context.Context, t *testing.T, ctrl *gomock.Controller, cfg HarnessCfg) {
|
||||
consensusEngine := h.consensusEngine(t, cfg)
|
||||
var parentBlock *types.Block
|
||||
err := h.chainDataDb.View(ctx, func(tx kv.Tx) (err error) {
|
||||
err := h.chainDataDB.View(ctx, func(tx kv.Tx) (err error) {
|
||||
parentBlock, err = h.blockReader.BlockByNumber(ctx, tx, 0)
|
||||
return err
|
||||
})
|
||||
@ -295,7 +353,7 @@ func (h *Harness) generateChain(ctx context.Context, t *testing.T, ctrl *gomock.
|
||||
h.chainConfig,
|
||||
parentBlock,
|
||||
consensusEngine,
|
||||
h.chainDataDb,
|
||||
h.chainDataDB,
|
||||
cfg.GenerateChainNumBlocks,
|
||||
func(i int, gen *core.BlockGen) {
|
||||
// seal parent block first so that we can Prepare the current header
|
||||
@ -310,13 +368,13 @@ func (h *Harness) generateChain(ctx context.Context, t *testing.T, ctrl *gomock.
|
||||
}
|
||||
|
||||
h.logger.Info("Adding 1 mock tx to block", "blockNum", gen.GetHeader().Number)
|
||||
chainId := uint256.Int{}
|
||||
overflow := chainId.SetFromBig(h.chainConfig.ChainID)
|
||||
chainID := uint256.Int{}
|
||||
overflow := chainID.SetFromBig(h.chainConfig.ChainID)
|
||||
require.False(t, overflow)
|
||||
from := h.genesisInitData.fundedAddresses[0]
|
||||
tx, err := types.SignTx(
|
||||
types.NewEIP1559Transaction(
|
||||
chainId,
|
||||
chainID,
|
||||
gen.TxNonce(from),
|
||||
from, // send to itself
|
||||
new(uint256.Int),
|
||||
@ -366,7 +424,7 @@ func (h *Harness) consensusEngine(t *testing.T, cfg HarnessCfg) consensus.Engine
|
||||
|
||||
borConsensusEng := bor.New(
|
||||
h.chainConfig,
|
||||
h.borConsensusDb,
|
||||
h.borConsensusDB,
|
||||
nil,
|
||||
h.borSpanner,
|
||||
h.heimdallClient,
|
||||
@ -385,8 +443,12 @@ func (h *Harness) consensusEngine(t *testing.T, cfg HarnessCfg) consensus.Engine
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Harness) SaveHeader(ctx context.Context, t *testing.T, header *types.Header) {
|
||||
h.saveHeaders(ctx, t, []*types.Header{header})
|
||||
}
|
||||
|
||||
func (h *Harness) saveHeaders(ctx context.Context, t *testing.T, headers []*types.Header) {
|
||||
rwTx, err := h.chainDataDb.BeginRw(ctx)
|
||||
rwTx, err := h.chainDataDB.BeginRw(ctx)
|
||||
require.NoError(t, err)
|
||||
defer rwTx.Rollback()
|
||||
|
||||
@ -493,6 +555,10 @@ func (h *Harness) mockHeimdallClient() {
|
||||
SelectedProducers: res.SelectedProducers,
|
||||
}
|
||||
|
||||
if selectedProducers, ok := h.heimdallProducersOverride[res.ID]; ok {
|
||||
res.SelectedProducers = selectedProducers
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}).
|
||||
AnyTimes()
|
||||
@ -501,12 +567,12 @@ func (h *Harness) mockHeimdallClient() {
|
||||
EXPECT().
|
||||
StateSyncEvents(gomock.Any(), gomock.Any(), gomock.Any()).
|
||||
DoAndReturn(func(_ context.Context, _ uint64, _ int64) ([]*clerk.EventRecordWithTime, error) {
|
||||
h.heimdallLastEventId++
|
||||
h.heimdallLastEventID++
|
||||
h.heimdallLastEventHeaderNum += h.chainConfig.Bor.CalculateSprint(h.heimdallLastEventHeaderNum)
|
||||
stateSyncDelay := h.chainConfig.Bor.CalculateStateSyncDelay(h.heimdallLastEventHeaderNum)
|
||||
newEvent := clerk.EventRecordWithTime{
|
||||
EventRecord: clerk.EventRecord{
|
||||
ID: h.heimdallLastEventId,
|
||||
ID: h.heimdallLastEventID,
|
||||
ChainID: h.chainConfig.ChainID.String(),
|
||||
},
|
||||
Time: time.Unix(int64(h.sealedHeaders[h.heimdallLastEventHeaderNum].Time-stateSyncDelay-1), 0),
|
||||
@ -518,7 +584,7 @@ func (h *Harness) mockHeimdallClient() {
|
||||
AnyTimes()
|
||||
}
|
||||
|
||||
func (h *Harness) findStateSyncStageById(id stages.SyncStage) (*stagedsync.Stage, bool) {
|
||||
func (h *Harness) findStateSyncStageByID(id stages.SyncStage) (*stagedsync.Stage, bool) {
|
||||
for _, s := range h.stateSyncStages {
|
||||
if s.ID == id {
|
||||
return s, true
|
@ -5,11 +5,11 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon-lib/common/dbg"
|
||||
"github.com/ledgerwatch/erigon-lib/kv"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
|
||||
"github.com/ledgerwatch/erigon/eth/ethconfig"
|
||||
"github.com/ledgerwatch/erigon/eth/stagedsync/stages"
|
||||
)
|
||||
@ -37,8 +37,21 @@ type Timing struct {
|
||||
took time.Duration
|
||||
}
|
||||
|
||||
func (s *Sync) Len() int { return len(s.stages) }
|
||||
func (s *Sync) PrevUnwindPoint() *uint64 { return s.prevUnwindPoint }
|
||||
func (s *Sync) Len() int {
|
||||
return len(s.stages)
|
||||
}
|
||||
|
||||
func (s *Sync) UnwindPoint() uint64 {
|
||||
return *s.unwindPoint
|
||||
}
|
||||
|
||||
func (s *Sync) UnwindReason() UnwindReason {
|
||||
return s.unwindReason
|
||||
}
|
||||
|
||||
func (s *Sync) PrevUnwindPoint() *uint64 {
|
||||
return s.prevUnwindPoint
|
||||
}
|
||||
|
||||
func (s *Sync) NewUnwindState(id stages.SyncStage, unwindPoint, currentProgress uint64) *UnwindState {
|
||||
return &UnwindState{id, unwindPoint, currentProgress, UnwindReason{nil, nil}, s}
|
||||
|
Loading…
Reference in New Issue
Block a user