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;
// 与状态变量交互的函数
}
这里声明了两个状态变量:creator
和 message
。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
函数会返回当前保存的 message
。constant
关键字表明该函数不修改合约状态,不会触发区块链写入。
通过调用 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.bin
和 Greeting.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 仓库。