github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/chaindump/dump_test.go (about)

     1  package chaindump_test
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  
     7  	"github.com/nspcc-dev/neo-go/internal/basicchain"
     8  	"github.com/nspcc-dev/neo-go/pkg/config"
     9  	"github.com/nspcc-dev/neo-go/pkg/core/block"
    10  	"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
    11  	"github.com/nspcc-dev/neo-go/pkg/io"
    12  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    13  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestBlockchain_DumpAndRestore(t *testing.T) {
    18  	t.Run("no state root", func(t *testing.T) {
    19  		testDumpAndRestore(t, func(c *config.Blockchain) {
    20  			c.StateRootInHeader = false
    21  			c.P2PSigExtensions = true
    22  		}, nil)
    23  	})
    24  	t.Run("with state root", func(t *testing.T) {
    25  		testDumpAndRestore(t, func(c *config.Blockchain) {
    26  			c.StateRootInHeader = true
    27  			c.P2PSigExtensions = true
    28  		}, nil)
    29  	})
    30  	t.Run("remove untraceable", func(t *testing.T) {
    31  		// Dump can only be created if all blocks and transactions are present.
    32  		testDumpAndRestore(t, func(c *config.Blockchain) {
    33  			c.P2PSigExtensions = true
    34  		}, func(c *config.Blockchain) {
    35  			c.MaxTraceableBlocks = 2
    36  			c.Ledger.RemoveUntraceableBlocks = true
    37  			c.P2PSigExtensions = true
    38  		})
    39  	})
    40  }
    41  
    42  func testDumpAndRestore(t *testing.T, dumpF, restoreF func(c *config.Blockchain)) {
    43  	if restoreF == nil {
    44  		restoreF = dumpF
    45  	}
    46  
    47  	bc, validators, committee := chain.NewMultiWithCustomConfig(t, dumpF)
    48  	e := neotest.NewExecutor(t, bc, validators, committee)
    49  
    50  	basicchain.Init(t, "../../../", e)
    51  	require.True(t, bc.BlockHeight() > 5) // ensure that test is valid
    52  
    53  	w := io.NewBufBinWriter()
    54  	require.NoError(t, chaindump.Dump(bc, w.BinWriter, 0, bc.BlockHeight()+1))
    55  	require.NoError(t, w.Err)
    56  
    57  	buf := w.Bytes()
    58  	t.Run("invalid start", func(t *testing.T) {
    59  		bc2, _, _ := chain.NewMultiWithCustomConfig(t, restoreF)
    60  
    61  		r := io.NewBinReaderFromBuf(buf)
    62  		require.Error(t, chaindump.Restore(bc2, r, 2, 1, nil))
    63  	})
    64  	t.Run("good", func(t *testing.T) {
    65  		bc2, _, _ := chain.NewMultiWithCustomConfig(t, dumpF)
    66  
    67  		r := io.NewBinReaderFromBuf(buf)
    68  		require.NoError(t, chaindump.Restore(bc2, r, 0, 2, nil))
    69  		require.Equal(t, uint32(1), bc2.BlockHeight())
    70  
    71  		r = io.NewBinReaderFromBuf(buf) // new reader because start is relative to dump
    72  		require.NoError(t, chaindump.Restore(bc2, r, 2, 1, nil))
    73  		t.Run("check handler", func(t *testing.T) {
    74  			lastIndex := uint32(0)
    75  			errStopped := errors.New("stopped")
    76  			f := func(b *block.Block) error {
    77  				lastIndex = b.Index
    78  				if b.Index >= bc.BlockHeight()-1 {
    79  					return errStopped
    80  				}
    81  				return nil
    82  			}
    83  			require.NoError(t, chaindump.Restore(bc2, r, 0, 1, f))
    84  			require.Equal(t, bc2.BlockHeight(), lastIndex)
    85  
    86  			r = io.NewBinReaderFromBuf(buf)
    87  			err := chaindump.Restore(bc2, r, 4, bc.BlockHeight()-bc2.BlockHeight(), f)
    88  			require.ErrorIs(t, err, errStopped)
    89  			require.Equal(t, bc.BlockHeight()-1, lastIndex)
    90  		})
    91  	})
    92  }