使用Java+Web3j和Ethereum网络交互(一):获取Ethereum信息
简介
web3j是一个高度模块化,响应式的,类型安全的Java和Android库,可以用于和以太坊网络上的节点以及智能合约进行交互。
Web3j使你与以太坊网络进行交互,不需要额外的去写与以太坊平台交互的代码开销。
特性
- 完整地实现了Ethereum中HTTP和IPC上的JSON-RPC客户端API
- 支持ethereum钱包
- 可以自动生成封装好的Java类型的智能合约(支持Solidity和Truffle定义的格式),可以通过Java代码进行合约的创建,部署,以及调用。
- 可以添加过滤器的响应式函数API
- 支持Ethereum Name Service(ENS)
- 支持个人创建的Ethereum网络和个人的Geth客户端API
- 支持Alchemy和Infura,所以无需自己运行以太坊客户端
- 支持ERC20和ERC721 Token标准
- 包括上述许多场景的全面的集成测试
- 命令行工具
- 可适配Android
- 可以通过web3j-quorm支持JP Morgan的Quorum
依赖
Web3j具有五个运行时依赖
- 响应式函数依赖RxJava
- Http连接依赖OKHttp
- JSON序列化以及反序列号依赖Jackson Core
- 加密依赖Bouncy Castle
- *nix(不适用Android)依赖Jnr-unixsocket
使用SpringBoot+Web3j搭建环境
2.1 Etherum环境
通过Web3j与以太坊进行交互前提条件是需要有Ethereum环境,搭建Ethherum环境可以通过多种方式,本文仅列出常用的两个:
- Ganache
- Docker
新建Springboot项目
首先在https://start.spring.io/ 上面初始化一个Springboot项目,导入Idea,或者直接在Idea上面创建。
导入Web3j
打开pom.xml文件,添加以下依赖:
<!-- https://mvnrepository.com/artifact/org.web3j/core -->
<dependency>
<groupId>org.web3j</groupId>
<artifactId>web3j-spring-boot-starter</artifactId>
<version>4.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.web3j/core -->
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>4.8.4</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
基本配置
接下来打开application.properties文件,添加以下内容:
# 应用名称
spring.application.name=ethereum-client
#访问端口
server.port=8081
#以太坊交互地址 如果以太坊环境搭建在本地就locallhost,否则使用对应的ip地址,端口默认使用8545
web3j.client-address=http://localhost:8545
基本使用
必要的配置已完成,接下来可以与Etherum交互了。这里列出常见的几个功能,文章最后给出完整的代码。
获取最新的区块号
EthBlockNumber ethBlockNumber = web3j.ethBlockNumber().sendAsync().get();
BigInteger blockNumber = ethBlockNumber.getBlockNumber();
获取所有账户信息
EthAccounts ethAccounts = web3j.ethAccounts().sendAsync().get();
List<String> accounts = ethAccounts.getAccounts();
查询Gas价格
EthGasPrice ethGasPrice = web3j.ethGasPrice().sendAsync().get();
BigInteger gasPrice = ethGasPrice.getGasPrice();
获取ChainId
EthChainId ethChainId = web3j.ethChainId().sendAsync().get();
BigInteger chainId = ethChainId.getChainId();
获取CoinBase
EthCoinbase ethCoinbase = web3j.ethCoinbase().sendAsync().get();
String coinBase = ethCoinbase.getAddress();
根据区块号获取区块信息
DefaultBlockParameterNumber defaultBlockParameterNumber = new DefaultBlockParameterNumber(blockNumber);
EthBlock ethBlock = web3j.ethGetBlockByNumber(defaultBlockParameterNumber,true).sendAsync().get();
EthBlock.Block block = ethBlock.getBlock();
根据区块号获取当前区块所有交易信息
DefaultBlockParameterNumber defaultBlockParameterNumber = new DefaultBlockParameterNumber(blockNumber);
EthBlock ethBlock = web3j.ethGetBlockByNumber(defaultBlockParameterNumber,true).sendAsync().get();
List<EthBlock.TransactionResult> transactionResults = ethBlock.getBlock().getTransactions();
根据交易哈希值获取交易信息
EthTransaction transaction = web3j.ethGetTransactionByHash(txHash).sendAsync().get();
Optional<Transaction> optionalTransaction = transaction.getTransaction();
账户相关
还可以通过私钥或者Key文件查询当前账户下的Ether余额。
查询Ether余额
BigInteger blockNumber = web3j.ethBlockNumber().sendAsync().get().getBlockNumber();
DefaultBlockParameterNumber defaultBlockParameterNumber = new DefaultBlockParameterNumber(blockNumber);
//根据请求参数获取余额
EthGetBalance ethGetBalance = web3j.ethGetBalance(credentials.getAddress(),defaultBlockParameterNumber).sendAsync().get();
源代码
/**
* @description 获取区块链信息
* @author newonexd
* @date 2022/6/22 21:14
*/
@RestController
@RequestMapping("/chainInfo")
public class BlockChainInfoController {
private static final Logger logger = LoggerFactory.getLogger(BlockChainInfoController.class);
@Autowired
private Web3j web3j;
/**
* @description 获取最新的区块号
* @author newonexd
* @date 2022/6/22 21:11
*
* * @return BigInteger
*/
@GetMapping("/blockNumber")
public BigInteger doGetLatestBlockNumber()throws Exception{
EthBlockNumber ethBlockNumber = web3j.ethBlockNumber().sendAsync().get();
BigInteger blockNumber = ethBlockNumber.getBlockNumber();
logger.info("BlockNumber: {}",blockNumber);
return blockNumber;
}
/**
* @description 获取所有账户
* @author newonexd
* @date 2022/6/22 21:11
*
* * @return List<String>
*/
@GetMapping("/accounts")
public List<String> doGetAllAccounts()throws Exception{
EthAccounts ethAccounts = web3j.ethAccounts().sendAsync().get();
List<String> accounts = ethAccounts.getAccounts();
logger.info("Accounts: {}",accounts);
return accounts;
}
/**
* @description 获取Gas价格
* @author newonexd
* @date 2022/6/22 21:11
*
* * @return BigInteger
*/
@GetMapping("/gasPrice")
public BigInteger doGetEthGasPrice()throws Exception{
EthGasPrice ethGasPrice = web3j.ethGasPrice().sendAsync().get();
BigInteger gasPrice = ethGasPrice.getGasPrice();
logger.info("Ethereum Gas Price: {}",gasPrice);
return gasPrice;
}
/**
* @description 获取链Id
* @author newonexd
* @date 2022/6/22 21:12
*
* * @return BigInteger
*/
@GetMapping("/chainId")
public BigInteger doGetChainId()throws Exception{
EthChainId ethChainId = web3j.ethChainId().sendAsync().get();
BigInteger chainId = ethChainId.getChainId();
logger.info("Ethereum Chain Id: {}",chainId);
return chainId;
}
/**
* @description 获取CoinBase
* @author newonexd
* @date 2022/6/22 21:12
*
* * @return String
*/
@GetMapping("/coinbase")
public String doGetCoinBase()throws Exception{
EthCoinbase ethCoinbase = web3j.ethCoinbase().sendAsync().get();
String coinBase = ethCoinbase.getAddress();
logger.info("Ethereum CoinBase Address: {}",coinBase);
return coinBase;
}
/**
* @description 根据区块号获取区块信息
* @author newonexd
* @date 2022/6/22 21:12
* @param blockNumber 区块号
* @return String
*/
@GetMapping("/getBlockInfo")
public String doGetAll(@RequestParam(value="blockNumber")Long blockNumber)throws Exception{
DefaultBlockParameterNumber defaultBlockParameterNumber = new DefaultBlockParameterNumber(blockNumber);
EthBlock ethBlock = web3j.ethGetBlockByNumber(defaultBlockParameterNumber,true).sendAsync().get();
EthBlock.Block block = ethBlock.getBlock();
Gson gson = new Gson();
String info = gson.toJson(block);
logger.info(info);
return info;
}
/**
* @description 根据区块号获取所有交易
* @author newonexd
* @date 2022/6/22 21:13
* @param blockNumber 区块号
* @return String
*/
@GetMapping("/getTransactionByBlockNumber")
public String doGetTransactionInfoByBlockNumber(@RequestParam(value="blockNumber")Long blockNumber)throws Exception{
DefaultBlockParameterNumber defaultBlockParameterNumber = new DefaultBlockParameterNumber(blockNumber);
EthBlock ethBlock = web3j.ethGetBlockByNumber(defaultBlockParameterNumber,true).sendAsync().get();
List<EthBlock.TransactionResult> transactionResults = ethBlock.getBlock().getTransactions();
List<Transaction> txInfos = new ArrayList<>();
transactionResults.forEach(txInfo->{
Transaction transaction = (Transaction)txInfo;
txInfos.add(transaction);
});
Gson gson = new Gson();
String transactionInfo = gson.toJson(txInfos);
logger.info(transactionInfo);
return transactionInfo;
}
/**
* @description 根据交易哈希值获取交易信息
* @author newonexd
* @date 2022/6/22 21:13
* @param txHash 交易哈希值
* @return String
*/
@GetMapping("/getTransactionInfoByHash")
public String doGetTransactionInfoByHash(@RequestParam(value="txHash")String txHash)throws Exception{
EthTransaction transaction = web3j.ethGetTransactionByHash(txHash).sendAsync().get();
Optional<Transaction> optionalTransaction = transaction.getTransaction();
StringBuilder txInfo = new StringBuilder();
if(optionalTransaction.isPresent()){
Transaction transactionInfo = optionalTransaction.get();
Gson gson = new Gson();
txInfo.append(gson.toJson(transactionInfo));
}
logger.info(txInfo.toString());
return txInfo.toString();
}
}