java开发以太坊---不搭节点开发

  • readme
  • 直接上代码

readme

以太坊区块链浏览器有提供官方api 已经满足了基本开发需求
api连接

优点: 可以不用搭建节点,节省内存,无须担心节点挂掉影响业务

缺点:官方限制请求接口频率最高为 每秒为5次/ip地址,无法像节点一样监听,需要跑定时任务去查询新的交易

之前写过了搭节点开发的教程 细节和概念不想再说一遍了 直接上代码

交易功能和搭节点有点差别 这里是 构建交易→离线签名→编码→用api接口广播

需要注意的是getTranNum接口有一点不同 还有因为接口请求频率原因 需要加锁及线程休眠的手段来控制频率 这里没有去做 自行处理

maven和jar包去 之前的博客 的3(web3j引入)看,一毛一样 不想再写一次 有不懂的也可以看一下

直接上代码

接口

package com.lim.service;import com.alibaba.fastjson.JSONObject;
import java.math.BigInteger;public interface IAccountService {/*** 离线创建账户* @param pwd* @return*/JSONObject createAccount(String pwd);/*** 获取当前gasPrice* @return*/JSONObject getGasPrice() throws Exception;/*** 检查交易状态 0-正常 1-交易错误* @param hash* @return* @throws Exception*/String checkTran(String hash) throws Exception;/*** 检查交易pending状态 0-失败 1-已完成 null/umpty-pending中* @return* @throws Exception*/String checkTranPending(String hash) throws Exception;/*** 获取地址的交易数量* @param address* @return* @throws Exception*/BigInteger getTranNum(String address) throws Exception;/*** 获取账户eth余额* @param address* @return*/String getEthBalance(String address) throws Exception;/*** 获取账户usdt余额* @param address* @return*/String getUsdtBalance(String address) throws Exception;/*** eth交易* @param from* @param to* @param privateKey* @param num* @param gasPrice* @param nonce* @return* @throws Exception*/JSONObject tranEth(String from, String to, String privateKey, String num, String gasPrice, String nonce) throws Exception;/*** usdt交易* @param from* @param to* @param privateKey* @param num* @param gasPrice* @param gaslimit* @param nonce* @return*/JSONObject tranUsdt(String from, String to, String privateKey, String num, String gasPrice, String gaslimit, String nonce)throws Exception;}

实现类

