diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index cf5dc1ea1..f083bdcb2 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -888,29 +888,12 @@ func (bc *Blockchain) resetStateInternal(height uint32, stage stateChangeStage) } func (bc *Blockchain) initializeNativeCache(blockHeight uint32, d *dao.Simple) error { - err := bc.contracts.NEO.InitializeCache(blockHeight, d) - if err != nil { - return fmt.Errorf("can't init cache for NEO native contract: %w", err) - } - err = bc.contracts.Management.InitializeCache(d) - if err != nil { - return fmt.Errorf("can't init cache for Management native contract: %w", err) - } - err = bc.contracts.Designate.InitializeCache(d) - if err != nil { - return fmt.Errorf("can't init cache for Designation native contract: %w", err) - } - bc.contracts.Oracle.InitializeCache(d) - if bc.P2PSigExtensionsEnabled() { - err = bc.contracts.Notary.InitializeCache(d) + for _, c := range bc.contracts.Contracts { + err := c.InitializeCache(blockHeight, d) if err != nil { - return fmt.Errorf("can't init cache for Notary native contract: %w", err) + return fmt.Errorf("failed to initialize cache for %s: %w", c.Metadata().Name, err) } } - err = bc.contracts.Policy.InitializeCache(d) - if err != nil { - return fmt.Errorf("can't init cache for Policy native contract: %w", err) - } return nil } diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 1d1448014..9a8270aab 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -153,6 +153,11 @@ type MethodAndPrice struct { // Contract is an interface for all native contracts. type Contract interface { Initialize(*Context) error + // InitializeCache aimed to initialize contract's cache when the contract has + // been deployed, but in-memory cached data were lost due to the node reset. + // It should be called each time after node restart iff the contract was + // deployed and no Initialize method was called. + InitializeCache(blockHeight uint32, d *dao.Simple) error Metadata() *ContractMD OnPersist(*Context) error PostPersist(*Context) error diff --git a/pkg/core/native/crypto.go b/pkg/core/native/crypto.go index 0228bc9cc..0fef3d73a 100644 --- a/pkg/core/native/crypto.go +++ b/pkg/core/native/crypto.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" @@ -147,6 +148,11 @@ func (c *Crypto) Initialize(ic *interop.Context) error { return nil } +// InitializeCache implements the Contract interface. +func (c *Crypto) InitializeCache(blockHeight uint32, d *dao.Simple) error { + return nil +} + // OnPersist implements the Contract interface. func (c *Crypto) OnPersist(ic *interop.Context) error { return nil diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index caf587ccf..12d8fd79a 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -132,7 +132,7 @@ func (s *Designate) Initialize(ic *interop.Context) error { // InitializeCache fills native Designate cache from DAO. It is called at non-zero height, thus // we can fetch the roles data right from the storage. -func (s *Designate) InitializeCache(d *dao.Simple) error { +func (s *Designate) InitializeCache(blockHeight uint32, d *dao.Simple) error { cache := &DesignationCache{} roles := []noderoles.Role{noderoles.Oracle, noderoles.NeoFSAlphabet, noderoles.StateValidator} if s.p2pSigExtensionsEnabled { diff --git a/pkg/core/native/ledger.go b/pkg/core/native/ledger.go index 51734c226..ba21a3487 100644 --- a/pkg/core/native/ledger.go +++ b/pkg/core/native/ledger.go @@ -85,6 +85,11 @@ func (l *Ledger) Initialize(ic *interop.Context) error { return nil } +// InitializeCache implements the Contract interface. +func (l *Ledger) InitializeCache(blockHeight uint32, d *dao.Simple) error { + return nil +} + // OnPersist implements the Contract interface. func (l *Ledger) OnPersist(ic *interop.Context) error { // Actual block/tx processing is done in Blockchain.storeBlock(). diff --git a/pkg/core/native/management.go b/pkg/core/native/management.go index 889ceab9c..f7148f8b5 100644 --- a/pkg/core/native/management.go +++ b/pkg/core/native/management.go @@ -608,7 +608,7 @@ func (m *Management) OnPersist(ic *interop.Context) error { // InitializeCache initializes contract cache with the proper values from storage. // Cache initialization should be done apart from Initialize because Initialize is // called only when deploying native contracts. -func (m *Management) InitializeCache(d *dao.Simple) error { +func (m *Management) InitializeCache(blockHeight uint32, d *dao.Simple) error { cache := &ManagementCache{ contracts: make(map[util.Uint160]*state.Contract), nep11: make(map[util.Uint160]struct{}), diff --git a/pkg/core/native/management_test.go b/pkg/core/native/management_test.go index a4cb7bc87..cc8e1e1f8 100644 --- a/pkg/core/native/management_test.go +++ b/pkg/core/native/management_test.go @@ -82,7 +82,7 @@ func TestManagement_Initialize(t *testing.T) { t.Run("good", func(t *testing.T) { d := dao.NewSimple(storage.NewMemoryStore(), false, false) mgmt := newManagement() - require.NoError(t, mgmt.InitializeCache(d)) + require.NoError(t, mgmt.InitializeCache(0, d)) }) /* See #2801 t.Run("invalid contract state", func(t *testing.T) { @@ -101,7 +101,7 @@ func TestManagement_GetNEP17Contracts(t *testing.T) { err := mgmt.Initialize(&interop.Context{DAO: d}) require.NoError(t, err) require.NoError(t, mgmt.Policy.Initialize(&interop.Context{DAO: d})) - err = mgmt.InitializeCache(d) + err = mgmt.InitializeCache(0, d) require.NoError(t, err) require.Empty(t, mgmt.GetNEP17Contracts(d)) diff --git a/pkg/core/native/native_gas.go b/pkg/core/native/native_gas.go index e60f3f959..7276572b6 100644 --- a/pkg/core/native/native_gas.go +++ b/pkg/core/native/native_gas.go @@ -99,6 +99,11 @@ func (g *GAS) Initialize(ic *interop.Context) error { return nil } +// InitializeCache implements the Contract interface. +func (g *GAS) InitializeCache(blockHeight uint32, d *dao.Simple) error { + return nil +} + // OnPersist implements the Contract interface. func (g *GAS) OnPersist(ic *interop.Context) error { if len(ic.Block.Transactions) == 0 { diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index 756f308ef..9014047f5 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -305,7 +305,8 @@ func (n *NEO) Initialize(ic *interop.Context) error { // InitializeCache initializes all NEO cache with the proper values from the storage. // Cache initialization should be done apart from Initialize because Initialize is -// called only when deploying native contracts. +// called only when deploying native contracts. InitializeCache implements the Contract +// interface. func (n *NEO) InitializeCache(blockHeight uint32, d *dao.Simple) error { cache := &NeoCache{ gasPerVoteCache: make(map[string]big.Int), diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go index 93f2af788..f58e628a7 100644 --- a/pkg/core/native/notary.go +++ b/pkg/core/native/notary.go @@ -152,7 +152,7 @@ func (n *Notary) Initialize(ic *interop.Context) error { return nil } -func (n *Notary) InitializeCache(d *dao.Simple) error { +func (n *Notary) InitializeCache(blockHeight uint32, d *dao.Simple) error { cache := &NotaryCache{ maxNotValidBeforeDelta: uint32(getIntWithKey(n.ID, d, maxNotValidBeforeDeltaKey)), notaryServiceFeePerKey: getIntWithKey(n.ID, d, notaryServiceFeeKey), diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index 0189f4fd3..ef943966e 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -251,10 +251,11 @@ func (o *Oracle) Initialize(ic *interop.Context) error { return nil } -func (o *Oracle) InitializeCache(d *dao.Simple) { +func (o *Oracle) InitializeCache(blockHeight uint32, d *dao.Simple) error { cache := &OracleCache{} cache.requestPrice = getIntWithKey(o.ID, d, prefixRequestPrice) d.SetCache(o.ID, cache) + return nil } func getResponse(tx *transaction.Transaction) *transaction.OracleResponse { diff --git a/pkg/core/native/policy.go b/pkg/core/native/policy.go index 570dfc40a..d45972c73 100644 --- a/pkg/core/native/policy.go +++ b/pkg/core/native/policy.go @@ -153,7 +153,7 @@ func (p *Policy) Initialize(ic *interop.Context) error { return nil } -func (p *Policy) InitializeCache(d *dao.Simple) error { +func (p *Policy) InitializeCache(blockHeight uint32, d *dao.Simple) error { cache := &PolicyCache{} err := p.fillCacheFromDAO(cache, d) if err != nil { diff --git a/pkg/core/native/std.go b/pkg/core/native/std.go index 733fd7338..18dabccc5 100644 --- a/pkg/core/native/std.go +++ b/pkg/core/native/std.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/mr-tron/base58" + "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" base58neogo "github.com/nspcc-dev/neo-go/pkg/encoding/base58" @@ -429,6 +430,11 @@ func (s *Std) Initialize(ic *interop.Context) error { return nil } +// InitializeCache implements the Contract interface. +func (s *Std) InitializeCache(blockHeight uint32, d *dao.Simple) error { + return nil +} + // OnPersist implements the Contract interface. func (s *Std) OnPersist(ic *interop.Context) error { return nil