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

news2024/9/27 21:28:13

 前言说明:

        本篇文章参考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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2104377.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络协议--HTTP 和 HTTPS 的区别

网络协议–HTTP 和 HTTPS 的区别 一、简述 HTTP (全称 Hyper Text Transfer Protocol)&#xff0c;就是超文本传输协议&#xff0c;用来在 Internet 上传送超文本。是互联网上应用最为广泛的一种网络协议&#xff0c;是一个客户端和服务器端请求和应答的标准(TCP)&#xff0c…

NET 8 + WPF 企业级工作流系统

目录 前言 项目介绍 功能模块 快速预览 1、快速预览方式1 2、快速预览方式2 3、快速预览方式3 项目框架 项目功能 1、快速代码生成 2、大屏界面&#xff08;可拖拽&#xff0c;可全屏&#xff09; 3、Form 表单 4、通用crud方法 5、大文件上传与下载 6、多窗口、…

【机器学习】集成学习的基本概念、Bagging和Boosting的区别以及集成学习方法在python中的运用(含python代码)

引言 集成学习是一种机器学习方法&#xff0c;它通过结合多个基本模型&#xff08;通常称为“弱学习器”&#xff09;来构建一个更加强大或更可靠的模型&#xff08;“强学习器”&#xff09; 文章目录 引言一、集成学习1.1 集成学习的核心思想1.2 常见的集成学习方法1.2.1 Bag…

SpringBoot3 + Spring Security6认证授权

SpringBoot3 Spring Security6 实现默认地址/login的认证 Spring Security 核心技术过滤器。一个web请求会经过一系列的过滤器进行认证授权。 主要是用默认的/login请求&#xff0c;继承UsernamePasswordAuthenticationFilter&#xff0c;来实现用户名和密码登录。 核心流程 …

idea一键自动化部署项目

文章目录 前言一、 IDEA插件安装1. 首先下载 Alibaba Cloud Toolkit 插件2. 插件下载完成后重启IDEA 二、SpringBoot项目准备1. pom.xml 文件2. controller3. 启动类 三、SpringBoot项目jar包部署1. Alibaba Cloud Toolkit 插件服务器配置2. 主机 IP、用户名、密码 点击测试链接…

5月,我面试60多号人,才发现很多人没有这项能力

很多 3~5 年开发经验的&#xff0c;都来自传统行业&#xff0c;所接触的都是一些非常传统的项目&#xff0c;像上面的一些案例场景&#xff0c;根本没碰到过&#xff0c;也不知道如何找到好的解决方案。 交流的过程中&#xff0c;发现这些很基本的问题&#xff0c;他们普遍都答…

Storm计算框架

工作流程 主要组件 streams spouts Bolt Tuple Topology stream grouping

Rust多线程编程概述

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学&#xff0c;之一 -CSDN博客 Rust到底值不值得学&#xff0c;之二-CSDN博客 12.2 多线程编程概述 12.2.1 线程…

校园洗护新体验:一键尽享便捷小程序功能全解析

校园洗护新体验&#xff1a;一键尽享便捷小程序功能全解析 1. **用户端尊享**&#xff1a;无论是渴望上门取件的便捷&#xff0c;还是偏爱送货至店的从容&#xff0c;乃至寄存网点的灵活&#xff0c;一切由您指尖掌控&#xff0c;尽享个性化服务。 2. **取货员专业视角**&…

云计算国标发布 云轴科技ZStack参编

近日&#xff0c;国家市场监督管理总局、国家标准化管理委员会发布中华人民共和国国家标准公告&#xff08;2024年第17号&#xff09;。上海云轴信息科技有限公司&#xff08;简称云轴科技ZStack&#xff09;参与起草的国家标准GB/T 32399-2024《信息技术 云计算 参考架构》正式…

分类预测|基于CNN提取特征使用支持向量机作为分类器进行分类预测CNN-SVM(SVM自动寻优c,g超参数)CNN和CNN-SVM