package com.lim.service.impl;import com.alibaba.fastjson.JSONObject;
import com.lim.eth.EthConstant;
import com.lim.redis.IRedisService;
import com.lim.service.IAccountService;
import com.lim.util.HttpUtils;
import io.github.novacrypto.bip39.MnemonicGenerator;
import io.github.novacrypto.bip39.SeedCalculator;
import io.github.novacrypto.bip39.Words;
import io.github.novacrypto.bip39.wordlists.English;
import io.github.novacrypto.hashing.Sha256;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.*;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;
import javax.annotation.Resource;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.*;@Slf4j
@Service
public class EAccountServiceImpl implements IAccountService {@Resourceprivate IRedisService redisService;private final Map<String, String> headers = new HashMap<>();private final Map<String, String> querys = headers;@Overridepublic JSONObject createAccount(String pwd) {StringBuilder sb = new StringBuilder();byte[] entropy = new byte[Words.TWELVE.byteLength()];new SecureRandom().nextBytes(entropy);new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, sb::append);String mnemonic = sb.toString();List mnemonicList = Arrays.asList(mnemonic.split(" "));byte[] seed = new SeedCalculator().withWordsFromWordList(English.INSTANCE).calculateSeed(mnemonicList, pwd);ECKeyPair ecKeyPair = ECKeyPair.create(Sha256.sha256(seed));String privateKey = ecKeyPair.getPrivateKey().toString(16);String publicKey = ecKeyPair.getPublicKey().toString(16);String address = "0x" + Keys.getAddress(publicKey);JSONObject json = new JSONObject();json.put("privateKey", privateKey);json.put("publicKey", publicKey);json.put("address", address);return json;}@Overridepublic JSONObject getGasPrice() throws Exception {StringBuffer path = new StringBuffer("/api?module=gastracker&action=gasoracle&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);String status = json.getString("status");if(!status.equals("1")){throw new Exception(json.getString("message"));}JSONObject resJson = json.getJSONObject("result");return resJson;}@Overridepublic String checkTran(String hash) throws Exception {StringBuffer path = new StringBuffer("/api?module=transaction&action=getstatus&txhash=").append(hash).append("&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);String status = json.getString("status");if(!status.equals("1")){throw new Exception(json.getString("message"));}JSONObject resJson = json.getJSONObject("result");return resJson.getString("isError");}@Overridepublic String checkTranPending(String hash) throws Exception {StringBuffer path = new StringBuffer("/api?module=transaction&action=gettxreceiptstatus&txhash=").append(hash).append("&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);String status = json.getString("status");if(!status.equals("1")){throw new Exception(json.getString("message"));}JSONObject resJson = json.getJSONObject("result");return resJson.getString("status");}@Overridepublic BigInteger getTranNum(String address) throws Exception {//注意这里api上是tag=lasted 是查不到pending中的交易的StringBuffer path = new StringBuffer("/api?module=proxy&action=eth_getTransactionCount&address=").append(address).append("&tag=pending&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);String result = json.getString("result");return new BigInteger(result.substring(2), 16);}@Overridepublic String getEthBalance(String address) throws Exception {StringBuffer path = new StringBuffer("/api?module=account&action=balance&address=").append(address).append("&tag=latest&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);String status = json.getString("status");if(!status.equals("1")){throw new Exception(json.getString("message"));}String num = json.getString("result");return Convert.fromWei(num, Convert.Unit.ETHER).toString();}@Overridepublic String getUsdtBalance(String address) throws Exception {StringBuffer path = new StringBuffer("/api?module=account&action=tokenbalance&contractaddress=").append(EthConstant.CONTRACTA_DDRESS).append("&address=").append(address).append("&tag=latest&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);String status = json.getString("status");if(!status.equals("1")){throw new Exception(json.getString("message"));}String num = json.getString("result");return Convert.fromWei(num, Convert.Unit.MWEI).toString();}@Overridepublic JSONObject tranEth(String from, String to, String privateKey, String num, String gasPrice, String nonce) throws Exception {BigInteger gasPriceNum = null;if(StringUtils.isNotBlank(gasPrice) && new BigInteger(gasPrice).compareTo(new BigInteger("1")) >= 0){gasPriceNum = Convert.toWei(gasPrice, Convert.Unit.GWEI).toBigInteger();} else {gasPriceNum = Convert.toWei(getGasPrice().getString("ProposeGasPrice"), Convert.Unit.GWEI).toBigInteger();}BigInteger nonceMum = null;if(StringUtils.isNotBlank(nonce) && new BigInteger(nonce).compareTo(new BigInteger("0")) >= 0  ){nonceMum = new BigInteger(nonce);} else {nonceMum = this.getTranNum(from);}RawTransaction rawTransaction = RawTransaction.createEtherTransaction( nonceMum, gasPriceNum, new BigInteger("21000"), to,Convert.toWei(num, Convert.Unit.ETHER).toBigInteger());Credentials credentials = Credentials.create(privateKey);byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);String hexValue = Numeric.toHexString(signedMessage);StringBuffer path = new StringBuffer("/api?module=proxy&action=eth_sendRawTransaction&hex=").append(hexValue).append("&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);log.info(json.toString());String hash = json.getString("result");if(StringUtils.isBlank(hash)){throw new Exception(json.getJSONObject("error").getString("message"));}JSONObject jsonObject = new JSONObject();jsonObject.put("nonce", nonce);jsonObject.put("hash", hash);return jsonObject;}@Overridepublic JSONObject tranUsdt(String from, String to, String privateKey, String num, String gasPrice, String gaslimit, String nonce) throws Exception {BigInteger tranNum = Convert.toWei(num, Convert.Unit.MWEI).toBigInteger();Function function = new Function("transfer",Arrays.asList( new Address(to), new Uint256(tranNum) ), Collections.emptyList());String encodeFunction = FunctionEncoder.encode(function);BigInteger gasPriceNum = null;if(StringUtils.isNotBlank(gasPrice) && new BigInteger(gasPrice).compareTo(new BigInteger("1")) >= 0){gasPriceNum = Convert.toWei(gasPrice, Convert.Unit.GWEI).toBigInteger();} else {gasPriceNum = Convert.toWei(getGasPrice().getString("ProposeGasPrice"), Convert.Unit.GWEI).toBigInteger();}BigInteger gasLimitNum = new BigInteger("100000");if(StringUtils.isNotBlank(gaslimit) && new BigInteger(gaslimit).compareTo(new BigInteger("21000")) >= 0){gasLimitNum = new BigInteger(gaslimit);}BigInteger nonceMum = null;if(StringUtils.isNotBlank(nonce) && new BigInteger(nonce).compareTo(new BigInteger("0")) >= 0  ){nonceMum = new BigInteger(nonce);} else {nonceMum = this.getTranNum(from);}RawTransaction rawTransaction = RawTransaction.createTransaction( nonceMum, gasPriceNum, gasLimitNum, EthConstant.CONTRACTA_DDRESS, encodeFunction);Credentials credentials = Credentials.create(privateKey);byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);String hexValue = Numeric.toHexString(signedMessage);StringBuffer path = new StringBuffer("/api?module=proxy&action=eth_sendRawTransaction&hex=").append(hexValue).append("&apikey=").append(EthConstant.ETHERSCAN_API_KEY);HttpResponse response = HttpUtils.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);String res = EntityUtils.toString(response.getEntity());JSONObject json = JSONObject.parseObject(res);log.info(json.toString());String hash = json.getString("result");if(StringUtils.isBlank(hash)){throw new Exception(json.getJSONObject("error").getString("message"));}JSONObject jsonObject = new JSONObject();jsonObject.put("nonce", nonceMum);jsonObject.put("hash", hash);return jsonObject;}
}

