最近Ethereum又学了一点点,学会了主网冲浪和钱包的地址和私钥的生成。分享一点点学习成果,分为3部分
因为是初学小白,所以这中间又进行了一些基础知识的补习,才慢慢使用Web3j。如果你也想了解区块链,建议先了解足够概念性的知识,这里我踩坑比较多,幸好有个小伙伴随时答疑,这里表示感谢。
infura apikey
在Ethereum官方的教程中,是给出了如何使用不同语言的Ethereum客户端连接主网同步区块链信息的。本人操作了两波,均已失败告终。后来去论坛看其他小白的帖子,发现这并不是说可以一键安装启动的过程,还需要进行不少的配置。索性我就放弃了。
为了进行主网的冲浪,特意查了一下,很多网上很多免费的Ethereum查询节点,这里我选择infura
,无他,它排第一。
首先去官网注册,申请apikey,然后查看使用规则,主要限速和次数限制。这一点非常赞,免费版每24小时10w次请求,足够我的使用,申请还能测试并发。
然后通过apikey管理端获取到主网的访问地址和验证信息。infura
还提供了请求次数,请求接口分布等功能,的确非常良心。
如果你想使用测试网,请注意:
FunTester原创专题推荐~Goerli 测试网已弃用(opens in a new tab)↗,它将在 2023 年被 Holesovice(opens in a new tab)↗ 取代。请考虑把你的应用程序迁移至 Sepolia。 -- By FunTester
Web3j API
这里先介绍Web3j
的HTTP API
其他协议的还在看,搞明白了在跟大家分享。
Web3j
使用的是okhttp
,具体的封装实现这里就不说了,重点是Web3j
的语法习惯。
创建客户端
首先我们需要创建一个Web3j
的对象,语法如下:
static Web3j web3 = Web3j.build(new HttpService("https://mainnet.infura.io/v3/{your apikey}"));
其实就是替换一下访问地址。
创建请求
Web3j
的语法有点类似「建造者模式(Builder Pattern)」,先构建request
,然后再send()
获取response
。创建语法:
Request<?, NetVersion> netVersionRequest = web3.netVersion();
这样我们就获取了一个request
,Web3j
所有的请求方法都在org.web3j.protocol.core.Ethereum
中定义了,有4中不同的实现,有兴趣的可以多翻一翻。
获取响应
书接上文,语法如下:
NetVersion send = netVersionRequest.send();
Web3j
对每个请求类型都封装了一个对象接收响应信息。响应中包含信息较多,如果不熟练的可以翻翻响应对象的源码。
PS:这里解析org.web3j.protocol.core.methods.response.EthBlock.TransactionResult
有个坑,需要强转一下,分享:
List<EthBlock.TransactionResult> transactions = web3.ethGetBlockByNumber(new DefaultBlockParameterNumber(blockNumber),true).send().getBlock().getTransactions();
transactions.forEach(f->{
EthBlock.TransactionObject f1 = (EthBlock.TransactionObject) f;
output(parse(f1));
});
关于异步
这里不提倡,因为之前文章Web3j异步导致JVM无法退出BUG分享提到,已经提了issue
,但是开发者并没有理我。看最新的代码依旧没打算修复这个问题。
如果你是开发服务,或者使用文章提到2种修复方案,异步还是很香的。
钱包
我之前一直有个困惑,钱包的信息是如何上传到区块链上的。区块链并没有认证机制来识别到底是不是有效的钱包,而且感觉好像谁都可以创建钱包。
学完这块我才明白,钱包实际就是地址,区块链只是记账,把账号(钱包)地址记住了。这个地址上面有多少余额。
而私钥就是取款密码,而且不可更改。这是密码学上的,加入私钥丢了,就是失去了一切了。
这里放一个生成本地钱包的方法,也是Web3j
提供的,并没有助记词的内容。据我查到资料,助记词是另外的工具包才有功能,实现也有很多,如需请自取。
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import java.io.File;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
public class Wallet {
public static void main(String[] args) throws CipherException, IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException{
// 钱包存放路径
String walletFilePath = "/Users/vallet/test";
// 钱包密码
String password = "";
//生成钱包,对应目录下会创建对应的私钥文件。
String walletFileName = WalletUtils.generateNewWalletFile(password, new File(walletFilePath), false);
// 加载指定位置的钱包
Credentials credentials = WalletUtils.loadCredentials(password, walletFilePath "/" walletFileName);
String address = credentials.getAddress();
System.out.println("address:" address);
System.out.println("PrivateKey:" credentials.getEcKeyPair().getPrivateKey());
System.out.println("PublicKey:" credentials.getEcKeyPair().getPublicKey());
}
}
如果你打开本地的钱包路径,内容是一个JSON
格式的字符串,还可以进行二次加密,让明文始终只存在于内存中。
PS:其实地址随便写都没问题。如下: