Merge pull request #1818 from nspcc-dev/fix/fee
Split native method price into Cpu and Storage fees
This commit is contained in:
commit
75ec20b8bd
24 changed files with 280 additions and 90 deletions
|
@ -110,15 +110,19 @@ 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}},
|
||||
}, nep17TestCases...))
|
||||
runNativeTestCases(t, cs.GAS.ContractMD, "gas", nep17TestCases)
|
||||
runNativeTestCases(t, cs.Oracle.ContractMD, "oracle", []nativeTestCase{
|
||||
{"getPrice", nil},
|
||||
{"request", []string{`"url"`, "nil", `"callback"`, "nil", "123"}},
|
||||
{"setPrice", []string{"10"}},
|
||||
})
|
||||
runNativeTestCases(t, cs.Designate.ContractMD, "roles", []nativeTestCase{
|
||||
{"designateAsRole", []string{"1", "[]interop.PublicKey{}"}},
|
||||
|
|
|
@ -1029,7 +1029,7 @@ func TestVerifyTx(t *testing.T) {
|
|||
fee.Opcode(bc.GetBaseExecFee(), // Notary verification script
|
||||
opcode.PUSHDATA1, opcode.RET, // invocation script
|
||||
opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call
|
||||
native.NotaryVerificationPrice // Notary witness verification price
|
||||
native.NotaryVerificationPrice*bc.GetBaseExecFee() // Notary witness verification price
|
||||
tx.Scripts = []transaction.Witness{
|
||||
{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, make([]byte, 64, 64)...),
|
||||
|
|
|
@ -90,7 +90,8 @@ type Method = func(ic *Context, args []stackitem.Item) stackitem.Item
|
|||
type MethodAndPrice struct {
|
||||
Func Method
|
||||
MD *manifest.Method
|
||||
Price int64
|
||||
CPUFee int64
|
||||
StorageFee int64
|
||||
SyscallOffset int
|
||||
RequiredFlags callflag.CallFlag
|
||||
}
|
||||
|
|
|
@ -92,13 +92,13 @@ func newDesignate(p2pSigExtensionsEnabled bool) *Designate {
|
|||
desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType,
|
||||
manifest.NewParameter("role", smartcontract.IntegerType),
|
||||
manifest.NewParameter("index", smartcontract.IntegerType))
|
||||
md := newMethodAndPrice(s.getDesignatedByRole, 1000000, callflag.ReadStates)
|
||||
md := newMethodAndPrice(s.getDesignatedByRole, 1<<15, callflag.ReadStates)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("designateAsRole", smartcontract.VoidType,
|
||||
manifest.NewParameter("role", smartcontract.IntegerType),
|
||||
manifest.NewParameter("nodes", smartcontract.ArrayType))
|
||||
md = newMethodAndPrice(s.designateAsRole, 0, callflag.States)
|
||||
md = newMethodAndPrice(s.designateAsRole, 1<<15, callflag.States)
|
||||
s.AddMethod(md, desc)
|
||||
|
||||
return s
|
||||
|
|
|
@ -34,8 +34,9 @@ func Call(ic *interop.Context) error {
|
|||
return fmt.Errorf("missing call flags for native %d `%s` operation call: %05b vs %05b",
|
||||
version, m.MD.Name, ic.VM.Context().GetCallFlags(), m.RequiredFlags)
|
||||
}
|
||||
// Native contract prices are not multiplied by `BaseExecFee`.
|
||||
if !ic.VM.AddGas(m.Price) {
|
||||
invokeFee := m.CPUFee*ic.Chain.GetPolicer().GetBaseExecFee() +
|
||||
m.StorageFee*ic.Chain.GetPolicer().GetStoragePrice()
|
||||
if !ic.VM.AddGas(invokeFee) {
|
||||
return errors.New("gas limit exceeded")
|
||||
}
|
||||
ctx := ic.VM.Context()
|
||||
|
|
|
@ -42,32 +42,32 @@ func newLedger() *Ledger {
|
|||
defer l.UpdateHash()
|
||||
|
||||
desc := newDescriptor("currentHash", smartcontract.Hash256Type)
|
||||
md := newMethodAndPrice(l.currentHash, 1000000, callflag.ReadStates)
|
||||
md := newMethodAndPrice(l.currentHash, 1<<15, callflag.ReadStates)
|
||||
l.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("currentIndex", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(l.currentIndex, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(l.currentIndex, 1<<15, callflag.ReadStates)
|
||||
l.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getBlock", smartcontract.ArrayType,
|
||||
manifest.NewParameter("indexOrHash", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(l.getBlock, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(l.getBlock, 1<<15, callflag.ReadStates)
|
||||
l.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getTransaction", smartcontract.ArrayType,
|
||||
manifest.NewParameter("hash", smartcontract.Hash256Type))
|
||||
md = newMethodAndPrice(l.getTransaction, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(l.getTransaction, 1<<15, callflag.ReadStates)
|
||||
l.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getTransactionHeight", smartcontract.IntegerType,
|
||||
manifest.NewParameter("hash", smartcontract.Hash256Type))
|
||||
md = newMethodAndPrice(l.getTransactionHeight, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(l.getTransactionHeight, 1<<15, callflag.ReadStates)
|
||||
l.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getTransactionFromBlock", smartcontract.ArrayType,
|
||||
manifest.NewParameter("blockIndexOrHash", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("txIndex", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(l.getTransactionFromBlock, 2000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(l.getTransactionFromBlock, 1<<16, callflag.ReadStates)
|
||||
l.AddMethod(md, desc)
|
||||
|
||||
return l
|
||||
|
|
|
@ -69,7 +69,7 @@ func newManagement() *Management {
|
|||
|
||||
desc := newDescriptor("getContract", smartcontract.ArrayType,
|
||||
manifest.NewParameter("hash", smartcontract.Hash160Type))
|
||||
md := newMethodAndPrice(m.getContract, 1000000, callflag.ReadStates)
|
||||
md := newMethodAndPrice(m.getContract, 1<<15, callflag.ReadStates)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("deploy", smartcontract.ArrayType,
|
||||
|
@ -99,16 +99,16 @@ func newManagement() *Management {
|
|||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("destroy", smartcontract.VoidType)
|
||||
md = newMethodAndPrice(m.destroy, 1000000, callflag.States|callflag.AllowNotify)
|
||||
md = newMethodAndPrice(m.destroy, 1<<15, callflag.States|callflag.AllowNotify)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getMinimumDeploymentFee", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(m.getMinimumDeploymentFee, 100_0000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(m.getMinimumDeploymentFee, 1<<15, callflag.ReadStates)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setMinimumDeploymentFee", smartcontract.VoidType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(m.setMinimumDeploymentFee, 300_0000, callflag.States)
|
||||
md = newMethodAndPrice(m.setMinimumDeploymentFee, 1<<15, callflag.States)
|
||||
m.AddMethod(md, desc)
|
||||
|
||||
hashParam := manifest.NewParameter("Hash", smartcontract.Hash160Type)
|
||||
|
|
|
@ -104,27 +104,27 @@ func newNameService() *NameService {
|
|||
|
||||
desc := newDescriptor("addRoot", smartcontract.VoidType,
|
||||
manifest.NewParameter("root", smartcontract.StringType))
|
||||
md := newMethodAndPrice(n.addRoot, 3000000, callflag.States)
|
||||
md := newMethodAndPrice(n.addRoot, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setPrice", smartcontract.VoidType,
|
||||
manifest.NewParameter("price", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.setPrice, 3000000, callflag.States)
|
||||
md = newMethodAndPrice(n.setPrice, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getPrice", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.getPrice, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.getPrice, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("isAvailable", smartcontract.BoolType,
|
||||
manifest.NewParameter("name", smartcontract.StringType))
|
||||
md = newMethodAndPrice(n.isAvailable, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.isAvailable, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("register", smartcontract.BoolType,
|
||||
manifest.NewParameter("name", smartcontract.StringType),
|
||||
manifest.NewParameter("owner", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.register, 1000000, callflag.States)
|
||||
md = newMethodAndPrice(n.register, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("renew", smartcontract.IntegerType,
|
||||
|
@ -135,32 +135,34 @@ func newNameService() *NameService {
|
|||
desc = newDescriptor("setAdmin", smartcontract.VoidType,
|
||||
manifest.NewParameter("name", smartcontract.StringType),
|
||||
manifest.NewParameter("admin", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.setAdmin, 3000000, callflag.States)
|
||||
md = newMethodAndPrice(n.setAdmin, 1<<15, callflag.States)
|
||||
md.StorageFee = 20
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setRecord", smartcontract.VoidType,
|
||||
manifest.NewParameter("name", smartcontract.StringType),
|
||||
manifest.NewParameter("type", smartcontract.IntegerType),
|
||||
manifest.NewParameter("data", smartcontract.StringType))
|
||||
md = newMethodAndPrice(n.setRecord, 30000000, callflag.States)
|
||||
md = newMethodAndPrice(n.setRecord, 1<<15, callflag.States)
|
||||
md.StorageFee = 200
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getRecord", smartcontract.StringType,
|
||||
manifest.NewParameter("name", smartcontract.StringType),
|
||||
manifest.NewParameter("type", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.getRecord, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.getRecord, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("deleteRecord", smartcontract.VoidType,
|
||||
manifest.NewParameter("name", smartcontract.StringType),
|
||||
manifest.NewParameter("type", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.deleteRecord, 1000000, callflag.States)
|
||||
md = newMethodAndPrice(n.deleteRecord, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("resolve", smartcontract.StringType,
|
||||
manifest.NewParameter("name", smartcontract.StringType),
|
||||
manifest.NewParameter("type", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.resolve, 3000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.resolve, 1<<17, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
return n
|
||||
|
|
|
@ -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.
|
||||
|
@ -62,8 +67,10 @@ const (
|
|||
// voterRewardFactor is a factor by which voter reward per committee is multiplied
|
||||
// to make calculations more precise.
|
||||
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
|
||||
// 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,48 +114,58 @@ 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),
|
||||
manifest.NewParameter("end", smartcontract.IntegerType))
|
||||
md := newMethodAndPrice(n.unclaimedGas, 3000000, callflag.ReadStates)
|
||||
md := newMethodAndPrice(n.unclaimedGas, 1<<17, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("registerCandidate", smartcontract.BoolType,
|
||||
manifest.NewParameter("pubkey", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(n.registerCandidate, 1000_00000000, callflag.States)
|
||||
md = newMethodAndPrice(n.registerCandidate, 0, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("unregisterCandidate", smartcontract.BoolType,
|
||||
manifest.NewParameter("pubkey", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(n.unregisterCandidate, 5000000, callflag.States)
|
||||
md = newMethodAndPrice(n.unregisterCandidate, 1<<16, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("vote", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("voteTo", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(n.vote, 5000000, callflag.States)
|
||||
md = newMethodAndPrice(n.vote, 1<<16, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getCandidates", smartcontract.ArrayType)
|
||||
md = newMethodAndPrice(n.getCandidatesCall, 100000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.getCandidatesCall, 1<<22, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getCommittee", smartcontract.ArrayType)
|
||||
md = newMethodAndPrice(n.getCommittee, 100000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.getCommittee, 1<<22, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType)
|
||||
md = newMethodAndPrice(n.getNextBlockValidators, 100000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.getNextBlockValidators, 1<<22, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getGasPerBlock", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.getGASPerBlock, 100_0000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.getGASPerBlock, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setGasPerBlock", smartcontract.VoidType,
|
||||
manifest.NewParameter("gasPerBlock", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.setGASPerBlock, 500_0000, callflag.States)
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -55,12 +55,12 @@ func newNEP17Native(name string, id int32) *nep17TokenNative {
|
|||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("totalSupply", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.TotalSupply, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.TotalSupply, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("balanceOf", smartcontract.IntegerType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.balanceOf, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.balanceOf, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
transferParams := []manifest.Parameter{
|
||||
|
@ -71,7 +71,8 @@ func newNEP17Native(name string, id int32) *nep17TokenNative {
|
|||
desc = newDescriptor("transfer", smartcontract.BoolType,
|
||||
append(transferParams, manifest.NewParameter("data", smartcontract.AnyType))...,
|
||||
)
|
||||
md = newMethodAndPrice(n.Transfer, 9000000, callflag.States|callflag.AllowCall|callflag.AllowNotify)
|
||||
md = newMethodAndPrice(n.Transfer, 1<<17, callflag.States|callflag.AllowCall|callflag.AllowNotify)
|
||||
md.StorageFee = 50
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
n.AddEvent("Transfer", transferParams...)
|
||||
|
@ -283,10 +284,10 @@ func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Para
|
|||
}
|
||||
}
|
||||
|
||||
func newMethodAndPrice(f interop.Method, price int64, flags callflag.CallFlag) *interop.MethodAndPrice {
|
||||
func newMethodAndPrice(f interop.Method, cpuFee int64, flags callflag.CallFlag) *interop.MethodAndPrice {
|
||||
return &interop.MethodAndPrice{
|
||||
Func: f,
|
||||
Price: price,
|
||||
CPUFee: cpuFee,
|
||||
RequiredFlags: flags,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,37 +77,38 @@ func newNonFungible(name string, id int32, symbol string, decimals byte) *nonfun
|
|||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("totalSupply", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.totalSupply, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.totalSupply, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("ownerOf", smartcontract.Hash160Type,
|
||||
manifest.NewParameter("tokenId", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(n.OwnerOf, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.OwnerOf, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("balanceOf", smartcontract.IntegerType,
|
||||
manifest.NewParameter("owner", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.BalanceOf, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.BalanceOf, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("properties", smartcontract.MapType,
|
||||
manifest.NewParameter("tokenId", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(n.Properties, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.Properties, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("tokens", smartcontract.AnyType)
|
||||
md = newMethodAndPrice(n.tokens, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.tokens, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("tokensOf", smartcontract.AnyType,
|
||||
manifest.NewParameter("owner", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.tokensOf, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.tokensOf, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("transfer", smartcontract.BoolType,
|
||||
manifest.NewParameter("to", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("tokenId", smartcontract.ByteArrayType))
|
||||
md = newMethodAndPrice(n.transfer, 9000000, callflag.States|callflag.AllowNotify)
|
||||
md = newMethodAndPrice(n.transfer, 1<<17, callflag.States|callflag.AllowNotify)
|
||||
md.StorageFee = 50
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
n.AddEvent("Transfer",
|
||||
|
|
|
@ -41,7 +41,7 @@ type Notary struct {
|
|||
const (
|
||||
notaryContractID = reservedContractID - 1
|
||||
// NotaryVerificationPrice is the price of `verify` Notary method.
|
||||
NotaryVerificationPrice = 100_0000
|
||||
NotaryVerificationPrice = 1 << 15
|
||||
|
||||
// prefixDeposit is a prefix for storing Notary deposits.
|
||||
prefixDeposit = 1
|
||||
|
@ -60,29 +60,29 @@ func newNotary() *Notary {
|
|||
manifest.NewParameter("from", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("amount", smartcontract.IntegerType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType))
|
||||
md := newMethodAndPrice(n.onPayment, 100_0000, callflag.States)
|
||||
md := newMethodAndPrice(n.onPayment, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("lockDepositUntil", smartcontract.BoolType,
|
||||
manifest.NewParameter("address", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("till", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.lockDepositUntil, 100_0000, callflag.States)
|
||||
md = newMethodAndPrice(n.lockDepositUntil, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("withdraw", smartcontract.BoolType,
|
||||
manifest.NewParameter("from", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("to", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.withdraw, 100_0000, callflag.States)
|
||||
md = newMethodAndPrice(n.withdraw, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("balanceOf", smartcontract.IntegerType,
|
||||
manifest.NewParameter("addr", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.balanceOf, 100_0000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.balanceOf, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("expirationOf", smartcontract.IntegerType,
|
||||
manifest.NewParameter("addr", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(n.expirationOf, 100_0000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.expirationOf, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("verify", smartcontract.BoolType,
|
||||
|
@ -91,12 +91,12 @@ func newNotary() *Notary {
|
|||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getMaxNotValidBeforeDelta", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(n.getMaxNotValidBeforeDelta, 100_0000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(n.getMaxNotValidBeforeDelta, 1<<15, callflag.ReadStates)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setMaxNotValidBeforeDelta", smartcontract.VoidType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 300_0000, callflag.States)
|
||||
md = newMethodAndPrice(n.setMaxNotValidBeforeDelta, 1<<15, callflag.States)
|
||||
n.AddMethod(md, desc)
|
||||
|
||||
return n
|
||||
|
|
|
@ -40,6 +40,9 @@ type Oracle struct {
|
|||
Desig *Designate
|
||||
oracleScript []byte
|
||||
|
||||
requestPrice atomic.Value
|
||||
requestPriceChanged atomic.Value
|
||||
|
||||
// Module is an oracle module capable of talking with the external world.
|
||||
Module atomic.Value
|
||||
// newRequests contains new requests created during current block.
|
||||
|
@ -55,13 +58,15 @@ const (
|
|||
// maxRequestsCount is the maximum number of requests per URL
|
||||
maxRequestsCount = 256
|
||||
|
||||
oracleRequestPrice = 5000_0000
|
||||
// DefaultOracleRequestPrice is default amount GAS needed for oracle request.
|
||||
DefaultOracleRequestPrice = 5000_0000
|
||||
)
|
||||
|
||||
var (
|
||||
prefixIDList = []byte{6}
|
||||
prefixRequest = []byte{7}
|
||||
prefixRequestID = []byte{9}
|
||||
prefixRequestPrice = []byte{5}
|
||||
prefixIDList = []byte{6}
|
||||
prefixRequest = []byte{7}
|
||||
prefixRequestID = []byte{9}
|
||||
)
|
||||
|
||||
// Various validation errors.
|
||||
|
@ -91,7 +96,7 @@ func newOracle() *Oracle {
|
|||
manifest.NewParameter("callback", smartcontract.StringType),
|
||||
manifest.NewParameter("userData", smartcontract.AnyType),
|
||||
manifest.NewParameter("gasForResponse", smartcontract.IntegerType))
|
||||
md := newMethodAndPrice(o.request, oracleRequestPrice, callflag.States|callflag.AllowNotify)
|
||||
md := newMethodAndPrice(o.request, 0, callflag.States|callflag.AllowNotify)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("finish", smartcontract.VoidType)
|
||||
|
@ -99,7 +104,7 @@ func newOracle() *Oracle {
|
|||
o.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("verify", smartcontract.BoolType)
|
||||
md = newMethodAndPrice(o.verify, 100_0000, callflag.NoneFlag)
|
||||
md = newMethodAndPrice(o.verify, 1<<15, callflag.NoneFlag)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
o.AddEvent("OracleRequest", manifest.NewParameter("Id", smartcontract.IntegerType),
|
||||
|
@ -109,6 +114,17 @@ func newOracle() *Oracle {
|
|||
o.AddEvent("OracleResponse", manifest.NewParameter("Id", smartcontract.IntegerType),
|
||||
manifest.NewParameter("OriginalTx", smartcontract.Hash256Type))
|
||||
|
||||
desc = newDescriptor("getPrice", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(o.getPrice, 1<<15, callflag.ReadStates)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setPrice", smartcontract.VoidType,
|
||||
manifest.NewParameter("price", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(o.setPrice, 1<<15, callflag.States)
|
||||
o.AddMethod(md, desc)
|
||||
|
||||
o.requestPriceChanged.Store(true)
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
|
@ -130,9 +146,15 @@ func (o *Oracle) OnPersist(ic *interop.Context) error {
|
|||
|
||||
// PostPersist represents `postPersist` method.
|
||||
func (o *Oracle) PostPersist(ic *interop.Context) error {
|
||||
p := o.getPriceInternal(ic.DAO)
|
||||
if o.requestPriceChanged.Load().(bool) {
|
||||
o.requestPrice.Store(p)
|
||||
o.requestPriceChanged.Store(false)
|
||||
}
|
||||
|
||||
var nodes keys.PublicKeys
|
||||
var reward []big.Int
|
||||
single := new(big.Int).SetUint64(oracleRequestPrice)
|
||||
single := big.NewInt(p)
|
||||
var removedIDs []uint64
|
||||
|
||||
orc, _ := o.Module.Load().(services.Oracle)
|
||||
|
@ -202,7 +224,15 @@ func (o *Oracle) Metadata() *interop.ContractMD {
|
|||
|
||||
// Initialize initializes Oracle contract.
|
||||
func (o *Oracle) Initialize(ic *interop.Context) error {
|
||||
return setIntWithKey(o.ID, ic.DAO, prefixRequestID, 0)
|
||||
if err := setIntWithKey(o.ID, ic.DAO, prefixRequestID, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, DefaultOracleRequestPrice); err != nil {
|
||||
return err
|
||||
}
|
||||
o.requestPrice.Store(int64(DefaultOracleRequestPrice))
|
||||
o.requestPriceChanged.Store(false)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getResponse(tx *transaction.Transaction) *transaction.OracleResponse {
|
||||
|
@ -281,6 +311,9 @@ func (o *Oracle) request(ic *interop.Context, args []stackitem.Item) stackitem.I
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !ic.VM.AddGas(o.getPriceInternal(ic.DAO)) {
|
||||
panic("insufficient gas")
|
||||
}
|
||||
if err := o.RequestInternal(ic, url, filter, cb, userData, gas); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -404,6 +437,32 @@ func (o *Oracle) verify(ic *interop.Context, _ []stackitem.Item) stackitem.Item
|
|||
return stackitem.NewBool(ic.Tx.HasAttribute(transaction.OracleResponseT))
|
||||
}
|
||||
|
||||
func (o *Oracle) getPrice(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
|
||||
return stackitem.NewBigInteger(big.NewInt(o.getPriceInternal(ic.DAO)))
|
||||
}
|
||||
|
||||
func (o *Oracle) getPriceInternal(d dao.DAO) int64 {
|
||||
if !o.requestPriceChanged.Load().(bool) {
|
||||
return o.requestPrice.Load().(int64)
|
||||
}
|
||||
return getIntWithKey(o.ID, d, prefixRequestPrice)
|
||||
}
|
||||
|
||||
func (o *Oracle) setPrice(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
price := toBigInt(args[0])
|
||||
if price.Sign() <= 0 || !price.IsInt64() {
|
||||
panic("invalid register price")
|
||||
}
|
||||
if !o.NEO.checkCommittee(ic) {
|
||||
panic("invalid committee signature")
|
||||
}
|
||||
if err := setIntWithKey(o.ID, ic.DAO, prefixRequestPrice, price.Int64()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
o.requestPriceChanged.Store(true)
|
||||
return stackitem.Null{}
|
||||
}
|
||||
|
||||
func (o *Oracle) getOriginalTxID(d dao.DAO, tx *transaction.Transaction) util.Uint256 {
|
||||
for i := range tx.Attributes {
|
||||
if tx.Attributes[i].Type == transaction.OracleResponseT {
|
||||
|
|
|
@ -72,45 +72,45 @@ func newPolicy() *Policy {
|
|||
defer p.UpdateHash()
|
||||
|
||||
desc := newDescriptor("getFeePerByte", smartcontract.IntegerType)
|
||||
md := newMethodAndPrice(p.getFeePerByte, 1000000, callflag.ReadStates)
|
||||
md := newMethodAndPrice(p.getFeePerByte, 1<<15, callflag.ReadStates)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("isBlocked", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(p.isBlocked, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(p.isBlocked, 1<<15, callflag.ReadStates)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getExecFeeFactor", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(p.getExecFeeFactor, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(p.getExecFeeFactor, 1<<15, callflag.ReadStates)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setExecFeeFactor", smartcontract.VoidType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setExecFeeFactor, 3000000, callflag.States)
|
||||
md = newMethodAndPrice(p.setExecFeeFactor, 1<<15, callflag.States)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("getStoragePrice", smartcontract.IntegerType)
|
||||
md = newMethodAndPrice(p.getStoragePrice, 1000000, callflag.ReadStates)
|
||||
md = newMethodAndPrice(p.getStoragePrice, 1<<15, callflag.ReadStates)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setStoragePrice", smartcontract.VoidType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setStoragePrice, 3000000, callflag.States)
|
||||
md = newMethodAndPrice(p.setStoragePrice, 1<<15, callflag.States)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("setFeePerByte", smartcontract.VoidType,
|
||||
manifest.NewParameter("value", smartcontract.IntegerType))
|
||||
md = newMethodAndPrice(p.setFeePerByte, 3000000, callflag.States)
|
||||
md = newMethodAndPrice(p.setFeePerByte, 1<<15, callflag.States)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("blockAccount", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(p.blockAccount, 3000000, callflag.States)
|
||||
md = newMethodAndPrice(p.blockAccount, 1<<15, callflag.States)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
desc = newDescriptor("unblockAccount", smartcontract.BoolType,
|
||||
manifest.NewParameter("account", smartcontract.Hash160Type))
|
||||
md = newMethodAndPrice(p.unblockAccount, 3000000, callflag.States)
|
||||
md = newMethodAndPrice(p.unblockAccount, 1<<15, callflag.States)
|
||||
p.AddMethod(md, desc)
|
||||
|
||||
return p
|
||||
|
|
|
@ -56,7 +56,10 @@ func (bc *Blockchain) registerNative(c interop.Contract) {
|
|||
bc.contracts.Contracts = append(bc.contracts.Contracts, c)
|
||||
}
|
||||
|
||||
const testSumPrice = 1 << 15 * interop.DefaultBaseExecFee // same as contract.Call
|
||||
const (
|
||||
testSumCPUFee = 1 << 15 // same as contract.Call
|
||||
testSumStorageFee = 200
|
||||
)
|
||||
|
||||
func newTestNative() *testNative {
|
||||
tn := &testNative{
|
||||
|
@ -76,7 +79,8 @@ func newTestNative() *testNative {
|
|||
}
|
||||
md := &interop.MethodAndPrice{
|
||||
Func: tn.sum,
|
||||
Price: testSumPrice,
|
||||
CPUFee: testSumCPUFee,
|
||||
StorageFee: testSumStorageFee,
|
||||
RequiredFlags: callflag.NoneFlag,
|
||||
}
|
||||
tn.meta.AddMethod(md, desc)
|
||||
|
@ -93,7 +97,7 @@ func newTestNative() *testNative {
|
|||
}
|
||||
md = &interop.MethodAndPrice{
|
||||
Func: tn.callOtherContractNoReturn,
|
||||
Price: testSumPrice,
|
||||
CPUFee: testSumCPUFee,
|
||||
RequiredFlags: callflag.NoneFlag}
|
||||
tn.meta.AddMethod(md, desc)
|
||||
|
||||
|
@ -108,7 +112,7 @@ func newTestNative() *testNative {
|
|||
}
|
||||
md = &interop.MethodAndPrice{
|
||||
Func: tn.callOtherContractWithReturn,
|
||||
Price: testSumPrice,
|
||||
CPUFee: testSumCPUFee,
|
||||
RequiredFlags: callflag.NoneFlag}
|
||||
tn.meta.AddMethod(md, desc)
|
||||
|
||||
|
@ -182,7 +186,8 @@ func TestNativeContract_Invoke(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// System.Contract.Call + "sum" itself + opcodes for pushing arguments.
|
||||
price := int64(testSumPrice * 2)
|
||||
price := int64(testSumCPUFee * chain.GetBaseExecFee() * 2)
|
||||
price += testSumStorageFee * chain.GetStoragePrice()
|
||||
price += 3 * fee.Opcode(chain.GetBaseExecFee(), opcode.PUSHINT8)
|
||||
price += 2 * fee.Opcode(chain.GetBaseExecFee(), opcode.SYSCALL, opcode.PUSHDATA1, opcode.PUSHINT8)
|
||||
price += fee.Opcode(chain.GetBaseExecFee(), opcode.PACK)
|
||||
|
@ -281,15 +286,16 @@ func TestNativeContract_InvokeOtherContract(t *testing.T) {
|
|||
cs, _ := getTestContractState(chain)
|
||||
require.NoError(t, chain.contracts.Management.PutContractState(chain.dao, cs))
|
||||
|
||||
baseFee := chain.GetBaseExecFee()
|
||||
t.Run("non-native, no return", func(t *testing.T) {
|
||||
res, err := invokeContractMethod(chain, testSumPrice*4+10000, tn.Metadata().Hash, "callOtherContractNoReturn", cs.Hash, "justReturn", []interface{}{})
|
||||
res, err := invokeContractMethod(chain, testSumCPUFee*baseFee*4+10000, tn.Metadata().Hash, "callOtherContractNoReturn", cs.Hash, "justReturn", []interface{}{})
|
||||
require.NoError(t, err)
|
||||
drainTN(t)
|
||||
require.Equal(t, vm.HaltState, res.VMState, res.FaultException)
|
||||
checkResult(t, res, stackitem.Null{}) // simple call is done with EnsureNotEmpty
|
||||
})
|
||||
t.Run("non-native, with return", func(t *testing.T) {
|
||||
res, err := invokeContractMethod(chain, testSumPrice*4+10000, tn.Metadata().Hash,
|
||||
res, err := invokeContractMethod(chain, testSumCPUFee*baseFee*4+10000, tn.Metadata().Hash,
|
||||
"callOtherContractWithReturn", cs.Hash, "ret7", []interface{}{})
|
||||
require.NoError(t, err)
|
||||
drainTN(t)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package core
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
|
@ -248,3 +249,9 @@ func TestOracle_Request(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetSetPrice(t *testing.T) {
|
||||
bc := newTestChain(t)
|
||||
testGetSet(t, bc, bc.contracts.Oracle.Hash, "Price",
|
||||
native.DefaultOracleRequestPrice, 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)
|
||||
})
|
||||
|
|
|
@ -98,8 +98,8 @@ func TestCreateResponseTx(t *testing.T) {
|
|||
tx, err := orc.CreateResponseTx(int64(req.GasForResponse), 1, resp)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 166, tx.Size())
|
||||
assert.Equal(t, int64(2215610), tx.NetworkFee)
|
||||
assert.Equal(t, int64(97784390), tx.SystemFee)
|
||||
assert.Equal(t, int64(2198650), tx.NetworkFee)
|
||||
assert.Equal(t, int64(97801350), tx.SystemFee)
|
||||
}
|
||||
|
||||
func TestOracle_InvalidWallet(t *testing.T) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -14,3 +14,13 @@ func Request(url string, filter []byte, cb string, userData interface{}, gasForR
|
|||
contract.States|contract.AllowNotify,
|
||||
url, filter, cb, userData, gasForResponse)
|
||||
}
|
||||
|
||||
// GetPrice represents `getPrice` method of Oracle native contract.
|
||||
func GetPrice() int {
|
||||
return contract.Call(interop.Hash160(Hash), "getPrice", contract.ReadStates).(int)
|
||||
}
|
||||
|
||||
// SetPrice represents `setPrice` method of Oracle native contract.
|
||||
func SetPrice(amount int) {
|
||||
contract.Call(interop.Hash160(Hash), "setPrice", contract.States, amount)
|
||||
}
|
||||
|
|
|
@ -694,7 +694,7 @@ func (c *Client) CalculateNotaryFee(nKeys uint8) (int64, error) {
|
|||
fee.Opcode(baseExecFee, // Notary node witness
|
||||
opcode.PUSHDATA1, opcode.RET, // invocation script
|
||||
opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // System.Contract.CallNative
|
||||
native.NotaryVerificationPrice + // Notary witness verification price
|
||||
native.NotaryVerificationPrice*baseExecFee + // Notary witness verification price
|
||||
feePerByte*int64(io.GetVarSize(make([]byte, 66))) + // invocation script per-byte fee
|
||||
feePerByte*int64(io.GetVarSize([]byte{})), // verification script per-byte fee
|
||||
nil
|
||||
|
|
|
@ -59,14 +59,21 @@ func Int(w *io.BinWriter, i int64) {
|
|||
val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i))
|
||||
Opcodes(w, val)
|
||||
default:
|
||||
buf := bigint.ToPreallocatedBytes(big.NewInt(i), make([]byte, 0, 32))
|
||||
// l != 0 becase of switch
|
||||
padSize := byte(8 - bits.LeadingZeros8(byte(len(buf)-1)))
|
||||
Opcodes(w, opcode.PUSHINT8+opcode.Opcode(padSize))
|
||||
w.WriteBytes(padRight(1<<padSize, buf))
|
||||
bigInt(w, big.NewInt(i))
|
||||
}
|
||||
}
|
||||
|
||||
func bigInt(w *io.BinWriter, n *big.Int) {
|
||||
buf := bigint.ToPreallocatedBytes(n, make([]byte, 0, 32))
|
||||
if len(buf) == 0 {
|
||||
Opcodes(w, opcode.PUSH0)
|
||||
return
|
||||
}
|
||||
padSize := byte(8 - bits.LeadingZeros8(byte(len(buf)-1)))
|
||||
Opcodes(w, opcode.PUSHINT8+opcode.Opcode(padSize))
|
||||
w.WriteBytes(padRight(1<<padSize, buf))
|
||||
}
|
||||
|
||||
// Array emits array of elements to the given buffer.
|
||||
func Array(w *io.BinWriter, es ...interface{}) {
|
||||
for i := len(es) - 1; i >= 0; i-- {
|
||||
|
@ -75,6 +82,8 @@ func Array(w *io.BinWriter, es ...interface{}) {
|
|||
Array(w, e...)
|
||||
case int64:
|
||||
Int(w, e)
|
||||
case *big.Int:
|
||||
bigInt(w, e)
|
||||
case string:
|
||||
String(w, e)
|
||||
case util.Uint160:
|
||||
|
|
|
@ -3,6 +3,8 @@ package emit
|
|||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||
|
@ -144,7 +146,10 @@ func TestBytes(t *testing.T) {
|
|||
func TestEmitArray(t *testing.T) {
|
||||
t.Run("good", func(t *testing.T) {
|
||||
buf := io.NewBufBinWriter()
|
||||
Array(buf.BinWriter, []interface{}{int64(1), int64(2)}, nil, int64(1), "str", true, []byte{0xCA, 0xFE})
|
||||
veryBig := new(big.Int).SetUint64(math.MaxUint64)
|
||||
veryBig.Add(veryBig, big.NewInt(1))
|
||||
Array(buf.BinWriter, big.NewInt(0), veryBig,
|
||||
[]interface{}{int64(1), int64(2)}, nil, int64(1), "str", true, []byte{0xCA, 0xFE})
|
||||
require.NoError(t, buf.Err)
|
||||
|
||||
res := buf.Bytes()
|
||||
|
@ -163,6 +168,9 @@ func TestEmitArray(t *testing.T) {
|
|||
assert.EqualValues(t, opcode.PUSH1, res[15])
|
||||
assert.EqualValues(t, opcode.PUSH2, res[16])
|
||||
assert.EqualValues(t, opcode.PACK, res[17])
|
||||
assert.EqualValues(t, opcode.PUSHINT128, res[18])
|
||||
assert.EqualValues(t, veryBig, bigint.FromBytes(res[19:35]))
|
||||
assert.EqualValues(t, opcode.PUSH0, res[35])
|
||||
})
|
||||
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
|
|
Loading…
Reference in a new issue