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...))
|
||||
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{}"}},
|
||||
|
|
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue