forked from TrueCloudLab/neoneo-go
native: allow to set oracle request price
This commit is contained in:
parent
27fc28bd69
commit
256cd09228
4 changed files with 84 additions and 6 deletions
|
@ -120,7 +120,9 @@ func TestNativeHelpersCompile(t *testing.T) {
|
||||||
}, nep17TestCases...))
|
}, nep17TestCases...))
|
||||||
runNativeTestCases(t, cs.GAS.ContractMD, "gas", nep17TestCases)
|
runNativeTestCases(t, cs.GAS.ContractMD, "gas", nep17TestCases)
|
||||||
runNativeTestCases(t, cs.Oracle.ContractMD, "oracle", []nativeTestCase{
|
runNativeTestCases(t, cs.Oracle.ContractMD, "oracle", []nativeTestCase{
|
||||||
|
{"getPrice", nil},
|
||||||
{"request", []string{`"url"`, "nil", `"callback"`, "nil", "123"}},
|
{"request", []string{`"url"`, "nil", `"callback"`, "nil", "123"}},
|
||||||
|
{"setPrice", []string{"10"}},
|
||||||
})
|
})
|
||||||
runNativeTestCases(t, cs.Designate.ContractMD, "roles", []nativeTestCase{
|
runNativeTestCases(t, cs.Designate.ContractMD, "roles", []nativeTestCase{
|
||||||
{"designateAsRole", []string{"1", "[]interop.PublicKey{}"}},
|
{"designateAsRole", []string{"1", "[]interop.PublicKey{}"}},
|
||||||
|
|
|
@ -40,6 +40,9 @@ type Oracle struct {
|
||||||
Desig *Designate
|
Desig *Designate
|
||||||
oracleScript []byte
|
oracleScript []byte
|
||||||
|
|
||||||
|
requestPrice atomic.Value
|
||||||
|
requestPriceChanged atomic.Value
|
||||||
|
|
||||||
// Module is an oracle module capable of talking with the external world.
|
// Module is an oracle module capable of talking with the external world.
|
||||||
Module atomic.Value
|
Module atomic.Value
|
||||||
// newRequests contains new requests created during current block.
|
// newRequests contains new requests created during current block.
|
||||||
|
@ -55,13 +58,15 @@ const (
|
||||||
// maxRequestsCount is the maximum number of requests per URL
|
// maxRequestsCount is the maximum number of requests per URL
|
||||||
maxRequestsCount = 256
|
maxRequestsCount = 256
|
||||||
|
|
||||||
oracleRequestPrice = 5000_0000
|
// DefaultOracleRequestPrice is default amount GAS needed for oracle request.
|
||||||
|
DefaultOracleRequestPrice = 5000_0000
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
prefixIDList = []byte{6}
|
prefixRequestPrice = []byte{5}
|
||||||
prefixRequest = []byte{7}
|
prefixIDList = []byte{6}
|
||||||
prefixRequestID = []byte{9}
|
prefixRequest = []byte{7}
|
||||||
|
prefixRequestID = []byte{9}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Various validation errors.
|
// Various validation errors.
|
||||||
|
@ -109,6 +114,17 @@ func newOracle() *Oracle {
|
||||||
o.AddEvent("OracleResponse", manifest.NewParameter("Id", smartcontract.IntegerType),
|
o.AddEvent("OracleResponse", manifest.NewParameter("Id", smartcontract.IntegerType),
|
||||||
manifest.NewParameter("OriginalTx", smartcontract.Hash256Type))
|
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
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +146,15 @@ func (o *Oracle) OnPersist(ic *interop.Context) error {
|
||||||
|
|
||||||
// PostPersist represents `postPersist` method.
|
// PostPersist represents `postPersist` method.
|
||||||
func (o *Oracle) PostPersist(ic *interop.Context) error {
|
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 nodes keys.PublicKeys
|
||||||
var reward []big.Int
|
var reward []big.Int
|
||||||
single := new(big.Int).SetUint64(oracleRequestPrice)
|
single := big.NewInt(p)
|
||||||
var removedIDs []uint64
|
var removedIDs []uint64
|
||||||
|
|
||||||
orc, _ := o.Module.Load().(services.Oracle)
|
orc, _ := o.Module.Load().(services.Oracle)
|
||||||
|
@ -202,7 +224,15 @@ func (o *Oracle) Metadata() *interop.ContractMD {
|
||||||
|
|
||||||
// Initialize initializes Oracle contract.
|
// Initialize initializes Oracle contract.
|
||||||
func (o *Oracle) Initialize(ic *interop.Context) error {
|
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 {
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
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 {
|
if err := o.RequestInternal(ic, url, filter, cb, userData, gas); err != nil {
|
||||||
panic(err)
|
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))
|
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 {
|
func (o *Oracle) getOriginalTxID(d dao.DAO, tx *transaction.Transaction) util.Uint256 {
|
||||||
for i := range tx.Attributes {
|
for i := range tx.Attributes {
|
||||||
if tx.Attributes[i].Type == transaction.OracleResponseT {
|
if tx.Attributes[i].Type == transaction.OracleResponseT {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"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)
|
||||||
|
}
|
||||||
|
|
|
@ -14,3 +14,13 @@ func Request(url string, filter []byte, cb string, userData interface{}, gasForR
|
||||||
contract.States|contract.AllowNotify,
|
contract.States|contract.AllowNotify,
|
||||||
url, filter, cb, userData, gasForResponse)
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue