Was ist der Prozess/Workflow hinter dem Prozess, bei dem ein Ethereum-Vertrag einige Daten von einer Website erhält?
Sie können ein Orakel verwenden . Ein Orakel ist ein beliebiges Gerät oder eine Entität, die reale Daten mit der Blockchain verbindet.
Es gibt mehrere Beispiele für Oracle-Technologien. Chainlink und Provable (ehemals Oraclize) sind zwei Beispiele, die genau das tun.
Hier finden Sie einige Codebeispiele sowie die Dokumentation unserer Solidity-API .
Oraclize ist sowohl im Mainnet als auch im Testnet verfügbar , also sollte es einfach sein, damit herumzustöbern, aber wenn Sie Unterstützung benötigen, fragen Sie einfach – wir haben hier sogar einen Gitter-Kanal .
Wie Sie sehen können, ist das Abrufen von Daten von einer Website so einfach wie die Verwendung der oraclize_query- Funktion.
Unser gutes Benehmen wird durch den TLSNotary- Nachweis gewährt und kann mit diesem webbasierten clientseitigen Netzwerkmonitor einfach überprüft werden .
Um beispielsweise den ETHXBT-Preis aus dem Kraken-Ticker abzurufen:
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
}
}
Sie können dies nicht direkt tun; Ethereum-Verträge können keine URLs treffen, da Ethereum jeden in der Lage sein muss, das Ergebnis der Ausführung eines bestimmten Vertrags unabhängig zu validieren, und Sie können nicht garantieren, dass sie alle das gleiche Ergebnis von einer bestimmten URL erhalten.
Was Sie tun können, ist, einen Drittanbieter oder eine Kombination von Drittanbietern dazu zu bringen, die URL für Sie zu finden und Ihnen mitzuteilen, was sie gefunden haben. Sie können dies entweder tun, indem sie die Daten signieren, damit Ihr Vertrag die Signatur überprüfen kann (das machen wir bei Reality Keys ) oder indem sie die Daten aus ihrem Vertrag an Ihren Vertrag senden (das macht Oraclize).
Werfen Sie einen Blick auf Etheropt auf GitHub für ein funktionierendes Beispiel.
Der Nachteil dieses Ansatzes besteht darin, dass Ihre Benutzer dem Dienst vertrauen müssen, der auf die URL zugreift. Wenn dieser Dienst beschädigt oder gehackt wird, führt dies zu SFYL. (Oraclize liefert einen TLS-Notarbeweis, dass die von ihnen bereitgestellten Daten die Daten waren, die sie Ihnen tatsächlich von der URL bereitgestellt haben, aber das hilft nicht wirklich beim tatsächlichen Sicherheitsrisiko; es ist einfach zu erkennen, dass sie Ihnen die falsche Antwort gegeben haben Das Problem ist, dass Ihr Vertrag immer noch ihre Antwort akzeptiert, obwohl jeder weiß, dass sie lügen ...)
Es gibt einige potenzielle alternative Ansätze für dieses Problem, die sich nicht auf die Reputation verlassen; Das bekannteste ist Augur, das die Marktteilnehmer dazu bringt, über das Ergebnis abzustimmen, und über ein System von Anreizen verfügt, von dem sie hoffen, dass die Menschen wahrheitsgemäß abstimmen. Es gibt auch einige interessante Vorschläge zwischen vollständig vertrauenswürdigen Diensten und reinem Benutzervoting, wie Martin Koeppelmanns "ultimatives Orakel" .
Für den Python-Ethereum-Client (pyethapp) wurde ein ausführliches Tutorial geschrieben, wie ein Vertrag Daten erhalten kann:
https://github.com/ethereum/pyethapp/wiki/Making-a-User-Service:-Tutorial
Eines der stärksten Unterscheidungsmerkmale von pyethapp ist seine Fähigkeit, integrierte Benutzerdienste einfach zu erstellen: in Python geschriebene Skripte, die neben pyethapp ausgeführt werden und beim Start und jedes Mal, wenn Sie einen neuen Block erhalten, Code ausführen. Auf diese Weise können Sie „Server-Daemons“ für Anwendungen erstellen, die regelmäßig automatisierte Unterstützung benötigen, wie z. B. RANDAO, Datenfeeds, „dezentrale Dropbox“-Apps, Wecker, dezentrale Cloud-Computing-Dienste usw.
Pyethapp stellt Hooks bereit, mit denen Code ausgeführt werden kann, wenn es gestartet wird und wenn es einen Block verarbeitet on_start
. on_block
Beispielcode aus dem Tutorial:
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'
Das Tutorial erklärt:
Im Wesentlichen ermöglicht eine Instanz dieses Dienstes, die von einer vertrauenswürdigen Partei betrieben wird, Ethereum-Verträgen den Zugriff auf alle Daten-Feeds, die über eine REST-API über das Internet verfügbar sind.
rewardTweeter(uint numberOfTweets, address tweeter)
. Ein Orakel müsste diese Funktion aufrufen.Wie andere gesagt haben, müssen Sie ein Orakel verwenden. Einige Projekte wie ChainLink und Oracleize erledigen dies für Sie.
Um ein Orakel in Eigenregie einzurichten, sieht der Prozess wie folgt aus:
Versuchen Sie dieses Beispiel in Javascript (basierend auf Oracles in 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))
})
Ein Orakel kann ein manuell gesteuertes menschliches Konto sein, das Daten zeitnah einspeist, oder besser ein automatisierter Haufen von Bots auf traditionellen Servern, die eine Website abkratzen und Daten über das Konto einspeisen. Sie müssten eine Vertragsadresse als Orakel wahrer Werte für Ihr Programm fest in Ihren Vertrag codieren. Der private Schlüssel wird privat gehalten, im Gegensatz zu einem Smart Contract, wo jeder ihn sehen kann. Für einen vollständig redundanten, zuverlässigen Betrieb ist möglicherweise eine Möglichkeit zum Deduplizieren und Konsensieren erforderlich.
Sie müssen ein Orakel verwenden .
Ein Orakel ist jedes Gerät, das Off-Chain-Daten an eine Blockchain sendet.
Es gibt viele Orakeldienste, die Ihnen helfen können, Daten innerhalb des Ethereum-Frameworks von Off-Chain zu On-Chain zu übertragen. Es ist wichtig zu beachten, dass jeder es sehr unterschiedlich macht, was zu vielen Überlegungen führt, warum/wie Sie ihre Technologie implementieren würden. Hier sind einige der beliebtesten:
Und hier ist ein Beispiel für das Abrufen von Daten über einen Chainlink-Knoten :
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))
}
}
}
Sie können Aktien-, Krypto-, ETF- usw. Daten aus dem Smart Contract von OrFeed.org abrufen :
Beispiele:
Devisen:
uint price = orfeed.getExchangeRate("JPY", "USD", "DEFAULT", 100000);
Aktie:
uint price = orfeed.getExchangeRate("AAPL", "USD", "PROVIDER1", 1);
oder in Echtzeit von einem DEX:uint price = orfeed.getExchangeRate("BTC", "DAI", "SELL-UNISWAP-EXCHANGE", 100);
Abstammung
Abstammung
Thomas Bertani
Jeff Colemann
0xtuytuy
Thomas Bertani
Matas Vaitkevicius
tatigo