分类预测|基于CNN提取特征使用支持向量机作为分类器进行分类预测CNN-SVM&#xff08;SVM自动寻优c&#xff0c;g超参数&#xff09;CNN和CNN-SVM 文章目录 一、基本原理1. 卷积神经网络&#xff08;CNN&#xff09;简介CNN的基本结构 2. 支持向量机&#xff08;SVM&#xff09;…

WPF-快速构建统计表、图表并认识相关框架

一、使用ScottPlot.Wpf 官网地址&#xff1a;https://scottplot.net/quickstart/wpf/ 1、添加NuGet包&#xff1a;ScottPlot.Wpf 2、XAML映射命名空间&#xff1a; xmlns:ScottPlot"clr-namespace:ScottPlot.WPF;assemblyScottPlot.WPF" 3、简单示例&#xff1a;…

当视频编辑完成后,要将视频进行导出,其中mp4是人们常用的视频格式, Camtasia如何导出工程文件

当视频编辑完成后&#xff0c;要将视频进行导出&#xff0c;其中mp4是人们常用的视频格式。如果视频编辑尚未完成&#xff0c;则可以将工程文件暂时保存在电脑中&#xff0c;以便下次打开使用。今天的文章将为大家介绍Camtasia关于保存的相关内容。接下来我将为大家介绍&#x…

数据结构:树与二叉树

1、树的基本概念 1.1树的定义 树是n个结点的有限集。 若n0&#xff0c;称为空树&#xff1b;若n>0称为非空树&#xff0c;非空树有且仅有一个称之为根的结点。 除根结点以外的其余结点可分成m个互不相交的有限集T1,T2,......Tm,每个有限集合本身又是一棵树&#xff0c;并…

CentOS 部署 RocketMQ 详细指南

1. RocketMQ 5.3.0 简介 什么是 RocketMQ&#xff1f; Apache RocketMQ 是一个分布式消息中间件&#xff0c;最初由阿里巴巴开发并开源。它基于发布-订阅&#xff08;Pub-Sub&#xff09;模式&#xff0c;具有高性能、低延迟和高可靠性等特点。RocketMQ 支持大规模消息流处理…

Win11怎么把C盘分成几个盘?

很多Windows11用户会发现&#xff0c;系统默认只给电脑分配了一个C盘&#xff0c;而C盘不仅是系统盘&#xff0c;还是软件的默认安装位置&#xff0c;并且个人数据也是保存在C盘。这种情况下&#xff0c;电脑使用时间久了会遇到一个常见问题&#xff1a;C盘空间不足或是需要将C…

elasticsearch文档Delete By Query API(一)

这里的查询需要使用和Search API&#xff08;后文会讲&#xff09;相同的方式来将查询条件作为query的值传递&#xff0c;当然也可以使用q关键字&#xff0c;例如如下请求&#xff1a; curl -X POST “localhost:9200/twitter/_delete_by_query?pretty&quser:kimchy” -H…

828华为云征文|华为云Flexus X实例docker部署srs6并调优,协议使用webrtc与rtmp

828华为云征文&#xff5c;华为云Flexus X实例docker部署srs6并调优&#xff0c;协议使用webrtc与rtmp 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务…

六西格玛项目:从定义问题到控制成果,全程无忧——张驰咨询

什么是六西格玛项目 六西格玛项目是一种旨在通过改善企业质量流程管理&#xff0c;以“零缺陷”的完美商业追求&#xff0c;带动质量大幅提高、成本大幅度降低&#xff0c;最终实现企业财务成效的提升与企业竞争力的突破的管理策略。它由摩托罗拉公司的工程师比尔史密斯于1986…

文心一眼 4.0Turbo 免费领取5天体验卡

注&#xff1a;这个是官方的活动&#xff0c;目的在于用户推广&#xff0c;任何账号点击连接都可以领取&#xff0c;被分享者领取5天&#xff0c;分享者获得3天&#xff0c;上限320天。 官方活动跳转地址如下&#xff1a;​​​​​​点击这里 跳转后登录&#xff0c;完成一次…