core: don't reset NEO's gasPerBlock cache

This commit is contained in:
Anna Shaleva 2022-04-19 19:40:27 +03:00
parent 35d160075d
commit adec635f0e
3 changed files with 23 additions and 27 deletions

View file

@ -41,10 +41,8 @@ type NEO struct {
} }
type NeoCache struct { type NeoCache struct {
// gasPerBlock represents current value of generated gas per block. // gasPerBlock represents the history of generated gas per block.
// It is append-only and doesn't need to be copied when used.
gasPerBlock gasRecord gasPerBlock gasRecord
gasPerBlockChanged bool
registerPrice int64 registerPrice int64
registerPriceChanged bool registerPriceChanged bool
@ -131,7 +129,9 @@ func copyNeoCache(src, dst *NeoCache) {
dst.registerPriceChanged = src.registerPriceChanged dst.registerPriceChanged = src.registerPriceChanged
dst.registerPrice = src.registerPrice 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)) dst.gasPerBlock = make(gasRecord, len(src.gasPerBlock))
copy(dst.gasPerBlock, 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}} gr := &gasRecord{{Index: index, GASPerBlock: *value}}
cache.gasPerBlock = *gr cache.gasPerBlock = *gr
cache.gasPerBlockChanged = false
ic.DAO.PutStorageItem(n.ID, []byte{prefixVotersCount}, state.StorageItem{}) ic.DAO.PutStorageItem(n.ID, []byte{prefixVotersCount}, state.StorageItem{})
setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, DefaultRegisterPrice) 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.gasPerBlock = n.getSortedGASRecordFromDAO(d)
cache.gasPerBlockChanged = false
d.Store.SetCache(n.ID, cache) d.Store.SetCache(n.ID, cache)
return nil 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 { if cache.registerPriceChanged {
p := getIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}) 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. // GetGASPerBlock returns gas generated for block with provided index.
func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int { func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int {
cache := d.Store.GetROCache(n.ID).(*NeoCache) cache := d.Store.GetROCache(n.ID).(*NeoCache)
var gr gasRecord gr := cache.gasPerBlock
if cache.gasPerBlockChanged {
gr = n.getSortedGASRecordFromDAO(d)
} else {
gr = cache.gasPerBlock
}
for i := len(gr) - 1; i >= 0; i-- { for i := len(gr) - 1; i >= 0; i-- {
if gr[i].Index <= index { if gr[i].Index <= index {
g := gr[i].GASPerBlock g := gr[i].GASPerBlock
return &g return &g
} }
} }
panic("contract not initialized") panic("NEO cache not initialized")
} }
// GetCommitteeAddress returns address of the committee. // 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) { if !n.checkCommittee(ic) {
return errors.New("invalid committee signature") return errors.New("invalid committee signature")
} }
cache := ic.DAO.Store.GetRWCache(n.ID).(*NeoCache)
cache.gasPerBlockChanged = true
n.putGASRecord(ic.DAO, index, gas) 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 return nil
} }
@ -693,13 +685,8 @@ func (n *NEO) CalculateNEOHolderReward(d *dao.Simple, value *big.Int, start, end
} else if value.Sign() < 0 { } else if value.Sign() < 0 {
return nil, errors.New("negative value") return nil, errors.New("negative value")
} }
var gr gasRecord
cache := d.Store.GetROCache(n.ID).(*NeoCache) cache := d.Store.GetROCache(n.ID).(*NeoCache)
if !cache.gasPerBlockChanged { gr := cache.gasPerBlock
gr = cache.gasPerBlock
} else {
gr = n.getSortedGASRecordFromDAO(d)
}
var sum, tmp big.Int var sum, tmp big.Int
for i := len(gr) - 1; i >= 0; i-- { for i := len(gr) - 1; i >= 0; i-- {
if gr[i].Index >= end { if gr[i].Index >= end {

View file

@ -104,7 +104,12 @@ func testGetSetCache(t *testing.T, c *neotest.ContractInvoker, name string, defa
tx2 = committeeInvoker.PrepareInvoke(t, getName) tx2 = committeeInvoker.PrepareInvoke(t, getName)
committeeInvoker.AddNewBlock(t, tx1, tx2) committeeInvoker.AddNewBlock(t, tx1, tx2)
committeeInvoker.CheckHalt(t, tx1.Hash()) committeeInvoker.CheckHalt(t, tx1.Hash())
if name != "GasPerBlock" {
committeeInvoker.CheckHalt(t, tx2.Hash(), stackitem.Make(newVal)) 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) { func setNodesByRole(t *testing.T, designateInvoker *neotest.ContractInvoker, ok bool, r noderoles.Role, nodes keys.PublicKeys) {

View file

@ -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) 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) { func TestNEO_RegisterPrice(t *testing.T) {
testGetSet(t, newNeoCommitteeClient(t, 100_0000_0000), "RegisterPrice", native.DefaultRegisterPrice, 1, math.MaxInt64) testGetSet(t, newNeoCommitteeClient(t, 100_0000_0000), "RegisterPrice", native.DefaultRegisterPrice, 1, math.MaxInt64)
} }