¿Cuál es el proceso/flujo de trabajo detrás del proceso en el que un contrato de Ethereum obtiene algunos datos de un sitio web?
Puedes usar un Oracle . Un oráculo es cualquier dispositivo o entidad que conecta datos del mundo real con la cadena de bloques.
Hay varios ejemplos de tecnologías Oracle. Chainlink y Provable (anteriormente Oraclize) son dos ejemplos que hacen exactamente eso.
Hay algunos ejemplos de código aquí , así como la documentación de nuestra Solidity API .
Oraclize está disponible tanto en la red principal como en la red de prueba, por lo que explorarlo debería ser fácil; sin embargo, si necesita ayuda, no dude en preguntar; incluso tenemos un canal gitter aquí .
Como puede ver , obtener datos de un sitio web es tan fácil como usar la función oraclize_query .
Nuestro buen comportamiento está garantizado por la prueba TLSNotary y se puede verificar fácilmente con este monitor de red del lado del cliente basado en la web .
Por ejemplo, para obtener el precio de ETHXBT del ticker de 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
}
}
No puedes hacer esto directamente; Los contratos de Ethereum no pueden llegar a las URL, porque Ethereum necesita que todos puedan validar de forma independiente el resultado de ejecutar un contrato determinado, y no puede garantizar que todos obtengan el mismo resultado de una URL determinada.
Lo que puede hacer es conseguir que un tercero, o una combinación de terceros, acceda a la URL por usted y le diga lo que encontró. Pueden hacerlo firmando los datos para que su contrato pueda verificar la firma (esto es lo que hacemos en Reality Keys ) o enviando los datos de su contrato a su contrato (esto es lo que hace Oraclize).
Eche un vistazo a Etheropt en GitHub para ver un ejemplo de trabajo.
La desventaja de este enfoque es que los usuarios deben confiar en el servicio que accede a la URL. Si ese servicio está dañado o pirateado, esto dará como resultado SFYL. (Oraclize proporciona una prueba notarial de TLS de que los datos que proporcionaron eran los datos que le proporcionaron a usted realmente fueron proporcionados por la URL, pero eso realmente no ayuda con el riesgo de seguridad real; Detectar que le dieron la respuesta incorrecta es fácil, el el problema es que su contrato seguirá aceptando su respuesta aunque todos saben que están mintiendo...)
Hay algunos enfoques alternativos potenciales para este problema que no se basan en la reputación; El más famoso es Augur, que hace que los participantes del mercado voten sobre el resultado y tiene un sistema de incentivos que esperan que haga que la gente vote con sinceridad. También hay algunas propuestas interesantes entre los servicios totalmente confiables y la votación pura de los usuarios, como el "último oráculo" de Martin Koeppelmann .
Se ha escrito un tutorial detallado sobre cómo un contrato puede obtener datos para el cliente Python Ethereum (pyethapp):
https://github.com/ethereum/pyethapp/wiki/Creación-de-un-servicio-de-usuario:-Tutorial
Una de las características distintivas más poderosas de pyethapp es su capacidad para crear fácilmente servicios de usuario integrados: scripts escritos en python que se ejecutan junto con pyethapp y ejecutan código al inicio y cada vez que recibe un nuevo bloque. Esto le permite crear "demonios de servidor" para aplicaciones que requieren soporte automatizado periódico, como RANDAO, fuentes de datos, aplicaciones de "buzón descentralizado", despertadores, servicios de computación en la nube descentralizados, etc.
Pyethapp proporciona enlaces on_start
que on_block
permiten que el código se ejecute cuando se inicia y cuando procesa un bloque. Código de ejemplo del 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'
El tutorial explica:
Esencialmente, una instancia de este servicio ejecutada por una parte confiable permite que los contratos de Ethereum accedan a cualquier fuente de datos que esté disponible a través de una API REST en Internet.
rewardTweeter(uint numberOfTweets, address tweeter)
. Un oráculo tendría que llamar a esa función.Como han dicho otros, debes usar un Oracle. Algunos proyectos como ChainLink y Oracleize harán esto por usted.
Para configurar un oráculo por su cuenta, el proceso se ve así:
Pruebe este ejemplo en Javascript (basado en Oracles en 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))
})
Un oráculo puede ser una cuenta humana controlada manualmente que alimenta datos de manera oportuna o mejor, un grupo automatizado de bots en servidores tradicionales que extraen un sitio web y alimentan datos a través de la cuenta. Necesitará codificar una dirección de contrato en su contrato como un oráculo de valores veraces para su programa. La clave privada se mantiene privada, a diferencia de un contrato inteligente, donde todos pueden verla. Es posible que se necesite alguna forma de deduplicar y formar consenso para una operación confiable completamente redundante.
Tienes que usar un oráculo .
Un oráculo es cualquier dispositivo que publica datos fuera de la cadena en una cadena de bloques.
Hay muchos servicios de Oracle que pueden ayudarlo a obtener datos fuera de la cadena dentro de la cadena dentro del marco de Ethereum. Es importante tener en cuenta que cada uno lo hace de manera muy diferente, lo que genera muchas consideraciones sobre por qué/cómo implementaría su tecnología. Estos son algunos de los más populares:
Y aquí hay un ejemplo de cómo obtener datos a través de un nodo 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))
}
}
}
Puede obtener datos de acciones, criptografía, ETF, etc. del contrato inteligente de OrFeed.org :
ejemplos:
divisas:
uint price = orfeed.getExchangeRate("JPY", "USD", "DEFAULT", 100000);
Valores:
uint price = orfeed.getExchangeRate("AAPL", "USD", "PROVIDER1", 1);
o en tiempo real desde un DEX:uint price = orfeed.getExchangeRate("BTC", "DAI", "SELL-UNISWAP-EXCHANGE", 100);
linaje
linaje
Tomas Bertani
jeff coleman
0xtuytuy
Tomas Bertani
Matas Vaitkevicius
tatigo