跳转到主要内容
Change page

详解智能合约

页面最后更新: 2026年4月15日

智能合约是一种在以太坊某个地址上运行的程序。 它们是由数据和函数组成的,可以在收到交易时执行。 以下概述一个智能合约的组成。

前提条件

请先确保您已阅读智能合约的相关信息。 本文档假设你已经熟悉某种编程语言,例如 JavaScript 或 Python。

数据

任何合约数据都必须分配到一个位置:storagememory。 在智能合约中修改存储消耗很大,因此你需要考虑数据在哪里存取。

存储

持久性数据被称之为存储,由状态变量表示。 这些值被永久地存储在区块链上。 你需要声明一个类型,以便于合约在编译时可以跟踪它在区块链上需要多少存储。

// Solidity 示例
contract SimpleStorage {
    uint storedData; // 状态变量
    // ...
}
# Vyper example
storedData: int128

如果用过面向对象编程语言,应该会熟悉大多数类型。 但如果是刚接触以太坊开发,则会发现 address 是一个新类型。

address 类型可以容纳一个以太坊地址,相当于 20 字节或 160 位。 它以十六进制的形式返回,前导是 0x。

其它类型包括:

  • 布尔
  • 整数(integer)
  • 定点数(fixed point numbers)
  • 固定大小的字节数组(fixed-size byte arrays)
  • 动态大小字节数组
  • 有理数和整数字面量
  • 字符串字面量
  • 十六进制字面量
  • 枚举

了解更多信息,请参阅文档:

内存

仅在合约函数执行期间存储的值被称为内存变量。 由于这些变量不是永久地存储在区块链上,所以它们的使用成本要低得多。

Solidity 文档 (opens in a new tab)中了解更多关于 EVM 如何存储数据(存储、内存和堆栈)的信息。

环境变量

除了在自己合约上定义的变量之外,还有一些特殊的全局变量。 它们主要用于提供有关区块链或当前交易的信息。

例子:

属性状态变量描述
区块时间戳uint256当前区块的时间戳
发送者地址消息的发送者(当前调用)

函数

用最简单的术语来说,函数可以获得信息或设置信息,以响应传入的交易。

有两种函数调用方式:

  • internal – 不会创建 EVM 调用
    • 内部函数和状态变量只能在内部访问(即从当前合约或其派生合约中访问)
  • external – 会创建 EVM 调用
    • External 函数是合约接口的一部分,这意味着他可以被其它合约和交易调用。 外部函数 f 不能在内部调用(即 f() 不起作用,但 this.f() 可以)。

它们也可以是 publicprivate

  • public 函数可以从合约内部调用,也可以通过消息从外部调用
  • private 函数仅在定义它们的合约中可见,在其派生合约中不可见

函数和状态变量都可以被定义为 public 或 private

下面是更新合约上一个状态变量的函数:

// Solidity example
function update_name(string value) public {
    dapp_name = value;
}
  • 类型为 string 的参数 value 被传递到函数 update_name
  • 它被声明为 public,意味着任何人都可以访问它
  • 它没有声明为 view,所以可以修改合约状态

视图函数

这些函数保证不会修改合约数据的状态。 常见的示例是 "getter" 函数 - 例如,它可以用于接收用户的余额。

// Solidity 示例
function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerPizzaCount[_owner];
}
dappName: public(string)

@view
@public
def readName() -> string:
  return dappName

这些操作被视为修改状态:

  1. 写入状态变量。
  2. 触发事件 (opens in a new tab)
  3. 创建其他合约 (opens in a new tab)
  4. 使用 selfdestruct
  5. 通过调用发送 ether。
  6. 调用任何未标记 view 或 pure 的函数。
  7. 使用底层调用。
  8. 使用包含某些操作码的内联程序组。

构造函数

constructor 函数仅在首次部署合约时执行一次。 与许多基于类的编程语言中的 constructor 一样,这些函数通常会将状态变量初始化为其指定值。

# Vyper 示例

@external
def __init__(_beneficiary: address, _bidding_time: uint256):
    self.beneficiary = _beneficiary
    self.auctionStart = block.timestamp
    self.auctionEnd = self.auctionStart + _bidding_time

内置函数

除了自己在合约中定义的变量和函数外,还有一些特殊的内置函数。 最明显的例子是:

  • address.send() – Solidity
  • send(address) – Vyper

这使合约可以发送以太币给其它帐户。

编写函数

你的函数需要:

  • 参数变量及其类型(如果它接受参数)
  • 声明为 internal/external
  • 声明为 pure/view/payable
  • 返回类型(如果它返回值)

一个完整的合约可能就是这样。 这里的 constructor 函数为 dapp_name 变量提供了一个初始值。

事件和日志

事件让你的智能合约能够与前端或其他订阅应用程序进行通信。 一旦交易被验证并添加到区块中,智能合约就可以触发事件并记录信息,然后前端就可以处理和利用这些信息。

带注解的示例

这是一些用 Solidity 写的例子。 如果你想体验一下这些代码,可以在 Remix (opens in a new tab) 中与它们交互。

Hello world

代币

独特的数字资产

扩展阅读{#further-reading}

查阅 Solidity 和 Vyper 文档,以获得关于智能合约的更完整概述:

这篇文章对您有帮助吗?