From adec635f0e755aca6ac5d89f1b4597afb1d8cdd4 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 19 Apr 2022 19:40:27 +0300 Subject: [PATCH] core: don't reset NEO's gasPerBlock cache --- pkg/core/native/native_neo.go | 39 ++++++++-------------- pkg/core/native/native_test/common_test.go | 7 +++- pkg/core/native/native_test/neo_test.go | 4 +++ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index e3d4274cf..c5abe230c 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -41,10 +41,8 @@ type NEO struct { } type NeoCache struct { - // gasPerBlock represents current value of generated gas per block. - // It is append-only and doesn't need to be copied when used. - gasPerBlock gasRecord - gasPerBlockChanged bool + // gasPerBlock represents the history of generated gas per block. + gasPerBlock gasRecord registerPrice int64 registerPriceChanged bool @@ -131,7 +129,9 @@ func copyNeoCache(src, dst *NeoCache) { dst.registerPriceChanged = src.registerPriceChanged dst.registerPrice = src.registerPrice - dst.gasPerBlockChanged = src.gasPerBlockChanged + // Can't omit copying because gasPerBlock is append-only, thus to be able to + // discard cache changes in case of FAULTed transaction we need a separate + // container for updated gasPerBlock values. dst.gasPerBlock = make(gasRecord, len(src.gasPerBlock)) copy(dst.gasPerBlock, src.gasPerBlock) @@ -271,7 +271,6 @@ func (n *NEO) Initialize(ic *interop.Context) error { gr := &gasRecord{{Index: index, GASPerBlock: *value}} cache.gasPerBlock = *gr - cache.gasPerBlockChanged = false ic.DAO.PutStorageItem(n.ID, []byte{prefixVotersCount}, state.StorageItem{}) setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, DefaultRegisterPrice) @@ -301,7 +300,6 @@ func (n *NEO) InitializeCache(bc interop.Ledger, d *dao.Simple) error { } cache.gasPerBlock = n.getSortedGASRecordFromDAO(d) - cache.gasPerBlockChanged = false d.Store.SetCache(n.ID, cache) return nil @@ -417,10 +415,6 @@ func (n *NEO) PostPersist(ic *interop.Context) error { } } } - if cache.gasPerBlockChanged { - cache.gasPerBlock = n.getSortedGASRecordFromDAO(ic.DAO) - cache.gasPerBlockChanged = false - } if cache.registerPriceChanged { p := getIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}) @@ -549,19 +543,14 @@ func (n *NEO) getSortedGASRecordFromDAO(d *dao.Simple) gasRecord { // GetGASPerBlock returns gas generated for block with provided index. func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int { cache := d.Store.GetROCache(n.ID).(*NeoCache) - var gr gasRecord - if cache.gasPerBlockChanged { - gr = n.getSortedGASRecordFromDAO(d) - } else { - gr = cache.gasPerBlock - } + gr := cache.gasPerBlock for i := len(gr) - 1; i >= 0; i-- { if gr[i].Index <= index { g := gr[i].GASPerBlock return &g } } - panic("contract not initialized") + panic("NEO cache not initialized") } // GetCommitteeAddress returns address of the committee. @@ -595,9 +584,12 @@ func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) er if !n.checkCommittee(ic) { return errors.New("invalid committee signature") } - cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache) - cache.gasPerBlockChanged = true n.putGASRecord(ic.DAO, index, gas) + cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache) + cache.gasPerBlock = append(cache.gasPerBlock, gasIndexPair{ + Index: index, + GASPerBlock: *gas, + }) return nil } @@ -693,13 +685,8 @@ func (n *NEO) CalculateNEOHolderReward(d *dao.Simple, value *big.Int, start, end } else if value.Sign() < 0 { return nil, errors.New("negative value") } - var gr gasRecord cache := d.Store.GetROCache(n.ID).(*NeoCache) - if !cache.gasPerBlockChanged { - gr = cache.gasPerBlock - } else { - gr = n.getSortedGASRecordFromDAO(d) - } + gr := cache.gasPerBlock var sum, tmp big.Int for i := len(gr) - 1; i >= 0; i-- { if gr[i].Index >= end { diff --git a/pkg/core/native/native_test/common_test.go b/pkg/core/native/native_test/common_test.go index 4cdf975f5..53a927a52 100644 --- a/pkg/core/native/native_test/common_test.go +++ b/pkg/core/native/native_test/common_test.go @@ -104,7 +104,12 @@ func testGetSetCache(t *testing.T, c *neotest.ContractInvoker, name string, defa tx2 = committeeInvoker.PrepareInvoke(t, getName) committeeInvoker.AddNewBlock(t, tx1, tx2) committeeInvoker.CheckHalt(t, tx1.Hash()) - committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(newVal)) + if name != "GasPerBlock" { + committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(newVal)) + } else { + committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(defaultValue)) + committeeInvoker.Invoke(t, newVal, getName) + } } func setNodesByRole(t *testing.T, designateInvoker *neotest.ContractInvoker, ok bool, r noderoles.Role, nodes keys.PublicKeys) { diff --git a/pkg/core/native/native_test/neo_test.go b/pkg/core/native/native_test/neo_test.go index 3ade90aa4..61118ff1d 100644 --- a/pkg/core/native/native_test/neo_test.go +++ b/pkg/core/native/native_test/neo_test.go @@ -42,6 +42,10 @@ func TestNEO_GasPerBlock(t *testing.T) { testGetSet(t, newNeoCommitteeClient(t, 100_0000_0000), "GasPerBlock", 5*native.GASFactor, 0, 10*native.GASFactor) } +func TestNEO_GasPerBlockCache(t *testing.T) { + testGetSetCache(t, newNeoCommitteeClient(t, 100_0000_0000), "GasPerBlock", 5*native.GASFactor) +} + func TestNEO_RegisterPrice(t *testing.T) { testGetSet(t, newNeoCommitteeClient(t, 100_0000_0000), "RegisterPrice", native.DefaultRegisterPrice, 1, math.MaxInt64) }