这篇文章很好的介绍了预言机的概念与一般用法,内容很长,本文在此进行了裁剪。
预言机
预言机是指数据馈送,它提取区块链数据源(下链)的数据并将数据存放到区块链(上链)上供智能合约使用。 因为运行在以太坊上的智能合约无法访问存储在区块链网络之外的信息,预言机是必不可少的。
赋予智能合约使用链下数据输入执行的能力,扩展了去中心化应用程序的价值。 例如,去中心化预测市场依靠预言机提供关于结果的信息,并且能够使用这些信息验证用户的预测。 假设 Alice 下注 20 个以太币赌谁将成为下一任美国 总统。 在这种情况下,预测市场去中心化应用程序需要预言机来确认选举结果,并判定 Alice 是否有资格获得付款。
前提条件
本页面假设读者熟悉以太坊基础知识,例如节点、共识机制和以太坊虚拟机等。 读者还应该深刻了解智能合约和智能合约分析,尤其要了解事件。
什么是区块链预言机?
预言机是指获取、验证外部信息(即存储在链下的信息)并将外部信息传送给在区块链上运行的智能合约的应用程序。 除了“拉取”链下数据并在以太坊进行广播之外,预言机还将信息从区块链“推送”到外部系统。 在用户通过以太坊交易发送费用后解锁智能锁的预言机就是一个推送信息的示例。
预言机充当一座“桥梁”,连接区块链上的智能合约与链下数据提供者。 如果没有预言机,智能合约应用程序只能访问链上数据。 预言机提供了一种使用链下数据触发智能合约功能的机制。
预言机的差别在于数据来源(一种或多种来源)、信任模型(中心化或去中心化)和系统架构(立即读取、发布-订阅和请求-响应)。 我们还可以根据以下因素区分预言机:是否检索外部数据供链上合约使用(输入预言机)、将区块链中的信息发送给链下应用程序(输出预言机)或在链下执行计算任务(计算预言机)。
智能合约为什么需要预言机?
大多数开发者只是将智能合约视为在区块链特定地址运行的代码段。 然而,对于智能合约更广义的观点是,智能合约是指在满足特定条件后能够执行各方之间协议的自执行软件程序,这解释了术语“智能合约”。
但是,使用智能合约执行人之间的协议并非易事,因为以太坊是确定性系统。 确定性系统(opens in a new tab)↗是指在给定初始状态和特定输入时总是产生相同结果的系统,即在使用输入计算输出的过程中不存在随机性或变化。
要实现确定性执行,区块链将节点限制为通过仅使用存储在区块链本身中的数据就简单的二进制 (true/false) 问题达成共识。 这类问题的示例包括:
-
“帐户所有者(由公钥识别)是否使用配对私钥签署该交易?”
-
“该帐户是否有足够资金支付这笔交易?”
-
“这笔交易在该智能合约中是否有效?”等等。
如果区块链从外部来源(例如现实世界)接收信息,确定性将不可能实现,阻止节点就区块链状态变化的有效性达成一致。 以一个智能合约为例,该合约根据从一个传统价格应用程序接口获得的当前以太币-美元汇率执行交易。 该汇率可能会经常变动(更不用说该应用程序接口可能被弃用或遭到黑客攻击),这意味着执行相同合约代码的节点会得出不同的结果。
对于在世界各地有数千个节点处理交易的公共区块链,如以太坊,确定性至关重要。 由于没有中心化组织作为真实性来源,期望节点应在进行相同交易后达到相同状态。 节点 A 执行智能合约的代码并得到结果“3”,而节点 B 在运行相同交易后得到“7”,这将打破共识并消除以太坊作为去中心化计算平台的价值。
前述情况还突出了设计区块链从外部来源获取信息的问题。 然而,预言机解决了这一问题,它从链下来源获取信息并存储在区块链上供智能合约使用。 由于存储在链上的信息是不可更改和公开可用的,以太坊节点可以安全地使用预言机导入的链下数据计算状态变化,且不会打破共识。
为此,预言机通常由链上运行的智能合约和一些链下组件构成。 链上合约接收其他智能合约的数据请求,并将这些请求传送给链下组件(称为预言机节点)。 这类预言机节点可以查询数据源—例如使用应用程序接口 (API)—并发送交易将请求的数据存储在智能合约的存储中。
就本质而言,区块链预言机弥合了区块链和外部环境之间的信息缺口,创建了“混合智能合约”。 混合智能合约的工作原理基于链上合约代码和链下基础设施的结合。 简介部分描述的去中心化预测市场就是混合智能合约的一个很好的示例。 其他示例可能包括作物保险智能合约,在一组预言机确定某些天气现象已经发生时这些合约做出赔付。
什么是预言机问题?
通过依赖一个实体(或多个实体)向区块链引入外部信息(即将信息存储在交易的数据有效负载中),很容易让智能合约获取链下数据。 但这带来了新问题:
-
如何验证注入信息是从正确来源提取的或者未被篡改?
-
如何确保这些数据始终可用并且定期更新?
所谓的“预言机问题”显示了使用区块链预言机给智能合约发送输入时出现的问题。 重要的是确保来自预言机的数据是正确的,否则智能合约执行会产生错误结果。 免信任也同样重要,必须“信任”预言机运营者能够可靠地提供准确信息,这会剥夺智能合约最关键的特性。
不同预言机在解决预言机问题方面采取的办法各不相同,我们稍后探讨这些办法。 虽然任何预言机都不是完美的,但预言机的优点应该根据它如何处理以下挑战来衡量:
-
正确性:预言机不应导致智能合约基于无效的链下数据触发状态变化。 因此,预言机必须保证数据的真实性和完整性—真实性是指数据是从正确来源获取的。完整性是指数据在发送到链上前保持完好无缺(即数据未修改过)。
-
可用性:预言机不应延迟或阻止智能合约执行操作或触发状态变化。 该特点要求预言机提供的数据在请求时可用并且不会出现间断。
-
激励兼容性:预言机应激励链下数据提供者向智能合约提交正确的信息。 奖励兼容性包括可归因性和问责性。 可归因性允许将一条外部信息与其提供者关联起来,而问责性将数据提供者与其提供的信息绑定,这样就可以根据所提供信息的质量对他们进行奖励或惩罚。
区块链预言机服务是如何运作的?
用户
用户是指需要区块链外部的信息以完成特定操作的实体(即智能合约)。 预言机服务的基本工作流程始于用户向预言机合约发送数据请求。 数据请求通常将回答下列一部分或所有问题:
-
链下节点可以在哪些来源中查询请求的信息?
-
报告者如何处理数据来源中的信息并提取有用的数据点?
-
有多少预言机节点可以参与数据检索?
-
应如何管理预言机报告中的差异?
-
在筛选提交并将报告聚合为单个值时应该采用什么方法?
预言机合约
预言机合约是预言机服务的链上组成部分:它侦听其他合约发出的数据请求。将数据查询转发到预言机节点并将返回的数据向客户端合约广播。 该合约还可以对返回的数据点进行一些计算,以产生聚合值并发送给请求合约。
预言机合约公开了一些函数,客户端合约在发出数据请求时调用它们。 收到新查询后,智能合约将触发一个日志事件,其中有数据请求详细信息。 这将通知订阅该日志的链下节点(通常使用类似 JSON-RPC eth_comment 的命令),让其继续检索日志事件中定义的数据。
下面是 Pedro Costa 提供的预言机合约示例(opens in a new tab)↗。 它是一个简单的预言机服务,可以在其他智能合约发出请求时查询链下应用程序接口,并在区块链上存储请求的信息:
pragma solidity >=0.4.21 <0.6.0;
contract Oracle {
Request[] requests; //list of requests made to the contract
uint currentId = 0; //increasing request id
uint minQuorum = 2; //minimum number of responses to receive before declaring final result
uint totalOracleCount = 3; // Hardcoded oracle count
// defines a general api request
struct Request {
uint id; //request id
string urlToQuery; //API url
string attributeToFetch; //json attribute (key) to retrieve in the response
string agreedValue; //value from key
mapping(uint => string) answers; //answers provided by the oracles
mapping(address => uint) quorum; //oracles which will query the answer (1=oracle hasn't voted, 2=oracle has voted)
}
//event that triggers oracle outside of the blockchain
event NewRequest (
uint id,
string urlToQuery,
string attributeToFetch
);
//triggered when there's a consensus on the final result
event UpdatedRequest (
uint id,
string urlToQuery,
string attributeToFetch,
string agreedValue
);
function createRequest (
string memory _urlToQuery,
string memory _attributeToFetch
)
public
{
uint length = requests.push(Request(currentId, _urlToQuery, _attributeToFetch, ""));
Request storage r = requests[length-1];
// Hardcoded oracles address
r.quorum[address(0x6c2339b46F41a06f09CA0051ddAD54D1e582bA77)] = 1;
r.quorum[address(0xb5346CF224c02186606e5f89EACC21eC25398077)] = 1;
r.quorum[address(0xa2997F1CA363D11a0a35bB1Ac0Ff7849bc13e914)] = 1;
// launch an event to be detected by oracle outside of blockchain
emit NewRequest (
currentId,
_urlToQuery,
_attributeToFetch
);
// increase request id
currentId++;
}
//called by the oracle to record its answer
function updateRequest (
uint _id,
string memory _valueRetrieved
) public {
Request storage currRequest = requests[_id];
//check if oracle is in the list of trusted oracles
//and if the oracle hasn't voted yet
if(currRequest.quorum[address(msg.sender)] == 1){
//marking that this address has voted
currRequest.quorum[msg.sender] = 2;
//iterate through "array" of answers until a position if free and save the retrieved value
uint tmpI = 0;
bool found = false;
while(!found) {
//find first empty slot
if(bytes(currRequest.answers[tmpI]).length == 0){
found = true;
currRequest.answers[tmpI] = _valueRetrieved;
}
tmpI++;
}
uint currentQuorum = 0;
//iterate through oracle list and check if enough oracles(minimum quorum)
//have voted the same answer has the current one
for(uint i = 0; i < totalOracleCount; i++){
bytes memory a = bytes(currRequest.answers[i]);
bytes memory b = bytes(_valueRetrieved);
if(keccak256(a) == keccak256(b)){
currentQuorum++;
if(currentQuorum >= minQuorum){
currRequest.agreedValue = _valueRetrieved;
emit UpdatedRequest (
currRequest.id,
currRequest.urlToQuery,
currRequest.attributeToFetch,
currRequest.agreedValue
);
}
}
}
}
}
}
预言机节点是预言机服务的链下组件:它从外部来源提取信息(例如在第三方服务器上托管的应用程序接口)并将信息置于链上供智能合约使用。 预言机节点侦听链上预言机合约中的事件,继而完成日志中描述的任务。
预言机节点的常见任务是,向应用程序接口服务发送 HTTP GET(opens in a new tab)↗ 请求,解析响应以提取相关数据,设置为区块链可读的输出格式,并通过将输入包含在预言机合约的交易中将其发送到链上 在利用“真实性证明”证明所提交信息的有效性和完整性时,可能也会用到预言机节点,我们稍后会对此进行探讨。
计算型预言机还依赖链下节点执行密集的计算任务,考虑到燃料成本和区块大小限制,这类计算在链上执行是不切实际的。 例如,预言机节点的任务可能是生成一个可验证的随机数字(例如,用于区块链游戏)。
预言机设计模式
预言机有不同的类型,包括立即读取、发布-订阅和请求-响应,后两者在太坊智能合约中最受欢迎。 下面简要介绍两类预言机服务:
发布-订阅预言机
基于发布-订阅机制的预言机服务公开“数据馈送”,其他合约可以定期读取以获取信息。 在这种情况下,数据可能会频繁变化,因此客户端合约必须侦听预言机存储中数据的更新。 向用户提供最新以太币-美元价格的预言机便是一个很好的示例。
请求-响应预言机
请求-响应设置允许客户端合约请求除发布-订阅预言机所提供数据以外的任意数据。 请求-响应预言机最适合以下条件下:
-
数据集过大,无法存储在智能合约的存储中
-
用户在任何时间点只需要一小部分数据
虽然比发布-订阅预言机复杂,但请求-响应预言机基本上和我们在上一节中描述的一样。 预言机将有一个链上组件,用于接收数据请求并传送给链下节点进行处理。
发起数据查询的用户必须承担从链下来源检索信息的费用。 客户端合约还必须提供资金,用以支付预言机合约通过请求中指定的回调函数返回响应所产生的燃料费用。
预言机的类型
中心化预言机
中心化预言机由单个实体控制,该实体负责聚合链下信息并按照请求更新预言机合约的数据。 中心化预言机效率高,因为它们依赖单一真实性来源。 在专有数据集由所有者直接发布并且有公认签名的情况下,中心化预言机甚至可能是更好的选择。 但是,使用中心化预言机会带来各种问题。
低正确性保障
使用中心化预言机时,无法确认提供的信息是否正确。 预言机提供者可能“信誉良好”,但这并不能排除有人行为不端或黑客篡改系统的可能性。 如果预言机被破坏,智能合约将基于错误数据执行。
可用性差
中心化预言机无法保证始终向其他智能合约提供链下数据。 如果提供者决定关闭服务或者黑客劫持了预言机的链下组件,智能合约则会面临拒绝服务 (Dos) 攻击的风险。
激励兼容性差
中心化预言机的激励往往设计不善或根本没有激励,鼓励数据提供者发送准确/未更改的信息。 为预言机的服务付费可能会鼓励诚实的行为,但这可能还不够。 由于智能合约控制着巨额价值,操纵预言机数据的收益是前所未有的。
去中心化预言机
去中心化预言机旨在通过消除单点故障来打破中性化预言机的局限性。 去中心化预言机服务由对等网络中的多个参与者组成,这些参与者就链下数据达成共识,然后再将数据发送到智能合约。
理想情况下,去中心化预言机应该是无需许可、免信任且不受中心机构管理;在现实中,预言机存在着不同程度的去中心化。 有半去中心化的预言机网络,任何人都可以参与其中,但由“所有者“根据以往表现批准和移除节点。 也存在着完全去中心化的预言机网络:这些网络通常作为独立区块链运行,并且已经确定了协调节点和惩罚不良行为的共识机制。
使用去中心化预言机有以下好处:
高正确性保障
去中心化预言机尝试使用不同的方法实现数据的正确性。 其中包括使用证明来证明返回信息的真实性和完整性,以及要求多个实体就链下数据的有效性集体达成一致。
真实性证明
真实性证明是一种加密机制,支持对从外部来源检索的信息进行独立验证。 这些证明可以验证信息的来源,并在检索后发现对数据可能进行的更改。
真实性证明的示例包括:
传输层安全性 (TLS) 证明:预言机节点通常使用基于传输层安全性 (TLS) 协议的安全 HTTP 连接从外部数据源检索数据。 一些去中心化预言机使用真实性证明验证传输层安全性会话(即,确认节点和特定服务器之间的信息交换),并确认会话内容未被改动。
可信执行环境 (TEE) 认证:可信执行环境(opens in a new tab)↗ (TEE) 是一种沙盒计算环境,它与主机系统的操作进程隔离。 可信执行环境确保在计算环境中存储/使用的任何应用代码或数据都保持完整性、保密性和不可变性。 用户还可以生成一个认证,证明应用程序实例正在可信执行环境中运行。
某些类别的去中心化预言机要求预言机节点运营者提供可信执行环境认证。 这向用户证实,节点运营者在可信执行环境中运行预言机客户端的实例。 可信执行环境防止外部进程更改或读取应用程序的代码和数据,因此,这些认证证明预言机节点保持了信息的完整性和保密性。
基于共识的信息验证
为智能合约提供数据时,中心化预言机依靠单一真实性来源,因此有可能发布不准确的信息。 去中心化预言机依靠多个预言机节点查询链下信息,解决了这个问题。 通过对多个来源的数据进行比较,去中心化预言机降低了将无效信息传递到链上合约的风险。
然而,去中心化预言机必须处理从多个链下来源检索的信息中的差异。 为了尽量减少信息差异并确保传送给预言机合约的数据反映了预言机节点的集体看法,去中心化预言机采用了下列机制:
对数据的准确性进行投票/质押
一些去中心化预言机网络要求参与者对数据查询答案的准确性进行投票或质押(例如,“谁赢得了 2020 年美国大选?”) (例如,“谁赢得了 2020 年美国大选?”) 然后,聚合协议聚合投票和质押,并将多数参与者支持的答案作为有效答案。
如果节点的答案不同于多数答案,将对其进行惩罚,即将其代币分发给提供更正确值的其他节点。 强制节点在提供数据之前提供保证金将激励节点做出诚实的响应,因为假定节点是理性的经济活动参与者,意在最大限度地增加回报。
质押/投票还保护去中心化预言机免受“女巫攻击”,在这种攻击中,恶意参与者创建多个身份来利用共识系统。 然而,质押机制不能防止“揩油行为”(预言机节点从其他节点复制信息)和“懒散验证”(预言机节点随大流而不亲自验证信息)。
谢林点机制
谢林点(opens in a new tab)↗是一个博弈论概念,它假设在缺乏任何沟通的情况下,多个实体总是默认对一个问题选择共同解决方案。 谢林点机制常用于去中心化预言机网络,使节点对数据请求的应答达成共识。
一个早期的示例是谢林币(opens in a new tab)↗,这是一种提议的数据馈送,参与者提交“标量”问题的答案(这些问题的答案由数量描述,例如“以太币的价格是多少?”)及存款。 提供的值在第 25 和第 75 百分位(opens in a new tab)↗之间的用户将得到奖励,而提供的值大幅偏离中值的用户将受到惩罚。
虽然谢林币目前已不存在,但许多去中心化预言机—特别是 Maker 协议预言机(opens in a new tab)↗—仍使用谢林点机制来提高预言机数据的准确性。 每个 Maker 预言机均由提交抵押品资产的市场价格的链下对等节点网络(“中继者”和“馈送者”)和链上“中值器”合约组成,后者计算所有提供价值的中值。 规定的延迟期结束后,该中值成为相关资产的新参考价格。
使用谢林点机制的其他预言机示例包括 Chainlink 链下报告(opens in a new tab)↗和 Witnet。 在这两种系统中,对等网络中的预言机节点的答复聚合成一个单一聚合值,如平均值或中值。 根据其答复与聚合值的一致或偏离程度奖励或惩罚节点。
谢林点机制具有吸引力,因为这类机制能够最大限度地减少对链上的影响(只需要发送一笔交易)同时又能保证去中心化。 后者是可行的,因为节点必须批准已提交答复的列表,然后再将答复输入生成平均值/中值的算法。
可用性
去中心化预言机服务确保链下数据对智能合约的高可用性。 高可用性是通过对链下信息来源和负责将信息传输到链上的节点同时去中心化实现的。
这确保了容错,因为预言机合约能够依靠多个节点(这些节点也依靠多个数据源)执行其他合约发出的查询。 在信息来源和节点运营商层面实现去中心化至关重要—提供从同一来源检索的信息的预言机节点网络将遇到与中心化预言机相同的问题。
基于质押的预言机也可以对未能快速响应数据请求的节点运营商进行惩罚。 这极大地激励了预言机节点投资于容错基础设施并及时提供数据。
激励兼容性好
去中心化预言机采纳了不同的激励设计,避免预言机节点中出现拜占庭(opens in a new tab)↗行为。 具体而言,它们实现了可归因性和问责性:
-
通常,要求去中心化预言机节点对它们为了响应数据请求而提供的数据签名。 这些信息有助于评估预言机节点的历史表现,让用户在发出数据请求时筛选掉不可靠的预言机节点。 示例包括 Chainlink 的预言机信誉(opens in a new tab)↗或 Witnet 的算法信誉系统(opens in a new tab)↗。
-
如前所述,去中心化预言机可能要求节点对其提交数据的真实性的可信度进行质押。 如果声明得到证实,这笔质押可以连同诚信服务的奖励一起返还。 但是如果信息不正确,也可以对节点进行惩罚,这就提供了一定程度的问责性。