Какой процесс/рабочий процесс стоит за процессом, когда контракт Ethereum получает некоторые данные с веб-сайта?
Вы можете использовать Oracle . Оракул — это любое устройство или объект, который связывает данные реального мира с блокчейном.
Есть несколько примеров технологий оракула. Chainlink и Provable (ранее Oraclize) — два примера, которые делают именно это.
Здесь есть несколько примеров кода, а также документация нашего Solidity API .
Oraclize доступен как в основной , так и в тестовой сети, поэтому разобраться с ним должно быть легко, однако, если вам нужна поддержка, не стесняйтесь спрашивать — у нас даже есть канал gitter здесь .
Как видите, получить данные с веб-сайта так же просто, как использовать функцию oraclize_query .
Наше хорошее поведение подтверждено доказательством TLSNotary и может быть легко проверено с помощью этого сетевого монитора на стороне клиента .
Например, чтобы получить цену ETHXBT из тикера Kraken:
import "dev.oraclize.it/api.sol";
contract KrakenPriceTicker is usingOraclize {
string public ETHXBT;
function PriceTicker() {
oraclize_setNetwork(networkID_testnet);
oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
oraclize_query("URL", "json(https://api.kraken.com/0/public/Ticker?pair=ETHXBT).result.XETHXXBT.c.0");
}
function __callback(bytes32 myid, string result, bytes proof) {
if (msg.sender != oraclize_cbAddress()) throw;
ETHXBT = result;
// do something with ETHXBT
}
}
Вы не можете сделать это напрямую; Контракты Ethereum не могут обращаться к URL-адресам, потому что Ethereum нуждается в том, чтобы каждый мог независимо проверять результат выполнения любого конкретного контракта, и вы не можете гарантировать, что все они получат одинаковый результат от любого заданного URL-адреса.
Что вы можете сделать, так это попросить третью сторону или комбинацию третьих сторон нажать на URL-адрес для вас и сообщить вам, что они нашли. Они могут сделать это либо подписав данные, чтобы ваш контракт мог проверить подпись (это то, что мы делаем в Reality Keys ), либо отправив данные из своего контракта в ваш контракт (это то, что делает Oraclize).
Взгляните на Etheropt на GitHub для рабочего примера.
Недостатком этого подхода является то, что ваши пользователи должны доверять сервису, который переходит по URL-адресу. Если эта служба повреждена или взломана, это приведет к SFYL. (Oraclize предоставляет нотариальное подтверждение TLS того, что данные, которые они предоставили, были данными, которые они предоставили вам, действительно были предоставлены URL-адресом, но это на самом деле не помогает с реальной угрозой безопасности. Обнаружение того, что они дали вам неправильный ответ, легко, проблема в том, что ваш контракт все равно примет их ответ, хотя все знают, что они лгут...)
Есть несколько потенциальных альтернативных подходов к этой проблеме, которые не зависят от репутации; Самым известным из них является Augur, который заставляет участников рынка голосовать за результат и имеет систему стимулов, которая, как они надеются, заставит людей голосовать честно. Есть также несколько интересных предложений между полностью доверенными сервисами и чистым голосованием пользователей, например , «окончательный оракул» Мартина Коппельманна .
Для клиента Python Ethereum (pyethapp) написано подробное руководство о том, как контракт может получать данные:
https://github.com/ethereum/pyethapp/wiki/Making-a-User-Service:-Tutorial
Одной из самых мощных отличительных особенностей pyethapp является его способность легко создавать встроенные пользовательские сервисы: сценарии, написанные на python, которые запускаются вместе с pyethapp и запускают код при запуске и каждый раз, когда вы получаете новый блок. Это позволяет создавать «серверные демоны» для приложений, которым требуется периодическая автоматизированная поддержка, таких как RANDAO, потоки данных, приложения «децентрализованные папки», будильники, децентрализованные службы облачных вычислений и т. д.
Pyethapp предоставляет on_start
хуки on_block
, которые позволяют запускать код при запуске и обработке блока. Пример кода из учебника:
https://github.com/ethereum/pyethapp/blob/develop/examples/urlfetcher.py
import json, re
import random
import sys
import ethereum.blocks
import ethereum.utils
import ethereum.abi
import rlp
try:
from urllib.request import build_opener
except:
from urllib2 import build_opener
my_privkey = ethereum.utils.sha3('qwufqhwiufyqwiugxqwqcwrqwrcqr')
my_address = ethereum.utils.privtoaddr(my_privkey).encode('hex')
print 'My address', my_address
# Address of the main proxy contract
my_contract_address = ethereum.utils.normalize_address('0xd53096b3cf64d4739bb774e0f055653e7f2cd710')
# Makes a request to a given URL (first arg) and optional params (second arg)
def make_request(*args):
opener = build_opener()
opener.addheaders = [('User-agent',
'Mozilla/5.0'+str(random.randrange(1000000)))]
try:
return opener.open(*args).read().strip()
except Exception as e:
try:
p = e.read().strip()
except:
p = e
raise Exception(p)
true, false = True, False
# ContractTranslator object for the main proxy contract
ct = ethereum.abi.ContractTranslator([{"constant": false, "type": "function", "name": "get(string)", "outputs": [{"type": "int256", "name": "out"}], "inputs": [{"type": "string", "name": "url"}]}, {"inputs": [{"indexed": false, "type": "string", "name": "url"}, {"indexed": false, "type": "address", "name": "callback"}, {"indexed": false, "type": "uint256", "name": "responseId"}, {"indexed": false, "type": "uint256", "name": "fee"}], "type": "event", "name": "GetRequest(string,address,uint256,uint256)"}])
# ContractTranslator object for the contract that is used for testing the main contract
ct2 = ethereum.abi.ContractTranslator([{"constant": false, "type": "function", "name": "callback(bytes,uint256)", "outputs": [], "inputs": [{"type": "bytes", "name": "response"}, {"type": "uint256", "name": "responseId"}]}])
app, my_nonce, chainservice = None, None, None
# Called once on startup
def on_start(_app):
print 'Starting URL translator service'
global app, my_nonce, chainservice
app = _app
chainservice = app.services.chain
my_nonce = chainservice.chain.head.get_nonce(my_address)
# Called every block
def on_block(blk):
global my_nonce, chainservice
for receipt in blk.get_receipts():
for _log in receipt.logs:
# Get all logs to the proxy contract address of the right type
if _log.address == my_contract_address:
log = ct.listen(_log)
if log and log["_event_type"] == "GetRequest":
print 'fetching: ', log["url"]
# Fetch the response
try:
response = make_request(log["url"])
except:
response = ''
print 'response: ', response
# Create the response transaction
txdata = ct2.encode('callback', [response, log["responseId"]])
tx = ethereum.transactions.Transaction(my_nonce, 60 * 10**9, min(100000 + log["fee"] / (60 * 10**9), 2500000), log["callback"], 0, txdata).sign(my_privkey)
print 'txhash: ', tx.hash.encode('hex')
print 'tx: ', rlp.encode(tx).encode('hex')
# Increment the nonce so the next transaction is also valid
my_nonce += 1
# Send it
success = chainservice.add_transaction(tx, broadcast_only=True)
assert success
print 'sent tx'
В учебнике объясняется:
По сути, экземпляр этой службы, управляемой доверенной стороной, позволяет контрактам Ethereum получать доступ к любому потоку данных, доступному через REST API через Интернет.
rewardTweeter(uint numberOfTweets, address tweeter)
. Оракул должен был вызвать эту функцию.Как уже говорили другие, вы должны использовать Oracle. Некоторые проекты, такие как ChainLink и Oracleize , сделают это за вас.
Чтобы настроить оракул самостоятельно, процесс выглядит так:
Попробуйте этот пример в Javascript (на основе оракулов в Ethereum ):
pragma solidity ^0.4.17;
contract GamescoreOracle {
address public owner;
string public gameWinner;
event CallbackGetGameWinner();
constructor() public {
owner = msg.sender;
}
function updateGameWinner() public {
emit CallbackGetGameWinner();
}
function setWinningTeam(string teamname) public {
require(msg.sender == owner, "Err: Not Authorized");
gameWinner = teamname;
}
function getGameWinner() public view returns (string) {
return gameWinner;
}
}
const fetch = require("fetch");
const OracleContract = require("./build/contracts/GamescoreOracle.json");
const contract = require("truffle-contract");
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));
const oracleContract = contract(OracleContract);
oracleContract.setProvider(web3.currentProvider);
web3.eth.getAccounts((err, accounts) => {
oracleContract.deployed()
.then((oracleInstance) => {
// watch event, respond to event with callback
oracleInstance.CallbackGetGameWinner()
.watch((err, event) => {
fetch.fetchUrl('http://www.mocky.io/v2/5baadacb3000002b00a68532', (err, m, response) => {
const games = JSON.parse(response.toString());
const winner = games.competitors.filter(team => team.isWinner)[0].team.nickname;
// Send data back contract on-chain
console.log(`Running contract.setWinningTeam(${winner})`)
oracleInstance.setWinningTeam(winner, { from: accounts[0] })
})
})
})
.catch(err => console.log(err))
})
Оракул может быть управляемой вручную учетной записью человека, которая своевременно передает данные, или, что еще лучше, автоматизированной группой ботов на традиционных серверах, которые очищают веб-сайт и передают данные через учетную запись. Вам нужно будет жестко закодировать адрес контракта в свой контракт как оракул правдивых значений для вашей программы. Закрытый ключ хранится в тайне, в отличие от смарт-контракта, где каждый может его увидеть. Может потребоваться какой-то способ дедупликации и формирования консенсуса для надежной работы с полным резервированием.
Вы должны использовать оракул .
Оракул — это любое устройство, которое отправляет данные вне сети в блокчейн.
Существует множество сервисов оракулов, которые могут помочь вам передавать данные из офчейна в цепочку в рамках Ethereum. Важно отметить, что каждый из них делает это по-разному, что приводит к множеству соображений о том, почему и как вы будете реализовывать их технологию. Вот некоторые из самых популярных:
А вот пример получения данных через узел Chainlink :
pragma solidity ^0.6.0;
import "github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
// MyContract inherits the ChainlinkClient contract to gain the
// functionality of creating Chainlink requests
contract ChainlinkExample is ChainlinkClient {
// Stores the answer from the Chainlink oracle
uint256 public currentPrice;
address public owner;
// The address of an oracle - you can find node addresses on https://market.link/search/nodes
address ORACLE_ADDRESS = 0xB36d3709e22F7c708348E225b20b13eA546E6D9c;
// The address of the http get job - you can find job IDs on https://market.link/search/jobs
string constant JOBID = "628eded7db7f4f799dbf69538dec7ff2";
// 17 0s = 0.1 LINK
// 18 0s = 1 LINK
uint256 constant private ORACLE_PAYMENT = 100000000000000000;
constructor() public {
setPublicChainlinkToken();
owner = msg.sender;
}
// Creates a Chainlink request with the uint256 multiplier job
// Ideally, you'd want to pass the oracle payment, address, and jobID as
function requestEthereumPrice()
public
onlyOwner
{
// newRequest takes a JobID, a callback address, and callback function as input
Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(JOBID), address(this), this.fulfill.selector);
// Adds a URL with the key "get" to the request parameters
req.add("get", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD");
// Uses input param (dot-delimited string) as the "path" in the request parameters
req.add("path", "USD");
// Adds an integer with the key "times" to the request parameters
req.addInt("times", 100);
// Sends the request with the amount of payment specified to the oracle
sendChainlinkRequestTo(ORACLE_ADDRESS, req, ORACLE_PAYMENT);
}
// fulfill receives a uint256 data type
function fulfill(bytes32 _requestId, uint256 _price)
public
// Use recordChainlinkFulfillment to ensure only the requesting oracle can fulfill
recordChainlinkFulfillment(_requestId)
{
currentPrice = _price;
}
// withdrawLink allows the owner to withdraw any extra LINK on the contract
function withdrawLink()
public
onlyOwner
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer");
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
// A helper funciton to make the string a bytes32
function stringToBytes32(string memory source) private pure returns (bytes32 result) {
bytes memory tempEmptyStringTest = bytes(source);
if (tempEmptyStringTest.length == 0) {
return 0x0;
}
assembly { // solhint-disable-line no-inline-assembly
result := mload(add(source, 32))
}
}
}
Вы можете получить данные об акциях, криптовалютах, ETF и т. д. из смарт- контракта OrFeed.org :
Примеры:
Форекс:
uint price = orfeed.getExchangeRate("JPY", "USD", "DEFAULT", 100000);
Запас:
uint price = orfeed.getExchangeRate("AAPL", "USD", "PROVIDER1", 1);
или в реальном времени с DEX:uint price = orfeed.getExchangeRate("BTC", "DAI", "SELL-UNISWAP-EXCHANGE", 100);
происхождение
происхождение
Томас Бертани
Джефф Коулман
0xtuytuy
Томас Бертани
Матас Вайткявичюс
татиго