core: add InitializeCache method to Contract interface

Make the contracts cache initialization unified. The order of cache
iniitialization is not important and Nottary contract is added to the
bc.contracts.Contracts wrt P2PSigExtensions setting, thus no functional
changes, just refactoring for future applications.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2023-04-26 12:52:59 +03:00
parent 97b93c6833
commit d0718a680f
13 changed files with 40 additions and 28 deletions

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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().

View file

@ -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{}),

View file

@ -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))

View file

@ -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 {

View file

@ -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),

View file

@ -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),

View file

@ -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 {

View file

@ -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 {

View file

@ -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