http工具类

package com.lim.util;import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class HttpUtils {public static HttpResponse doGet(String host, String path, String method, Map<String, String> headers, Map<String, String> querys)throws Exception {       HttpClient httpClient = wrapClient(host);HttpGet request = new HttpGet(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}return httpClient.execute(request);}public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, Map<String, String> bodys)throws Exception {        HttpClient httpClient = wrapClient(host);HttpPost request = new HttpPost(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (bodys != null) {List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();for (String key : bodys.keySet()) {nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));}UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");request.setEntity(formEntity);}return httpClient.execute(request);}private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {StringBuilder sbUrl = new StringBuilder();sbUrl.append(host);if (!StringUtils.isBlank(path)) {sbUrl.append(path);}if (null != querys) {StringBuilder sbQuery = new StringBuilder();for (Map.Entry<String, String> query : querys.entrySet()) {if (0 < sbQuery.length()) {sbQuery.append("&");}if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {sbQuery.append(query.getValue());}if (!StringUtils.isBlank(query.getKey())) {sbQuery.append(query.getKey());if (!StringUtils.isBlank(query.getValue())) {sbQuery.append("=");sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));}}}if (0 < sbQuery.length()) {sbUrl.append("?").append(sbQuery);}}return sbUrl.toString();}private static HttpClient wrapClient(String host) {HttpClient httpClient = new DefaultHttpClient();if (host.startsWith("https://")) {sslClient(httpClient);}return httpClient;}private static void sslClient(HttpClient httpClient) {try {SSLContext ctx = SSLContext.getInstance("TLS");X509TrustManager tm = new X509TrustManager() {public X509Certificate[] getAcceptedIssuers() {return null;}public void checkClientTrusted(X509Certificate[] xcs, String str) {}public void checkServerTrusted(X509Certificate[] xcs, String str) {}};ctx.init(null, new TrustManager[] { tm }, null);SSLSocketFactory ssf = new SSLSocketFactory(ctx);ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);ClientConnectionManager ccm = httpClient.getConnectionManager();SchemeRegistry registry = ccm.getSchemeRegistry();registry.register(new Scheme("https", 443, ssf));} catch (KeyManagementException ex) {throw new RuntimeException(ex);} catch (NoSuchAlgorithmException ex) {throw new RuntimeException(ex);}}
}

常量类

