什麼是以太坊預言機?智能合約就其性質而言,可以運行各類算法並能夠存儲和查詢數據。預言機能夠監控區塊鏈事件並能將監控結果發回智能合約。由於每一個節點每次都須要大量計算,因此從Ethereum智能合約開發中進行頻繁的網絡請求是切不實際的。這樣,智能合約就能夠與鏈外的世界進行互動了。前端
可是這樣有一個明顯的信任問題。與信任單一外部數據源的分佈式智能合約有些矛盾。不過這能夠經過讓多個獨立的預言機來響應相同的查詢最終造成共識來緩解這個問題。node
有關預言機的更多信息,請查看在分佈式應用程序之間提供「可靠鏈接」的FinTech公司Oraclize。 他們對預言機的解釋很不錯。git
Tinypay的預言機作了三件簡單的事情:github
我經歷了幾回迭代,最終實現了,我但願經過它們來引導您瞭解以太坊的發展。web
我第一次寫預言機,我用了Go-Ethereum。我想直接使用RPC API與Ethereum節點進行全部通訊。算法
這頗有趣,由於我可以學習不少關於以太坊協議如何進行存儲和數據編碼等較底層的內容。我必須手動從新在代碼中建立ABI(應用程序二進制接口),並使用它來發送和解密消息。 ABI對於定義合約如何交互以及如何從線上的原始字節中提取數據是必需的。json
從事件中實際提取數據證實比我想象的要複雜得多。Go-Ethereum的處理事件沒完成。我被迫手動輪詢RPC端點,並找出如何未來自原始事件的二進制數據解碼。Go-Ethereum固然彷佛是以太坊團隊關注的焦點,他們應該很清楚Go-Ethereum在觀看和解碼事件方面的問題。我但願他們能很快有所提高,這會使得Go-Ethereum成爲編寫預言機和其餘以太坊客戶端應用程序的更好選擇。網絡
低級別的RPC API和解碼API被證實是很是低效率的,而且他們正在更快地進行迭代,因此...oracle
對於第二次迭代,我切換到node.js並使用web3庫與geth節點進行通訊。 這給了我內置的抽象了的事件查詢,數據提取和格式化,並且明顯使開發變得更容易。框架
我開始使用Alex Beregszaszi很是有用的'tinyoracle'指南,這讓我在第二版中得到了不錯的成果
下面的代碼是通過選擇編輯的,完整的代碼能夠在github存儲庫中找到(本次迭代的標籤爲v0.0.2)
var Web3 = require('web3'); var web3 = new Web3(); var contracts = require(path.join(__dirname, 'gen_contracts.json')); // First we instruct web3 to use the RPC provider //首先咱們指定web3使用RPC接口 web3.setProvider( new web3.providers.HttpProvider( 'http://' + opts.rpc_host + ':' + opts.rpc_port)); // This isn't strictly necessary here, but goes to show the step // required to "unlock" the account before sending transactions. // 這並非嚴格須要的,但它顯示了在發送交易以前「解鎖」賬戶所需的步驟。 if (!web3.personal.unlockAccount( web3.eth.coinbase, opts.wallet_password)) { console.error('Could not unlock'); process.exit(); } //Here we register the filter with the ethereum node, //and then begin polling for updates. //在這裏,咱們用以太坊節點註冊過濾器,而後開始輪詢更新 function runLoop(o) { var filter = web3.eth.filter({address: o.contract_address}); filter.watch(function (err, results) { if (err) { console.log('WATCH ERROR: ', err); process.exit(); } console.debug(results); }); } // If the contract isn't deployed yet, we deploy it here //若是尚未部署合約,咱們在這裏部署它。 if (!opts.contract_address) { // This block of code loads the ABI for interpreting contract data. // 該代碼塊加載ABI來解釋合約數據。 var dmC = web3.eth.contract(JSON.parse(contracts.DomainMicropay.abi)); var x = { from: web3.eth.coinbase, data: contracts.DomainMicropay.bin, gas: 1000000 }; // send the transaction for installing the contract. //發送用於部署合約的交易。 dmC.new(x, function (err, resp) { if (err) { console.error('Loading contract', err); process.exit(); } var addr = resp.address; if (!addr) { console.log('Pending tx: ', resp.transactionHash); } else { console.log('Deployed Address: ', addr); opts.contract_address = addr; runLoop(opts); } }); } else { runLoop(opts); // in either case, start the polling event loop. //在任一種狀況下,啓動輪詢事件循環 }
最後,在第三次迭代中,我放棄了本身搞的這一切。 咱們已經在咱們的網絡前端使用ConsenSys的優秀工具Truffle。 我只是將生成的構件複製到個人node.js項目中,並直接將其包含在內,而後就開始工做。
使用Truffle,咱們可以將咱們的Solidity合約編譯成的一個JavaScript庫,它能夠確認各類重要的細節,如合同的部署地址,並徹底代替低級RPC通訊。 查看事件,發送交易和查詢數據變成了直接從咱們的合同中生成的簡單API調用。
// This code extract shows the whole event loop abstracted behind the actual event name: ClientConfirmed and ClientCreated. // 這段代碼顯示了整個事件循環中的抽象後的實際事件:ClientConfirmed 和 ClientCreated。 startWatcher: function (rpcUrl, unlockPass) { password = unlockPass || password; web3.setProvider(new web3.providers.HttpProvider(rpcUrl)); DomainMicropay.setProvider(web3.currentProvider); contract.ClientConfirmed({}, eventOpts(), function (err, data) { if (err) { console.log('Error ClientConfirmed: ', err); return; } console.log('Event ClientConfirmed: ', data.args.domain); }); contract.ClientCreated({}, eventOpts(), function (err, data) { if (err) { console.log('Error ClientCreated: ', err); return; } console.log('Event ClientCreated: ', data.args.domain); contract.getPaymentContractForDomain .call(data.args.domain) .then(beginDomainVerification(data)) .catch(errFn('Unhandled Error: ')); }); }
正如您所看到的,Truffle爲使用智能合約並與之交互提供了一些很是好的抽象。這並不完美,也不能解決合約版本問題等問題。可是咱們須要在其餘文章中再介紹這些內容。
但願贏得你喜歡,並能夠幫助你開發下一個「DApp」。 若是您正在尋求幫助理解或利用區塊鏈技術,請聯繫 we@mustwin.com 並參考本文。
原文:medium.com/@mustwin/building-an-oracle-for-an-ethereum-contract-6096d3e39551
安利兩個實戰教程: