forked from TrueCloudLab/neoneo-go
native: allow to set candidate register price
This commit is contained in:
parent
b780a64b4d
commit
27fc28bd69
5 changed files with 84 additions and 1 deletions
|
@ -110,8 +110,10 @@ func TestNativeHelpersCompile(t *testing.T) {
|
|||
{"getCommittee", nil},
|
||||
{"getGasPerBlock", nil},
|
||||
{"getNextBlockValidators", nil},
|
||||
{"getRegisterPrice", nil},
|
||||
{"registerCandidate", []string{pub}},
|
||||
{"setGasPerBlock", []string{"1"}},
|
||||
{"setRegisterPrice", []string{"10"}},
|
||||
{"vote", []string{u160, pub}},
|
||||
{"unclaimedGas", []string{u160, "123"}},
|
||||
{"unregisterCandidate", []string{pub}},
|
||||
|
|
|
@ -37,6 +37,9 @@ type NEO struct {
|
|||
gasPerBlock atomic.Value
|
||||
gasPerBlockChanged atomic.Value
|
||||
|
||||
registerPrice atomic.Value
|
||||
registerPriceChanged atomic.Value
|
||||
|
||||
votesChanged atomic.Value
|
||||
nextValidators atomic.Value
|
||||
validators atomic.Value
|
||||
|
@ -53,6 +56,8 @@ const (
|
|||
neoContractID = -5
|
||||
// NEOTotalSupply is the total amount of NEO in the system.
|
||||
NEOTotalSupply = 100000000
|
||||
// DefaultRegisterPrice is default price for candidate register.
|
||||
DefaultRegisterPrice = 1000 * GASFactor
|
||||
// prefixCandidate is a prefix used to store validator's data.
|
||||
prefixCandidate = 33
|
||||
// prefixVotersCount is a prefix for storing total amount of NEO of voters.
|
||||
|
@ -64,6 +69,8 @@ const (
|
|||
voterRewardFactor = 100_000_000
|
||||
// prefixGASPerBlock is a prefix for storing amount of GAS generated per block.
|
||||
prefixGASPerBlock = 29
|
||||
// prefixRegisterPrice is a prefix for storing candidate register price.
|
||||
prefixRegisterPrice = 13
|
||||
// effectiveVoterTurnout represents minimal ratio of total supply to total amount voted value
|
||||
// which is require to use non-standby validators.
|
||||
effectiveVoterTurnout = 5
|
||||
|
@ -107,6 +114,7 @@ func newNEO() *NEO {
|
|||
n.validators.Store(keys.PublicKeys(nil))
|
||||
n.committee.Store(keysWithVotes(nil))
|
||||
n.committeeHash.Store(util.Uint160{})
|
||||
n.registerPriceChanged.Store(true)
|
||||
|
||||
desc := newDescriptor("unclaimedGas", smartcontract.IntegerType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type),
|
||||
|
@ -151,6 +159,15 @@ func newNEO() *NEO {
|
|||
md = newMethodAndPrice(n.setGASPerBlock, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getRegisterPrice", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.getRegisterPrice, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setRegisterPrice", smartcontract.VoidType,
|
||||
manifest.NewParameter("registerPrice", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.setRegisterPrice, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -196,6 +213,12 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
err = setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, DefaultRegisterPrice)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.registerPrice.Store(int64(DefaultRegisterPrice))
|
||||
n.registerPriceChanged.Store(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -323,6 +346,12 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
|
|||
n.gasPerBlock.Store(gr)
|
||||
n.gasPerBlockChanged.Store(false)
|
||||
}
|
||||
|
||||
if n.registerPriceChanged.Load().(bool) {
|
||||
p := getIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice})
|
||||
n.registerPrice.Store(p)
|
||||
n.registerPriceChanged.Store(false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -482,6 +511,34 @@ func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) er
|
|||
return n.putGASRecord(ic.DAO, index, gas)
|
||||
}
|
||||
|
||||
func (n *NEO) getRegisterPrice(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||
return stackitem.NewBigInteger(big.NewInt(n.getRegisterPriceInternal(ic.DAO)))
|
||||
}
|
||||
|
||||
func (n *NEO) getRegisterPriceInternal(d dao.DAO) int64 {
|
||||
if !n.registerPriceChanged.Load().(bool) {
|
||||
return n.registerPrice.Load().(int64)
|
||||
}
|
||||
return getIntWithKey(n.ID, d, []byte{prefixRegisterPrice})
|
||||
}
|
||||
|
||||
func (n *NEO) setRegisterPrice(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
price := toBigInt(args[0])
|
||||
if price.Sign() <= 0 || !price.IsInt64() {
|
||||
panic("invalid register price")
|
||||
}
|
||||
if !n.checkCommittee(ic) {
|
||||
panic("invalid committee signature")
|
||||
}
|
||||
|
||||
err := setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, price.Int64())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
n.registerPriceChanged.Store(true)
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
func (n *NEO) dropCandidateIfZero(d dao.DAO, pub *keys.PublicKey, c *candidate) (bool, error) {
|
||||
if c.Registered || c.Votes.Sign() != 0 {
|
||||
return false, nil
|
||||
|
@ -592,6 +649,9 @@ func (n *NEO) registerCandidate(ic *interop.Context, args []stackitem.Item) stac
|
|||
} else if !ok {
|
||||
return stackitem.NewBool(false)
|
||||
}
|
||||
if !ic.VM.AddGas(n.getRegisterPriceInternal(ic.DAO)) {
|
||||
panic("insufficient gas")
|
||||
}
|
||||
err = n.RegisterCandidateInternal(ic, pub)
|
||||
return stackitem.NewBool(err == nil)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
"sort"
|
||||
"testing"
|
||||
|
@ -290,3 +291,9 @@ func TestNEO_TransferOnPayment(t *testing.T) {
|
|||
require.Equal(t, neoOwner.BytesBE(), arr[1].Value())
|
||||
require.Equal(t, big.NewInt(amount), arr[2].Value())
|
||||
}
|
||||
|
||||
func TestRegisterPrice(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
testGetSet(t, bc, bc.contracts.NEO.Hash, "RegisterPrice",
|
||||
native.DefaultRegisterPrice, 1, math.MaxInt64)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/random"
|
||||
|
@ -46,7 +47,10 @@ func testGetSet(t *testing.T, chain *Blockchain, hash util.Uint160, name string,
|
|||
|
||||
if maxValue != 0 {
|
||||
t.Run("set, too large value", func(t *testing.T) {
|
||||
res, err := invokeContractMethodGeneric(chain, 100000000, hash, setName, true, maxValue+1)
|
||||
// use big.Int because max can be `math.MaxInt64`
|
||||
max := big.NewInt(maxValue)
|
||||
max.Add(max, big.NewInt(1))
|
||||
res, err := invokeContractMethodGeneric(chain, 100000000, hash, setName, true, max)
|
||||
require.NoError(t, err)
|
||||
checkFAULTState(t, res)
|
||||
})
|
||||
|
|
|
@ -59,6 +59,16 @@ func SetGASPerBlock(amount int) {
|
|||
contract.Call(interop.Hash160(Hash), "setGasPerBlock", contract.States, amount)
|
||||
}
|
||||
|
||||
// GetRegisterPrice represents `getRegisterPrice` method of NEO native contract.
|
||||
func GetRegisterPrice() int {
|
||||
return contract.Call(interop.Hash160(Hash), "getRegisterPrice", contract.ReadStates).(int)
|
||||
}
|
||||
|
||||
// SetRegisterPrice represents `setRegisterPrice` method of NEO native contract.
|
||||
func SetRegisterPrice(amount int) {
|
||||
contract.Call(interop.Hash160(Hash), "setRegisterPrice", contract.States, amount)
|
||||
}
|
||||
|
||||
// RegisterCandidate represents `registerCandidate` method of NEO native contract.
|
||||
func RegisterCandidate(pub interop.PublicKey) bool {
|
||||
return contract.Call(interop.Hash160(Hash), "registerCandidate", contract.States, pub).(bool)
|
||||
|
|
Loading…
Reference in a new issue