Java连接以太坊节点,实践指南与代码示例

投稿 2026-02-16 6:18 点击数: 1

以太坊作为全球领先的智能合约平台,吸引了大量开发者的关注,在实际应用开发中,我们经常需要使用Java等编程语言与以太坊节点进行交互,例如查询账户余额、发送交易、调用智能合约等,本文将详细介绍如何使用Java连接到以太坊节点,并实现基本的交互功能。

准备工作

在开始之前,你需要确保以下准备工作已完成:

  1. 以太坊节点

    • 本地节点:你可以运行自己的以太坊节点客户端,如Geth(Go语言实现)或Parity(Rust语言实现),启动节点时,需要确保启用了HTTP-RPC接口,默认端口为8545,Geth启动命令可能包含 --http --http.addr "0.0.0.0" --http.port "8545" --http.api "eth,net,web3,personal" 等参数。
    • 远程节点:你也可以使用远程的以太坊节点服务,如Infura、Alchemy等,这些服务通常提供一个HTTP或WebSocket的URL。
  2. Java开发环境:确保你已经安装了JDK(建议版本8或以上)和Maven(或Gradle)构建工具。

  3. 以太坊Java库:我们将使用目前较为流行和维护良好的 Web3j 库,它是一个轻量级的、异步的Java库,用于与以太坊节点交互。

引入Web3j依赖

如果你使用Maven,在pom.xml文件中添加以下依赖:

<dependencies>
    <!-- Web3j Core -->
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>core</artifactId>
        <version>4.9.8</version> <!-- 请查阅Web3j官网获取最新版本 -->
    </dependency>
    <!-- Web3j Console (可选,提供命令行工具) -->
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>console</artifactId>
        <version>4.9.8</version>
    </dependency>
    <!-- Web3j Utils (可选,提供一些实用工具) -->
    <dependency>
        <groupId>org.web3j</groupId>
        <artifactId>utils</artifactId>
        <version>4.9.8</version>
    </dependency>
</dependencies>

如果你使用Gradle,在build.gradle文件中添加:

implementation 'org.web3j:core:4.9.8' // 请查阅Web3j官网获取最新版本
implementation 'org.web3j:console:4.9.8'
implementation 'org.web3j:utils:4.9.8'

连接以太坊节点

Web3j提供了多种方式连接到以太坊节点,最常用的是通过HTTP/HTTPS。

连接到本地节点

假设你的本地以太坊节点运行在 http://localhost:8545

import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import java.io.IOException;
public class EthereumConnector {
    private static final String NODE_URL = "http://localhost:8545";
    private Web3j web3j;
    public void connect() {
        // 创建Web3j实例,连接到指定的节点URL
        web3j = Web3j.build(new HttpService(NODE_URL));
        System.out.println("Connecting to Ethereum node at: " + NODE_URL);
        try {
            // 测试连接,获取客户端版本
            String clientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion();
            System.out.println("Connected successfully! Client version: " + clientVersion);
        } catch (IOException e) {
            System.err.println("Failed to connect to Ethereum node: " + e.getMessage());
            e.printStackTrace();
        }
    }
    public Web3j getWeb3j() {
        return web3j;
    }
    public static void main(String[] args) {
        EthereumConnector connector = new EthereumConnector();
        connector.connect();
    }
}

连接到远程节点(如Infura)

以In

随机配图
fura为例,你需要先注册Infura并获取一个项目ID,然后构造相应的URL。

Infura的Rinkeby测试网URL格式为:https://rinkeby.infura.io/v3/YOUR_PROJECT_ID

public class RemoteEthereumConnector {
    private static final String INFURA_URL = "https://rinkeby.infura.io/v3/YOUR_PROJECT_ID"; // 替换为你的Infura项目ID
    private Web3j web3j;
    public void connect() {
        web3j = Web3j.build(new HttpService(INFURA_URL));
        System.out.println("Connecting to remote Ethereum node at: " + INFURA_URL);
        try {
            String clientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion();
            System.out.println("Connected successfully! Client version: " + clientVersion);
        } catch (IOException e) {
            System.err.println("Failed to connect to remote Ethereum node: " + e.getMessage());
            e.printStackTrace();
        }
    }
    // 其他方法与上面类似...
}

基本交互示例

成功连接到节点后,我们可以进行一些基本的操作。

获取最新区块号

try {
    BigInteger latestBlockNumber = web3j.ethBlockNumber().send().getBlockNumber();
    System.out.println("Latest block number: " + latestBlockNumber);
} catch (IOException e) {
    e.printStackTrace();
}

获取账户余额

假设我们有一个以太坊地址 0x...,我们需要知道它的余额(单位:Wei)。

String address = "0xYourEthereumAddressHere"; // 替换为实际的以太坊地址
try {
    EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();
    BigInteger balanceInWei = balance.getBalance();
    System.out.println("Balance of " + address + ": " + balanceInWei.toString() + " Wei");
    // 将Wei转换为Ether (1 Ether = 10^18 Wei)
    BigDecimal balanceInEther = new BigDecimal(balanceInWei).divide(new BigDecimal(BigInteger.TEN.pow(18)));
    System.out.println("Balance in Ether: " + balanceInEther);
} catch (IOException e) {
    e.printStackTrace();
}

发送交易(转账)

发送交易是一个相对复杂的过程,需要以下步骤:

  • 解锁账户(如果是本地节点且账户有密码):personalUnlockAccount
  • 构造交易EthSendTransaction
  • 等待交易确认ethGetTransactionReceipt

注意:实际发送交易需要账户的私钥,切勿在代码中硬编码私钥,应该使用安全的方式(如环境变量、密钥库文件+密码)来管理私钥,以下仅为演示如何调用发送交易的方法,不包含私钥处理。

// !!! 警告:以下代码仅为演示,实际使用时切勿硬编码私钥 !!!
String fromAddress = "0xSenderAddress";
String toAddress = "0xReceiverAddress";
String privateKey = "YOUR_PRIVATE_KEY_HERE"; // 危险!不要这样做!
// 1. 解锁账户 (本地节点可能需要)
// try {
//     personalUnlockAccount = web3j.personalUnlockAccount(fromAddress, privateKeyPassword).send();
//     if (!personalUnlockAccount.accountUnlocked()) {
//         System.out.println("Failed to unlock account");
//         return;
//     }
// } catch (IOException e) {
//     e.printStackTrace();
// }
// 2. 构造交易
BigInteger value = new BigInteger("1000000000000000000"); // 1 Ether in Wei
BigInteger gasLimit = BigInteger.valueOf(21000); // 转账通常21000 gas
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice(); // 获取当前建议gas价格
Transaction transaction = Transaction.createEtherTransaction(
        fromAddress,
        nonce, // 需要获取nonce
        gasPrice,
        gasLimit,
        toAddress,
        value
);
// 3. 发送交易
try {
    EthSendTransaction ethSendTransaction = web3j.ethSendTransaction(transaction).send();
    if (ethSendTransaction.getTransactionHash() != null) {
        System.out.println("Transaction sent! Hash: " + ethSendTransaction.getTransactionHash());
        // 4. 等待交易确认 (可选)
        // TransactionReceipt receipt = web3j.ethGetTransactionReceipt(ethSendTransaction.getTransactionHash()).send();
        // while (receipt.getTransactionReceipt() == null) {
        //     Thread.sleep(1000);
        //     receipt = web3j.ethGetTransactionReceipt(ethSendTransaction.getTransactionHash()).send();
        // }
        // System.out.println("Transaction confirmed! Status: " + receipt.getTransactionReceipt().getStatus());
    } else {
        System.out.println("Failed to send transaction: " + eth