Python 智能合约基础详解

在本章中,我们将探讨智能合约的基础知识。在比特币中我们存储价值,而在以太坊中我们存储代码。我们存储在以太坊中的代码称为智能合约。智能合约是一种不可信任的代码,这意味着代码的完整性由算法和密码保护。我们可以存储这些代码,这些代码可以抵抗审查,并且能够避免第三方的干扰,即使是来自智能合同的开发者。这为创建多种类型的应用打开了可能性,例如透明数字代币、不可信任的众售、安全投票系统和自治组织。

本章将介绍以下主题:

现在是创建智能合约的时候了。如果您熟悉 Solidity、Truffle、Ganache 和智能合约基础知识,您可以跳到第 3 章使用 Vyper实现智能合约。在这里,我们将重点介绍使用 Solidity 创建的智能合约的内容。在本书的其余部分中,我们将使用 Vyper 编程语言来开发智能合约。但是,在本书的其余部分中,我们仍将使用相同的开发环境(如 Ganache)。

Node.js 是开发 web 应用、移动应用和去中心应用的流行框架。前往https://nodejs.org 下载最新版本(撰写本文时为第 10 版)。以下是如何在 Ubuntu Linux 平台上安装 Node.js:

$ curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
$ sudo apt-get install -y nodejs
$ node --version
v10.15.0

块菌是一个开发框架,用于开发具有坚固性的智能合约。您可以创建一个没有块菌,但块菌使它更容易。没有块菌,您仍然可以编写智能合约,但要编译它,您必须启动带有特定标志的 Solidity 编译器。然后,为了将此智能合约部署到区块链,您必须创建一个脚本来将字节码发送到区块链。使用 Truffle,为了编译,您需要调用,truffle compile命令,为了向区块链部署智能合约,您需要在编写简单迁移脚本后调用truffle migrate命令。块菌还为您提供了与区块链网络中的智能合约交互的工具。它提供了开发智能合约所需的一切。但是,如前所述,我们在下一章中将不使用此框架。

我们将首先使用 Node.js 包管理器安装 Truffle。在 Ubuntu Linux 中,为了在全球范围内安装块菌,我们必须使用sudo。如前一段所述,Truffle 是一个智能合约开发框架,包含许多工具,包括与区块链网络交互的控制台应用和开发区块链软件。除此之外,使用块菌,您还可以获得 Solidity 编译器。

但首先,您需要确保npm在您的主目录中全局安装软件:

$ mkdir ~/.npm-global
$ npm config set prefix '~/.npm-global' 

然后将此行附加到~/.配置文件:

export PATH=~/.npm-global/bin:$PATH

现在,打开一个新的终端,使新的配置文件生效,或者执行以下操作:

$ source ~/.profile

然后,我们可以按如下方式安装块菌:

$ npm install -g truffle
$ truffle version
Truffle v5.0.2 (core: 5.0.2)
Solidity v0.5.0 (solc-js)
Node v10.15.0 

为了开发智能合约,人们通常使用 Ganache。Ganache 是一个专用的、开发性的以太坊网络,您只能在以太坊开发阶段使用。块菌框架已经包括以太坊区块链网络,其目的与 Ganache 相同。两者之间的区别在于 Ganache 有一个前端 GUI 和一个更为用户友好的界面。

当您启动 Ganache 时,您将配备 10 个帐户,每个帐户中填充 100 个以太,这是以太坊区块链中的货币。正如您将在本章后面看到的,以太坊编程中的货币概念(如持有、发送和接收货币,以及跟踪余额)非常重要。您需要花钱在以太坊区块链中启动智能合约。您可以将资金从帐户发送到智能合约,而智能合约又可以将资金发送到其他智能合约或其他帐户。

要下载软件,请访问 Ganache 网站:https://www.truffleframework.com/ganache 。对于 Linux 平台,该软件称为ganache-1.2.3-x86_64.AppImage。下载此文件后,必须在执行之前设置正确的权限:

$ chmod a+x ganache-1.2.3-x86_64.AppImage
$ ./ganache-1.2.3-x86_64.AppImage

一旦安装了所有必需的软件,我们就可以开始编写智能合同了。首先,我们将创建一个新目录,然后使用 Truffle 开发工具对其进行初始化:

