java开发以太坊---不搭建节点之扫描区块完成账户监听

6 篇文章 0 订阅
3 篇文章 5 订阅

readme

定时任务扫描区块逻辑:
从redis获取已经同步的区块号 → 获取最新区块号 → 判断最新区块是否 > 已经同步的区块 + 1 → 大于则说明已经有完整的新区块可以进行扫描 → 扫描区块 → 判断是代币交易还是eth交易 → 如果是代币交易判断是否是转账操作(因为会有一些发币/授权/发合约…这种我们不需要的交易) → 判断to地址是否是系统内账户的(看具体项目 做可导入钱包那种项目就忽略这一步) → 计算交易金额 → 自行进行逻辑处理 → 保存刚同步的区块号到redis
返回数据的讲解:
先看一下api接口返回的数据结构
在这里插入图片描述
一般我们需要的字段hash input from to value
特别注意input 和 value字段
to是就是交易接收方的地址 代币交易时则为对应的合约地址
value是交易的eth金额 当交易为代币交易时value为0x0
input反过来 eth交易时input为0x 代币交易时是一个138位的十六进制编码 这个编码由三部分组成
1-34位为交易函数编码 例如transfer approve transferFrom等
35-74位为代币交易的实际的to地址 需要在前边拼接0x
75-138位是代币交易的十六进制的金额
transfer的十六进制编码为 0xa9059cbb
其他参考这里
ok明白这里接下来就很简单了

上代码


	@Resource
    private IRedisService redisService;

	/**
     * 扫描区块定时任务--检查到账
     */
    @Scheduled(cron="0/10 * * * * ?")
    public void task(){
        System.out.println("定时任务开始");

        try {
        	//获取当前同步的区块号
            String block_re = redisService.getString(EthConstant.ETH_BLOCK_NUM);
            //获取最新区块号
            BigInteger block_now = this.getBlockNum();
            //初始化
            if(block_re == null){
                redisService.setString(EthConstant.ETH_BLOCK_NUM, block_now.toString());
                return ;
            }
            BigInteger block = new BigInteger(block_re).add(new BigInteger("1"));
            if( block_now.compareTo(block) == 1 ){
                //有新区块
                List<JSONObject> list = this.getBlock(block.toString());

                for (JSONObject json: list) {
                    //交易from地址
                    String from = json.getString("from");
                    //交易的to地址
                    String to = json.getString("to");
                    String input = json.getString("input");
                    if(input.length() > 30){
                        //确定为代币交易
                        if(input.substring(0, 10).equals("0xa9059cbb")){
                            //确定是代币转账操作  那么to就是合约地址了
							//代币交易to地址
							String receive = input.substring(34, 40);
                            receive = "0x" + receive;
                            //交易hash
                            String hash = json.getString("hash")
                            //交易数量 已转为10进制的  目前单位的wei
                            BigDecimal num = new BigDecimal(new BigInteger(input.substring(75), 16));
                            
                            //合约地址 交易数量 收款账户 出账账户 交易hash 需要的信息都已拿到 剩下自行处理 
                        }
                    } else {
                        //eth交易
                        EthAccountEntity account = accountService.getAccount(to);
                        if(account != null){
                            //是系统内账户
                            String hash = json.getString("hash");
                            //交易数量单位是wei
							BigDecimal num = new BigDecimal(new BigInteger(json.getString("value"), 16));
							//交易数量单位是ether
							BigDecimal numStr = Convert.fromWei(num, Convert.Unit.ETHER);
							//交易数量 收款账户 出账账户 交易hash 需要的信息都已拿到 剩下自行处理 
                        }
                    }

                }
                redisService.setString(EthConstant.ETH_BLOCK_NUM, block.toString());
            }

        } catch (Exception e){
            log.info("定时扫描出口异常", e);
        }
    }
    
	/**
     * 获取当前区块号
     * @return
     * @throws Exception
     */
	public BigInteger getBlockNum() throws Exception {
	
        StringBuffer path = new StringBuffer("/api?module=proxy&action=eth_blockNumber&apikey=").append(EthConstant.ETHERSCAN_API_KEY);

        HttpResponse response = HttpUtil.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);
    }

	/**
     * 查询区块交易
     * @param blockNum
     * @return
     * @throws Exception
     */
	public List<JSONObject> getBlock(String blockNum) throws Exception {

        StringBuffer path = new StringBuffer("/api?module=proxy&action=eth_getBlockByNumber&tag=").append(blockNum)
                .append("&boolean=true&apikey=").append(EthConstant.ETHERSCAN_API_KEY);

        HttpResponse response = HttpUtil.doGet("https://api.etherscan.io", path.toString(), "GET", headers, querys);

        String res = EntityUtils.toString(response.getEntity());
        JSONObject json = JSONObject.parseObject(res);
        JSONObject result = json.getJSONObject("result");
        return JSON.parseArray(result.getString("transactions"), JSONObject.class);
    }
    

工具类

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 HttpUtil {

	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);
        }
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bug的搬运工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值