首先需要拿到当前USDT高度(也可以去TokenView去查)
通过grpc也好,封装的api也可以,我这里是通过client的方式
currentHeigth = omniCoreClient.currentBlockHeight();
每次扫完要把当前高度存到数据库中,下次从DB中的高度继续扫描(这里我防止意外情况,又引入了Redis存放高度,每次扫先和DB的比较谁高用谁)
log.info("当前最新高度:{}",currentHeigth);
log.info("DB中上次高度:{}",index);
//这个标志位是为了跳出下面while用的
boolean flag = true;
Integer block = (Integer) redisTemplate.opsForValue().get("IN_BLOCK");
if(block != null){
if(block > index){
log.info("redis中高度大 使用{}",block);
index = block;
}else{
log.info("数据库中高度大 使用{}",index);
}
}else{
log.info("数据库中高度大 使用{}",index);
}
然后就是扫块的方法
while (flag && index <= currentHeigth.intValue()-1){
List<Sha256Hash> sha256Hashes = omniCoreClient.getOmniClient().omniListBlockTransactions(index);
for (Sha256Hash txid : sha256Hashes) {
LinkedHashMap jsonObject = omniCoreClient.getOmniClient().send("omni_gettransaction",txid.toString().trim());
if(jsonObject==null){
continue;
}
if(jsonObject.get("propertyid")==null || !jsonObject.get("propertyid").equals(31)){
log.info("非USDT交易跳过 {}",txid.toString());
continue;
}
if(!(boolean)jsonObject.get("valid")){
log.info("并不是有效数据跳过 {}",txid.toString());
continue;
}
if((int)jsonObject.get("confirmations") <= 1 ){
flag = false;
log.info("确认数小于2 不增加高度等待下次扫描 {}",txid.toString());
break;
}
}}
每次要从DB或Redis的最新高度-1开始扫,也就是最低多扫两个高度。
解释一下上面为什么要确认小于2的跳过,因为如果确认只有1的话会有一定几率被退回,这样的话钱已经转入了,数据库的记录也有了,但是实际上钱并没有打进来,被退回了
jsonObject.get("referenceaddress")
接下来就可以去拿数据库中的地址去和扫到的地址比对,如果相同的,并且事务ID没有被记录过就开始自己的业务逻辑(加钱,插入记录等)
由于每次index会从-1开始扫,有概率会重复扫到,只凭地址是无法判断是否扫过了,这个时候就需要事务ID来记录(txid,hex)
if(index == currentHeigth.intValue()){
redisTemplate.opsForValue().set("BLOCK_HEIGHT",index-1);
operationExtendMapper.updateDbIndex(String.valueOf(index-1));
log.info("更新到高度{}",index-1);
}else{
redisTemplate.opsForValue().set("BLOCK_HEIGHT",index);
operationExtendMapper.updateDbIndex(String.valueOf(index));
log.info("更新到高度{}",index);
}
上面的全部结束之后就可以更新本次的高度了.
由于这个API受到限制所以绝大部分都使用原生归集(下次说)
本次使用的归集方法是omni_funded_send方式,这个方法本身是有问题的,为什么这么说,看一下api的介绍
omni_funded_send
omni_funded_send调用创建并发送一个简单充值交易。
发送方发出的所有比特币都将被消耗掉,如果比特币来自指定的手续费 来源,那么找零将返回该来源地址。
没错,它每次都会把BTC耗空,也就是说用户连续充值多次,只有一次能够被归集成功,,其他的几次归集会全部失败,因为没有账户btc。
(如果是每次都单笔充值的情况是没问题的,也不需要打0.00000546,用户充值会带进来一笔,并且需要一个代扣手续费的地址,这个地址一定要有足够的BTC)
下面方法设置本次手续费(这个可以通过其他方式获取到全网平均手续费,太少了到账慢,太多了浪费)
omniClient.setTxFee();
接下来就等待归集完成,如果记录够全面的话,就可以连续查询到两笔转账记录,从外面转入内部地址,从内部地址转入(冷,热地址)汇集地址。
一般这个扫块作为定时服务存在程序里面,我设置是5分钟,你也可以设置其他时间,USDT每天会平均生成80个高度,每个高度150-1000+的交易记录,建议每次扫到就进行逻辑处理,不需要加事务,每次扫的速度取决于链上的交易笔数,越多则越慢