mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-05-06 09:55:09 +00:00
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},
|
{"getCommittee", nil},
|
||||||
{"getGasPerBlock", nil},
|
{"getGasPerBlock", nil},
|
||||||
{"getNextBlockValidators", nil},
|
{"getNextBlockValidators", nil},
|
||||||
|
{"getRegisterPrice", nil},
|
||||||
{"registerCandidate", []string{pub}},
|
{"registerCandidate", []string{pub}},
|
||||||
{"setGasPerBlock", []string{"1"}},
|
{"setGasPerBlock", []string{"1"}},
|
||||||
|
{"setRegisterPrice", []string{"10"}},
|
||||||
{"vote", []string{u160, pub}},
|
{"vote", []string{u160, pub}},
|
||||||
{"unclaimedGas", []string{u160, "123"}},
|
{"unclaimedGas", []string{u160, "123"}},
|
||||||
{"unregisterCandidate", []string{pub}},
|
{"unregisterCandidate", []string{pub}},
|
||||||
|
|
|
@ -37,6 +37,9 @@ type NEO struct {
|
||||||
gasPerBlock atomic.Value
|
gasPerBlock atomic.Value
|
||||||
gasPerBlockChanged atomic.Value
|
gasPerBlockChanged atomic.Value
|
||||||
|
|
||||||
|
registerPrice atomic.Value
|
||||||
|
registerPriceChanged atomic.Value
|
||||||
|
|
||||||
votesChanged atomic.Value
|
votesChanged atomic.Value
|
||||||
nextValidators atomic.Value
|
nextValidators atomic.Value
|
||||||
validators atomic.Value
|
validators atomic.Value
|
||||||
|
@ -53,6 +56,8 @@ const (
|
||||||
neoContractID = -5
|
neoContractID = -5
|
||||||
// NEOTotalSupply is the total amount of NEO in the system.
|
// NEOTotalSupply is the total amount of NEO in the system.
|
||||||
NEOTotalSupply = 100000000
|
NEOTotalSupply = 100000000
|
||||||
|
// DefaultRegisterPrice is default price for candidate register.
|
||||||
|
DefaultRegisterPrice = 1000 * GASFactor
|
||||||
// prefixCandidate is a prefix used to store validator's data.
|
// prefixCandidate is a prefix used to store validator's data.
|
||||||
prefixCandidate = 33
|
prefixCandidate = 33
|
||||||
// prefixVotersCount is a prefix for storing total amount of NEO of voters.
|
// prefixVotersCount is a prefix for storing total amount of NEO of voters.
|
||||||
|
@ -64,6 +69,8 @@ const (
|
||||||
voterRewardFactor = 100_000_000
|
voterRewardFactor = 100_000_000
|
||||||
// prefixGASPerBlock is a prefix for storing amount of GAS generated per block.
|
// prefixGASPerBlock is a prefix for storing amount of GAS generated per block.
|
||||||
prefixGASPerBlock = 29
|
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
|
// effectiveVoterTurnout represents minimal ratio of total supply to total amount voted value
|
||||||
// which is require to use non-standby validators.
|
// which is require to use non-standby validators.
|
||||||
effectiveVoterTurnout = 5
|
effectiveVoterTurnout = 5
|
||||||
|
@ -107,6 +114,7 @@ func newNEO() *NEO {
|
||||||
n.validators.Store(keys.PublicKeys(nil))
|
n.validators.Store(keys.PublicKeys(nil))
|
||||||
n.committee.Store(keysWithVotes(nil))
|
n.committee.Store(keysWithVotes(nil))
|
||||||
n.committeeHash.Store(util.Uint160{})
|
n.committeeHash.Store(util.Uint160{})
|
||||||
|
n.registerPriceChanged.Store(true)
|
||||||
|
|
||||||
desc := newDescriptor("unclaimedGas", smartcontract.IntegerType,
|
desc := newDescriptor("unclaimedGas", smartcontract.IntegerType,
|
||||||
manifest.NewParameter("account", smartcontract.Hash160Type),
|
manifest.NewParameter("account", smartcontract.Hash160Type),
|
||||||
|
@ -151,6 +159,15 @@ func newNEO() *NEO {
|
||||||
md = newMethodAndPrice(n.setGASPerBlock, 1<<15, callflag.States)
|
md = newMethodAndPrice(n.setGASPerBlock, 1<<15, callflag.States)
|
||||||
n.AddMethod(md, desc)
|
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
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +213,12 @@ func (n *NEO) Initialize(ic *interop.Context) error {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,6 +346,12 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
|
||||||
n.gasPerBlock.Store(gr)
|
n.gasPerBlock.Store(gr)
|
||||||
n.gasPerBlockChanged.Store(false)
|
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
|
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)
|
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) {
|
func (n *NEO) dropCandidateIfZero(d dao.DAO, pub *keys.PublicKey, c *candidate) (bool, error) {
|
||||||
if c.Registered || c.Votes.Sign() != 0 {
|
if c.Registered || c.Votes.Sign() != 0 {
|
||||||
return false, nil
|
return false, nil
|
||||||
|
@ -592,6 +649,9 @@ func (n *NEO) registerCandidate(ic *interop.Context, args []stackitem.Item) stac
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
return stackitem.NewBool(false)
|
return stackitem.NewBool(false)
|
||||||
}
|
}
|
||||||
|
if !ic.VM.AddGas(n.getRegisterPriceInternal(ic.DAO)) {
|
||||||
|
panic("insufficient gas")
|
||||||
|
}
|
||||||
err = n.RegisterCandidateInternal(ic, pub)
|
err = n.RegisterCandidateInternal(ic, pub)
|
||||||
return stackitem.NewBool(err == nil)
|
return stackitem.NewBool(err == nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -290,3 +291,9 @@ func TestNEO_TransferOnPayment(t *testing.T) {
|
||||||
require.Equal(t, neoOwner.BytesBE(), arr[1].Value())
|
require.Equal(t, neoOwner.BytesBE(), arr[1].Value())
|
||||||
require.Equal(t, big.NewInt(amount), arr[2].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
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"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 {
|
if maxValue != 0 {
|
||||||
t.Run("set, too large value", func(t *testing.T) {
|
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)
|
require.NoError(t, err)
|
||||||
checkFAULTState(t, res)
|
checkFAULTState(t, res)
|
||||||
})
|
})
|
||||||
|
|
|
@ -59,6 +59,16 @@ func SetGASPerBlock(amount int) {
|
||||||
contract.Call(interop.Hash160(Hash), "setGasPerBlock", contract.States, amount)
|
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.
|
// RegisterCandidate represents `registerCandidate` method of NEO native contract.
|
||||||
func RegisterCandidate(pub interop.PublicKey) bool {
|
func RegisterCandidate(pub interop.PublicKey) bool {
|
||||||
return contract.Call(interop.Hash160(Hash), "registerCandidate", contract.States, pub).(bool)
|
return contract.Call(interop.Hash160(Hash), "registerCandidate", contract.States, pub).(bool)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue