1. 概述

以太坊区块链之所以能成为颠覆性技术,核心在于它能运行智能合约。在解释智能合约前,先明确下区块链的定义:

区块链是一个永久记录数字交易的公共数据库。它作为无需信任的交易系统运行,允许个人之间直接进行点对点交易,无需依赖第三方中介或相互信任。

接下来我们看看如何用 Solidity 在以太坊上创建智能合约:

2. 以太坊

以太坊是一个高效利用区块链技术构建去中心化应用的平台。

去中心化应用(Dapp)是让不同参与方无需中心化中介即可协作的工具。早期典型案例包括 BitTorrent(文件共享)和比特币(货币)。

简单说,以太坊就是内置了编程语言的区块链。

2.1. 以太坊虚拟机(EVM)

从实践角度看,EVM 可视为一个包含数百万对象的去中心化系统,这些对象称为账户,能维护内部数据库、执行代码并相互通信。

第一种账户类型是普通用户最熟悉的:EOA(外部拥有账户),用于传输价值(如以太币),由私钥控制。

另一种账户类型是合约账户,接下来重点讨论:

3. 什么是智能合约?

智能合约是独立运行的脚本,通常用 Solidity 编写,编译成二进制或 JSON 格式后部署到区块链的特定地址。就像调用 REST API 的接口执行逻辑一样,我们通过提交正确数据和必要以太币,即可调用部署在特定地址的已编译 Solidity 函数

从商业角度看,智能合约函数天然支持货币化(类似 AWS Lambda 按计算周期收费)。但需注意:⚠️ 并非所有智能合约函数运行都需要消耗以太币。

简单理解:智能合约就是存储在区块链网络中的代码集合,定义了所有参与方共同遵守的规则。

这为开发者创造了无限可能——无需中介,没有对手方风险。我们可以创建新型市场、存储债务或承诺记录,并确信交易得到网络共识验证。

任何人都可以支付与代码存储大小成比例的费用,将智能合约部署到去中心化数据库。使用该合约的节点需向网络广播其参与结果。

3.1. Solidity

以太坊的主要语言是 Solidity —— 一种类 JavaScript 语言,专为编写智能合约设计。Solidity 是静态类型语言,支持继承、库和复杂自定义类型等特性。

Solidity 编译器将代码转换为 EVM 字节码,然后作为部署交易发送到以太坊网络。这类部署交易费用远高于合约交互,必须由合约所有者支付。

4. 用 Solidity 创建智能合约

Solidity 合约首行需声明源码版本,确保新编译器不会改变合约行为:

pragma solidity ^0.4.0;

示例合约名为 Greeting,其创建方式类似 Java 等面向对象语言中的类:

contract Greeting {
    address creator;
    string message;

    // 与状态变量交互的函数
}

这里声明了两个状态变量:creatormessage。Solidity 中使用 address 类型存储账户地址。

接下来需要在构造函数中初始化这些变量。

4.1. 构造函数

使用 function 关键字加合约名声明构造函数(类似 Java)。

构造函数是特殊函数,仅在合约首次部署到以太坊区块链时执行一次。每个合约只能有一个构造函数:

function Greeting(string _message) {
    message = _message;
    creator = msg.sender;
}

我们将初始字符串 _message 作为参数注入,并赋值给 message 状态变量。

第二行将 creator 初始化为 msg.sender。无需注入 msg 是因为它是全局变量,提供消息发送方地址等信息。

这类信息可用于实现函数访问控制。

4.2. Setter 和 Getter 方法

最后实现 message 的 setter 和 getter 方法:

function greet() constant returns (string) {
    return message;
}

function setGreeting(string _message) {
    message = _message;
}

调用 greet 函数会返回当前保存的 messageconstant 关键字表明该函数不修改合约状态,不会触发区块链写入。

通过调用 setGreeting 可修改合约状态值。任何人都能调用此函数更改值。该方法无返回类型,但接受 String 类型参数。

创建完首个智能合约后,下一步是将其部署到以太坊区块链。推荐使用 Remix —— 目前最易用的在线 IDE。

5. 与智能合约交互

要与去中心化网络(区块链)中的智能合约交互,需访问客户端节点:

自建节点
使用 Infura 等远程节点服务

Infura 是最简单方案,注册获取免费访问令牌后,选择 Rinkeby 测试网 URL:"https://rinkeby.infura.io/<token>"

要在 Java 中与智能合约交互,需使用 Web3j 库。Maven 依赖:

<dependency>
    <groupId>org.web3j</groupId>
    <artifactId>core</artifactId>
    <version>3.3.1</version>
</dependency>

Gradle 配置:

compile ('org.web3j:core:3.3.1')

编码前需完成以下准备工作:

5.1. 创建钱包

Web3j 提供命令行工具支持:

  • 钱包创建
  • 密码管理
  • 资金转账
  • 生成 Solidity 合约函数包装器

从项目发布页下载 zip/tarball,或 macOS 用户通过 Homebrew 安装:

brew tap web3j/web3j
brew install web3j

生成新以太坊钱包:

$ web3j wallet create

按提示设置密码和保存路径。钱包文件为 JSON 格式,关键信息是其中的以太坊地址,下一步将用于申请以太币。

5.2. 在 Rinkeby 测试网申请以太币

⚠️ Rinkeby 测试网已弃用,建议改用 Sepolia 测试网。

为防止恶意行为者耗尽资金,需提供包含以太坊地址的社交媒体公开链接。操作简单,通常能即时获得测试以太币。

5.3. 生成智能合约包装器

Web3j 可自动生成智能合约包装代码,无需离开 JVM 即可部署和交互合约。

生成包装代码前需先编译合约。安装编译器参考说明。编译命令:

$ solc Greeting.sol --bin --abi --optimize -o <output_dir>/

这将生成 Greeting.binGreeting.abi 两个文件。使用 web3j 命令行工具生成包装代码:

$ web3j solidity generate /path/to/Greeting.bin 
  /path/to/Greeting.abi -o /path/to/src/main/java -p com.your.organisation.name

现在主代码中已有与合约交互的 Java 类。

6. 与智能合约交互实战

在主类中,首先创建 web3j 实例连接远程节点:

Web3j web3j = Web3j.build(
  new HttpService("https://rinkeby.infura.io/<your_token>"));

然后加载以太坊钱包文件:

Credentials credentials = WalletUtils.loadCredentials(
    "your_password", 
    "/path/to/wallet/file");

部署合约(网络繁忙时可能耗时较长):

Greeting contract = Greeting.deploy(
    web3j, 
    credentials, 
    Contract.GAS_PRICE, 
    Contract.GAS_LIMIT,
    "Initial message"
).send();

部署后保存合约地址:

String contractAddress = contract.getContractAddress();

所有合约交易可在 https://rinkeby.etherscan.io/address/<contract_address> 查看。

修改合约状态值:

TransactionReceipt transactionReceipt = contract.setGreeting("Hello again").send();

查询新存储值:

String newValue = contract.greet().send();

7. 总结

本教程展示了 Solidity 作为静态类型语言,专为开发 EVM 智能合约设计。

我们用该语言创建了一个简单合约,其语法与其他编程语言高度相似。

智能合约本质是促进价值交换的计算机代码。在区块链上运行时,它成为自动执行的程序,满足特定条件即触发操作。

以太坊的核心差异在于支持链上代码执行,使开发者能构建超越传统应用的新型去中心化应用。

完整代码示例见 GitHub 仓库


原始标题:Creating and Deploying Smart Contracts with Solidity | Baeldung