mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
parent
75753afc33
commit
e0e7fd5367
2 changed files with 50 additions and 22 deletions
|
@ -27,6 +27,11 @@ type NEO struct {
|
|||
nep5TokenNative
|
||||
GAS *GAS
|
||||
|
||||
// gasPerBlock represents current value of generated gas per block.
|
||||
// It is append-only and doesn't need to be copied when used.
|
||||
gasPerBlock atomic.Value
|
||||
gasPerBlockChanged atomic.Value
|
||||
|
||||
votesChanged atomic.Value
|
||||
nextValidators atomic.Value
|
||||
validators atomic.Value
|
||||
|
@ -188,6 +193,8 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
|||
n.mint(ic, h, big.NewInt(NEOTotalSupply))
|
||||
|
||||
gr := &state.GASRecord{{Index: 0, GASPerBlock: *big.NewInt(5 * GASFactor)}}
|
||||
n.gasPerBlock.Store(*gr)
|
||||
n.gasPerBlockChanged.Store(false)
|
||||
err = ic.DAO.PutStorageItem(n.ContractID, []byte{prefixGASPerBlock}, &state.StorageItem{Value: gr.Bytes()})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -249,17 +256,24 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
|
|||
|
||||
// PostPersist implements Contract interface.
|
||||
func (n *NEO) PostPersist(ic *interop.Context) error {
|
||||
gas, err := n.GetGASPerBlock(ic, ic.Block.Index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
|
||||
pubs := n.GetCommitteeMembers()
|
||||
index := int(ic.Block.Index) % len(ic.Chain.GetConfig().StandbyCommittee)
|
||||
gas.Mul(gas, big.NewInt(committeeRewardRatio))
|
||||
n.GAS.mint(ic, pubs[index].GetScriptHash(), gas.Div(gas, big.NewInt(100)))
|
||||
n.OnPersistEnd(ic.DAO)
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnPersistEnd updates cached values if they've been changed.
|
||||
func (n *NEO) OnPersistEnd(d dao.DAO) {
|
||||
if n.gasPerBlockChanged.Load().(bool) {
|
||||
gr := n.getGASRecordFromDAO(d)
|
||||
n.gasPerBlock.Store(gr)
|
||||
n.gasPerBlockChanged.Store(false)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.StorageItem, amount *big.Int) error {
|
||||
acc, err := state.NEOBalanceStateFromBytes(si.Value)
|
||||
if err != nil {
|
||||
|
@ -322,26 +336,32 @@ func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem
|
|||
}
|
||||
|
||||
func (n *NEO) getGASPerBlock(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||
gas, err := n.GetGASPerBlock(ic, ic.Block.Index)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
|
||||
return stackitem.NewBigInteger(gas)
|
||||
}
|
||||
|
||||
// GetGASPerBlock returns gas generated for block with provided index.
|
||||
func (n *NEO) GetGASPerBlock(ic *interop.Context, index uint32) (*big.Int, error) {
|
||||
si := ic.DAO.GetStorageItem(n.ContractID, []byte{prefixGASPerBlock})
|
||||
func (n *NEO) getGASRecordFromDAO(d dao.DAO) state.GASRecord {
|
||||
var gr state.GASRecord
|
||||
if err := gr.FromBytes(si.Value); err != nil {
|
||||
return nil, err
|
||||
si := d.GetStorageItem(n.ContractID, []byte{prefixGASPerBlock})
|
||||
_ = gr.FromBytes(si.Value)
|
||||
return gr
|
||||
}
|
||||
|
||||
// GetGASPerBlock returns gas generated for block with provided index.
|
||||
func (n *NEO) GetGASPerBlock(d dao.DAO, index uint32) *big.Int {
|
||||
var gr state.GASRecord
|
||||
if n.gasPerBlockChanged.Load().(bool) {
|
||||
gr = n.getGASRecordFromDAO(d)
|
||||
} else {
|
||||
gr = n.gasPerBlock.Load().(state.GASRecord)
|
||||
}
|
||||
for i := len(gr) - 1; i >= 0; i-- {
|
||||
if gr[i].Index <= index {
|
||||
return &gr[i].GASPerBlock, nil
|
||||
g := gr[i].GASPerBlock
|
||||
return &g
|
||||
}
|
||||
}
|
||||
return nil, errors.New("contract not initialized")
|
||||
panic("contract not initialized")
|
||||
}
|
||||
|
||||
// GetCommitteeAddress returns address of the committee.
|
||||
|
@ -381,6 +401,7 @@ func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) (b
|
|||
GASPerBlock: *gas,
|
||||
})
|
||||
}
|
||||
n.gasPerBlockChanged.Store(true)
|
||||
return true, ic.DAO.PutStorageItem(n.ContractID, []byte{prefixGASPerBlock}, &state.StorageItem{Value: gr.Bytes()})
|
||||
}
|
||||
|
||||
|
|
|
@ -130,8 +130,7 @@ func TestNEO_SetGasPerBlock(t *testing.T) {
|
|||
|
||||
h := neo.GetCommitteeAddress()
|
||||
t.Run("Default", func(t *testing.T) {
|
||||
g, err := neo.GetGASPerBlock(ic, 0)
|
||||
require.NoError(t, err)
|
||||
g := neo.GetGASPerBlock(ic.DAO, 0)
|
||||
require.EqualValues(t, 5*native.GASFactor, g.Int64())
|
||||
})
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
|
@ -149,23 +148,31 @@ func TestNEO_SetGasPerBlock(t *testing.T) {
|
|||
})
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
setSigner(tx, h)
|
||||
ok, err := neo.SetGASPerBlock(ic, 10, big.NewInt(native.GASFactor))
|
||||
ok, err := neo.SetGASPerBlock(ic, 10, big.NewInt(native.GASFactor*2))
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
neo.OnPersistEnd(ic.DAO)
|
||||
_, err = ic.DAO.Persist()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Again", func(t *testing.T) {
|
||||
setSigner(tx, h)
|
||||
ok, err := neo.SetGASPerBlock(ic, 10, big.NewInt(native.GASFactor))
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
|
||||
t.Run("NotPersisted", func(t *testing.T) {
|
||||
g := neo.GetGASPerBlock(bc.dao, 10)
|
||||
// Old value should be returned.
|
||||
require.EqualValues(t, 2*native.GASFactor, g.Int64())
|
||||
})
|
||||
})
|
||||
|
||||
g, err := neo.GetGASPerBlock(ic, 9)
|
||||
require.NoError(t, err)
|
||||
neo.OnPersistEnd(ic.DAO)
|
||||
g := neo.GetGASPerBlock(ic.DAO, 9)
|
||||
require.EqualValues(t, 5*native.GASFactor, g.Int64())
|
||||
|
||||
g, err = neo.GetGASPerBlock(ic, 10)
|
||||
require.NoError(t, err)
|
||||
g = neo.GetGASPerBlock(ic.DAO, 10)
|
||||
require.EqualValues(t, native.GASFactor, g.Int64())
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue