我们可以直接使用下面代码引入redis的Bean

package com.example.demo;import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;@Component
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {private static ApplicationContext applicationContext = null;/*** 取得存储在静态变量中的ApplicationContext.*/public static ApplicationContext getApplicationContext() {return applicationContext;}/*** 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) {return (T) applicationContext.getBean(name);}/*** 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.*/public static <T> T getBean(Class<T> requiredType) {return applicationContext.getBean(requiredType);}public static <T> T getBean(String name, Class<T> clazz) {return getApplicationContext().getBean(name, clazz);}/*** 清除SpringContextHolder中的ApplicationContext为Null.*/public static void clearHolder() {applicationContext = null;}/*** 实现ApplicationContextAware接口, 注入Context到静态变量中.*/@Overridepublic void setApplicationContext(ApplicationContext appContext) {applicationContext = appContext;}/*** 实现DisposableBean接口, 在Context关闭时清理静态变量.*/@Overridepublic void destroy() {SpringContextHolder.clearHolder();}
}
Maven配置如下:
<dependency><groupId>org.web3j</groupId><artifactId>core</artifactId><version>3.4.0</version>
</dependency>
com.odcchina:# 区块链节点地址bscChainUrl: 'https://data-seed-prebsc-1-s1.binance.org:8545/'contracts:# 合约地址bscContractUrl: '0x165fa14332d0ac163513d65D415aD2D692296B4d'

        下面的每一段代码写的非常详细,我们需要注意的是我们合约日志如果加了indexed的话请使用:  logObject.getTopics();

如果没有加indexed的话可以使用下面代码获取,需要注意的是没有加indexed的日志他是将你那一条所有没有加indexed的参数拼接成字符串的,所以我们需要进行拆分,代码里面也写的非常详细了:

logObject.getData().substring(2, logObject.getData().length());

package com.example.demo.web3jLog;import com.example.demo.util.RedisUtil;
import io.micrometer.core.instrument.util.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.web3j.abi.EventEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.methods.request.EthFilter;
import org.web3j.protocol.core.methods.response.EthLog;
import org.web3j.protocol.http.HttpService;import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;@Component
public class Web3jTest {//第一步操作,完成Redis的配置。//第二步操作,完成web3j的maven配置/*** <dependency>*    <groupId>org.web3j</groupId>*    <artifactId>core</artifactId>*    <version>3.4.0</version>* </dependency>*///第三步,配置好数据库的定时任务/*** 启动类上面加上下面注解** @EnableCaching // 启用缓存功能* @EnableScheduling // 开启定时任务功能*///定时任务类加上 @Component注解,方法上面加上 @Scheduled(cron = "*/15 * * * * ?"),里面的表达式自定义设置/*** 需要同步的合约地址*/@Value("${com.odcchina.contracts.bscContractUrl}")private String bscContractUrl;/*** 完成web3的初始化   下面的地址引入区块链节点地址  BNB或者ETH的*/private Web3j bscWeb3j = Web3j.build(new HttpService("https://data-seed-prebsc-1-s1.binance.org:8545/"));/*** 每分钟同步一次,获取区块链最新区块号** @throws IOException*/@Scheduled(initialDelay = 1 * 1000, fixedDelay = 1 * 1000)public void latestBlockTask() throws IOException {//同步最新区块BigInteger latestBlock = bscWeb3j.ethBlockNumber().send().getBlockNumber();RedisUtil.set("end-wen3jLogs", latestBlock.toString());//第一次执行将退20000块开始扫描String start = RedisUtil.get("start-wen3jLogs");if (start == null || start.isEmpty()) {RedisUtil.set("start-wen3jLogs", latestBlock.subtract(BigInteger.valueOf(20000)).toString());}}/*** 开始扫描日志*/@Scheduled(initialDelay = 1 * 1000, fixedDelay = 1 * 1000)public void bscScanTask() {String start = RedisUtil.get("start-wen3jLogs");if (StringUtils.isEmpty(start)) {try {//如果没有块的话将获取块在进行扫描日志latestBlockTask();} catch (IOException e) {return;}}BigInteger scannedBlock = new BigInteger(start);//最新区块BigInteger latestBlock = new BigInteger(RedisUtil.get("end-wen3jLogs"));//一次性同步多少块BigInteger offset;int times = 0;//如果有1块的话就执行 并且 这里考虑性能一次性任务只跑60次   大于2是因为开始块要加1,比如上次同步到了区块5,那么这次要从第6块开始同步。while (latestBlock.subtract(scannedBlock).longValue() > 2 && times++ < 60) {if (latestBlock.longValue() - scannedBlock.longValue() > 10000) {//如果大于1万块的话每次同步500块数据offset = BigInteger.valueOf(500);} else if (latestBlock.longValue() - scannedBlock.longValue() > 1000) {//如果大于1000块的话每次同步200块数据offset = BigInteger.valueOf(200);} else if (latestBlock.longValue() - scannedBlock.longValue() > 100) {//如果大于100块的话每次同步80块数据offset = BigInteger.valueOf(80);} else if (latestBlock.longValue() - scannedBlock.longValue() > 10) {//如果大于10块的话每次同步8块数据offset = BigInteger.valueOf(8);} else if (latestBlock.longValue() - scannedBlock.longValue() > 4) {offset = BigInteger.valueOf(3);} else {//最后一条一条数据同步offset = BigInteger.valueOf(1);}if (latestBlock.subtract(scannedBlock).longValue() < offset.longValue()) {break;}//根据区块值查询日志  如果原来同步到区块5的话    那么现在就从区块6开始同步List<EthLog.LogResult> resp = scanBlock(scannedBlock.add(BigInteger.ONE), scannedBlock.add(offset));for (EthLog.LogResult logItem : resp) {//循环同步下来的地址,筛选我们需要获取的日志handleLogEvent((EthLog.LogObject) logItem.get());}//日志同步完毕,将本次同步的区块数量加到初始区块号上面进行缓存scannedBlock = scannedBlock.add(offset);RedisUtil.set("start-wen3jLogs", scannedBlock.toString());}}/*** 根据区块号查询日志** @param startBlock* @param endBlock* @return*/private List<EthLog.LogResult> scanBlock(BigInteger startBlock, BigInteger endBlock) {EthFilter filter = new EthFilter(DefaultBlockParameter.valueOf(startBlock),DefaultBlockParameter.valueOf(endBlock),Arrays.asList(bscContractUrl));EthLog send = null;try {send = bscWeb3j.ethGetLogs(filter).send();} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e.getMessage());}return send.getLogs();}@Transactionalvoid handleLogEvent(EthLog.LogObject logObject) {{//这段代码会将日志没有加indexed的打印出来,并且组成数组//event TestWeb3jToken2(address indexed userAddress, uint256 indexed order,address  userAddress1, uint256  order1);//比如上面这段合约就会将第三个地址userAddress1和第四个order1取出来,我们可以处理一些业务逻辑String data = logObject.getData().substring(2);List<String> dataList = new ArrayList<>(data.length() / 64);int beginIndex = 0;while (beginIndex < data.length()) {dataList.add(data.substring(beginIndex, beginIndex + 64));beginIndex += 64;}}//这就是获取出来的数据,数据是日志加了indexed参数的List<String> topList = logObject.getTopics();String code = handle(logObject);//对TestWeb3jToken1的日志开始处理if (code != null && code.equals("TestWeb3jToken2")) {//下面将进行数据的解析和存储//第0个参数一般是固定  hash直接取String topHash = topList.get(0);//我们第1个参数为地址,需要截取取出  数据状态格式为 0x0000000000000000000000009175f9ecbbddc078e40c5e037ad31f4abf36628aString addsser = topList.get(1);addsser = "0x" + addsser.substring(26, addsser.length());//我们日志里面的第二个参数为订单号,我们截取出来为16进制,需要我们转换成10进制//一般数据格式为  0x00000000000000000000000000000000000000000000000004380663b7c5ec3cString order = topList.get(2);order = order.substring(2, order.length());order = getBin16By10(order) + "" ;{//下面这段代码也是可以处理没有加indexed参数的日志//event TestWeb3jToken2(address indexed userAddress, uint256 indexed order,address  userAddress1, uint256  order1);String date = logObject.getData().substring(2, logObject.getData().length());String address = "0x" + date.substring(0, 64).substring(26, addsser.length());String order1 = date.substring(64, date.length());BigInteger typePas = getBin16By10(order1);//上面的参数我们可以进行存储和业务逻辑处理}}//记录事件/*ChainEventLogRecord eventRecord = dslContext.newRecord(CHAIN_EVENT_LOG);eventRecord.setContract(logObject.getAddress());eventRecord.setTxHash(logObject.getTransactionHash());eventRecord.setBlockHash(logObject.getBlockHash());eventRecord.setBlockNum(logObject.getBlockNumber().longValue());eventRecord.setEvent("ignore");eventRecord.setToppics(String.join(",", logObject.getTopics()));eventRecord.setData(logObject.getData());eventRecord.setMd5(Md5Util.md5(eventRecord.getTxHash() + eventRecord.getToppics() + eventRecord.getData()));RedisUtil.lock("MTXM-UMTP:txLock:" + eventRecord.getMd5(), 5);int count = dslContext.selectCount().from(CHAIN_EVENT_LOG).where(CHAIN_EVENT_LOG.MD5.eq(eventRecord.getMd5()).and(CHAIN_EVENT_LOG.TX_HASH.eq(eventRecord.getTxHash()))).fetchOneInto(Integer.class);//下面是为了防止存入重复日志if (count > 0) {log.info("tx_hash = {} 已录入,跳过", eventRecord.getTxHash());RedisUtil.del("MTXM-UMTP:txLock:" + eventRecord.getMd5());return;}if (logObject.getAddress().equalsIgnoreCase(smtAddress)) {smTokenService.handle(logObject, dataList, eventRecord);}eventRecord.store();*/}/*** 需要获取的合约日志* 合约日志代码* TODO TestWeb3jToken(address,uint256) 中间一定不能留空格* event TestWeb3jToken(address indexed userAddress, uint256 indexed order);* event TestWeb3jToken1(address  userAddress, uint256  order);* event TestWeb3jToken2(address indexed userAddress, uint256 indexed order,address  userAddress1, uint256  order1);*/final String TESTWEB3JTOKEN = EventEncoder.buildEventSignature("TestWeb3jToken(address,uint256)");final String TestWeb3jToken1 = EventEncoder.buildEventSignature("TestWeb3jToken1(address,uint256)");final String TESTWEB3JTOKEN2 = EventEncoder.buildEventSignature("TestWeb3jToken2(address,uint256,address,uint256)");/*** 如果该日志是这个方法打印出来的将该方法返回** @param logObject* @return*/public String handle(EthLog.LogObject logObject) {if (logObject.getTopics().get(0).equalsIgnoreCase(TESTWEB3JTOKEN)) {return "TestWeb3jToken" ;} else if (logObject.getTopics().get(0).equalsIgnoreCase(TestWeb3jToken1)) {return "TestWeb3jToken1" ;} else if (logObject.getTopics().get(0).equalsIgnoreCase(TESTWEB3JTOKEN2)) {return "TestWeb3jToken2" ;}return null;}/*** 16进制转10进制** @param code* @return*/public static BigInteger getBin16By10(String code) {return new BigInteger(code, 16);}}

下面为大家准备了两份合约代码,可以直接运行的,配置上面Java代码可以直接呈现和测试,第一份合约就是一个普通的方法,里面打印了3条不同的日志,第二个合约是日志的定义。

pragma solidity ^0.5.1;import "./web3j_tokenBasic.sol";contract business_token is web3j_tokenBasic{function orderPayBnb() public  returns (bool success) {//不做任何业务处理,直接打印3种不同的日志address tsc = 0xa7B049d3A19796B195B0e976ec43EB7a12f07Bf9;emit TestWeb3jToken(msg.sender, 2555);emit TestWeb3jToken1(msg.sender, 3000);emit TestWeb3jToken2(msg.sender, 7000,tsc, 8000);return true;}}
pragma solidity ^0.5.1;contract web3j_tokenBasic {event TestWeb3jToken(address indexed userAddress, uint256 indexed order);event TestWeb3jToken1(address  userAddress, uint256  order);event TestWeb3jToken2(address indexed userAddress, uint256 indexed order,address  userAddress1, uint256  order1);
}

如何同步BNB智能合约logs相关推荐

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

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

  2. 以太坊开发实战:通过truffle-contract与智能合约交互

    以太坊开发实战:通过truffle-contract与智能合约交互 与以太坊的智能合约交互,除了使用web3.js,还可以使用另外一个Javascript库,就是truffle-contract.tr ...

  3. Foundry教程:ERC-20代币智能合约从编写到部署全流程开发

    概述 如果你想获得更好的阅读体验,请前往我的博客 本博客的内容主要分为以下四部分: 一是Foundry的介绍与安装,主要介绍为什么选择Foundry进行智能合约开发和安装过程中的各种官方文档中未提及的 ...

  4. 区块链100讲:Truffle——一个更简单的部署智能合约的方法

    本期<区块链100讲>我们将介绍一个更简单的部署智能合约的方法:Truffle. 1 什么是Truffle ? Truffle是针对基于以太坊的Solidity语言的一套开发框架.本身基于 ...

  5. Truffle - 2 利用Truffle编写、测试智能合约并将其部署到不同的测试网络

    2 利用Truffle编写.测试智能合约并将其部署到不同的测试网络 2.1创建项目 建一个文件夹 mkdir truffle-project truffle init //初始化qinjianquan ...

  6. 使用ganache-cli和truffle构建以太坊智能合约,以实现“基于哈希锁定的跨链技术”为例

    目录 配置以太坊开发环境 部署智能合约 调用智能合约 配置以太坊开发环境 系统与工具的版本:Ubuntu 21.04 npm 7.5.2 Ganache CLI v6.12.2 (ganache-co ...

  7. 一起学:以太坊智能合约开发

    课程介绍 无论在科技圈还是金融圈,"区块链"俨然成了最热的词汇.2016年,区块链写入了国家的十三五规划中:2017年,央行基于区块链技术的数字票据交易平台测试成功:同年,工信部发 ...

  8. solidity开发智能合约

    文章目录 1 Solidity与智能合约 2 智能合约概述 3 以太坊简介 4 以太坊交互工具 5 开发环境搭建 5.1 remix在线编译器 5.2 搭建本地网络 5.2.1 安装本地remix-i ...

  9. 深度解读波卡智能合约平台Gear:通往并行架构公链之路

    本篇节选自:深度解读波卡智能合约平台Gear:通往并行架构公链之路 摘要 2021 年 11 月,随着波卡主网正式开启平行链插槽拍卖,波卡生态顿时成为一股耀眼的新势力.其创始人 Gavin Wood ...

最新文章

  1. 构建一个给爬虫使用的代理IP池
  2. windows下安装nodejs及框架express
  3. spring中的IOC和AOP
  4. USACO2.4のP1522-牛的旅行(Cow Tours)【最短路Flody】
  5. 洛谷P2347 砝码称重 某一年noip提高组原题
  6. 【Prince2科普】P2七大主题之变更
  7. GPU并行计算OpenCL(1)——helloworld
  8. AV-TEST最新Windows 10平台最佳杀毒软件测试结果
  9. win7计算机桌面文件位置更改,Win7系统怎么更改桌面文件路径_win7修改桌面文件保存路径的方法...
  10. 追光的人对Echo,SkyReach的Beta产品测试报告
  11. C# WPF设备监控软件(经典)-上篇
  12. Echarts的世界、中国、省份地图
  13. java web: 上午 org.apache.catalina.core log 信息: 将servlet[***]标记为不可用/或者XXX资源不可用
  14. MATLAB随机森林回归模型
  15. 2022年搭载国产芯片的手机推荐 这3款性能就不错
  16. 多态 在游戏程序实例
  17. python场景动画_昨夜星辰多媒体情景动画
  18. SLAM导航机器人零基础实战系列:(四)差分底盘设计——5.底盘PID控制参数整定
  19. Android学习--RecyclerView的使用
  20. “0x00000014”内存。该内存不能为“Written”(或“Read”)的解决办法。

热门文章

  1. 对称加密、非对称加密、公钥、私钥究竟是个啥?
  2. html显示毒经,谁能肩负剑三PVE王者之名?哪怕职业再强,这点恐怕都比不上毒经...
  3. OKX和UniSat联手革新比特币区块链上的BRC-20
  4. python 模拟微信浏览器请求_用chrome模拟微信浏览器访问需要OAuth2.0网页授权的页面...
  5. 什么是除权(除息)基准价 ?
  6. Cad二次开发绘图1
  7. 艾司博讯:拼多多开店选择那些类目好
  8. 从Preact中了解React组件和hooks基本原理
  9. python ndarray find_在列表中查找numpy数组的索引(Find index of numpy array in list)
  10. Linux忘记登陆密码之破解Linux密码