使用Web3j的轻量级以太坊客户端

2025/03/31

1. 简介

本教程介绍了Web3j,它是流行的Web3抽象库的Java实现。

Web3j用于通过使用JSON-RPC或熟悉的标准(如HTTP、WebSockets、IPC)连接到以太坊节点来与以太坊网络进行交互

以太坊本身就是一个完整的主题,所以让我们首先快速了解一下它是什么。

2. 以太坊

以太坊是一种(1)加密货币(代币符号为ETH)、(2)分布式超级计算机、(3)区块链、和(4)用Solidity编写的智能合约网络。

换句话说,以太坊(网络)由一组称为节点的连接服务器运行,这些服务器以一种网状拓扑结构进行通信(从技术上讲,这并不完全正确,但足够接近,以便更深入地了解它的工作原理)。

Web3j及其父库Web3允许Web应用程序连接到其中一个节点,从而提交以太坊交易,这些交易实际上都是已编译的Solidity智能合约函数,这些函数之前已部署到以太坊网络。有关智能合约的更多信息,请参阅我们关于使用Solidity创建和部署智能合约的文章。

每个节点都会向其他所有节点广播自己的更改,以便达成共识和验证。因此,每个节点同时包含以太坊区块链的整个历史记录,从而以防篡改的方式创建所有数据的冗余备份,并通过网络中所有其他节点的共识和验证。

有关以太坊的更多详细信息,请查看官方页面

3. 设置

要使用Web3j提供的全部功能,我们需要比平时做更多的设置。首先,Web3j提供几个独立的模块,每个模块都可以选择添加到核心pom.xml依赖中:

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

请注意,Web3j团队提供了预先构建的Spring Boot Starter,其中内置了一些配置和有限的功能

在本文中,我们将重点介绍核心功能(包括如何将Web3j添加到Spring MVC应用程序中,以获得与更广泛的Spring Webapps的兼容性)。

这些模块的完整列表可以在Maven Central上找到。

3.1 编译合约:Truffle或Solc

编译和部署以太坊智能合约(.solc文件)主要有两种方式:

  1. 官方Solidity编译器
  2. Truffle(用于测试、部署和管理智能合约的抽象套件)

在本文中,我们将坚持使用Truffle。Truffle简化并抽象了编译智能合约、迁移智能合约并将其部署到网络的过程。它还包装了Solc编译器,让我们能够获得一些这方面的经验。

要设置Truffle:

$ npm install truffle -g
$ truffle version

我们将使用4个关键命令分别来初始化我们的项目、编译我们的应用程序、将我们的应用程序部署到区块链以及对其进行测试:

$ truffle init
$ truffle compile
$ truffle migrate
$ truffle test

现在,我们来看一个简单的例子:

pragma solidity ^0.4.17;

contract Example {
    function Example() {
        // constructor
    }
}

编译后将产生以下ABI JSON:

{
    "contractName": "Example",
    "abi": [
        {
            "inputs": [],
            "payable": false,
            "stateMutability": "nonpayable",
            "type": "constructor"
        }
    ],
    "bytecode": "0x60606040523415600e57600080fd5b603580601b6...,
    "deployedBytecode": "0x6060604052600080fd00a165627a7a72305...,
    //...
}

然后,我们可以在应用程序中使用提供的字节码和ABI与已部署的合约进行交互。

3.2 测试合约:Ganache

使用以太坊测试网最简单的方法之一就是启动自己的Ganache服务器,我们将使用预构建的开箱即用解决方案,因为它最容易设置和配置。它还为Ganache CLI提供了一个接口和服务器shell,用于驱动Ganache的底层运行。

我们可以通过默认提供的URL地址连接到我们的Ganache服务器:http://localhost:8545或http://localhost:7545。

还有其他几种流行的建立测试网络的方法,包括使用Meta-MaskInfuraGo-Lang和Geth

在本文中,我们将坚持使用Ganache,因为设置自己的GoLang实例(并将其配置为自定义测试网)可能非常棘手,并且Chrome上Meta-Mask的状态目前尚不确定。

我们可以将Ganache用于手动测试场景(调试或完成集成测试时)或将其用于自动化测试场景(我们必须围绕其构建测试,因为在这种情况下,我们可能没有可用的端点)。

4. Web3和RPC

Web3提供了一个外观和接口,可轻松与以太坊区块链和以太坊服务器节点进行交互。换句话说,Web3通过JSON-RPC促进客户端与以太坊区块链之间的互通。Web3J是Web3的官方Java端口

我们可以通过传入提供程序(例如第三方或本地以太坊节点的端点)来初始化Web3j以在我们的应用程序中使用:

Web3j web3a = Web3j.build(new HttpService());
Web3j web3b = Web3j.build(new HttpService("YOUR_PROVIDER_HERE"));
Web3j myEtherWallet = Web3j.build(new HttpService("https://api.myetherapi.com/eth"));

第三个选项显示如何添加第三方提供者(从而连接到他们的以太坊节点),但我们也可以选择将提供者选项留空。在这种情况下,将改为使用localhost上的默认端口(8545)。

5. 基本Web3方法

现在我们知道如何初始化我们的应用程序以便与以太坊区块链进行通信,让我们看看与以太坊区块链交互的几种核心方法。

用CompletableFuture包装你的Web3方法来处理对配置的以太坊节点发出的JSON-RPC请求的异步特性是一个很好的策略。

5.1 当前区块编号

例如,我们可以返回当前的块号

public EthBlockNumber getBlockNumber() {
    EthBlockNumber result = new EthBlockNumber();
    result = this.web3j.ethBlockNumber()
            .sendAsync()
            .get();
    return result;
}

5.2 账户

获取指定地址的账户

public EthAccounts getEthAccounts() {
    EthAccounts result = new EthAccounts();
    result = this.web3j.ethAccounts()
            .sendAsync()
            .get();
    return result;
}

5.3 账户交易次数

要获取给定地址的交易数量

public EthGetTransactionCount getTransactionCount() {
    EthGetTransactionCount result = new EthGetTransactionCount();
    result = this.web3j.ethGetTransactionCount(DEFAULT_ADDRESS,
                    DefaultBlockParameter.valueOf("latest"))
            .sendAsync()
            .get();
    return result;
}

5.4 账户余额

最后,获取地址或钱包的当前余额

public EthGetBalance getEthBalance() {
    EthGetBalance result = new EthGetBalance();
    this.web3j.ethGetBalance(DEFAULT_ADDRESS,
                    DefaultBlockParameter.valueOf("latest"))
            .sendAsync()
            .get();
    return result;
}

6. 在Web3j中使用合约

一旦我们使用Truffle编译了我们的Solidity合约,我们就可以使用此处提供的独立Web3j命令行工具或此处的独立zip文件来处理我们编译的应用程序二进制接口(ABI)。

6.1 CLI魔法

然后,我们可以使用以下命令自动生成Java智能合约包装器(本质上是公开智能合约ABI的POJO):

$ web3j truffle generate [--javaTypes|--solidityTypes] 
  /path/to/<truffle-smart-contract-output>.json 
  -o /path/to/src/main/java -p com.your.organisation.name

在项目根目录中运行以下命令:

web3j truffle generate dev_truffle/build/contracts/Example.json 
  -o src/main/java/cn/tuyucheng/taketoday/web3/contract -p cn.tuyucheng.taketoday

生成了我们的Example类:

public class Example extends Contract {
    private static final String BINARY = "0x60606040523415600e576...";
    // ...
}

6.2 Java POJO

现在我们有了智能合约包装器,我们可以以编程方式创建钱包,然后将合约部署到该地址

WalletUtils.generateNewWalletFile("PASSWORD", new File("/path/to/destination"), true);
Credentials credentials = WalletUtils.loadCredentials("PASSWORD", "/path/to/walletfile");

6.3 部署合约

我们可以像这样部署我们的合约:

Example contract = Example.deploy(this.web3j,
    credentials,
    ManagedTransaction.GAS_PRICE,
    Contract.GAS_LIMIT).send();

然后获取地址:

contractAddress = contract.getContractAddress();

6.4 发送交易

要使用我们合约的函数发送交易,我们可以使用输入值列表和输出参数列表初始化Web3j函数:

List inputParams = new ArrayList();
List outputParams = new ArrayList();
Function function = new Function("functionName", inputParams, outputParams);
String encodedFunction = FunctionEncoder.encode(function);

然后,我们可以使用必要的gas(用于执行交易)和nonce参数来初始化我们的交易:

BigInteger nonce = BigInteger.valueOf(100);
BigInteger gasprice = BigInteger.valueOf(100);
BigInteger gaslimit = BigInteger.valueOf(100);

Transaction transaction = Transaction
    .createFunctionCallTransaction("FROM_ADDRESS", 
        nonce, gasprice, gaslimit, "TO_ADDRESS", encodedFunction);

EthSendTransaction transactionResponse = web3j.ethSendTransaction(transaction).sendAsync().get();
transactionHash = transactionResponse.getTransactionHash();

有关智能合约功能的完整列表,请参阅官方文档

7. 总结

就这样,我们已经用Web3j设置了一个Java Spring MVC应用程序。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章