使用web3j构建以太坊钱包

创建一个以太坊钱包有多种方式,一般情况下可以通过geth、EtherumWallet等客户端。对于前端,可以使用插件MetaMask进行创建。这几种方式技术实现虽然不同,但底层原理是一致的。本文主要介绍如何通过web3j架构创建一个以太坊的冷钱包,从而实现将这一过程部署在服务端或者android端。

文中涉及到的技术栈有:

Web3j :轻量级java库,用于连接以太坊客户端或节点

Infura :以太坊基础设施,用于访问以太坊主网络或测试网络

Java:编程语言

1.Web3j的安装

无论是java工程还是android工程,web3j都提供了maven和grade 两种依赖方式:

  1. java工程
  • manen依赖
<dependency>
  <groupId>org.web3j</groupId>
  <artifactId>core</artifactId>
  <version>3.3.1</version>
</dependency>
  • gradle依赖
compile ('org.web3j:core:3.3.1')
  1. android工程
  • maven依赖
<dependency>
  <groupId>org.web3j</groupId>
  <artifactId>core</artifactId>
  <version>3.3.1-android</version>
</dependency>
  • gradle依赖
compile ('org.web3j:core:3.3.1-android')

值得注意的是,目前的web3j对于高版本JDK存在不兼容的问题,如果出现如下类似的问题,直接更换JDK为version 8即可。

<u>Could not determine Java version using executable /Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home/bin/java.</u>

2.关于Infura

以太坊的客户端实现有多种,但很多都需要在本地同步所有的节点数据而占用大量硬盘存储空间,并且需要消耗同步的时间。Infura就是提供一种中心化的服务,通过web3.js或者web3j使前端或服务端能便捷的访问以太坊所有节点。可以理解为一种以太坊客户端的云端版本。使用过程需要注册,一个专属的访问token。本文中使用的客户端都是Infura提供的Rinkeby测试网络。

3.新建钱包文件keyfile

在以太坊中,钱包(wallet)和账户(account)是两个不同的概念。账户是以太坊的核心,由一对秘钥组成-公钥和私钥。账户可以分为两种,外部账户和合约账户。而钱包是指保存 地址、公钥、私钥的文件或其他机构,每个钱包文件至少包含一个账户。创建钱包的同时也是创建一个以太坊账户的过程不同的客户端创建钱包的方式不一致但原理相同,有关钱包是具体是如何生成的可以查看另外这篇文章。

  1. 新建一个java工程,初始化gradle或者maven
  2. 依赖web3j
  3. 新建Application.java文件,设置程序入口main函数
  4. 调用钱包工具类生成钱包文件
/*************创建一个钱包文件**************/
private void creatAccount() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, CipherException, IOException {
    String walletFileName0="";//文件名
    String walletFilePath0="/Users/yepeng/MyGitHub/z_wallet_temp";
    //钱包文件保持路径,请替换位自己的某文件夹路径

    walletFileName0 = WalletUtils.generateNewWalletFile("123456", new File(walletFilePath0), false);
    //WalletUtils.generateFullNewWalletFile("password1",new File(walleFilePath1));
    //WalletUtils.generateLightNewWalletFile("password2",new File(walleFilePath2));
    log.info("walletName: "+walletFileName0);
}

钱包构建的过程中需要输入的三个参数,分别设置钱包的密码、保存路径、以及是否轻量级钱包。

执行创建函数后,会自动在指定路径生成一个json 文件,即钱包keyfiles。


屏幕快照 2018-04-10 上午11.04.24.png

钱包文件结构:


屏幕快照 2018-04-10 上午11.14.03.png
  • cipher:加密算法,AES算法,用于加密以太坊私钥
  • cipherparams:cipher算法需要的参数,参数iv,是aes-128-ctr加密算法需要的初始化向量
  • ciphertext:加密后的密文,aes-128-ctr函数的加密输入密文;
  • kdf:秘钥生成函数,用于使用密码加密keystore文件
  • kdfparams:kdf算法所需要的参数
  • mac:验证密码的编码

生成钱包的逆向过程 为加载钱包。

4.加载钱包文件

加载钱包的过程需要提供钱包文件和密码

/********加载钱包文件**********/
private void loadWallet() throws IOException, CipherException {
    String walleFilePath="/Users/yepeng/MyGitHub/z_wallet_temp/UTC--2018-04-10T02-51-24.815000000Z--12571f46ec3f81f7ebe79112be5883194d683787.json";
    String passWord="123456";
    credentials = WalletUtils.loadCredentials(passWord, walleFilePath);
    String address = credentials.getAddress();
    BigInteger publicKey = credentials.getEcKeyPair().getPublicKey();
    BigInteger privateKey = credentials.getEcKeyPair().getPrivateKey();

    log.info("address="+address);
    log.info("public key="+publicKey);
    log.info("private key="+privateKey);

}