package com.lim.eth;public class EthConstant {//redis key 存储账户地址的pending交易集 用于计算noncepublic static final String ADDRESS_TRAN_PENDING_KEY = "address.tran.pending.key-";//etherscan api秘钥public static final String ETHERSCAN_API_KEY = "******自己申请的秘钥******";//ERC20_USDT合约地址public static final String CONTRACTA_DDRESS = "0xdac17f958d2ee523a2206206994597c13d831ec7";}

java开发以太坊---不搭节点开发相关推荐

  1. JAVA使用web3j开发以太坊实战案例

    JAVA使用web3j开发以太坊实战案例 必读 1.前言 2.基础(必看) 3.web3j引入 4.创建账户(离线创建) 5.geth节点搭建.基本使用及一般问题 6.常量类 后面内容都要用到(必备! ...

  2. java和以太坊交互_java类库web3j开发以太坊智能合约快速入门

    web3j简介 web3j是一个轻量级.高度模块化.响应式.类型安全的Java和Android类库提供丰富API,用于处理以太坊智能合约及与以太坊网络上的客户端(节点)进行集成. 可以通过它进行以太坊 ...

  3. 不同步节点在线使用Remix开发以太坊Dapp及solidity学习入门 ( 一 ):智能合约HelloWorld

    有问题可以点击–>加群互相学习 本人本来想自己写公链,结果发现任重道远: 遂,开始写Dapp,顺便写的时候搞个教程吧... 通过系列教程学习将会: 1.基本使用solidity 语言开发智能合约 ...

  4. java开发以太坊应用的库ethereumj

    EthereumJ是以太坊协议的纯Java实现.有关以太坊及其目标的高级信息,请访问ethereum.org,其白皮书提供了一个完整的概念的概述,和黄皮书一起提供了协议的正式定义. 我们尽可能保持Et ...

  5. 为什么选择Java进行以太坊区块链开发

    当有人说Java时,你会想到什么?如果没有,你可以试试old.虽然,其他人可能会说它坚固,可靠和安全.而对于Oodles Blockchain来说,Java意味着"企业级". 毫无 ...

  6. python智能合约编程_如何用Python Flask开发以太坊智能合约

    将数据存储在数据库中是任何软件应用程序不可或缺的一部分.无论如何控制该数据库都有一个该数据的主控.区块链技术将数据存储到区块链网络内的区块中.因此,只要某个节点与网络同步,它们就会获得区块中数据的副本 ...

  7. 以太坊区块链Ethereum开发资料汇总

    2019独角兽企业重金招聘Python工程师标准>>> 基本概念介绍 :国内介绍区块链比较详细的资料 终于把区块链的技术与应用讲清楚了 http://business.sohu.co ...

  8. 以太坊去中心化_开发以太坊去中心化投票应用程序的指南

    以太坊去中心化 by Timothy Ko 蒂莫西·高(Timothy Ko) 开发以太坊去中心化投票应用程序的指南 (A guide to developing an Ethereum decent ...

  9. 用Visual Studio开发以太坊智能合约

    2019独角兽企业重金招聘Python工程师标准>>> 区块链和以太坊 自从我熟悉区块链.以太坊和智能合约以来,一直失眠. 我一直在阅读,阅读和阅读,最后我能够使用一些工具,他们建议 ...

最新文章

  1. Python+OpenCV实现自动扫雷,挑战扫雷世界记录!
  2. 《职场》笔记20061119
  3. C++ 智能指针详解
  4. C# WinForm控件、自定义控件整理(大全)
  5. python paramiko包 ssh报错No existing session 解决方法
  6. xml相关php函数,PHP利用xml常用函数的详细集合示例
  7. Triangular Sums http://acm.nyist.net/JudgeOnline/problem.php?pid=122
  8. 专访《花亦山心之月》:朝夕光年首款自研国风手游有啥不一样?
  9. 【LightOJ - 1027】A Dangerous Maze(概率dp,数学期望)
  10. @aspect注解类不生效_Spring Boot从入门到精通(三)常用注解含义及用法分析总结...
  11. 打开桌面计算机窗口闪动,电脑进去桌面就一直闪
  12. 怎么将PDF转换成Word?PDF转Word如何不乱码?
  13. html的个人简历边框,怎样制作简历模板边框
  14. 简要的谈谈文本数据挖掘的一般步骤
  15. Minecraft Mod 开发:0-前言
  16. c语言过磅系统,衡安无人值守地磅称重系统过磅流程
  17. usaco#2018#January#Silver
  18. 下一代英伟达H100 GPU发布时,国产芯片能追上吗?
  19. outlook邮箱邮件大小限制_outlook 附件大小限制
  20. esp32 micropython 控制ws2812 RGB灯带

热门文章

  1. 设计模式——装饰模式详解
  2. arduino测方波频率(外部中断)
  3. 开关灯效果HTML,js实现开关灯效果
  4. MakefileCMake
  5. 字符函数库cctype的使用_C++
  6. 杂项-PPT:如何把幻灯片ppt转换成视频
  7. 企业知识管理实施的流程和步骤有哪些?
  8. 【微信小程序】免费的高德地图api——获取天气(全过程)
  9. 《音乐之声》萨尔斯堡的歌声如此旖旎
  10. 【Python杂记】:课程表生成日历程序(生成.ics文件可直接导入日历)