core: fix restoring chain with StateRootInHeader = true

Close #3597

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
Ekaterina Pavlova 2024-11-22 11:33:05 +03:00
parent cdbc026c27
commit 85c3b96f82
2 changed files with 76 additions and 3 deletions

View file

@ -12,9 +12,11 @@ import (
"github.com/nspcc-dev/neo-go/internal/testchain" "github.com/nspcc-dev/neo-go/internal/testchain"
"github.com/nspcc-dev/neo-go/pkg/config" "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/block"
"github.com/nspcc-dev/neo-go/pkg/core/chaindump"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -414,3 +416,72 @@ func TestNewBlockchain_InitHardforks(t *testing.T) {
}, bc.GetConfig().Hardforks) }, bc.GetConfig().Hardforks)
}) })
} }
type nopCloserStorage struct {
storage.Store
}
func (nopCloserStorage) Close() error {
return nil
}
func TestBlockchainRestoreStateRootInHeader(t *testing.T) {
bc := newTestChainWithCustomCfg(t, func(c *config.Config) {
c.ProtocolConfiguration.StateRootInHeader = true
})
require.NoError(t, bc.AddBlock(bc.newBlock()))
require.NoError(t, bc.AddBlock(bc.newBlock()))
require.NoError(t, bc.AddBlock(bc.newBlock()))
w := io.NewBufBinWriter()
require.NoError(t, chaindump.Dump(bc, w.BinWriter, 0, 4))
require.NoError(t, w.Err)
data := w.Bytes()
fcfg := func(c *config.Config) { c.ProtocolConfiguration.StateRootInHeader = true }
initChain := func(st storage.Store) *Blockchain {
chain := initTestChain(t, st, fcfg)
go chain.Run()
return chain
}
t.Run("empty MemoryStore", func(t *testing.T) {
bc := initChain(storage.NewMemoryStore())
r := io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 0, 4, nil))
bc.Close()
})
t.Run("not empty MemoryStore, one block", func(t *testing.T) {
st := nopCloserStorage{Store: storage.NewMemoryStore()}
bc := initChain(st)
r := io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 0, 1, nil))
expected := bc.stateRoot.CurrentLocalStateRoot()
bc.Close()
bc = initChain(st)
actual := bc.stateRoot.CurrentLocalStateRoot()
require.Equal(t, expected, actual)
r = io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 1, 1, nil))
bc.Close()
})
t.Run("not empty MemoryStore, multiple blocks", func(t *testing.T) {
st := nopCloserStorage{Store: storage.NewMemoryStore()}
{
bc := initChain(st)
r := io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 0, 2, nil))
expected := bc.stateRoot.CurrentLocalStateRoot()
bc.Close()
bc = initChain(st)
actual := bc.stateRoot.CurrentLocalStateRoot()
require.Equal(t, expected, actual)
r = io.NewBinReaderFromBuf(data)
require.NoError(t, chaindump.Restore(bc, r, 2, 1, nil))
bc.Close()
}
})
}

View file

@ -183,13 +183,15 @@ func (s *Module) Init(height uint32) error {
updateStateHeightMetric(h) updateStateHeightMetric(h)
} }
if height == 0 { if s.mpt == nil {
s.mpt = mpt.NewTrie(nil, s.mode, s.Store) s.mpt = mpt.NewTrie(nil, s.mode, s.Store)
s.currentLocal.Store(util.Uint256{})
return nil
} }
r, err := s.getStateRoot(makeStateRootKey(height)) r, err := s.getStateRoot(makeStateRootKey(height))
if err != nil { if err != nil {
if height == 0 {
s.currentLocal.Store(util.Uint256{})
return nil
}
return err return err
} }
s.currentLocal.Store(r.Root) s.currentLocal.Store(r.Root)