区块链本身是封闭的。区块链的确定性模型基于这样一个事实:在交易执行时区块链不能执行任何来自外部的逻辑,所有的外部数据只能通过交易进入到系统中。预言机 /Oracle就是通过交易为智能合约提供可信数据的服务。Oracle 虽然听起来神秘,但实现并不复杂,在这篇文章里,我们将介绍预言机的作用以及运作原理,并通过天气数据预言机 WeatherOracle 的完整实现过程,来帮助你快速掌握区块链预言机 /Oracle 的精髓。
1、为什么智能合约需要预言机 /Oracle?
在智能合约中执行的逻辑不可以执行区块链之外的任何操作,例如它不可以访问互联网上的 web 服务。外部数据进入智能合约的唯一方法是将其置入一个交易中,通过向系统发送一个新的交易来触发区块链状态的更新。
试着考虑一下,如果智能合约在执行时可以访问外部的一个 API 来获取数据,会出现什么情况?
如果今天部署这个合约,那么 API 可能会返回如下的数据:
{"foo": "bar"}
但是明天再部署时,API 可能就会返回新的数据,例如:
{"foo": "baz"}
那么可以想像,一个月以后如果有人进行以太坊区块链的同步,这个智能合约就会被执行,但是 API 的响应数据是和一个月之前不同的,这就会导致新同步的
区块链状态不同于之前已经存在的节点状态。
这就不再是完全自确定的区块链了。经历相同的同步过程,我的区块链和你的区块链却不一样!
让我们再换个说法:给定一组区块,一个节点必须能够从零开始重现区块链的最终状态,而无需互联网连接。
那么这一点对于智能合约的开发者意味着什么?Oralce(预言机),开发者必须构造一个预言机来和实现智能合约与外部世界的交互。
2、如何实现一个简单的预言机 /Oracle?
现在让我们创建一个简单的预言机 /Oracle,来将外部的天气数据传入智能合约:
在最底层的区块链平台,我们需要部署一个智能合约,这个合约有一个方法 updateWeather()
用来更新天气状态,只有在合约白名单里的地址才可以调用这个方法。updateWeather 方法接受天气数据作为参数,同时触发一个以太坊合约事件并将天气数据作为事件的参数,这样 JavaScript 应用就可以订阅这个事件并获得异步通知了。
同时我们将创建两个 nodejs 进程,其中之一就是预言机 /Oracle,它的实现逻辑就是周期性地轮询第三方天气 API 来获取天气数据,然后将天气数据提交给智能合约以便进行历史审计。
另一个 nodejs 进程则负责订阅智能合约的天气事件,然后在控制台输出事件参数。正如之前所述,每当预言机 /Oracle 调用合约的 updateWeather()方法时,都会触发天气事件。
需要指出的是,为了便于理解预言机的核心实现思路,下面的代码进行了简化,剔除了必要的错误处理,因此并不适用于生产环境。
源代码在这里:
- 预言机合约 – https://github.com/decentorga…
- 预言机服务 – https://github.com/decentorga…
接下来我们详细讲解这个简单的预言机的实现。
3、预言机智能合约实现
智能合约有一个公开的 oracleAddress 状态变量,用来表示允许调用智能合约的 updateWeather 方法的账户地址,我们在构造函数中对其进行赋值:
contract WeatherOracle {
address public oracleAddress;
constructor (address _oracleAddress) public {oracleAddress = _oracleAddress;}
// ...
}
接下来我们要定义天气事件,这个事件将在 weatherUpdate()调用成功时触发。同样为了简化,我们让这个事件简单的附带一个表示温度的字符串参数。
event WeatherUpdate (string temperature);
最后我们要实现 updateWeather()方法。它的可见性为 public,意思是可以从外部调用这个方法:
function updateWeather (string temperature) public {require(msg.sender == oracleAddress);
emit WeatherUpdate (temperature);
}
请注意 require 语句。只有当调用地址(msg.sender)和白名单地址(oracleAddress)一致时才允许继续执行该方法,否则将回滚交易。
好了,就这么简单。
4、预言机服务
我们的预言机就是一个简单的 nodejs 服务。它使用 request 库来调用外部天气 API,解析 API 的响应,然后构造并提交交易给智能合约,然后等一会儿,重复上面的工作,如此
周而复始。
让我们从访问 API 开始,我们将 API 的地址放在一个环境变量里,以便在开发 / 生产环境切换时避免修改源代码:
const options = {uri: process.env.WEATHER_URL, json: true};
const start = () => {request(options)
.then(parseData)
.then(updateWeather)
.then(restart)
.catch(error);
};
下面的代码用来解析 API 的响应结果:
const parseData = (body) => {return new Promise((resolve, reject) => {const temperature = body.main.temp.toString();
resolve({temperature});
});
};
现在要做的就是构造一个调用智能合约的 updateWeather()
方法的以太坊交易。注意 account()
是一个异步方法,它的作用是载入一个以太坊账户,contract
是一个 js
对象,它包含了之前部署的 WeatherOracle 智能合约的部署地址和 ABI 接口数据。这些与智能合约相关的函数都来自于著名的 web3 开发包:)
const updateWeather = ({temperature}) => {return new Promise((resolve, reject) => {account().then(account => {contract.updateWeather(temperature, { from: account}, (err, res) => {resolve(res);
});
});
});
};
最后,我们只需要在指定超时后重新启动这个过程即可。wait()
函数将在指定的超时时间之后解析。
const restart = () => {wait(process.env.TIMEOUT).then(start);
};
搞定了!上面的代码实现了一个简单服务,它可以从 API 获取数据,然后再输入智能合约。
注意:
- 当我们构造以太坊交易时,我们使用
{from:account}
来指定调用账户,account
所指向的这个账户需要有一些以太币来支付交易的手续费。 - 我们使用环境变量来配置一个私钥,用来实例化 account 对象。这个私钥必须是用来部署 WeatherOracle 智能合约时传入的那个白名单地址所对应的私钥。
5、天气事件的利用服务
这是另一个简单的 nodejs 服务。同样,contract
是一个包含了合约的部署地址和 ABI 信息的 js 对象,调用 WeatherUpdate
并传入一个回调就是我们订阅天气事件的所有代码:
const consume = () => {contract.WeatherUpdate((error, result) => {console.log("NEW WEATHER DATA EVENT ON SMART CONTRACT");
console.log("BLOCK NUMBER:");
console.log(" " + result.blockNumber)
console.log("WEATHER DATA:");
console.log(result.args);
console.log("\n");
});
}
当这个服务运行时,随着交易成功入块上链,它将会周期性地向控制台输出数据:
NEW WEATHER DATA EVENT ON SMART CONTRACT
BLOCK NUMBER:
3424586
WEATHER DATA:
{temperature: '74.75'}
如果你想学习区块链并在 Blockchain Technologies 建立职业生涯,那么请查看我们分享的一些以太坊、比特币、EOS、Fabric、Tendermint 等区块链相关的交互式在线编程实战教程:
- java 比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与 UTXO 等,同时也详细讲解如何在 Java 代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是 Java 工程师不可多得的比特币开发学习课程。
- php 比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与 UTXO 等,同时也详细讲解如何在 Php 代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是 Php 工程师不可多得的比特币开发学习课程。
- c#比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与 UTXO 等,同时也详细讲解如何在 C#代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是 C# 工程师不可多得的比特币开发学习课程。
- java 以太坊开发教程,主要是针对 java 和 android 程序员进行区块链以太坊开发的 web3j 详解。
- python 以太坊,主要是针对 python 工程师使用 web3.py 进行区块链以太坊开发的详解。
- php 以太坊,主要是介绍使用 php 进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
- 以太坊入门教程,主要介绍智能合约与 dapp 应用开发,适合入门。
- 以太坊开发进阶教程,主要是介绍使用 node.js、mongodb、区块链、ipfs 实现去中心化电商 DApp 实战,适合进阶。
- ERC721 以太坊通证实战,课程以一个数字艺术品创作与分享 DApp 的实战开发为主线,深入讲解以太坊非同质化通证的概念、标准与开发方案。内容包含 ERC-721 标准的自主实现,讲解 OpenZeppelin 合约代码库二次开发,实战项目采用 Truffle,IPFS,实现了通证以及去中心化的通证交易所。
- C#以太坊,主要讲解如何使用 C# 开发基于.Net 的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
- EOS 入门教程,本课程帮助你快速入门 EOS 区块链去中心化应用的开发,内容涵盖 EOS 工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签 DApp 的开发。
- 深入浅出玩转 EOS 钱包开发,本课程以手机 EOS 钱包的完整开发过程为主线,深入学习 EOS 区块链应用开发,课程内容即涵盖账户、计算资源、智能合约、动作与交易等 EOS 区块链的核心概念,同时也讲解如何使用 eosjs 和 eosjs-ecc 开发包访问 EOS 区块链,以及如何在 React 前端应用中集成对 EOS 区块链的支持。课程内容深入浅出,非常适合前端工程师深入学习 EOS 区块链应用开发。
- Hyperledger Fabric 区块链开发详解,本课程面向初学者,内容即包含 Hyperledger Fabric 的身份证书与 MSP 服务、权限策略、通道配置与启动、链码通信接口等核心概念,也包含 Fabric 网络设计、nodejs 链码与应用开发的操作实践,是 Nodejs 工程师学习 Fabric 区块链开发的最佳选择。
- Hyperledger Fabric java 区块链开发详解,课程面向初学者,内容即包含 Hyperledger Fabric 的身份证书与 MSP 服务、权限策略、通道配置与启动、链码通信接口等核心概念,也包含 Fabric 网络设计、java 链码与应用开发的操作实践,是 java 工程师学习 Fabric 区块链开发的最佳选择。
- tendermint 区块链开发详解,本课程适合希望使用 tendermint 进行区块链开发的工程师,课程内容即包括 tendermint 应用开发模型中的核心概念,例如 ABCI 接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是 go 语言工程师快速入门区块链开发的最佳选择。
原文:Building your first Ethereum Oracle
汇智网翻译整理,转载请标明出处