Commit 6699e8fb authored by jianhua.zhang's avatar jianhua.zhang

区块总大小、总交易数量、总账户数量统计功能开发

parent f25e2d98
......@@ -2,6 +2,7 @@ package com.wuban.tron.explore;
import com.wuban.tron.explore.constant.Constant;
import com.wuban.tron.explore.fetch.Engine;
import com.wuban.tron.explore.service.CensusService;
import com.wuban.tron.explore.service.LastBlockService;
import com.wuban.tron.explore.service.TransactionService;
import com.wuban.tron.explore.util.DateUtil;
......@@ -35,13 +36,15 @@ public class Bootstrapper {
private final TransactionService transactionService;
private final CensusService censusService;
/**
* 定时任务 - 业务线程池
*/
private ScheduledThreadPoolExecutor executorService;
private void init() {
this.executorService = new ScheduledThreadPoolExecutor(3, new ThreadFactory() {
this.executorService = new ScheduledThreadPoolExecutor(2, new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
......@@ -62,16 +65,17 @@ public class Bootstrapper {
public synchronized void start() {
this.init();
this.startEngine();
this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.sync(), 0, 3, TimeUnit.MINUTES);
this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.refresh(), 1, 1, TimeUnit.MINUTES);
this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.sync(), 0, 1, TimeUnit.SECONDS);
this.executorService.scheduleWithFixedDelay(() -> this.censusService.updateTotalAccount(), 0, 5, TimeUnit.SECONDS);
this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.refresh(), 0, 500, TimeUnit.MILLISECONDS);
this.executorService.scheduleWithFixedDelay(() -> this.transactionService.censusBlockByLastDay(), getInitialDelay(), 24 * 60 * 60, TimeUnit.SECONDS);
}
private long getInitialDelay() {
Date nextDate = DateUtil.addDays(new Date(), 1);
String date = DateUtil.getFormatDate(nextDate, DateUtil.PATTERN_YMD) + " 00:00:03";
long millis = (DateUtil.getDateFromDateStr(date, DateUtil.PATTERN_YMD_HMS) - System.currentTimeMillis())/1000;
return millis;
long seconds = (DateUtil.getDateFromDateStr(date, DateUtil.PATTERN_YMD_HMS) - System.currentTimeMillis())/1000;
return seconds;
}
private synchronized void startEngine() {
......
......@@ -30,14 +30,30 @@ public class Constant {
public static final String OS_NMAE = "WINDOWS";
public static final long FIFTY_THOUSAND = 50000;
public static final long FIVE_THOUSAND = 5000;
/**
* 区块高度:已同步
*/
public static final String BLOCK_NUM_KEY = "block_num";
/**
* 需要同步区块列表
*/
public static final String BLOCK_NUM_LIST_KEY = "block_num_list";
/**
* 账户地址:根据此地址抓取账户余额
*/
public static final String ADDRESS_KEY = "address";
/**
* 数据统计:根据此数据(账户数量、交易数量、区块大小)更新DB统计信息
*/
public static final String CENSUS_ADDRESS = "census_address";
public static final String CENSUS_TRANS = "census_trans";
public static final String CENSUS_BLOCK_SIZE = "census_block_size";
/**
* 数据同步阀值
*/
......
......@@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
......@@ -50,6 +51,8 @@ public class TransactionControllerV1 {
private final LastBlockService lastBlockService;
private final CensusService censusService;
/**
* 首页 - 搜索
*
......@@ -397,8 +400,6 @@ public class TransactionControllerV1 {
List<TransInfoModel> modelList = new ArrayList<>();
if (!CollectionUtils.isEmpty(pageInfo.getList())) {
modelList = transferTransInfoModel(pageInfo);
//resDataModel.setTotal(Integer.valueOf(pageInfo.getTotal()+""));
//resDataModel.setData(modelList);
}
return ResponseKit.success(modelList);
......@@ -530,6 +531,72 @@ public class TransactionControllerV1 {
return ResponseKit.success(modelList);
}
/**
* 交易TPS
*
* @return
*/
@RequestMapping(value="trans/tps", method = RequestMethod.GET)
public ApiResponse transTPS() {
CensusModel censusModel = new CensusModel();
// 当前毫秒
long curMillis = System.currentTimeMillis();
// 上一分钟毫秒
long millis = curMillis - (60*1000);
/*
计算上一分钟交易tps
*/
TransactionExample example = new TransactionExample();
example.createCriteria().andTimestampBetween(millis, curMillis);
List<Transaction> list = this.transactionService.getByExample(example);
BigDecimal tps = new BigDecimal(0);
if (!StringUtils.isEmpty(list)) {
tps = BigDecimalUtil.getDevide(1, new BigDecimal(list.size()), new BigDecimal(60));
}
censusModel.setTps(tps.toPlainString());
// 最新区块高度
LastBlock lastBlock = this.lastBlockService.getOneByExample();
if (lastBlock != null) {
if (lastBlock.getLastBlockNum() != null) {
censusModel.setBlockNumber(lastBlock.getLastBlockNum().toString());
}
}
// 区块、交易、账户数统计
Census census = this.censusService.selectOneByExample();
if (census != null) {
if (census.getTotalAccount() != null) {
censusModel.setAddressNumber(census.getTotalAccount().toString());
}
if (census.getTotalBlockSize() != null) {
censusModel.setBlockSize(census.getTotalBlockSize().toString());
}
if (census.getTotalTrans() != null){
censusModel.setTransTotal(census.getTotalTrans().toString());
}
}
// 前一天交易数
BlockDayCensusExample example1 = new BlockDayCensusExample();
Date date = DateUtil.addDays(new Date(), -1);
String censusDate = DateUtil.getFormatDate(date, DateUtil.PATTERN_YMD);
example1.createCriteria().andCensusDateEqualTo(censusDate);
List<BlockDayCensus> tmpList = this.blockDayCensusService.getByExample(example1);
if (!CollectionUtils.isEmpty(tmpList)) {
Integer totalVolume = tmpList.get(0).getTotalVolume();
censusModel.setTransNumber(totalVolume.toString());
}
censusModel.setDifficulty("");
return ResponseKit.success(censusModel);
}
public final static boolean isNumeric(String s) {
if (s != null && !"".equals(s.trim())) {
return s.matches("^[0-9]*$");
......
......@@ -42,11 +42,25 @@ public interface AddressRepository {
/**
* 分页查询
*
* @param example 查询条件参数
* @param example 检索条件
* @return 分页记录列表
*/
List<Address> selectByPager(@Param("example") AddressExample example);
/**
* 根据条件检索账户信息
*
* @param example 检索条件
* @return
*/
List<Address> selectByExample(@Param("example") AddressExample example);
/**
* 账户总记录数
*
* @param example 检索条件
* @return
*/
Integer countByPager(@Param("example") AddressExample example);
}
\ No newline at end of file
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.Census;
import com.wuban.tron.explore.entity.example.CensusExample;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
/**
* <core>数据统计DAO</core>
*
* @author sky
* @date 2020/11/25
*/
@Repository
public interface CensusRepository {
/**
* 添加统计信息
*
* @param record
* @return
*/
int insert(@Param("record") Census record);
/**
* 查询统计信息
*
* @param example 检索条件
* @return
*/
Census selectOneByExample(@Param("example") CensusExample example);
/**
* 根据主键更新统计信息
*
* @param record
*/
void updateById(@Param("record") Census record);
}
......@@ -2,6 +2,12 @@ package com.wuban.tron.explore.domain;
import lombok.Data;
/**
* <core>波场交易结果</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class TransactionsRet {
......
......@@ -2,6 +2,12 @@ package com.wuban.tron.explore.domain;
import lombok.Data;
/**
* <core>波场账户余额信息</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class TronFreeze {
......
package com.wuban.tron.explore.entity;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 区块、交易、账户统计表
* @author sky
* @date 2020-11-24
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Census {
/**
*
*/
private Long id;
/**
* 总交易数
*/
private Long totalTrans;
/**
* 总区块大小
*/
private Long totalBlockSize;
/**
* 总账户数
*/
private Long totalAccount;
public static Census getInstance() {
return Census.builder()
.id(0L)
.totalTrans(0L)
.totalBlockSize(0L)
.totalAccount(0L)
.build();
}
}
\ No newline at end of file
package com.wuban.tron.explore.fetch;
import com.wuban.tron.explore.constant.Constant;
import com.wuban.tron.explore.entity.Census;
import com.wuban.tron.explore.handler.CensusDataHandler;
import com.wuban.tron.explore.handler.ICensusDataHandler;
import com.wuban.tron.explore.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* <core>统计数据抓取者服务接口方法实现类</core>
*
* @author sky
* @date 2020/11/12
*/
@Slf4j
public class CensusDataFetcher<T> extends AbstractJob implements ICensusDataFetcher {
private ICensusDataHandler handler;
private StringRedisTemplate stringRedisTemplate;
CensusDataFetcher(final CensusDataHandler handler) {
this.handler = handler;
stringRedisTemplate = SpringContextUtil.getBean(StringRedisTemplate.class);
}
@Override
public List fetch() {
List<Census> dataList = new ArrayList<>();
try {
// Redis 获取区块大小
String blockSize = this.stringRedisTemplate.opsForList().rightPop(Constant.CENSUS_BLOCK_SIZE);
// Redis 获取交易数量
String transNumber = this.stringRedisTemplate.opsForList().rightPop(Constant.CENSUS_TRANS);
Census census = new Census();
boolean flag = false;
if (!StringUtils.isEmpty(blockSize)) {
flag = true;
census.setTotalBlockSize(Long.valueOf(blockSize));
}
if (!StringUtils.isEmpty(transNumber)) {
flag = true;
census.setTotalTrans(Long.valueOf(transNumber));
}
if (flag) {
dataList.add(census);
}
} catch (Exception e) {
log.info(e.getMessage(), e);
}
return dataList;
}
@Override
public void send(List list) throws InterruptedException {
if (CollectionUtils.isEmpty(list)) {
return;
}
this.handler.receive(list);
}
@Override
public boolean execute() {
try {
final List<Census> list = fetch();
if (CollectionUtils.isEmpty(list)) {
return false;
}
send(list);
return true;
} catch (final Exception e) {
log.error("fetch exception", e);
return false;
}
}
}
package com.wuban.tron.explore.fetch;
import com.wuban.tron.explore.entity.Census;
import com.wuban.tron.explore.handler.AddressBalanceHandler;
import com.wuban.tron.explore.handler.BlockDataHandler;
import com.wuban.tron.explore.domain.TronAccount;
import com.wuban.tron.explore.domain.TronResponseData;
import com.wuban.tron.explore.handler.CensusDataHandler;
import lombok.extern.slf4j.Slf4j;
/**
......@@ -45,7 +47,17 @@ public class Engine {
*/
private AddressBalanceHandler addressHandler;
public static final int BLOCK_FETCHER_NUM = 5;
/**
* 数据统计猎手
*/
private CensusDataFetcher<Census> censusDataFetcher;
/**
* 数据统计处理者
*/
private CensusDataHandler censusDataHandler;
public static final int BLOCK_FETCHER_NUM = 3;
public static final int BALANCE_FETCHER_NUM = 3;
......@@ -91,6 +103,11 @@ public class Engine {
for (int i = 0; i < BALANCE_FETCHER_NUM; i++) {
this.executor.execute(this.addressFetcher);
}
this.censusDataHandler = new CensusDataHandler();
this.censusDataFetcher = new CensusDataFetcher<>(this.censusDataHandler);
this.executor.execute(this.censusDataFetcher);
this.executor.execute(this.censusDataHandler);
}
......
......@@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
public class Executor {
private static final int SIZE = 15;
private static final int SIZE = 10;
private final List<AbstractJob> jobList = new ArrayList<>();
private final String name;
private ThreadPoolExecutor pool;
......
package com.wuban.tron.explore.fetch;
import java.util.List;
/**
* <core>统计数据抓取者服务接口方法</core>
*
* @author sky
* @date 2020/11/24
*/
public interface ICensusDataFetcher<T> {
/**
* 抓取数据
*
* @return
*/
List<T> fetch();
/**
* 发送数据
*
* @param list
* @throws InterruptedException
*/
void send(final List<T> list) throws InterruptedException;
}
......@@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
public class PersistThreadPool {
private static final int POLL_SIZE = ThreadPoolUtil.getCupNum();
private static final int POLL_SIZE = 1;
public final List<ThreadPoolExecutor> executors = new ArrayList<>(POLL_SIZE);
......
......@@ -75,7 +75,7 @@ public class AddressBalanceHandler extends AbstractJob implements IAddressBalanc
obj.setFrozenBalance(frozenBalance.longValue());
this.addressService.updateById(obj);
log.info("更新账户余额 account:{}", obj.toString());
log.info("更新账户余额 {}", obj.toString());
}
}
......
......@@ -49,8 +49,15 @@ public class BlockDataHandler extends AbstractJob implements IBlockDataHandler {
}
@Override
public void flush(List e) {
this.transactionService.save(e);
public void flush(List list) {
if (!CollectionUtils.isEmpty(list)) {
try {
this.transactionService.save(list);
} catch (Exception e) {
log.info("同步到DB失败 param:{}", list.toString());
}
}
}
......
package com.wuban.tron.explore.handler;
import com.wuban.tron.explore.entity.Census;
import com.wuban.tron.explore.fetch.AbstractJob;
import com.wuban.tron.explore.fetch.PersistThreadPool;
import com.wuban.tron.explore.service.CensusService;
import com.wuban.tron.explore.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
/**
* <core>统计数据处理者服务接口方法实现类</core>
*
* @author sky
* @date 2020/11/24
*/
@Slf4j
public class CensusDataHandler extends AbstractJob implements ICensusDataHandler<Census> {
private CensusService service;
private PersistThreadPool threadPool;
private final LinkedBlockingQueue<List<Census>> dataList;
public CensusDataHandler() {
this.dataList = new LinkedBlockingQueue<>();
service = SpringContextUtil.getBean(CensusService.class);
threadPool = new PersistThreadPool();
}
@Override
public boolean execute() {
final List<Census> list = this.dataList.poll();
if(list != null && list.size() != 0) {
threadPool.getPool().execute(() -> flush(list));
}
return true;
}
@Override
public void receive(List<Census> e) throws InterruptedException {
if (!CollectionUtils.isEmpty(e)) {
this.dataList.put(e);
}
}
@Override
public void flush(List<Census> e) {
if (!CollectionUtils.isEmpty(e)) {
Census census = e.get(0);
this.service.saveOrUpdateCensus(census);
log.info("区块大小、交易数量统计 {}", census.toString());
}
}
}
package com.wuban.tron.explore.handler;
import java.util.List;
/**
* <core>统计数据处理者服务接口方法</core>
*
* @author sky
* @date 2020/11/24
*/
public interface ICensusDataHandler<T> {
/**
* 接收统计数据
*
* @param e 区块数据
* @throws InterruptedException 异常
*/
void receive(List<T> e) throws InterruptedException;
/**
* 数据刷入DB
*
* @param e 用户余额数据
*/
void flush(List<T> e);
}
......@@ -3,6 +3,12 @@ package com.wuban.tron.explore.param.response;
import lombok.Builder;
import lombok.Data;
/**
* <core>账户信息MODEL</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
@Builder
public class AddessInfoModel {
......
package com.wuban.tron.explore.param.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* <core>统计数据MODEL</core>
*
* @author sky
* @date 2020/11/26
*/
@Data
public class CensusModel {
@JsonProperty(value="block_size")
private String blockSize;
@JsonProperty(value="trans_total")
private String transTotal;
@JsonProperty(value="trans_number")
private String transNumber;
@JsonProperty(value="block_number")
private String blockNumber;
private String tps;
private String difficulty;
@JsonProperty(value="address_number")
private String addressNumber;
}
......@@ -3,6 +3,12 @@ package com.wuban.tron.explore.param.response;
import lombok.Builder;
import lombok.Data;
/**
* <core>交易统计图表MODEL</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
@Builder
public class ChartModel {
......
......@@ -2,6 +2,12 @@ package com.wuban.tron.explore.param.response;
import lombok.Data;
/**
* <core>首页图标MODEL</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class HomeChartModel {
......
......@@ -47,6 +47,19 @@ public interface AddressService {
*/
PageInfo<Address> selectByPager(Integer startIndex, Integer pageSize, AddressExample example);
/**
* 根据条件检索账户信息
*
* @param example 检索条件
* @return
*/
List<Address> selectByExample(@Param("example") AddressExample example);
/**
* 账户总记录数
*
* @return
*/
Integer countByPager();
}
package com.wuban.tron.explore.service;
import com.wuban.tron.explore.entity.Census;
/**
* <core>数据统计接口</core>
*
* @author sky
* @date 2020/11/24
*/
public interface CensusService {
/**
* 添加、更新数据统计信息
*
* @param census
*/
void saveOrUpdateCensus(Census census);
/**
* 更新账户总记录数
*/
void updateTotalAccount();
/**
* 获取统计信息
*
* @return
*/
Census selectOneByExample();
}
......@@ -64,4 +64,9 @@ public class AddressServiceImpl implements AddressService {
return this.addressRepository.selectByExample(example);
}
@Override
public Integer countByPager() {
return this.addressRepository.countByPager(null);
}
}
package com.wuban.tron.explore.service.impl;
import com.wuban.tron.explore.dao.AddressRepository;
import com.wuban.tron.explore.dao.CensusRepository;
import com.wuban.tron.explore.entity.Census;
import com.wuban.tron.explore.service.CensusService;
import com.wuban.tron.explore.util.BigDecimalUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
/**
* <core>数据统计接口实现类</core>
*
* @author sky
* @date 2020/11/24
*/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class CensusServiceImpl implements CensusService {
private final CensusRepository censusRepository;
private final AddressRepository addressRepository;
@Override
@Transactional(rollbackFor = Exception.class)
public void saveOrUpdateCensus(Census census) {
Census obj = this.censusRepository.selectOneByExample(null);
if (obj == null) {
this.censusRepository.insert(census);
return;
}
long totalTrans = 0;
if (census.getTotalTrans() != null) {
totalTrans = obj.getTotalTrans() + census.getTotalTrans();
}
long totalBlockSize = 0;
if (census.getTotalBlockSize() != null) {
BigDecimal bg = BigDecimalUtil.getAdd(new BigDecimal(obj.getTotalBlockSize()), new BigDecimal(census.getTotalBlockSize()));
totalBlockSize = bg.longValue();
}
if (totalTrans != 0) {
obj.setTotalTrans(totalTrans);
}
if (totalBlockSize != 0) {
obj.setTotalBlockSize(totalBlockSize);
}
this.censusRepository.updateById(obj);
}
@Override
public void updateTotalAccount() {
Integer totalAccount = this.addressRepository.countByPager(null);
Census obj = this.censusRepository.selectOneByExample(null);
Census census = new Census();
if (obj == null) {
census.setTotalTrans(0L);
census.setTotalBlockSize(0L);
census.setTotalAccount(Long.valueOf(totalAccount));
this.censusRepository.insert(census);
return;
}
obj.setTotalAccount(Long.valueOf(totalAccount));
this.censusRepository.updateById(obj);
}
@Override
public Census selectOneByExample() {
return this.censusRepository.selectOneByExample(null);
}
}
......@@ -78,15 +78,21 @@ public class LastBlockServiceImpl implements LastBlockService {
@Override
public void refresh() {
Integer latestNum = 1;
TronResponseArrayData ret = this.tronService.getBlockByLatestNum(latestNum);
if (ret != null && !CollectionUtils.isEmpty(ret.getBlock())) {
TronResponseData data = ret.getBlock().get(0);
LastBlock record = new LastBlock();
record.setId(1L);
record.setLastBlockNum(data.getBlock_header().getRaw_data().getNumber());
this.lastBlockRepository.updateById(record);
log.info("定时任务-已更新区块高度num:{}",data.getBlock_header().getRaw_data().getNumber());
try {
TronResponseArrayData ret = this.tronService.getBlockByLatestNum(latestNum);
if (ret != null && !CollectionUtils.isEmpty(ret.getBlock())) {
TronResponseData data = ret.getBlock().get(0);
LastBlock record = new LastBlock();
record.setId(1L);
record.setLastBlockNum(data.getBlock_header().getRaw_data().getNumber());
this.lastBlockRepository.updateById(record);
log.info("定时任务-已更新区块高度num:{}",data.getBlock_header().getRaw_data().getNumber());
}
} catch (Exception e) {
log.error("定时任务-抓取区块高度失败");
}
}
/**
......@@ -109,25 +115,33 @@ public class LastBlockServiceImpl implements LastBlockService {
String redisBlockNum = this.stringRedisTemplate.opsForValue().get(Constant.BLOCK_NUM_KEY);
if (StringUtils.isEmpty(redisBlockNum)) {
startNum = lastBlock.getCurBlockNum();
bg = BigDecimalUtil.getAdd(new BigDecimal(lastBlock.getCurBlockNum()), new BigDecimal(Constant.FIFTY_THOUSAND));
bg = BigDecimalUtil.getAdd(new BigDecimal(lastBlock.getCurBlockNum()), new BigDecimal(Constant.FIVE_THOUSAND));
} else {
startNum = Long.parseLong(redisBlockNum);
long size = this.stringRedisTemplate.opsForList().size(Constant.BLOCK_NUM_LIST_KEY);
if (size - Constant.THRESHOLD > 0) {
return;
}
bg = BigDecimalUtil.getAdd(new BigDecimal(redisBlockNum), new BigDecimal(Constant.FIFTY_THOUSAND));
bg = BigDecimalUtil.getAdd(new BigDecimal(redisBlockNum), new BigDecimal(Constant.FIVE_THOUSAND));
}
diff = BigDecimalUtil.getSubtract(bg, new BigDecimal(lastBlock.getLastBlockNum()));
// 判断已缓存 + BLOCK_NUM_KEY 是否超过区块的最大高度值
if (diff.longValue() < 0) {
this.stringRedisTemplate.opsForValue().set(Constant.BLOCK_NUM_KEY, bg.toPlainString());
endNum = bg.longValue();
} else {
// 替换掉"-"号,相当于去绝对值
endNum = lastBlock.getLastBlockNum() - 1;
}
if (startNum == endNum) {
return;
}
if (diff.longValue() < 0) {
this.stringRedisTemplate.opsForValue().set(Constant.BLOCK_NUM_KEY, bg.toPlainString());
} else {
this.stringRedisTemplate.opsForValue().set(Constant.BLOCK_NUM_KEY, lastBlock.getLastBlockNum().toString());
endNum = lastBlock.getLastBlockNum();
}
// 将区块高度同步到redis list中
......@@ -138,7 +152,6 @@ public class LastBlockServiceImpl implements LastBlockService {
for (long i = startNum; i <= endNum; i++) {
conn.lPush(Constant.BLOCK_NUM_LIST_KEY, Long.toString(i));
}
//log.info("sync redis block num start={},end={}", startNum, endNum);
return null;
}
});
......
......@@ -64,6 +64,7 @@ public class TransactionServiceImpl implements TransactionService {
List<BlockHeader> headerList = new ArrayList<>(dataList.size());
List<Transaction> transactionList = new ArrayList<>(dataList.size());
List<TransactionHex> hexList = new ArrayList<>(dataList.size());
dataList.forEach(o -> {
TronBlockHeader tronBlockHeader = o.getBlock_header();
BlockHeader header = transferBlockHeader(o.getBlockID(), tronBlockHeader);
......@@ -77,15 +78,8 @@ public class TransactionServiceImpl implements TransactionService {
transactionList.addAll(list);
// hex设置
TransactionHex hex = new TransactionHex();
trList.forEach(obj -> {
hex.setBlockId(o.getBlockID());
hex.setTxId(obj.getTxID());
hex.setHex(obj.getRaw_data_hex());
hex.setSignature(obj.getSignature().get(0));
hex.setCreateTime(new Date());
hexList.add(hex);
});
List<TransactionHex> tmpList = transferTransactionHex(o.getBlockID(), trList);
hexList.addAll(tmpList);
}
// 区块bytes设置
......@@ -99,13 +93,17 @@ public class TransactionServiceImpl implements TransactionService {
headerList.add(header);
});
Integer censusTransNumber = 0;
String censusBlockSize = headerList.get(0).getBlockBytes();
/*
区块头、区块交易、hex持久化
*/
this.blockHeaderRepository.batchInsert(headerList);
Set<String> hexSet = new HashSet<>();
Set<String> base58Set = new HashSet<>();
Set<String> base58Set = new HashSet<>();
if (transactionList.size() != 0) {
censusTransNumber = transactionList.size();
transactionList.forEach(o -> {
// hex 数据转换成base58
String ownerAddress;
......@@ -132,6 +130,7 @@ public class TransactionServiceImpl implements TransactionService {
});
this.transactionRepository.batchInsert(transactionList);
this.transactionHexRepository.batchInsert(hexList);
}
// 更新区块高度
......@@ -146,10 +145,17 @@ public class TransactionServiceImpl implements TransactionService {
this.addressRepository.batchInsertOnDuplicateKey(records);
addressPushRedis(hexSet);
}
// 数据统计
this.censusFlushRedis(censusBlockSize, censusTransNumber);
}
}
/**
* 账户地址同步到redis
* @param set
*/
private void addressPushRedis(Set<String> set) {
stringRedisTemplate.executePipelined(new RedisCallback<Object>() {
@Override
......@@ -242,6 +248,31 @@ public class TransactionServiceImpl implements TransactionService {
return retList;
}
private List<TransactionHex> transferTransactionHex(String blockId, List<Transactions> trList) {
List<TransactionHex> hexList = new ArrayList<>();
TransactionHex hex = new TransactionHex();
trList.forEach(obj -> {
hex.setBlockId(blockId);
hex.setTxId(obj.getTxID());
hex.setHex(obj.getRaw_data_hex());
hex.setSignature(obj.getSignature().get(0));
hex.setCreateTime(new Date());
hexList.add(hex);
});
return hexList;
}
private void censusFlushRedis(String blockSize, Integer transNumber) {
if (!StringUtils.isEmpty(blockSize) && !blockSize.equals("0")) {
this.stringRedisTemplate.opsForList().leftPush(Constant.CENSUS_BLOCK_SIZE, blockSize);
}
if (transNumber != 0) {
this.stringRedisTemplate.opsForList().leftPush(Constant.CENSUS_TRANS, transNumber.toString());
}
}
@Override
public Long getBlockMinTime() {
return this.blockHeaderRepository.selectBlockMinTime();
......
package com.wuban.tron.explore.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.wuban.tron.explore.constant.Constant;
import com.wuban.tron.explore.domain.TronAccount;
import com.wuban.tron.explore.domain.TronResponseArrayData;
import com.wuban.tron.explore.domain.TronResponseData;
import com.wuban.tron.explore.service.BaseCommonService;
import com.wuban.tron.explore.service.TronService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Request;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
......@@ -20,12 +24,18 @@ import java.util.Map;
* @date 2020/11/02
*/
@Service
@Slf4j
public class TronServiceImpl extends BaseCommonService implements TronService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public TronResponseData getBlockByNum(Long blockNum) {
String str = this.analysisBlock(GET_BLOCK_BYNUM, blockNum);
if (StringUtils.isEmpty(str)) {
stringRedisTemplate.opsForList().leftPush(Constant.BLOCK_NUM_LIST_KEY, blockNum.toString());
log.warn("区块高度blockNum:{}抓取失败,重新放置到队列中.", blockNum);
return null;
}
......@@ -64,6 +74,8 @@ public class TronServiceImpl extends BaseCommonService implements TronService {
Request request = this.builder(GET_ACCOUNT, map);
String str = this.execute(request);
if (StringUtils.isEmpty(str)) {
this.stringRedisTemplate.opsForSet().add(Constant.ADDRESS_KEY, address);
log.warn("账户余额address:{}抓取失败,重新放置到队列中.", address);
return null;
}
......
......@@ -20,6 +20,11 @@ public class BigDecimalUtil {
return bg1.divide(bg2, mc);
}
public static BigDecimal getDevide(int scale, BigDecimal bg1, BigDecimal bg2){
MathContext mc = new MathContext(scale, RoundingMode.HALF_DOWN);
return bg1.divide(bg2, mc);
}
public static BigDecimal getMultiply(BigDecimal bg1, BigDecimal bg2){
MathContext mc = new MathContext(SCALE, RoundingMode.HALF_UP);
return bg1.multiply(bg2, mc);
......
......@@ -7,7 +7,7 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://123.56.5.114:13306/test_tron?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
url: jdbc:mysql://123.56.5.114:13306/tron-explore?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root123456
# 初始化大小,最小,最大
......@@ -38,4 +38,4 @@ spring:
min-idle: 100
timeout: 10000
password: 123456
database: 2
\ No newline at end of file
database: 6
\ No newline at end of file
......@@ -7,7 +7,7 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://123.56.5.114:13306/test_tron?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
url: jdbc:mysql://123.56.5.114:13306/tron-explore?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root123456
# 初始化大小,最小,最大
......@@ -38,4 +38,4 @@ spring:
min-idle: 100
timeout: 10000
password: 123456
database: 2
\ No newline at end of file
database: 4
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.wuban.tron.explore.dao.CensusRepository">
<!-- CodeBuilder Generated-->
<resultMap id="CensusMap" type="com.wuban.tron.explore.entity.Census">
<id column="id" property="id" jdbcType="BIGINT" />
<result column="total_trans" property="totalTrans" jdbcType="BIGINT" />
<result column="total_block_size" property="totalBlockSize" jdbcType="BIGINT" />
<result column="total_account" property="totalAccount" jdbcType="BIGINT" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" suffix=")" prefixOverrides="and">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach collection="criterion.value" item="listItem" open="(" close=")"
separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Table_Name">tron_census</sql>
<sql id="Base_Column_List_Without_Id">
total_trans , total_block_size , total_account </sql>
<sql id="Base_Column_List">
id ,
<include refid="Base_Column_List_Without_Id"/>
</sql>
<sql id="Insert_Columns">
<if test="record.totalTrans != null">total_trans,</if>
<if test="record.totalBlockSize != null">total_block_size,</if>
<if test="record.totalAccount != null">total_account,</if>
</sql>
<sql id="Insert_Values">
<if test="record.totalTrans != null">#{record.totalTrans,jdbcType=BIGINT},</if>
<if test="record.totalBlockSize != null">#{record.totalBlockSize,jdbcType=BIGINT},</if>
<if test="record.totalAccount != null">#{record.totalAccount,jdbcType=BIGINT},</if>
</sql>
<sql id="Batch_Insert_Values">
#{record.totalTrans,jdbcType=BIGINT},
#{record.totalBlockSize,jdbcType=BIGINT},
#{record.totalAccount,jdbcType=BIGINT},
</sql>
<sql id="Batch_Insert_Values_On_DuplicateKey">
#{record.id,jdbcType=BIGINT},
<include refid="Batch_Insert_Values"/>
</sql>
<sql id="Update_Set_From_Bean">
<if test="record.totalTrans != null">total_trans = #{record.totalTrans,jdbcType=BIGINT} ,</if>
<if test="record.totalBlockSize != null">total_block_size = #{record.totalBlockSize,jdbcType=BIGINT} ,</if>
<if test="record.totalAccount != null">total_account = #{record.totalAccount,jdbcType=BIGINT} ,</if>
</sql>
<!-- insert -->
<insert id="insert" parameterType="java.util.Map">
<selectKey resultType="java.lang.Long" keyProperty="record.id" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into <include refid="Table_Name"/>
<trim prefix="(" suffix=")" suffixOverrides=",">
<include refid="Insert_Columns"/>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<include refid="Insert_Values"/>
</trim>
</insert>
<insert id="batchInsert" parameterType="java.util.Map">
insert into <include refid="Table_Name"/>
<trim prefix="(" suffix=")" suffixOverrides=",">
<include refid="Base_Column_List_Without_Id"/>
</trim>
values
<foreach collection="records" item="record" index="index" separator=",">
<trim prefix="(" suffix=")" suffixOverrides=",">
<include refid="Batch_Insert_Values"/>
</trim>
</foreach>
</insert>
<insert id="batchInsertOnDuplicateKey" parameterType="java.util.Map">
insert into <include refid="Table_Name"/>
<trim prefix="(" suffix=")" suffixOverrides=",">
<include refid="Base_Column_List"/>
</trim>
values
<foreach collection="records" item="record" index="index" separator=",">
<trim prefix="(" suffix=")" suffixOverrides=",">
<include refid="Batch_Insert_Values_On_DuplicateKey"/>
</trim>
</foreach>
ON DUPLICATE KEY UPDATE
total_trans = VALUES(total_trans),total_block_size = VALUES(total_block_size) ,total_account = VALUES(total_account)
</insert>
<!-- end insert -->
<!-- delete -->
<delete id="deleteById" parameterType="java.util.Map">
delete from <include refid="Table_Name"/> where id = #{id,jdbcType=BIGINT}
</delete>
<delete id="deleteByExample" parameterType="java.util.Map">
delete from <include refid="Table_Name"/>
<if test="example != null">
<include refid="Example_Where_Clause"/>
</if>
</delete>
<delete id="deleteIn" parameterType="java.util.Map">
delete from <include refid="Table_Name"/> where id in
<foreach collection="records" item="record" index="index" open="(" separator="," close=")">
#{record.id,jdbcType=BIGINT}
</foreach>
</delete>
<!-- end delete -->
<!-- update -->
<update id="updateById" parameterType="java.util.Map">
update <include refid="Table_Name"/>
<set>
<include refid="Update_Set_From_Bean"/>
</set>
where id = #{record.id,jdbcType=BIGINT}
</update>
<update id="updateByExample" parameterType="java.util.Map">
update <include refid="Table_Name"/>
<set>
<include refid="Update_Set_From_Bean"/>
</set>
<if test="example != null">
<include refid="Example_Where_Clause"/>
</if>
</update>
<update id="batchUpdate" parameterType="java.util.Map">
<foreach collection="records" item="record" index="index" open="" close="" separator=";">
update <include refid="Table_Name"/>
<set>
<include refid="Update_Set_From_Bean"/>
</set>
where id=#{record.id,jdbcType=BIGINT}
</foreach>
</update>
<!-- end update -->
<!-- select -->
<select id="selectById" resultMap="CensusMap" parameterType="java.util.Map">
select
<include refid="Base_Column_List"/>
from <include refid="Table_Name"/>
where id = #{id,jdbcType=BIGINT}
</select>
<select id="selectByExample" resultMap="CensusMap" parameterType="java.util.Map">
select
<if test="example != null and example.distinct">
distinct
</if>
<include refid="Base_Column_List"/>
from <include refid="Table_Name"/>
<if test="example != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="example != null and example.orderByClause != null">
order by ${example.orderByClause}
</if>
</select>
<select id="selectOneByExample" resultMap="CensusMap" parameterType="java.util.Map">
select
<include refid="Base_Column_List"/>
from <include refid="Table_Name"/>
<if test="example != null">
<include refid="Example_Where_Clause"/>
</if>
limit 1
for update
</select>
<select id="selectIn" resultMap="CensusMap" parameterType="java.util.Map">
select
<include refid="Base_Column_List"/>
from <include refid="Table_Name"/>
where id IN
<foreach collection="records" item="record" index="index" open="(" separator="," close=")">
#{record.id,jdbcType=BIGINT}
</foreach>
</select>
<select id="countByExample" resultType="java.lang.Integer" parameterType="java.util.Map">
select count(*) as total from <include refid="Table_Name"/>
<if test="example != null">
<include refid="Example_Where_Clause"/>
</if>
</select>
<select id="countByPager" resultType="java.lang.Integer" parameterType="java.util.Map">
select count(*) as total from <include refid="Table_Name"/>
<if test="example != null">
<include refid="Example_Where_Clause"/>
</if>
</select>
<select id="selectByPager" resultMap="CensusMap" parameterType="java.util.Map">
select
<include refid="Base_Column_List"/>
from <include refid="Table_Name"/>
<if test="example != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="pager.sortItem != null and pager.sortItem != '' ">
order by ${pager.sortItem} ${pager.sortType}
</if>
limit #{pager.startIndex} , #{pager.pageSize}
</select>
<!-- end select -->
<!-- My Custom Interfaces -->
</mapper>
package com.wuban.tron.explore.service.impl;
import com.wuban.tron.explore.BaseTest;
import com.wuban.tron.explore.entity.Census;
import com.wuban.tron.explore.service.CensusService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.jupiter.api.Assertions.*;
class CensusServiceImplTest extends BaseTest {
@Autowired
private CensusService censusService;
Census census;
@BeforeEach
void setUp() {
census = Census.getInstance();
}
@Test
void saveOrUpdateCensus() {
this.censusService.saveOrUpdateCensus(census);
census.setTotalBlockSize(1000L);
census.setTotalTrans(1L);
census.setTotalAccount(20L);
this.censusService.saveOrUpdateCensus(census);
}
}
\ No newline at end of file
......@@ -90,7 +90,7 @@ CREATE TABLE `tron_last_block` (
-- ----------------------------
-- Records of tron_last_block
-- ----------------------------
INSERT INTO `tron_last_block` VALUES ('1', '8000000', '9585054');
INSERT INTO `tron_last_block` VALUES ('1', '1', '1');
-- ----------------------------
-- Table structure for `tron_transaction`
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment