作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
注意:本指南出于历史目的保留在这里,但是 松露 到2023年9月日落的时间.
Ethereum Smart Contracts are more than just “the new hot thing.“我相信,在即将到来的互联网新时代,它们(或相关的东西)将改变人类彼此做生意的方式. 时间会证明情况是否如此.
这是三部分文章的第一部分 以太坊智能合约开发 与可靠性, 最具体的是探索所谓的“神谕”合约的使用,这些合约基本上是将数据注入区块链以供其他智能合约使用的合约.
这样做的目的是, 本系列的第1部分, 不是要深入了解oracle契约的概念吗, 它们背后的哲学, or even very deeply 成 what they are; the goal of this part of our Ethereum oracle tutorial is simply to:
定义:甲骨文. 一种智能合约从区块链外部访问数据的方法. 一种智能合约, 甲骨文从外部世界获取数据,并将其放入区块链中,供其他智能合约使用.
本文的第一部分将包括所有先决条件的设置. Then, we’ll set up a single Ethereum contract 和 测试 it with 松露. Finally, we’ll separate the oracle 从 the client 和 测试 them jointly.
本系列文章 可以 作为智能合约的第一个介绍, 但它很快就会发展成更高级的概念. 如果这是您的第一个eth智能合约教程,请准备好快速攀升. 如果你感到自信, great; if not, 你可以先获得一两个更简单的“hello world”类型的教程. 看看 以太坊的一篇或以前的文章 和 Cryptozombies对于初学者来说.
Caveat: The smart contract space, being so new, changes quickly. 当您阅读本文时,撰写本文时新的坚实语法特性可能已经被弃用或过时了. Geth版本可能来来去去. 可靠性 is always adding new language features 和 deprecating old ones. 许多新功能目前正在开发中. So, be prepared if necessary to adapt the information in this article to the new l和scape of the future; if you’re serious ab出 learning smart contract development, 那我就对你有信心.
用例:用户在拳击比赛中下注.
Smart contracts are still kind of a new thing; they’ve yet to take the mainstream, 而且它们将如何运作的许多方面还没有被敲定和标准化. I will briefly explain the impetus behind the idea of the “oracle”—和 be patient; we’ll get 成 it in more depth in later parts.
设计区块链合约 难道不像编程客户机-服务器应用程序吗. One important difference is that data with which the contract interacts, 一定已经在区块链上了. 没有召唤 出 区块链的. 它不仅不被语言支持,也不被区块链范式支持. The contract 可以 take bets in the form of Ethereum-based currency, 将它们存储在合同中, 和 release them to the correct wallet addresses according to a formula, 当宣布比赛的获胜者时. 但是合同怎么知道谁是赢家呢? 它不能查询REST API或类似的东西. 它只能使用已经在区块链中的数据! 智能合约的许多用例都遇到了类似的问题——除非它们能够与区块链之外的世界进行交互,否则它们会受到严重的限制.
如果合约只能与区块链上的数据交互, an obvious 索尔ution is to inject the necessary data 成 the blockchain. 这就是神谕. 神谕是另一种契约, 谁将数据注入区块链, 允许其他合约使用它. 虽然这可能会引发信任和不信任的问题, 现在就接受这就是神谕吧. 在本系列的第3部分中,我们将讨论这些细微差别. 在我们的示例用例中, the oracle will be the contract that injects data 成 the blockchain, regarding (a) what matches are available 和 (b) who won those matches, 一旦决定.
对于基本设置,我们将安装:
本文篇幅有限,不能作为环境设置的完整指南,只能作为一个粗略的指南. 没关系, 虽然, 因为对于你的特定操作系统,已经有很多更完整的安装指南了,而且互联网真的不需要新的. 因此,我将带您快速了解这条路径,并根据需要为您提供一些资源,以获取更多细节. 根据您的系统要求和Google的指示,准备好安装要求和先决条件.
Geth是go -以太坊, the Ethereum core software; while it’s not necessary for this exercise at all, 任何想要成为以太坊开发者的人都应该拥有它并熟悉它. 如果您打算将智能合约部署到实时以太坊网络,这将是必要的.
松露是我们用于开发的主要原料, 绝对是本指南的要求.
我建议安装 巧克力酱CLI 作为另一个测试工具使用,尽管我们不会在教程中实际使用它. 它是可选的.
使用任何简单的文本编辑器都不可能完成整个教程, 像记事本+ +, 中用户, vi, 或您选择的任何文本编辑器或IDE. I personally am using Visual Studio Code with the following extensions:
注意:扩展不是必需的—它们只是为了更好的编码环境.
松露 is a very convenient tool for compiling smart contracts, 将它们迁移到区块链, 它还提供了开发和调试实用程序. Some project setup will be necessary in order to integrate with 松露. 现在我们将在松露和目录结构中为我们的项目设置shell. Just sit back, follow the steps robotically for now, 和 enjoy.
Create a directory to house all the code; call it oracle-example.
在根目录中, 创建两个子目录, 因为最终, 该项目将包括两个子项目. 创建目录:
进入客户端文件夹,因为这是我们要开发的第一个项目. 打开终端(命令行)窗口 / oracle-example /客户端 文件夹.
运行命令 松露init
.
注意,在创建的许多文件中有 松露-config.js 和 松露.js. 我们不需要两个,所以删掉 松露-config.js (只是为了避免混淆和混乱).
我们需要编辑 松露.js, in order to point 松露 in the right direction for 测试ing. 替换的内容 松露.js 下面是:
模块.出口= {
网络:{
发展:{
主持人:“localhost”,
端口:8545
network_id: "*" //匹配任意网络id
}
}
};
httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step1/client/Truffle.js
注意,松露 init创建了一个名为 迁移 (oracle-example /客户/迁移). 在该文件夹中应该有一个名为 1 _initial_migration.js.
在迁移目录中添加另一个文件并命名它 2 _deploy_contracts.js,内容如下:
var BoxingBets =工件.要求(“BoxingBets”);
模块.导出=函数(部署器){
部署人员.部署(BoxingBets);
};
httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step1
现在 that the simple setup is 出 of the way, we’re set to begin coding. 还记得, 本文的这一部分仍然是介绍和设置, 我们很快地看一下代码. We’ll get 成 more in-depth explanations of the code in part 2, 和 more in-depth discussion of the architecture 和 concept in part 3. 也就是说,我们将快速触及代码中一些明显的核心概念. 小心跟随以跟上.
The full code for this step in the process is available on GitHub: httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step1
可靠性中的“契约”大致类似于其他面向对象语言中的类. 该语言本身已被拿来与Golang和JavaScript等进行比较. 索尔idworks中的其他一些语言结构(我们将在后面举例)是修饰语, 库, 和接口. Inheritance (including multiple inheritance) is supported for contracts. 坚实合同文件有一个 .索尔扩展.
将这个文件添加到你的项目中: / oracle-example /客户/合同/ 甲骨文Interface.索尔
Normally, the oracle interface would be just that—an interface. 对于第一次迭代, it’s just a simple class contained within the 可靠性 project, 现在只是一个占位符. 我们将在下一步中将其移出, 在我们成功编译并在松露上运行契约之后. 稍后将其转换为实际接口后,函数实现将为空.
将这个文件添加到你的项目中: / oracle-example /客户/合同/ BoxingBets.索尔
httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step1/client/contracts/BoxingBets.sol
这是消耗拳击比赛数据的合同, 允许用户查询可用的匹配项, 并在他们身上下注. 在以后的迭代中,它将计算并支付奖金.
现在 is when we’ll see if we got everything right the first time!
打开终端 / oracle-example /客户/ 文件夹
用下面的命令编译代码:
松露编译
备用方案:使用我的recompile.Sh shell脚本(httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step1/client/recompile.sh).
请注意,您将看到许多警告,因为我们的代码尚未形成最终形式!
打开松露开发控制台:
松露开发
现在, in the 松露 developer con索尔e, migrate to the 测试 network:
松露(develop)> migrate
At the development con索尔e prompt, enter the following line of code:
松露(develop)> BoxingBets.部署().then(inst => { instance = inst })
现在, “instance”是指向BoxingBets合约的变量,可以用来调用它的公共方法.
使用以下命令测试它:
松露(develop)> instance.测试(3、4)
中包含了一个公共“测试”函数 BoxingBets.索尔. 它会将你传递给它的两个数字相加, 只是为了证明合约正在执行代码, 我们可以从松露开发控制台调用它. 如果我们得到一个看起来很正常的回复(见下文),那么我们的工作就完成了(至少现在是这样)。.
如果到目前为止一切都很成功,那么我们就渡过了难关. 接下来我们要做的是将oracle合同从BoxingBets合同中分离出来. 在实际使用中, oracle的合约将与区块链上的客户端合约分开存在, 所以我们需要能够:
简而言之, 我们现在要做的是将oracle和客户端分离为两个独立的区块链合约实体, 让他们互相交谈. 客户端将通过地址实例化oracle并调用它.
第一个, 我们将修改客户端契约(client),使其指向oracle的动态接口,而不是具体的类. 然后我们将确保它从外部契约实例化oracle.
进入 / oracle-example /客户/合同/ 甲骨文Interface.索尔. 正如我们之前提到的,这目前还不是一个接口,但我们即将使它成为一个接口. 将其中的内容替换为:
实用可靠度^0.4.17;
契约甲骨文Interface
enum MatchOutcome {
Pending, //match还没有被决定
正在进行,//比赛已经开始 & 正在进行中
平局,//除明显的赢家以外的任何东西(例如.g. 取消)
决定//获胜者的参与者索引
}
getPendingMatches()公共视图返回(bytes32[]);
函数getAllMatches ()公共视图返回(bytes32[]);
function matchExists(bytes32 _matchId) public view returns (bool);
getMatch(bytes32 _matchId)
bytes32 id,
字符串的名字,
字符串的参与者,
uint8 participantCount,
使用uint日期,
MatchOutcome结果,
int8赢家);
function getMostRecentMatch(bool _pending) public view returns (
bytes32 id,
字符串的名字,
字符串的参与者,
使用uint participantCount,
使用uint日期,
MatchOutcome结果,
int8赢家);
函数测试Connection () public pure returns (bool);
函数addTestData () public;
}
In BoxingBets.索尔,我们将替换这一行:
甲骨文Interface internal boxing甲骨文 = new 甲骨文Interface();
用这两行:
oracleaddr = 0;
甲骨文Interface internal boxing甲骨文 = 甲骨文Interface(boxing甲骨文Addr);
现在我们需要的是一种设置oracle地址的方法, 动态, 和 a function that we 可以 call to find 出 the current oracle address. 将这两个函数添加到 BoxingBets.索尔:
/// @notice sets the address of the boxing oracle contract to use
/// @dev设置错误的地址可能会导致错误的返回值或错误
/// @param _oracleAddress打包oracle的地址
/// @return 真正的 if connection to the new oracle address was successful
函数set甲骨文Address(地址_oracleAddress)外部onlyOwner返回(bool) {
boxing甲骨文Addr = _oracleAddress;
boxing甲骨文 = 甲骨文Interface(boxing甲骨文Addr);
返回boxing甲骨文.测试Connection ();
}
/// @notice获取正在使用的装箱oracle的地址
/// @返回当前设置的oracle地址
function get甲骨文Address() external view returns (address) {
返回boxing甲骨文Addr;
}
最后,为了测试客户端和oracle之间的连接,我们可以替换 测试 function in BoxingBets with a function to 测试 the oracle connection:
/// @notice for 测试ing; 测试s that the boxing oracle is callable
///如果连接成功,返回真正的
函数测试甲骨文Connection ()公共视图返回(bool) {
返回boxing甲骨文.测试Connection ();
}
注意,的定义 set甲骨文Address
有一个 onlyOwner
后面跟着修饰语. 这限制了该函数不能被合约所有者以外的任何人调用, 即使函数是公共的. 这不是一种语言特性. 这是所有权合同提供给我们的, 它是从OpenZeppelin的通用实用程序可靠性合约库中提取出来的. 我们将在第2部分详细介绍,但为了便于使用 onlyOwner
修饰语,我们需要做一些改变:
复制 Ownable.索尔 从 httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step2/client/contracts/Ownable.sol 成 / / oracle-example /客户/合同.
在顶部添加对它的引用 BoxingBets.索尔,像这样:
进口”./ Ownable.索尔”;
(您可以将它添加到导入的行下面 甲骨文Interface.索尔.)
修改BoxingBets的合同声明,使其继承Ownable,如下所示:
合同{
:
合同BoxingBets是可拥有的{
我们应该都准备好了. 完整的代码在这里,以防你迷路了: httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step2/client/contracts
现在,BoxingBets合约试图通过地址引用一个完全独立的合约(即oracle), 我们的下一项工作是创建oracle合同. 现在我们要创建一个包含oracle契约的独立项目. It’s essentially the same setup that we’ve already done for the client contract project; that is, 设置松露进行编译和开发.
您应该已经有一个名为 / oracle-example / oracle / 这是我们在上一步中创建的目录(如果没有,现在就创建空目录). 在该目录下打开终端.
松露init
. 模块.出口= {
网络:{
发展:{
主持人:“localhost”,
端口:8545
network_id: "*" //匹配任意网络id
}
}
};
请看下面的例子: httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step2/oracle/Truffle.js
内部 / oracle-example / oracle /迁移,创建一个名为 2 _deploy_contracts.js,内容如下:
var Boxing甲骨文 = artifacts.要求(“Boxing甲骨文”);
模块.导出=函数(部署器){
部署人员.部署(Boxing甲骨文);
};
对于这一步,只需从 httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step2/oracle/contracts/ 到你的 / / oracle-example / oracle /合同
文件夹:
现在, 在项目的当前迭代中, 我们真的需要彻底测试我们的智能合约oracle, since that will be our base on which we’ll build the rest of the project. 那么,现在我们已经设置了oracle项目并复制了代码,我们想要:
还在一个候机楼 / oracle-example / oracle /
,执行如下命令. 再一次。, 这些步骤与我们已经完成的编译和迁移客户端契约的步骤相同.
松露编译
备用方案:使用我的recompile.Sh shell脚本(httpTo this://github.com/jrkosinski/oracle-example/tree/part1-step2/oracle/recompile.sh).
打开松露开发控制台:
松露开发
迁移到测试网络:
松露(develop)> migrate
仍然在松露开发控制台, enter this to capture a usable pointer to the oracle contract:
松露(develop)> Boxing甲骨文.部署().then(inst => { instance = inst })
现在我们可以(也应该)在oracle契约上运行一套测试来测试它. Try running the following comm和s, each in turn, 和 examine the results.
松露(develop)> instance.测试Connection ()
...
松露(develop)> instance.getAllMatches ()
...
松露(develop)> instance.addTestData ()
...
松露(develop)> instance.getAllMatches ()
...
You are encouraged at this point to have a look through the oracle code, 查看有哪些公共方法可用, 阅读代码中的注释, 提出一些您自己要运行的测试(并在控制台中运行它们), 如上所示).
现在我们准备进行最后的测试:测试客户端合约是否可以调用已经在区块链上的oracle合约, 然后利用它的数据. 如果所有这些都有效,那么我们就有了一个客户端-oracle对,我们可以使用它进行进一步的实验. 运行端到端测试的步骤:
打开两个终端窗口:
我建议你保留 / oracle-example /客户/ 一个在左边开着,另一个 / oracle-example / oracle / one open on the right, 和 follow along closely to avoid confusion.
中执行以下命令 / oracle-example / oracle / 终端:
bash重新编译.sh
松露开发
松露(develop)> migrate
松露(develop)> Boxing甲骨文.部署().then(inst => { instance = inst })
中执行以下命令 / oracle-example /客户/ 终端:
bash重新编译.sh
松露开发
松露(develop)> migrate
松露(develop)> BoxingBets.部署().then(inst => { instance = inst })
执行以下命令在 / oracle-example / oracle / 终端:
松露(develop)> instance.getAddress ()
复制 the address which is the 出put 从 this call; 和 use it in the next step.
执行以下命令来松露 / oracle-example /客户/ 终端:
松露(develop)> instance.set甲骨文Address('')
然后测试一下:
松露(develop)> instance.测试甲骨文Connection ()
如果输出为 真正的
,那么我们就可以开始了.
执行以下命令来松露 / oracle-example /客户/ 终端:
松露(develop)> instance.getBettableMatches ()
它应该返回一个空数组,因为还没有测试数据被添加到oracle端.
执行以下命令来松露 / oracle-example / oracle / 终端添加测试数据:
松露(develop)> instance.addTestData ()
执行以下命令来松露 / oracle-example /客户/ 终端,看是否可以从客户端拾取到新增的测试数据:
松露(develop)> instance.getBettableMatches ()
现在, if you take individual addresses 从 the array returned by getBettableMatches ()
,并将它们插入 getMatch ()
.
You are encouraged at this point to have a look through the client code, 查看有哪些公共方法可用, 阅读代码中的注释, 提出一些您自己要运行的测试(并在控制台中运行它们), 如上所述).
我们的研究结果是有限的, 但我们的目标也是如此, 为了保持现实的节奏. 我们的客户还没有能力下注、处理资金、分配奖金等. What we do have—aside 从 the knowledge 和 experienced gained—is:
对于一篇短文来说,这还不算太糟.
In 本系列的第二部分, 我们将更深入地研究代码,并研究智能合约开发特有的一些功能,以及可靠性特有的一些语言功能. 在这一部分中被掩盖的许多事情将在下一部分中解释.
In 本系列的第三部分, we will discuss a bit ab出 the philosophy 和 design of smart contracts, 特别是与神谕的使用有关.
独自实验是学习的好方法. 如果您正在考虑如何扩展本教程以获得更多知识,这里有一些简单的建议(以下内容在第2部分和第3部分都不会涉及):
Good luck, 和 please feel free to contact me with any questions. I 可以’t guarantee a speedy reply necessarily, but I will do my best.
The programming language used in Ethereum development is 可靠性. 它是一种受JavaScript、Python和c++启发的面向契约的编程语言.
一个所谓的 区块链甲骨文 是一个可信的数据源,提供关于智能合约使用的各种状态和事件的信息.
智能合约预言机用于提供现实世界事件与数字合约之间的联系. oracle提供的外部数据可能(也可能不)触发智能合约的执行.
世界级的文章,每周发一次.
世界级的文章,每周发一次.