$ mkdir my_first_smart_contract
$ cd my_first_smart_contract
$ truffle init

truffle init命令的输出如下:

这将命令 Truffle 将您的目录初始化为智能合约开发项目。在此项目目录中开发智能合同时,您可以使用以下几个目录:

$ ls
contracts migrations test truffle-config.js

您通常将智能合约的源代码合并到contracts文件夹中。migrations文件夹保存智能合约部署中使用的文件,test文件夹保存test文件。您可以在truffle-config.js文件中配置智能合约部署设置。我们将创建第一个智能合约,并使用以下代码将其命名为donation.sol

pragma solidity ^0.5.0;

contract Donation {
  address public donatur;
  address payable donatee;
  uint public money;
  string public useless_variable;

  constructor() public {
    donatee = msg.sender;
    useless_variable = "Donation string";
  }

  function change_useless_variable(string memory param) public {
    useless_variable = param;
  }

  function donate() public payable {
    donatur = msg.sender;
    money = msg.value;
  }

  function receive_donation() public {
    donatee.transfer(address(this).balance);
  }
}

如果您是智能合约的新手,在前面的示例中可能有一些不熟悉的关键字。在本章中,我们将不讨论与坚固性相关的所有问题。相反,我们将只研究构建智能合同和学习智能合同概念所需的坚固性特征。

但首先,让我们将这个智能合约编译成以太坊字节码和一个应用二进制接口abi)。为此,我们将在 Truffle 项目目录中运行以下命令:

$ truffle compile

编译的结果可以在名为Donation.jsonbuild/contracts文件夹中看到:

