一个简单的合约:一个test ether faucet

以太坊有许多不同的高级语言,所有这些语言都可用于编写合约并生成EVM字节码。你可以阅读 [high_level_languages] 中许多最成功和有趣的内容。一种智能合约编程的主要高级语言:Solidity。本书的合著者Gavin Wood创建了Solidity,已经成为以太坊及以太坊外最广泛使用的语言。我们将使用Solidity编写我们的第一份合约。

作为我们的第一个例子,我们将编写一个控制_faucet_的合约。我们已经使用了faucent在Ropsten测试网络上获得测试ether。faucet是一件相对简单的事情:它给任何地址发放ether,可以定期补充。你可以将faucet实现为由人类(或网络服务器)控制的钱包,但我们将编写一个实现faucet的Solidity合约:

Faucet.sol : A Solidity contract implementing a faucet

  1. link:code/Solidity/Faucet.sol[]

这是一个非常简单的合约。这也是一个有*缺陷*的合约,显示了一些不良做法和安全漏洞。我们将通过检查后面章节中的所有缺陷来学习。但现在,让我们逐行看下这个合约的作用,以及它是如何工作的。

第一行是注释

  1. // Version of Solidity compiler this program was written for

注释用于人类阅读,不包含在可执行的EVM字节码中。我们通常将注释放在我们试图解释的代码之前,有时在同一行上。评论从两个正斜杠 // 开始。从斜线和直到该行结束的所有内容都被视为空白行并被忽略。

下一行是我们的_真正的_合约开始的地方:

  1. contract Faucet {

该行声明了一个合约对象,类似于JavaScript,Java或C++等其他面向对象语言中的 class 声明。合约的定义包含了大括号中的所有行 {},它定义了 +范围 +,就像在其他许多编程语言中使用花括号一样。

接下来,我们声明faucet合约的第一个函数:

  1. function withdraw(uint withdraw_amount) public {

函数名为 withdraw,它接收一个无符号整数(uint)名为 withdraw_amount 的参数。它被声明为 public 函数,意味着它可以被其他合约调用。函数定义在花括号之间:

  1. require(withdraw_amount <= 100000000000000000);

withdraw+方法的第一部分设置了取款限制。它使用内置的Solidity函数 +require 来测试前提条件,即 withdraw_amount 小于或等于100000000000000000 wei,它是ether的基本单位(参见 Ether Denominations and Unit Names),等于0.1 ether。如果使用 withdraw_amount 大于该数量调用 withdraw 函数,则此处的 require 函数将导致合约执行停止并失败,并显示_异常_。

合约的这部分是我们faucet的主要逻辑。它通过设定提款限额来控制合约的资金流出。这是一个非常简单的控制,但可以让你看到可编程区块链的强大功能:去中心化控制货币的软件。

Next comes the actual withdrawal:

  1. msg.sender.transfer(withdraw_amount);

这里发生了一些有趣的事情。msg 对象是所有合约可以访问的输入之一。它代表触发执行此合约的交易。属性 sender 是交易的发件人地址。函数 transfer 是一个内置函数,它将ether从合约传递到调用它的地址。从后往前读,表示 transfer 到触发此合约执行的 msg 的 sender。transfer 函数将一个金额作为唯一的参数。我们传递之前声明为 withdraw 方法的参数的 withdraw_amount 值。

紧接着的一行是结束大括号,表示 withdraw 函数定义的结束。

下面我们又声明了一个函数:

  1. function () public payable {}

此函数是所谓的_“fallback”_或_default_函数,如果合约的交易没有命名合约中任何已声明的功能或任何功能,或者不包含数据,则触发此函数。合约可以有一个这样的默认功能(没有名字),它通常是接收ether的那个。这就是为什么它被定义为 public 和 payable 函数,这意味着它可以接受合约中的ether。除了大括号中的空白定义 {} 所指示的以外,它不会执行任何操作。如果我们进行一次向这个合约地址发送ether的交易,就好像它是一个钱包一样,该函数将处理它。

在我们的默认函数下面是最后一个关闭花括号,它关闭了合约 faucet 的定义。就是这样!