7589733017
And include some node-specific configurations there with backwards compatibility. Note that in the future we'll remove Ledger's fields from the ProtocolConfiguration and it'll be possible to access them in Blockchain directly (not via .Ledger). The other option tried was using two configuration types separately, but that incurs more changes to the codebase, single structure that behaves almost like the old one is better for backwards compatibility. Fixes #2676.
92 lines
2.8 KiB
Go
92 lines
2.8 KiB
Go
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.True(t, errors.Is(err, errStopped))
|
|
require.Equal(t, bc.BlockHeight()-1, lastIndex)
|
|
})
|
|
})
|
|
}
|