如果你打开这个文件,你会看到很多有趣的东西。这个.json文件有 1530 行长。此文件中的json对象有 14 个键。你现在只需要考虑两个键。第一个是接口(称为abi),第二个是可以在以太坊虚拟机上执行的二进制文件(称为bytecode。有关本节中的代码,请参阅以下 GitLab 链接中的代码文件:https://gitlab.com/arjunaskykok/hands-on-blockchain-for-python-developers/blob/master/chapter_02/my_first_smart_contract/build/contracts/Donation.json

我们不能像编译 C 代码并直接执行二进制文件那样运行这个二进制文件。我们需要将这个二进制文件放入以太坊虚拟机。当我们开发一个分散的应用时,我们需要接口本身来与智能合约交互。当您将智能合约部署到以太坊区块链时,您需要字节码。当您想要与以太坊区块链中已经部署的智能合约交互时,您需要abi接口。

以下是使用块菌将智能合约部署到以太坊区块链的步骤:

  1. 编写迁移脚本:要部署智能合约,需要编写迁移文件,创建一个名为migrations/2_deploy_donation.js的新文件。然后,我们用以下脚本填充此文件:
var Donation = artifacts.require("./Donation.sol");

module.exports = function(deployer) {
  deployer.deploy(Donation);
};

至于migrations/1_initial_migration.jscontracts/Migrations.sol文件,我们暂时保留它们。为了部署智能合约,Truffle 需要这些文件。

  1. 启动 Ganache(以太坊开发区块链):现在您需要启动 Ganache。假设您已获得适当的权限,请运行以下命令行以执行该文件:
./ganache-1.2.3-x86_64.AppImage

正如您在以下屏幕截图中所看到的,您有许多帐户,每个帐户的余额为 100 以太:

您将从 Ganache 屏幕中注意到的一件事是位于http://127.0.0.1:7545中的RPC 服务器。这就是以太坊区块链位于Truffle项目目录中的位置。

  1. 编辑块菌配置文件:如果打开truffle-config.js,删除注释行后代码如下:
module.exports = {
  networks: {
  },
  mocha: {
  },
  compilers: {
    solc: {
    }
  }
};

将其删除并将以下代码行添加到truffle-config.js文件中:

module.exports = {
  networks: {
    "development": {
      network_id: 5777,
      host: "localhost",
      port: 7545
    },
  }
};

hostport取自 Ganache 屏幕中的 RPC 服务器,network_id取自 Ganache 屏幕中的网络 ID。

  1. 执行迁移脚本:要部署您的智能合约,您可以按如下方式执行:
$ truffle migrate

块菌框架将获取Donation.json文件中定义的字节码,并将其发送给以太坊区块链或 Ganache。这将为您提供以下输出:

2_deploy_donation.js部分,注意contract address:之后的十六进制数字,即0x3e9417399786347b6ab38f59d3f00829d6bba7b8。这是智能合约的地址,类似于 web 应用的 URL。

如果在您尝试部署智能合约时输出了Network is up to date.,您可以删除build/contracts目录中的文件,并使用truffle migrate命令运行此版本:

$ truffle migrate --reset

现在,我们将查看 Ganache 屏幕上的更改:

需要注意的最重要的一点是,第一个账户0xb105F01Ce341Ef9282dc2201BDfdA2c26903da77已经亏损。余额不再是 100 以太;它是**99.98 ETH**。那么 0.02 ETH 去了哪里?为了将您的智能合同写入以太坊区块链,需要激励矿工。请注意,当前块不再是 0,而是 4。因此,0.02 ETH 将是成功将包含您的智能合约的区块放入区块链的矿工的费用。但是,当然,在这种情况下,没有 miner,因为我们使用 Ganache,以太坊开发区块链。Ganache 只是通过将智能合约纳入区块链来模拟交易费用。

如果单击“事务”选项卡,您将看到如下内容:

您现在已经创建了两个合同(捐赠和迁移)。一旦部署了智能合约,除非您应用方法关闭它,否则它将永远在区块链中。如果智能合约中存在缺陷,则无法修补。您必须在不同的地址部署固定智能合约。

要与以太坊区块链中的智能合约交互,请在Truffle项目目录中执行以下命令:

$ truffle console

然后,在truffle控制台提示下,执行以下命令:

truffle(development)> Donation.deployed().then(function(instance) { return instance.useless_variable.call(); });
'Donation string'

如果您对then感到困惑,那么 Truffle 控制台使用回调的概念,在回调上异步执行对智能合约对象的访问。在执行回调之前,Truffle 控制台中的这条语句立即返回。在回调函数中,您将接受智能合约实例作为instance参数。然后,我们可以从这个instance参数访问我们的useless_variable变量。然后,为了检索该值,我们必须对该变量执行call方法。

块菌框架将使用Donation.json文件中定义的abi来理解智能合约中有哪些接口可用。回想一下,您在智能合约中定义了useless_variable,并在构造函数(或初始化)函数中将其设置为Donation string。以这种方式读取公共变量是自由的;它不需要任何乙醚,因为它存储在区块链中。

让我提醒您,如果变量存储在区块链中,这意味着什么。如果您将此智能合约纳入以太坊生产区块链,useless_variable变量将存储在每个以太坊节点中。在编写本文时,大约有 10000 个节点。这个数字一直在变化,如图所示:https://www.ethernodes.org 。一个节点可以在一台计算机中,一台计算机可以容纳两个节点。然而,很可能一台计算机只拥有一个节点,因为成为节点主机的要求非常高。如果您想要与区块链交互,您需要一个节点(还有其他选项,例如使用 API 与其他人的节点交互)。因此,可以自由读取useless_variable变量,因为您只需从计算机中读取。

如果您对这个自由概念感到困惑,那么让我们通过将useless_variable变量更改为其他变量来澄清:

truffle(development)> Donation.deployed().then(function(instance) { return instance.change_useless_variable("sky is blue", {from: "0xb105F01Ce341Ef9282dc2201BDfdA2c26903da77" }); });

您将获得以下输出:

在单词from之后还有一个神秘的十六进制数字,即0xb105F01Ce341Ef9282dc2201BDfdA2c26903da77。这是 Ganache 第一个帐户的公共地址。您可以通过查看 Ganache 屏幕来确认。在这里,您读取useless_variable变量并使用不同内容设置它的方式有所不同。更改变量的内容需要不同的语法,更重要的是,需要使用一个帐户。需要账户,因为在区块链中更改变量时需要花费一些钱。当您在区块链的智能合约中更改此useless_variable变量的值时,您基本上是在向以太坊生产区块链中的所有以太坊节点广播,以太坊生产区块链中约有 10000 个节点可用于更新useless_variable的内容。我们使用的是 Ganache,这是以太坊开发区块链,但在生产环境中,您需要签署交易,以使用私钥更改变量的内容。私钥的用途类似于帐户上的密码,但私钥不能更改,而您可以随时更新密码。如果忘记了密码,可以重置密码,然后单击确认电子邮件中的链接进行更新。在区块链中,这不是一个选项。

如果你现在检查 Ganache,你的余额保持不变;只有块编号从 4 增加到 5:

这是因为所需的资金非常少。在执行最后一个命令后,您可以查看命令的输出来更改useless_variable的值。看看用过的气田;这是您在智能合约中执行函数时所花费的费用。使用的气体量为 33684,但这是 gwei,而不是乙醚。1 乙醚等于 100000000 gwei,因此约为 0.00003 乙醚。在这种情况下,气体会自动计算,但稍后,您可以设置在以太坊区块链中执行任何功能时要分配多少气体。如果你没有贡献太多的乙醚,并且分配的气体量很小,那么你的执行很有可能会被给予较低的优先级。确认交易将花费更长的时间(意味着变量的值已更改)。如果网络流量过大,它可能会被矿工拒绝

这种花钱改变项目状态的观念是新的。读取区块链中的所有内容都是免费的,因为所有数据都在您的计算机中(如果您有以太坊节点),但在区块链中更改或添加内容需要金钱。这是因为您更改了全球所有以太坊节点中的数据,这非常昂贵!除了改变智能合约的状态,在内存中运行的计算也需要钱。

现在,让我们向智能合约发送一些乙醚。让我们使用第二个帐户。第二个帐户希望使用智能合约捐赠 5 台以太,如下所示:

truffle(development)> Donation.deployed().then(function(instance) { return instance.donate({ from: "0x6d3eBC3000d112B70aaCA8F770B06f961C852014", value: 5000000000000000000 }); });

您将获得以下输出:

除了from字段外,还需要添加一个value字段。在此value字段中,您输入要发送到智能合约的金额。你可能想知道为什么这个数字有这么多零。当您在以太坊区块链中转账时,必须使用最低的货币单位(类似于从美元到美分的转换),称为。1 乙醚为 10000000000000000 微(18 个零)。你想发送 5 个以太,使其 5000000000000000000。现在,如果你看你的 Ganache 屏幕,你会注意到平衡下降到 95。因此,5 乙醚现在保存在智能合约中,如以下屏幕截图所示:

让我们使用第一个帐户取款:

truffle(development)> Donation.deployed().then(function(instance) { return instance.receive_donation({ from: "0xb105F01Ce341Ef9282dc2201BDfdA2c26903da77" }); });

您将获得以下输出:

此执行的语法与前面相同,但不包括value字段。现在看看 Ganache 屏幕。第一个帐户具有介于 104 和 105 之间的乙醚(例如 104.8 或 104.9 乙醚)。这并不是因为我们已经花费了一些钱使用第一个帐户启动智能合约,以及在执行智能合约中的某些功能时支付交易费:

现在,您已经看到了一个智能合同的实施。那么,所有的大惊小怪是怎么回事?智能合约能做哪些传统程序(普通 web 应用)做不到的事情?当涉及到更改网络程序中变量的值时,我们可以使用远程过程调用。更常见的是,我们可以在数据库中存储变量,人们可以通过 web 应用更改数据库中的值。在汇款时,我们可以将我们的 web 应用与 Stripe 或 PayPal 集成,为我们提供汇款的手段。或者,您可以在数据库中创建一个表来存储数字货币。以太坊中的以太基本上是数字货币。事实上,一个普通的 web 应用可以做智能合约所能做的一切,但速度更快、成本更低。关键区别在于区块链解决方案可以是不可信的。这意味着您可以信任程序本身,但不能信任操作员。

在普通的 web 应用中,我们依赖于信任 web 应用的操作员(开发人员或系统管理员)。我们希望他们诚实地开发和部署 web 应用。作为 web 应用的用户,我们没有办法确保 web 应用按照它告诉每个人它要做的事情去做。

假设我们有一个 web 应用,它可以承载视频(比如 YouTube 或 Vimeo)。如果用户单击 Like 按钮,web 应用可以增加视频上的 Like 数量。规则是用户只能喜欢一个视频一次。因此,您可能希望一个包含 400 个用户喜欢的视频有 400 个用户喜欢该视频。如果我告诉你,在幕后,系统管理员可以人为地增加喜欢的数量,那会怎么样?这意味着在 400 个喜欢中,可能只有 300 个喜欢来自真正的用户。其他 100 个相似项由系统管理员夸大。它不必像通过UPDATE video_likes SET likes_amount = 400 WHERE video_id = 5;直接更新数据库中的表那样原始。可以在系统中嵌入增加同类数量的方法

普通用户不会注意到这一点。开发 web 应用的公司可以在 GitHub 上发布源代码。但是如何确保 web 应用确实是从 GitHub 上托管的源代码构建的呢?如果部署 web 应用后,系统管理员或开发人员对系统进行了修补,该怎么办

有很多方法可以防止这种数字欺骗。首先,我们可以介绍一位 IT 审计员。这些组织可以是政府组织或非政府组织。他们将审核系统的源代码,更重要的是,检查代码在生产系统中的作用。在这种情况下,您将信任从开发人员或系统管理员转移到第三方审计员。

作为一名 IT 顾问,我通过构建 web 应用和移动应用谋生。我曾经遇到一位潜在客户,他想制作一份数字报纸(类似《卫报》或《纽约时报》)。这位客户问我是否有办法根据需要将任何文章移动到浏览量最高的文章部分。这里的动机是推广特定的文章,即使这意味着系统会对用户撒谎,说他们最常看的文章是什么。

Reddit 的首席执行官最近公开道歉,因为他被发现修改了网站上关于他的评论。更多信息请参见以下链接:https://techcrunch.com/2016/11/23/reddit-huffman-trump/

即使是知名网站也在玩数字作弊。例如,一些加密货币交易所伪造交易量。更多信息请参见以下链接:https://medium.com/@sylvainartplayribes/chasing-fake-volume-a-crypto-peas-ea1a3c1e0b5e

智能合约是防止数字欺诈的另一种手段。智能合约的开发人员可以发布源代码并将智能合约部署到以太坊区块链中。人们可以验证发布的源代码和部署的智能合约是否相同。开发者可以创建一种在智能合约内作弊的方法,但这将被用户捕获,因为他们可以从区块链中智能合约的字节码重构智能合约的源代码。开发人员无法修补已部署的智能合约。

还有其他智能合约属性,比如自治和抵制审查。然而,这些特性中没有一个能超过它的透明度。或者,为了保护以太坊系统的可靠性,您必须拥有比所有 10000 个节点协同工作更大的功率。为了简化计算,您需要购买 5000 多台配备高端 GPU 的计算机。假设你有那么多的资源来作弊。当你在以太坊系统中作弊时,诚实的矿工会受到警告,他们会在互联网上发出噪音。因此,如果你有办法在以太坊作弊,你就不能偷偷摸摸。此外,如果您有能力获得 5000 台配备高端 GPU 的计算机,您可以成为以太坊平台的矿工,并获得可观的收入。因此,在以太坊平台上很难作弊。

在本章中,我们探讨了如何安装 Solidity 开发工具:Node.js、Truffle 或 Ganache。然后,我们学习了如何编写智能合约并进行编译。之后,我们研究了将智能合约部署到以太坊区块链的概念,然后与使用 Truffle 控制台工具部署的智能合约进行交互。我们了解了向智能合约发送乙醚的概念,以及在智能合约中执行功能时的气体使用情况。在最后一步中,我们熟悉了为什么 smart 概念如此有效,有可能创建一个抵制审查、透明、无法规避的程序。

在下一章中,我们将学习如何使用 Vyper 实现智能合约。

以太坊黄纸:https://ethereum.github.io/yellowpaper/paper.pdf

以太坊白皮书:https://github.com/ethereum/wiki/wiki/White-Paper

教程来源于Github,感谢apachecn大佬的无私奉献,致敬!

技术教程推荐

消息队列高手课 -〔李玥〕

Service Mesh实战 -〔马若飞〕

Spark核心原理与实战 -〔王磊〕

爆款文案修炼手册 -〔乐剑峰〕

超级访谈:对话张雪峰 -〔张雪峰〕

业务开发算法50讲 -〔黄清昊〕

深入浅出分布式技术原理 -〔陈现麟〕

结构学习力 -〔李忠秋〕

Midjourney入门实践课 -〔Jovi〕