parent
75753afc33
commit
e0e7fd5367
2 changed files with 50 additions and 22 deletions
|
@ -27,6 +27,11 @@ type NEO struct {
|
||||||
nep5TokenNative
|
nep5TokenNative
|
||||||
GAS *GAS
|
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
|
votesChanged atomic.Value
|
||||||
nextValidators atomic.Value
|
nextValidators atomic.Value
|
||||||
validators atomic.Value
|
validators atomic.Value
|
||||||
|
@ -188,6 +193,8 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
||||||
n.mint(ic, h, big.NewInt(NEOTotalSupply))
|
n.mint(ic, h, big.NewInt(NEOTotalSupply))
|
||||||
|
|
||||||
gr := &state.GASRecord{{Index: 0, GASPerBlock: *big.NewInt(5 * GASFactor)}}
|
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()})
|
err = ic.DAO.PutStorageItem(n.ContractID, []byte{prefixGASPerBlock}, &state.StorageItem{Value: gr.Bytes()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -249,17 +256,24 @@ func (n *NEO) OnPersist(ic *interop.Context) error {
|
||||||
|
|
||||||
// PostPersist implements Contract interface.
|
// PostPersist implements Contract interface.
|
||||||
func (n *NEO) PostPersist(ic *interop.Context) error {
|
func (n *NEO) PostPersist(ic *interop.Context) error {
|
||||||
gas, err := n.GetGASPerBlock(ic, ic.Block.Index)
|
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pubs := n.GetCommitteeMembers()
|
pubs := n.GetCommitteeMembers()
|
||||||
index := int(ic.Block.Index) % len(ic.Chain.GetConfig().StandbyCommittee)
|
index := int(ic.Block.Index) % len(ic.Chain.GetConfig().StandbyCommittee)
|
||||||
gas.Mul(gas, big.NewInt(committeeRewardRatio))
|
gas.Mul(gas, big.NewInt(committeeRewardRatio))
|
||||||
n.GAS.mint(ic, pubs[index].GetScriptHash(), gas.Div(gas, big.NewInt(100)))
|
n.GAS.mint(ic, pubs[index].GetScriptHash(), gas.Div(gas, big.NewInt(100)))
|
||||||
|
n.OnPersistEnd(ic.DAO)
|
||||||
return nil
|
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 {
|
func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.StorageItem, amount *big.Int) error {
|
||||||
acc, err := state.NEOBalanceStateFromBytes(si.Value)
|
acc, err := state.NEOBalanceStateFromBytes(si.Value)
|
||||||
if err != nil {
|
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 {
|
func (n *NEO) getGASPerBlock(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||||
gas, err := n.GetGASPerBlock(ic, ic.Block.Index)
|
gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return stackitem.NewBigInteger(gas)
|
return stackitem.NewBigInteger(gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGASPerBlock returns gas generated for block with provided index.
|
func (n *NEO) getGASRecordFromDAO(d dao.DAO) state.GASRecord {
|
||||||
func (n *NEO) GetGASPerBlock(ic *interop.Context, index uint32) (*big.Int, error) {
|
|
||||||
si := ic.DAO.GetStorageItem(n.ContractID, []byte{prefixGASPerBlock})
|
|
||||||
var gr state.GASRecord
|
var gr state.GASRecord
|
||||||
if err := gr.FromBytes(si.Value); err != nil {
|
si := d.GetStorageItem(n.ContractID, []byte{prefixGASPerBlock})
|
||||||
return nil, err
|
_ = 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-- {
|
for i := len(gr) - 1; i >= 0; i-- {
|
||||||
if gr[i].Index <= index {
|
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.
|
// 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,
|
GASPerBlock: *gas,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
n.gasPerBlockChanged.Store(true)
|
||||||
return true, ic.DAO.PutStorageItem(n.ContractID, []byte{prefixGASPerBlock}, &state.StorageItem{Value: gr.Bytes()})
|
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()
|
h := neo.GetCommitteeAddress()
|
||||||
t.Run("Default", func(t *testing.T) {
|
t.Run("Default", func(t *testing.T) {
|
||||||
g, err := neo.GetGASPerBlock(ic, 0)
|
g := neo.GetGASPerBlock(ic.DAO, 0)
|
||||||
require.NoError(t, err)
|
|
||||||
require.EqualValues(t, 5*native.GASFactor, g.Int64())
|
require.EqualValues(t, 5*native.GASFactor, g.Int64())
|
||||||
})
|
})
|
||||||
t.Run("Invalid", func(t *testing.T) {
|
t.Run("Invalid", func(t *testing.T) {
|
||||||
|
@ -149,23 +148,31 @@ func TestNEO_SetGasPerBlock(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("Valid", func(t *testing.T) {
|
t.Run("Valid", func(t *testing.T) {
|
||||||
setSigner(tx, h)
|
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.NoError(t, err)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
neo.OnPersistEnd(ic.DAO)
|
||||||
|
_, err = ic.DAO.Persist()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("Again", func(t *testing.T) {
|
t.Run("Again", func(t *testing.T) {
|
||||||
setSigner(tx, h)
|
setSigner(tx, h)
|
||||||
ok, err := neo.SetGASPerBlock(ic, 10, big.NewInt(native.GASFactor))
|
ok, err := neo.SetGASPerBlock(ic, 10, big.NewInt(native.GASFactor))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, ok)
|
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)
|
neo.OnPersistEnd(ic.DAO)
|
||||||
require.NoError(t, err)
|
g := neo.GetGASPerBlock(ic.DAO, 9)
|
||||||
require.EqualValues(t, 5*native.GASFactor, g.Int64())
|
require.EqualValues(t, 5*native.GASFactor, g.Int64())
|
||||||
|
|
||||||
g, err = neo.GetGASPerBlock(ic, 10)
|
g = neo.GetGASPerBlock(ic.DAO, 10)
|
||||||
require.NoError(t, err)
|
|
||||||
require.EqualValues(t, native.GASFactor, g.Int64())
|
require.EqualValues(t, native.GASFactor, g.Int64())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue