详解如何在以太坊智能合约中集成可证明的Oracle-part1

信息发布员 5月前 73

从本质上讲,智能合约是自包含的代码脚本,这意味着它们本质上无法访问外部信息,例如Web API或文件系统。这有一个很好的理由:以太坊的情况全都与确定性和可验证的数据有关。

当某人成功发布智能合约时,它将每台机器上执行维护区块链完整副本。重要的是,此执行在所有计算机上均应保持一致,以便每次都产生相同的结果。

否则每个以太坊节点将无法就当前状态达成共识。互联网是具有不确定性因素,因为它随着时间的推移而改变。从外部资源(如比特币价格标签)检索数据可以而且通常会返回不同的结果。这就给我们留下了一个问题,我们如何将非确定性数据聚合到诸如智能合约之类的确定性环境中?

“Provable”(以前称为“Oraclize”)是一种称为“oracle”的服务,专门为解决此问题而构建。oracle通过聚合来自外部源(如随机数生成器、价格标签和计算引擎)的数据来充当中继器。一旦收集到数据,oracle就会将其输入智能合约。

您可能想知道,第三方中继器是否会破坏数据分散化的目的?好吧,你是绝对正确的。因此,Provable实施了真实性证明的概念。使用安全加密技术,我们可以验证通过的信息没有有被原始来源篡改。因此可以相信oracle将确定性结果传递给确定性环境。

让我们通过一个示例来研究一下。也许您是房东,并且希望以安全可靠的方式收取押金和租金。在本教程中,我们将为房东创建一种为租户草拟租约的方法。运作方式如下:

1. 房东和房客本人就租赁条款达成一致(即每月$1000,共6个月,另加按金$500。每次付款应在每月的第一天支付)。

2. 房东通过智能合约创建租约,并提供条款和租户的以太坊地址。所有金额均以美元表示。

3. 租户将初始押金发送到智能合约,智能合约规定了首笔每月租赁付款的期限。

4. 智能合约通过使用Provable(可证明) Oracle提供的转换数据将发送的以太币金额转换为美元,从而确保存款和每月付款额。

5. 租约完成后,租户可以收回押金。

6. 如果租户未能在期限前每月付款,则房东可以没收押金。

7. 房东可以随时存放以太币并提取租金收入。

对房东来说,唯一的风险是以太坊的价值可能在租赁期内下降。在这种情况下,必须在智能合约中存入更多以太坊,以满足租户的押金退款条件。

注意:这是一个中级教程。建议您对Ethereum、javascript、Solidity和Truffle框架有基本的了解,但并非完全必要。此外,本指南相当冗长。与往常一样,将逐行解释代码以确保正确理解。

搭建环境

1.安装NodeJS,访问其官方网站或使用HomeBrew安装。

brew install node

2.确保是在全局模式下安装truffle。打开命令行或终端:

npm install -g truffle

3.为项目创建一个新目录并输入。

mkdir leaseGenerator

cd leaseGenerator

4.初始化系统truffle项目。

truffle init

5.创建package.json和package-lock.json

npm init -y

npm install

6.安装ganache-cli,这是一个模拟以太坊的本地测试区块链。

npm install -g ganache-cli

7.确保安装了文本编辑器(我更喜欢Visual Studio Code),然后在编辑器中打开项目。

// if using VS code:

code .

8.文件/文件夹结构将如下所示:

contracts/

migrations/

test/

package-lock.json

package.json

truffle-config.js

9.现在安装ethereum-bridge,该软件允许我们在本地开发区块链上使用Provable,而无需将智能合约部署到实际网络中。

npm install ethereum-bridge

10.在package.json内部,使用以下命令创建脚本条目:

"scripts": {

    "bridge": "./node_modules/.bin/ethereum-bridge -a 9 

    -H 127.0.0.1 -p 8546 --dev",

    "chain": "ganache-cli -p 8546 --defaultBalanceEther 10000 --db 

    ./ganache/"

  },

bridge负责启动以太坊桥。-a标志指定在我们的本地区块链上使用哪个帐户来部署Provable连接器智能合约,从而允许我们隔离的本地项目与网络的其余部分进行通信。然后我们传入运行区块链的主机和端口。--dev模式只是加快了内部桥接任务的速度,从而加快了开发速度。

chain在指定的主机和端口上启动ganache-cli的本地实例。defaultBalanceEther为每个帐户配备10,000的初始余额,这最终将非常有用。--db设置存储位置以保留ganache的数据,从而使我们下次运行启动命令时可以重新实例化同一实例。

配置Truffle

在我们必须编辑truffle配置文件以满足我们的开发环境,由于我们仅在本地进行开发,因此配置非常简单。打开truffle-config.js,删除内容并编写以下内容:

module.exports = {

  networks: {

    development: {

     host: "127.0.0.1",     

     port: 8546,            

     network_id: "*",       

    }

  },

  compilers: {

    solc: {

      version: "0.5.17",    

    }

  }

}

在这里,我们指定Truffle将使用哪些网络来部署智能合约。development是一个特殊的关键字,告诉Truffle这是默认网络。填写适当的主机和端口。Provide*对于network\u id.solc是一个solidity的编译器, 确保solc的版本设置为0.5.17。在撰写本文时,最新版本的Solidity为0.6.4。由于Provable尚未提供0.6兼容性,因此我们使用的是0.5系列的最新版本。

依赖库

该项目依赖于两个库SafeMath和provableAPI。在/ contracts中创建2个新的.sol文件,并复制每个库的源。

租赁产生者智能合约

现在我们已经配置好了环境信息,是时候开始编写智能合约了。导航到/ contracts并创建LeaseGenerator.sol

(cd contracts && touch LeaseGenerator.sol)

大括号可以让我们快速回到工作目录,这是一个不错的小技巧。打开LeaseGenerator.sol

 1pragma solidity ^0.5.17;

 2import "./SafeMath.sol";

 3import "./provableAPI.sol";

 4

 5contract LeaseGenerator is usingProvable {

 6

 7    using SafeMath for uint;

 8

 9    address payable landlordAddress;

10    address payable tenantAddress;

11

12    uint ETHUSD;

13    uint tenantPayment;

14    uint leaseBalanceWei;

15

16    enum State {

17        payingLeaseDeposit,

18        payingLease,

19        collectingLeaseDeposit,

20        reclaimingLeaseDeposit,

21        idle

22    }

23

24    State workingState;

25

26    struct Lease {

27        uint8 numberOfMonths;

28        uint8 monthsPaid;

29        uint16 monthlyAmountUsd;

30        uint16 leaseDepositUsd;

31        uint32 leasePaymentWindowSeconds;

32        uint64 leasePaymentWindowEnd;

33        uint64 depositPaymentWindowEnd;

34        bool leaseDepositPaid;

35        bool leaseFullyPaid;

36    }

37

38    mapping (bytes32 => bool) validIds;

39    mapping (address => Lease) tenantLease;

40

41    modifier onlyLandlord() {

42        require(msg.sender == landlordAddress, 

         "Must be the landlord to create a lease");

43        _;

44    }

45

46    event leaseCreated(

47        uint8 numberOfMonths,

48        uint8 monthsPaid,

49        uint16 monthlyAmountUsd,

50        uint16 leaseDepositUsd,

51        uint32 leasePaymentWindowSeconds,

52        bool leaseDepositPaid,

53        bool leaseFullyPaid,

54    );

55

56    event leaseDepositPaid(

57        address tenantAddress,

58        uint amountSentUsd

59    );

60

61    event leasePaymentPaid(

62        address tenantAddress,

63        uint amountSentUsd

64    );

65

66    event leaseDepositCollected(

67        address tenantAddress,

68        uint amountCollected

69    );

70

71    event leaseDepositReclaimed(

72        address tenantAddress,

73        uint amountReclaimed

74    );

75

76    event leaseFullyPaid(

77        address tenantAddress,

78        uint numberOfmonths,

79        uint monthsPaid

80    );

81

82    event fundsWithdrawn(

83        uint transferAmount,

84        uint leaseBalanceWei

85    );

86}

第1行是每个新dApp项目的开始。全球的以太坊开发人员应该珍惜这一刻,以此作为新起点的象征。不要轻视在文件顶部声明solidity版本的重要性!

第2至3行导入了我们的依赖库。

第5行打开了一个新智能合约,该智能合约继承自usingProvable,其中包含进行数据查询的所有逻辑。

第7行声明我们对uint变量类型使用SafeMath。这使我们可以将.add或.sub等添加到任何uint类型,以进行简单,安全的算术运算。

第9行声明了应付地址的类型变量,其中包含房东的以太坊地址。应付账款是确保可以将资金发送到该地址。

第10行声明了应为该租户另一个address payable。每当给定的租户执行某项操作(例如支付租赁押金)时,都会更新此变量。

第12行存储了ETH到USD的汇率。每当我们从oracle中检索新汇率时,将设置此变量。

第13行用于设置wei中的租户发送的押金或月租付款额。然后用于计算等价的美元金额,以更新智能合约的状态。

第16-22行表示一个枚举类型,它本质上是一个自定义类型,可以是大括号中列出的任何值。第24行将workState声明为具有上面我们声明的State类型的变量。对于执行的每个操作(例如支付定金),都会更新workingState以反映该状态。例如如果租户要支付租赁押金,我们会将workingState更新为payingLeaseDeposit。目的是为oracle提供相关信息。oracle收到一些请求的数据后,它会触发一个回调函数__callback(),该函数使我们可以自定义处理传入数据的方式。这将完全取决于workingState的值。如果我们要支付LeaseDeposit,则回调函数会指示您支付租赁押金。

第26–36行声明Lease对象及其所有属性。当房东决定创建新租约时,会创建一个新的Lease实例。特性:

1. numberOfMonths:租约的期限,以月为单位

2. monthsPaid:租户支付的总月数

3. monthAmountUsd:每月要支付的总金额(美元)

4. leaseDepositUsd:要支付的租赁押金的价值

5. leasePaymentWindowSeconds:租户每月支付的时间(以秒为单位),在租户支付了租赁押金后生效

6. leasePaymentWindowEnd:租户支付租约为Unix时间戳的截止日期

7. depositPaymentWindowEnd:租户进行租赁押金为Unix时间戳的截止日期

8. leaseDepositPaid:告知是否已支付租赁押金

9. leaseFullyPaid:告知整个租赁是否已全额支付

第38行存储了ID的映射。每次创建新的oracle查询时,都会返回唯一的ID。该ID被添加到__callback()所使用的映射中,以确保每个查询仅被处理一次。

第39行将租户映射到租约。当房东创建租约时,给定的租户地址将参考新的租约实例存储在此处,以便在执行租约操作时可以将其检索到。

第41-44行声明一个修饰符。我们会把这个附加到我们只想被房东调用的函数中。如果一个随机的人可以把智能合约里的钱都掏空,那就没有意义了,对吧?

第46-85行声明了所有可以执行的动作的事件。相应的动作完成后,将触发每个事件。在dApp中,此类事件对于前端代码响应和更新UI很有用。


少客联盟- 版权声明 1、本主题所有言论和图片纯属会员个人意见,与少客联盟立场无关。
2、本站所有主题由该帖子作者发表,该帖子作者信息发布员少客联盟享有帖子相关版权。
3、少客联盟管理员和版主有权不事先通知发贴者而删除本文。
4、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者信息发布员少客联盟的同意。
5、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任。
6、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责。
7、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意。
8、官方反馈邮箱:chinasuc@chinasuc.cn


上一篇:区块链之所以能够去信任的关键技术:非对称加密
下一篇:Casper FFG 的可审计安全性和近似活性
人生的价值,并不是用时间,而是用深度去衡量的。
最新回复 (0)
    • 少客联盟
      2
        登录 注册 QQ登录(停用)
返回