函数运行的结果:


屏幕快照 2018-04-10 上午11.10.19-3417487.png

通过工具类 WalletUtols的函数 loadCredentials(),会返回一个对象Credentials,这个对象即包含了钱包文件的所有信息,包括地址、秘钥对。

至此,钱包的创建和加载已经完成,但这一过程全部发生在本地,并未同步到以太坊区块链。查询地址余额前,需要连接以太坊结点。

5.构建Web3j实体,连接以太坊结点

web3j是连接java端与以太坊的桥梁,广播交易,查询账户都需要通过web3j实体。web3j支持通过http进行构建,而且兼容了infura。在本文中,使用的是infura的测试网络Rinkeby。

/*******连接以太坊客户端**************/
private void conectETHclient() throws IOException {
    //连接方式1:使用infura 提供的客户端
    web3j = Web3j.build(new HttpService("https://rinkeby.infura.io/zmd7VgRt9go0x6qlJ2Mk"));// TODO: 2018/4/10 token更改为自己的
    //连接方式2:使用本地客户端
    //web3j = Web3j.build(new HttpService("127.0.0.1:7545"));
    //测试是否连接成功
    String web3ClientVersion = web3j.web3ClientVersion().send().getWeb3ClientVersion();
    log.info("version=" + web3ClientVersion);
}

web3j实体构建完成后,可以打印出版本号以测试是否连接成功。如果成功,就可以做其他的事情了。值得注意的是,web3j采用的是RxJava的设计,所以许多函数的返回值是 Request<?,?>,这个对象有两种执行方式,异步和同步,即send()和sendAsyn()。

6.查询账户余额

查询账户的余额的方式:

/***********查询指定地址的余额***********/
private void getBlanceOf() throws IOException {
    if (web3j == null) return;
    String address = "0x41F1dcbC0794BAD5e94c6881E7c04e4F98908a87";//等待查询余额的地址
    //第二个参数:区块的参数,建议选最新区块
    EthGetBalance balance = web3j.ethGetBalance(address, DefaultBlockParameter.valueOf("latest")).send();
    //格式转化 wei-ether
    String blanceETH = Convert.fromWei(balance.getBalance().toString(), Convert.Unit.ETHER).toPlainString().concat(" ether");
    log.info(blanceETH);
}

其中核心方法 web3j.ethGetBalance(address, defaultBlockParameter) 中的第二个参数比较特殊,指默认的区块参数。当请求余额的方法作用与以太坊的区块网络时,这个参数决定了查询区块的高度。

  • HEX String - 一个整数块号
  • String "earliest" 为最早/起源块
  • String "latest" - 为最新的采矿块
  • String "pending" - 待处理状态/交易

一般情况下,选择“latest”即可。

以太坊中,如果没有特殊标示,数字的单位都是小数点后18位,因此查询账户余额有必要将wei转化成ether

6.使用钱包进行转账

作为一个钱包,除了保存账户资产外,最重要的就是转账或交易了,利用web3j可以便捷的实现eth的转移。

/    /****************交易*****************/
    private void transto() throws Exception {
        if (web3j == null) return;
        if (credentials == null) return;
        //开始发送0.01 =eth到指定地址
        String address_to = "0x41F1dcbC0794BAD5e94c6881E7c04e4F98908a87";
        TransactionReceipt send = Transfer.sendFunds(web3j, credentials, address_to, BigDecimal.ONE, Convert.Unit.FINNEY).send();

        log.info("Transaction complete:");
        log.info("trans hash=" + send.getTransactionHash());
        log.info("from :" + send.getFrom());
        log.info("to:" + send.getTo());
        log.info("gas used=" + send.getGasUsed());
        log.info("status: " + send.getStatus());
    }

核心方法需要提供4个参数:

  • web3j实体
  • Credentials 源账户
  • address 转出地址
  • value 数量
  • uint 单位

等待片刻后,会返回转账结果

屏幕快照 2018-04-11 上午11.32.12.png

可以看到交易hash、转入转出地址、gas消耗等信息。同时可以在etherscan-rinkeby上进行查看本次交易详情

7.总结

上面的代码已经完成了一个以太坊钱包所需的所有基本功能,包括创建、加载、转账、查询。本文中采用的网络是infura提供的Rinkeby测试网络,创建的钱包地址为 0x12571F46Ec3f81F7EbE79112Be5883194d683787

在具体的业务场景中,只要将测试网络更换为以太坊主网络即可。

源码地址 https://github.com/initsysctrl/we3jdemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容