core: initialize natives cache wrt NativeActivations
If the contract was deployed then cache must be initialized after in-memory data reset. If the contract isn't active yet, then no cache will be initialized on deploy (i.e. on call to Initialize() method by native Management). Close #2984. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
parent
33c971b0e4
commit
edb2d46d5b
2 changed files with 73 additions and 3 deletions
|
@ -1012,9 +1012,14 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage)
|
|||
|
||||
func (bc *Blockchain) initializeNativeCache(blockHeight uint32, d *dao.Simple) error {
|
||||
for _, c := range bc.contracts.Contracts {
|
||||
err := c.InitializeCache(blockHeight, d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize cache for %s: %w", c.Metadata().Name, err)
|
||||
for _, h := range c.Metadata().UpdateHistory {
|
||||
if blockHeight >= h { // check that contract was deployed.
|
||||
err := c.InitializeCache(blockHeight, d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize cache for %s: %w", c.Metadata().Name, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -299,6 +299,71 @@ func TestBlockchain_StartFromExistingDB(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// This test enables Notary native contract at non-zero height and checks that no
|
||||
// Notary cache initialization is performed before that height on node restart.
|
||||
func TestBlockchain_InitializeNativeCacheWrtNativeActivations(t *testing.T) {
|
||||
const notaryEnabledHeight = 3
|
||||
ps, path := newLevelDBForTestingWithPath(t, "")
|
||||
customConfig := func(c *config.Blockchain) {
|
||||
c.P2PSigExtensions = true
|
||||
c.NativeUpdateHistories = make(map[string][]uint32)
|
||||
for _, n := range []string{
|
||||
nativenames.Neo,
|
||||
nativenames.Gas,
|
||||
nativenames.Designation,
|
||||
nativenames.Management,
|
||||
nativenames.CryptoLib,
|
||||
nativenames.Ledger,
|
||||
nativenames.Management,
|
||||
nativenames.Oracle,
|
||||
nativenames.Policy,
|
||||
nativenames.StdLib,
|
||||
nativenames.Notary,
|
||||
} {
|
||||
if n == nativenames.Notary {
|
||||
c.NativeUpdateHistories[n] = []uint32{notaryEnabledHeight}
|
||||
} else {
|
||||
c.NativeUpdateHistories[n] = []uint32{0}
|
||||
}
|
||||
}
|
||||
}
|
||||
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, ps)
|
||||
require.NoError(t, err)
|
||||
go bc.Run()
|
||||
e := neotest.NewExecutor(t, bc, validators, committee)
|
||||
e.AddNewBlock(t)
|
||||
bc.Close() // Ensure persist is done and persistent store is properly closed.
|
||||
|
||||
ps, _ = newLevelDBForTestingWithPath(t, path)
|
||||
|
||||
// If NativeActivations are not taken into account during native cache initialization,
|
||||
// bs.init() will panic on Notary cache initialization as it's not deployed yet.
|
||||
require.NotPanics(t, func() {
|
||||
bc, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, ps)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
go bc.Run()
|
||||
defer bc.Close()
|
||||
e = neotest.NewExecutor(t, bc, validators, committee)
|
||||
h := e.Chain.BlockHeight()
|
||||
|
||||
// Notary isn't initialized yet, so accessing Notary cache should panic.
|
||||
require.Panics(t, func() {
|
||||
_ = e.Chain.GetMaxNotValidBeforeDelta()
|
||||
})
|
||||
|
||||
// Ensure Notary will be properly initialized and accessing Notary cache works
|
||||
// as expected.
|
||||
for i := 0; i < notaryEnabledHeight; i++ {
|
||||
require.NotPanics(t, func() {
|
||||
e.AddNewBlock(t)
|
||||
}, h+uint32(i)+1)
|
||||
}
|
||||
require.NotPanics(t, func() {
|
||||
_ = e.Chain.GetMaxNotValidBeforeDelta()
|
||||
})
|
||||
}
|
||||
|
||||
func TestBlockchain_AddHeaders(t *testing.T) {
|
||||
bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
|
||||
c.StateRootInHeader = true
|
||||
|
|
Loading…
Reference in a new issue