Oracle Process Flow
Let us take a look at an example and some sample code with respect to Oracle contract
An Oracle contract can be deployed on the Ontology network to send Oracle requests and fetch data from outside world and make it accessible to other smart contracts.
In the future, all the deployed Oracle contracts will be listed on the Oracle market
The sample Oracle contract that we will be looking at here fetches sports statistics, i.e., match details.
Let's say the address of an example Oracle contract is as follows:
The structure of the Oracle request is of the form:
operation = "CreateOracleRequest"
request = """{
"scheduler": {
"type": "runAfter",
"params": "2018-06-15 08:37:18"
},
"tasks": [
{
"type": "httpGet",
"params": {
"url": "https://bitstamp.net/api/ticker/"
}
},
{
"type": "jsonParse",
"params":
{
"data":
[
{
"type": "String",
"path": ["timestamp"]
},
{
"type": "String",
"path": ["last"]
},
{
"type": "Float",
"decimal": 100,
"path": ["open"]
}
]
}
}
]
}"""
args = [request, address]
The response is as follows:
{
"high": "5610.00000000",
"last": "5518.70",
"timestamp": "1542359479",
"bid": "5518.12",
"vwap": "5436.78",
"volume": "16423.18407040",
"low": "5199.80000000",
"ask": "5518.69",
"open": 5571.12
}
Parameters:
url
, URL of the GET requestJsonParse will parse the
http
response with the parameter path list as key. The result will then be serialized to form a data structure, as defined by the user, and then finally written in the Oracle contract.
Here is a list of the parameters:Parameter | Description |
data | Data structure defined by the user |
type | Data type, support int, float(* decimal as int), string, array, map, struct |
sub_type | Sub-type of the array, map and struct |
decimal | decimal places of floating point value |
path | Iterator list of JSON parse key, if data is json , write key in list, if data is array, write index as string in list |
Here's a complex JsonParse example:
var request = """{
"scheduler": {
"type": "runAfter",
"params": "2018-06-15 08:37:18"
},
"tasks": [
{
"type": "httpGet",
"params": {
"url": "http://data.nba.net/prod/v2/20181129/scoreboard.json"
}
},
{
"type": "jsonParse",
"params":
{
"data":
[
{
"type": "Array",
"path": ["games"],
"sub_type":
[
{
"type": "Struct",
"sub_type":
[
{
"type": "String",
"path": ["gameId"]
},
{
"type": "String",
"path": ["vTeam", "teamId"]
},
{
"type": "String",
"path": ["vTeam", "score"]
},
{
"type": "String",
"path": ["hTeam", "teamId"]
},
{
"type": "String",
"path": ["hTeam", "score"]
}
]
}
]
}
]
}
}
]
}"""
A part of the raw
HTTP
response is:{
"numGames": 3,
"games": [{
"gameId": "0021800316",
"vTeam": {
"teamId": "1610612744",
"score": "128"
},
"hTeam": {
"teamId": "1610612761",
"score": "131"
}
},
{
"gameId": "0021800317",
"vTeam": {
"teamId": "2610612744",
"score": "96"
},
"hTeam": {
"teamId": "2610612761",
"score": "131"
}
},
{
"gameId": "0021800318",
"vTeam": {
"teamId": "3610612744",
"score": "128"
},
"hTeam": {
"teamId": "3610612761",
"score": "131"
}
}
]
}
Here, the raw
HTTP
response is parsed and then a structure is created based on the data structure, which is then serialized.An application smart contract calls the Oracle contract to fetch the result and then deserializes it as follows:
[
[
["0021800316", "1610612744", "128", "1610612761", "131"],
["0021800317", "2610612744", "128", "2610612761", "131"],
["0021800318", "3610612744", "128", "3610612761", "131"]
]
]
This option is used to fix the time when a contract or task will be executed. It's format is as follows:
{
"type": "",
"params": "",
}
Currently it only supports one execution method, runAfter.
runAfter is used to specify a time when the task is to be run. For example, this can be used to send scores to the user after a game has ended. If the
type
field is left empty, the task will be run immediately. While the params
field is used to specify the time in this format: YYYY-MM-DD HH:MM:SS
Example - "2018-06-15 08:37:18"The request format is as follows:
operation = "CreateOracleRequest"
request = """{
"scheduler": {
"type": "runAfter",
"params": "2018-06-15 08:37:18"
},
"tasks":[
{
"type": "httpPost",
"params": {
"url": "https://api.random.org/json-rpc/1/invoke",
"contentType": "application/json-rpc",
"body": "{\\"jsonrpc\\": \\"2.0\\",\\"method\\": \\"generateSignedIntegers\\",\\"params\\": {\\"apiKey\\": \\"c7511065-c88d-4f28-af4f-293c91ad20d9\\",\\"n\\": 6,\\"min\\": 1,\\"max\\": 10,\\"replacement\\": false,\\"base\\": 10},\\"id\\": 1}"
}
},
{
"type": "jsonParse",
"params":
{
"data":
[
{
"type": "Array",
"path": ["result", "random", "data"],
"sub_type":
[
{
"type": "Int"
}
]
}
]
}
}
]
}"""
args = [request, address]
The raw
HTTP
response is:{
"jsonrpc": "2.0",
"result": {
"random": {
"method": "generateSignedIntegers",
"hashedApiKey": "oT3AdLMVZKajz0pgW/8Z+t5sGZkqQSOnAi1aB8Li0tXgWf8LolrgdQ1wn9sKx1ehxhUZmhwUIpAtM8QeRbn51Q==",
"n": 6,
"min": 1,
"max": 6,
"replacement": true,
"base": 10,
"data": [
2,
4,
4,
1,
5,
3
],
"completionTime": "2013-09-30 14:58:03Z",
"serialNumber": 69260
},
"signature": "BxHxajeRg7Q+XGjBdFS1c7wkZbJgJlverfZ5TVDyzCKqo2K5A4pD+54EMqmysRYwkL3w2NS2DFLVrsyO1o96bW9BGp5zjjrEegz9mB+04iOTaRwmdQnLJAj/m3WRptA+qzodPCTaqud8YWBifqWCM34q98XwjX+nlahyHVHT9vf5KO0YVkD/yRI1WN5M/qX21chVvSxhWdmIrdCkrovGnysFq8SzCRNhpYx+/1P+YT2IKsH8jth9z82IAz1ANVh918H/UdpuD1dR7TD6nk3ntRgGrIiu2qqVzFi8A7/6viVgRqtffE4KVZY6O9mUJ+sGkF5Ohayms7LHSFy1VC8wMbMgwod+A8nr5yzjAC4SCUkT1bKAyWNF3SdVcLtvWdcf97Ew6RjohzCW4Vs3jUlh6jF/pj3b3++U3lBHCh43IIonw8MQ7afwpqP12yvyDym1isNjhMKYjmzWRerSvnsMyQIH8xFW7IHt2g/0qnzJgABFmUNBRKJPCD9CMgjh60sSwW7EyrGMy7/qisfE0IU74P/F7KCty/g1jIlXX5/O1lQjwY34wnoP0NXL08QteukRZZUfJQnscx1NGE+HX1c9bMBI8LC0ZFYFk+uY6ib/0rCV5OcLLE9PihCdC8WoI1x3bobr8tbtfgnXMTjogxwVXiiSN1TMnTIWlJ+KM5eSWrw=",
"bitsUsed": 16,
"bitsLeft": 932400,
"requestsLeft": 199991,
"advisoryDelay": 1000
},
"id": 1
}
An application contract deserializes the result as follows:
[
[
2,
4,
4,
1,
5,
3
]
]
The
HTTP
post example above fetches a random number from random.org. This Ontology Oracle packages a more convenient method randomOrg
to get a signed random number.The request is as follows:
operation = "CreateOracleRequest"
request = """{
"scheduler": {
"type": "runAfter",
"params": "2018-06-15 08:37:18"
},
"tasks": [
{
"type": "randomOrg",
"params": {
"method": "GenerateSignedIntegers",
"n": 10,
"min": 1,
"max": 10,
"replacement": false
}
},
{
"type": "jsonParse",
"params":
{
"data":
[
{
"type": "Array",
"path": ["data"],
"sub_type":
[
{
"type": "Int"
}
]
},
{
"type": "String",
"path": ["signature"]
}
]
}
}
]
}"""
args = [request, address]
Here is the list of parameters:
Parameter | Description |
n | Number of random numbers |
min | Lower limit for random numbers |
max | Upper limit for random numbers |
replacement | true : random number can occur multiple times, false : numbers are unique |
The response is:
type SignedIntegerData struct {
Raw json.RawMessage `json:"raw"`
HashedApiKey string `json:"hashedApiKey"`
SerialNumber int `json:"serialNumber"`
Data []int `json:"data"`
Signature string `json:"signature"`
}
Unsigned random numbers can also be generated as follows:
operation = "{
"scheduler": {
"type": "runAfter",
"params": "2018-06-15 08:37:18"
},
"tasks": [
{
"type": "randomOrg",
"params": {
"method": "GenerateIntegers",
"n": 10,
"min": 1,
"max": 10,
"replacement": false
}
},
{
"type": "jsonParse",
"params":
{
"data":
[
{
"type": "Array",
"path": ["data"],
"sub_type":
[
{
"type": "Int"
}
]
},
{
"type": "String",
"path": ["completionTime"]
}
]
}
}
]
}"""
args = [request, address]
Parameter | Description |
n | Number of random numbers |
min | Lower limit for random numbers |
max | Upper limit for random numbers |
replacement | true : random number can occur multiple times, false : numbers are unique |
The response is as follows:
type IntegerData struct {
Data []interface{} `json:"data"`
CompletionTime string `json:"completionTime"`
}
The transaction hash
txhash
can be used to fetch the result of the on-chain Oracle request. The request format is:operation = "GetOracleOutcome"
args = txhash