Как договор Ethereum может получать данные с веб-сайта?
Каков процесс /рабочий процесс за процессом, в котором контракт Ethereum получает некоторые данные с веб-сайта?
4 ответа
Вы можете использовать Oraclize , чтобы сделать именно это. (Это пример Oracle - механизм получения информации о реальном мире в контракт и из него.)
Ниже приведены примеры здесь , а также документирование нашего API Solidity .
Oraclize доступен как на mainnet, так и testnet , так что с ним нужно быть уверенным, но если вам нужна любая поддержка, не стесняйтесь спрашивать - у нас даже есть канал 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 /вики /Создание-а-User-Service: -Tutorial
Одной из самых сильных отличительных особенностей pyethapp является его способность легко создавать встроенные пользовательские сервисы: скрипты, написанные на python которые запускаются вместе с pyethapp и запускают код при запуске и каждый раз вы получаете новый блок. Это позволяет создавать «серверные демоны», для приложений, для которых требуется периодическая автоматическая поддержка, например RANDAO, каналы передачи данных, «децентрализованные приложения Dropbox», будильники, децентрализованные службы облачных вычислений и т. д.
Pyethapp предоставляет on_start
и on_block
крючки, которые позволяют запускать код при запуске и при обработке блока. Пример кода из учебника:
https://github.com/ethereum/pyethapp/blob/разработка /примеры /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 через Интернет.
Оракул может быть управляемой вручную учетной записью человека, которая передает данные. Или автоматический робот, который скрежет веб-сайт и передает данные через учетную запись. Вам необходимо будет жестко закодировать контрактный адрес в своем контракте как оракул правдивых значений для вашей программы.