波场(Tron)监听区块交易(TRX,USDT)

 前言说明:

        本篇文章参考GitHub一位伙伴的代码,再代码基础上优化改良以后的结果,但是一下找不到那位大佬的GitHub链接了,如有侵权请联系作者调整文章,让跟多人收益。谢谢。

实现思路:

           波场链是一条很新奇的链,他提供了专门的http api相关链接,我们可以通过链接去获取区块上面的事件,同时解析数据来判定交易流水以及方向,再结合业务从而实现我们系统的充值转账等操作。缺点就是他只提供了根据区块号取单个区块的交易数据(目前结合文档看只能单个单个区块的取)。并且容易触发限流控制。

           首先会获取最新区块号,放入缓存Redis里面,定时任务每10秒执行一次,获取上次Redis缓存区块和本次最新区块号对比,开始遍历每个区块获取节点数据(数据获取到了以后就解析处理数据),获取到数据的区块将区块号跟新到Redis里面去。

技术准备:

              先去这个网站申请一个api keys吧,地址 ,申请的key每天可以调用50万次的,完全够用了,这个就很好,如果有更高需求的话可以付费升级的。如果不申请的话很可能会触发RQS限制。

导入依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.7</version>
</dependency>

实现代码:

package com.app.web.task;

import com.app.web.trx.TrxEventDataService;
import com.app.web.web3.Erc20Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;


/**
 * 用户冲提币监听
 */
@Slf4j
@Component
public class Web3Task {

    @Resource
    private TrxEventDataService trxEventDataService;

    /**
     * 监听入账数据
     */
    @Scheduled(initialDelay = 20_000, fixedDelay = 10_000)
    public void exec() {
        //我们需要监听的是TRX链代币USDT    所以这里是USDT的合约地址
        String contractUsdt = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
        String url = "https://api.trongrid.io";
        // 设置API key,设置自己的,要不然会触发RQS限制
        // https://www.trongrid.io/ 申请下欧~
        String apiKey = "填入申请的key";
        trxEventDataService.exec(contractUsdt,url,apiKey);
        System.out.printf("同步完成-------------");

    }

}


注意事项:

                备注都有应该都可以看懂吧,下面获取区块高度我是用的gethub大佬jar包里面的,所以这一块需要大家下载一下jar包导入自己的项目里面引用,当然也可以自己写一个获取区块高度的代码也行,比导入jar方便实在的多。这里给你们提供一下文档自己去看下 HTTP API - Java Tron ,我也写了,但是没有测试就不贴代码出来了。

package com.app.web.trx;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.app.common.util.RedisUtil;
import org.springframework.stereotype.Service;
import tron_scan.ScanBlock;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * TRX同步线上数据
 */
@Service
public class TrxEventDataService {

    // 初始化扫描器   一定要全局哟  这个包需要我们将下面的jar包导入我们项目里面才能引入进来
    private static final ScanBlock scan = new ScanBlock();

    //缓存的最新区块号key
    public static String REDIS_BLOCK_NUM = "REDIS_BLOCK_NUM";

