package chaindump_test import ( "errors" "testing" "github.com/nspcc-dev/neo-go/internal/basicchain" "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/chaindump" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/neotest" "github.com/nspcc-dev/neo-go/pkg/neotest/chain" "github.com/stretchr/testify/require" ) func TestBlockchain_DumpAndRestore(t *testing.T) { t.Run("no state root", func(t *testing.T) { testDumpAndRestore(t, func(c *config.Blockchain) { c.StateRootInHeader = false c.P2PSigExtensions = true }, nil) }) t.Run("with state root", func(t *testing.T) { testDumpAndRestore(t, func(c *config.Blockchain) { c.StateRootInHeader = true c.P2PSigExtensions = true }, nil) }) t.Run("remove untraceable", func(t *testing.T) { // Dump can only be created if all blocks and transactions are present. testDumpAndRestore(t, func(c *config.Blockchain) { c.P2PSigExtensions = true }, func(c *config.Blockchain) { c.MaxTraceableBlocks = 2 c.Ledger.RemoveUntraceableBlocks = true c.P2PSigExtensions = true }) }) } func testDumpAndRestore(t *testing.T, dumpF, restoreF func(c *config.Blockchain)) { if restoreF == nil { restoreF = dumpF } bc, validators, committee := chain.NewMultiWithCustomConfig(t, dumpF) e := neotest.NewExecutor(t, bc, validators, committee) basicchain.Init(t, "../../../", e) require.True(t, bc.BlockHeight() > 5) // ensure that test is valid w := io.NewBufBinWriter() require.NoError(t, chaindump.Dump(bc, w.BinWriter, 0, bc.BlockHeight()+1)) require.NoError(t, w.Err) buf := w.Bytes() t.Run("invalid start", func(t *testing.T) { bc2, _, _ := chain.NewMultiWithCustomConfig(t, restoreF) r := io.NewBinReaderFromBuf(buf) require.Error(t, chaindump.Restore(bc2, r, 2, 1, nil)) }) t.Run("good", func(t *testing.T) { bc2, _, _ := chain.NewMultiWithCustomConfig(t, dumpF) r := io.NewBinReaderFromBuf(buf) require.NoError(t, chaindump.Restore(bc2, r, 0, 2, nil)) require.Equal(t, uint32(1), bc2.BlockHeight()) r = io.NewBinReaderFromBuf(buf) // new reader because start is relative to dump require.NoError(t, chaindump.Restore(bc2, r, 2, 1, nil)) t.Run("check handler", func(t *testing.T) { lastIndex := uint32(0) errStopped := errors.New("stopped") f := func(b *block.Block) error { lastIndex = b.Index if b.Index >= bc.BlockHeight()-1 { return errStopped } return nil } require.NoError(t, chaindump.Restore(bc2, r, 0, 1, f)) require.Equal(t, bc2.BlockHeight(), lastIndex) r = io.NewBinReaderFromBuf(buf) err := chaindump.Restore(bc2, r, 4, bc.BlockHeight()-bc2.BlockHeight(), f) require.ErrorIs(t, err, errStopped) require.Equal(t, bc.BlockHeight()-1, lastIndex) }) }) }