    /**
     * 监听的合约地址,本方法经过测试以及很稳定了,可以直接用的
     * 需要注意的是建议项目别停止太久,这个方法基本1秒同步一个区块,而区块3秒才生成一个,差的不多能快速追上的
     * @param contractUsdt   USDT合约地址
     * @param url            tron api的URL地址
     * @param apiKey         我们申请的key
     */
    public void exec(String contractUsdt,String url,String apiKey){
        scan.set_api_key(apiKey);
        // 设置主节点
        scan.set_uri(url);
        // 获取最新的区块号
        String endNumStr = scan.GetNowBlockNum();
        String startNumber = RedisUtil.get(REDIS_BLOCK_NUM);
        if(startNumber == null){
            RedisUtil.set(REDIS_BLOCK_NUM,endNumStr);
            startNumber = endNumStr;
        }
        Integer start = Integer.parseInt(startNumber);
        Integer end = Integer.parseInt(endNumStr);
        // 执行任务
        for (int i = start + 1; i < end; i++) {
            final int index = i;
            String return_str = this.sendPost(url+"/walletsolidity/getblockbynum","{\"num\":" + i + "}",apiKey);
            if (JSON.isValid(return_str)) {
                JSONObject Json = JSON.parseObject(return_str);
                if(Json.size() == 0){
                    //取不到数据,我们这里休息30秒重试,有可能是被封了,或者取出来的区块里面还没有写入数据,我们等等就好了
                    try {
                        System.out.printf("取不到数据,我们这里休息30秒重试-----------------\n");
                        Thread.sleep(30000L);
                        //休息完以后我们重新获取一下上次没有获取到的区块数据
                        return_str = this.sendPost(url,"{\"num\":" + i + "}",apiKey);
                        Json = JSON.parseObject(return_str);
                    } catch (InterruptedException var7) {
                    }
                }
                if (Json.containsKey("blockID")) {
                    if (Json.containsKey("transactions")) {
                        String value = AnalysisOt.getTransferEvent(Json.getJSONArray("transactions").toJSONString(), i+"");
                        //获取出来的数据我们解析一下数据就好啦
                        processTransferData(value,contractUsdt);
                    }
                    //防止内存使用太大,我们GC清理一下
                    System.gc();
                }
            }
            //区块的数据我们获取到了,将本次的区块高度更新到Redis吧
            RedisUtil.set(REDIS_BLOCK_NUM,index+"");
            System.out.printf("本次执行的区块是:"+ i+"休眠一秒再继续执行-----------------\n");
            try {
                //这里一定需要休眠,不然会被封掉无法获取到数据的
                Thread.sleep(1000L);
            } catch (InterruptedException var7) {
            }
        }
    }

    // 回调 转账信息
    private void processTransferData(String allData,String contractUsdt) {
        JSONArray jsonArray = JSON.parseArray(allData);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject transfer = jsonArray.getJSONObject(i);
            if ("SUCCESS".equals(transfer.getString("contractRet"))) {
                String type = transfer.getString("type");
                BigDecimal amount = new BigDecimal(transfer.getString("amount"));
                BigDecimal divisor = new BigDecimal("1000000");
                String formattedAmount = amount.divide(divisor, 6, BigDecimal.ROUND_HALF_UP).toString();
                if ("TriggerSmartContract".equals(type) && contractUsdt.toLowerCase().equals(transfer.getString("contract_address").toLowerCase())) {
                    //这个是USDT代币的交易流水
                    System.out.println("USDT transfer: " +
                        transfer.getString("from_address") + " -> " +
                        transfer.getString("to_address") + " -> " +
                        formattedAmount + " -> " +
                        transfer.getString("txID"));
                } else if ("TransferContract".equals(type)) {
                    //这里是TRX交易的流水
                    System.out.println("TRX transfer: " +
                        transfer.getString("from_address") + " -> " +
                        transfer.getString("to_address") + " -> " +
                        formattedAmount + " -> " +
                        transfer.getString("txID"));
                }
            }
        }
    }

    public String sendPost(String url, String json,String apiKey) {
        StringBuilder response = new StringBuilder();
        try {
            URL requestUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection)requestUrl.openConnection();
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(10000);
            connection.setRequestProperty("accept", "application/json");
            connection.setRequestProperty("TRON-PRO-API-KEY", apiKey);
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0");
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            Throwable var6 = null;
            BufferedReader in = null;
            try {
                OutputStream outputStream = connection.getOutputStream();

                try {
                    byte[] requestData = json.getBytes(StandardCharsets.UTF_8);
                    outputStream.write(requestData, 0, requestData.length);
                    outputStream.flush();
                } finally {
                    if (outputStream != null) {
                        outputStream.close();
                    }
                }
            } catch (Throwable var17) {
                if (var6 == null) {
                    var6 = var17;
                } else if (var6 != var17) {
                    var6.addSuppressed(var17);
                }
                throw var6;
            }
            int responseCode = connection.getResponseCode();
            if (responseCode == 200) {
                in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

                String line;
                while((line = in.readLine()) != null) {
                    response.append(line);
                }

                in.close();
            }
        } catch (Throwable var18) {
        }
        System.gc();
        return response.toString();
    }

}

这里是下载jar包的链接,或者你们私信作者发你们也行的。

https://download.csdn.net/download/qq_38935605/89712274

如果这篇文章在你一筹莫展的时候帮助到了你,可以请作者吃个棒棒糖🙂,如果有啥疑问或者需要完善的地方欢迎大家在下面留言或者私信作者优化改进。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值