Commit 25af91cc authored by jianhua.zhang's avatar jianhua.zhang

波场浏览器JAVA版

parents
package com.wuban.tron.explore;
import com.wuban.tron.explore.fetch.Engine;
import com.wuban.tron.explore.service.LastBlockService;
import com.wuban.tron.explore.service.TransactionService;
import com.wuban.tron.explore.util.DateUtil;
import com.wuban.tron.explore.util.SpringContextUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* <core>区块服务引导项</core>
*
* @author sky
* @date 2020/11/04
*/
@Slf4j
//@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class Bootstrapper {
private final SpringContextUtil springContextUtil;
private final LastBlockService lastBlockService;
private final TransactionService transactionService;
/**
* 定时任务 - 业务线程池
*/
private ScheduledThreadPoolExecutor executorService;
private void init() {
this.executorService = new ScheduledThreadPoolExecutor(3, new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(final Runnable r) {
final Thread t = new Thread(r, "schedule-business" + this.threadNumber.getAndIncrement());
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
});
}
@PostConstruct
public synchronized void start() {
this.init();
this.startEngine();
this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.sync(), 0, 30, TimeUnit.MINUTES);
this.executorService.scheduleWithFixedDelay(() -> this.lastBlockService.refresh(), 1, 1, TimeUnit.MINUTES);
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) - System.currentTimeMillis())/1000;
return millis;
}
private synchronized void startEngine() {
/*try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
Engine engine = new Engine("tron");
engine.start();
}
}
package com.wuban.tron.explore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ExploreApplication {
public static void main(String[] args) {
SpringApplication.run(ExploreApplication.class, args);
}
}
package com.wuban.tron.explore.constant;
import okhttp3.MediaType;
/**
* <core>常量定义类</core>
*
* @author sky
* @date 2020/11/02
*/
public class Constant {
/**
* 结果码:
*/
public static final int SUCCESS_CODE = 200;
/**
* 波场API地址
*/
public static final String HOST = "https://api.shasta.trongrid.io";
/**
* 请求数据类型:JSON
*/
public static final MediaType JSON_TYPE = MediaType.parse("application/json");
public static final String CONTENT_TYPE_KEY = "Content-Type";
public static final String CONTENT_TYPE_VAL = "application/json";
public static final String OS_NMAE = "WINDOWS";
public static final long FIFTY_THOUSAND = 50000;
public static final String BLOCK_NUM_KEY = "block_num";
public static final String BLOCK_NUM_LIST_KEY = "block_num_list";
/**
* 数据同步阀值
*/
public static final long THRESHOLD = 30000;
/**
* 用户地址长度
*/
public static final int USER_ADDRESS_LEN = 42;
/**
* txID长度
*/
public static final int TX_ID_LEN = 64;
public static final String EXCUTOR_NAME_ACCOUNT = "tron.account";
public static final String EXCUTOR_NAME_BLOCK = "tron.block";
}
package com.wuban.tron.explore.constant;
public enum HomeSearchTypeEnum {
ADDRESS_INFO(0,"地址详情"),
TRANSACTION_INFO(1, "交易详情"),
BLOCK_INFO(2,"区块详情");
private int code;
private String desc;
HomeSearchTypeEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
}
package com.wuban.tron.explore.constant;
public class PageConstant {
/**
* 页码默认值:1
*/
public static final int DEFAULT_START_INDEX = 1;
/**
* 每页记录数:10
*/
public static final int DEFAULT_PAGE_SIZE = 10;
/**
* 每页记录数最大值:10
*/
public static final int MAX_PAGE_SIZE = 100;
}
package com.wuban.tron.explore.controller;
import com.wuban.tron.explore.param.request.CensusRequest;
import com.wuban.tron.explore.service.TransactionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@Slf4j
@RestController
@RequestMapping("/census")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class CensusController {
private final TransactionService transactionService;
@RequestMapping(method = RequestMethod.POST)
public void census(@RequestBody @Valid CensusRequest reqParam) {
new Thread(()->this.transactionService.censusBlockByDate(reqParam.getStartDate(), reqParam.getEndDate())).start();
}
}
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.Address;
import com.wuban.tron.explore.entity.example.AddressExample;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface AddressRepository {
/**
* 批量添加、更新账户地址信息
*
* @param records
*/
void batchInsertOnDuplicateKey(@Param("records") List<Address> records);
/**
* 获取账户地址信息
*
* @param example 查询条件参数
* @return 记录
*/
Address selectOneByExample(@Param("example") AddressExample example);
/**
* 修改账户信息
*
* @param record
*/
void updateById(@Param("record") Address record);
}
\ No newline at end of file
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.BlockDayCensus;
import com.wuban.tron.explore.entity.example.BlockDayCensusExample;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface BlockDayCensusRepository {
int insert(@Param("record") BlockDayCensus record);
/**
* 按照时间统计区块信息
*
* @param start 开始时间秒
* @param end 结束时间秒
* @return BlockDayCensus
*/
BlockDayCensus censusBlockByTime(@Param("start") Long start, @Param("end") Long end);
/**
* 分页查询
*
* @param example 查询条件参数
* @return 分页记录列表
*/
List<BlockDayCensus> selectByPager(@Param("example") BlockDayCensusExample example);
/**
* 根据条件检索列表数据
*
* @param example 查询条件参数
* @return 记录列表
*/
List<BlockDayCensus> selectByExample(@Param("example") BlockDayCensusExample example);
}
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.BlockHeader;
import com.wuban.tron.explore.entity.example.BlockHeaderExample;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface BlockHeaderRepository {
int insert(@Param("record") BlockHeader record);
/**
* 批量:持久化区块头信息
* @param records 区块头信息
* @return
*/
int batchInsert(@Param("records") List<BlockHeader> records);
/**
* 获取所有区块头中最小时间
*
* @return 时间
*/
Long selectBlockMinTime();
/**
* 根据条件检索区块头信息
*
* @param example 检索条件
* @return
*/
BlockHeader selectOneByExample(@Param("example")BlockHeaderExample example);
}
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.LastBlock;
import com.wuban.tron.explore.entity.example.LastBlockExample;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface LastBlockRepository {
LastBlock selectByIdForUpdate(@Param("id") Long id);
LastBlock selectOneByExample(@Param("example") LastBlockExample example);
int updateById(@Param("record") LastBlock record);
int updateCurBlockNumById(@Param("record") LastBlock record);
}
\ No newline at end of file
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.TransactionHex;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TransactionHexRepository {
int insert(@Param("record") TransactionHex record);
int batchInsert(@Param("records") List<TransactionHex> records);
}
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.Transaction;
import com.wuban.tron.explore.entity.example.TransactionExample;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TransactionRepository {
int insert(@Param("record") Transaction record);
int batchInsert(@Param("records") List<Transaction> records);
/**
* 分页查询
*
* @param example 查询条件参数
* @return 分页记录列表
*/
List<Transaction> selectByPagerEx(@Param("example") TransactionExample example);
/**
* 根据条件检索
*
* @param example 检索条件
* @return
*/
List<Transaction> selectByExample(@Param("example") TransactionExample example);
/**
* 根据账户地址查询交易信息
*
* @param address 账户地址
*
* @param timestamp
*
* @return
*/
List<Transaction> selectListByAddress(@Param("address") String address, @Param("t") long timestamp);
}
package com.wuban.tron.explore.dao.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
/**
* @author sky
*
*/
@Configuration
@MapperScan(basePackages = "com.wuban.tron.explore.dao", sqlSessionTemplateRef = "sqlSessionTemplateEX")
public class DataSourceConfigEX {
@Value("${spring.datasource.type}")
private Class<? extends DataSource> dataSourceType;
@Bean(name = "dataSourceEX")
@ConfigurationProperties(prefix = "spring.datasource")
@Primary
public DataSource buildDataSource() {
return DataSourceBuilder.create().type(this.dataSourceType).build();
}
@Bean(name = "sqlSessionFactoryEX")
@Primary
public SqlSessionFactory buildSqlSessionFactory(@Qualifier("dataSourceEX") final DataSource dataSource)
throws Exception {
final SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setConfigLocation(
new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mybatis-config.xml"));
bean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
return bean.getObject();
}
@Bean(name = "transactionManagerEX")
@Primary
public DataSourceTransactionManager buildTransactionManager(
@Qualifier("dataSourceEX") final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "sqlSessionTemplateEX")
@Primary
public SqlSessionTemplate buildSqlSessionTemplate(
@Qualifier("sqlSessionFactoryEX") final SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
\ No newline at end of file
package com.wuban.tron.explore.domain;
import lombok.Data;
import java.util.List;
@Data
public class ActivePermission {
private String type;
private Integer id;
private String permission_name;
private Integer threshold;
private String operations;
private List<Keys> keys;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
/**
* <core>区块头信息类</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class BlockHeaderRawData {
private Long number;
private String txTrieRoot;
private String witness_address;
private String parentHash;
private Integer version;
private Long timestamp;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
@Data
public class Contract {
private ContractParameter parameter;
private String type;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
@Data
public class ContractParameter {
private ContractParameterValue value;
private String type_url;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
@Data
public class ContractParameterValue {
private String owner_address;
private Long amount;
private String to_address;
private String data;
private String contract_address;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
@Data
public class Keys {
private String address;
private Integer weight;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
import java.util.List;
@Data
public class OwnerPermission {
private String permission_name;
private Integer threshold;
private List<Keys> keys;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
import java.util.List;
/**
* <core>区块交易信息类</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class Transactions {
private List<TransactionsRet> ret;
private List<String> signature;
private String txID;
private String raw_data_hex;
private TransactionsRawData raw_data;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
import java.util.List;
@Data
public class TransactionsRawData {
private List<Contract> contract;
private String ref_block_bytes;
private String ref_block_hash;
private Long expiration;
private Long timestamp;
private Long fee_limit;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
@Data
public class TransactionsRet {
private String contractRet;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
@Data
public class TronAccount {
private String address;
private Long balance;
/* private Long create_time;
private Long latest_opration_time;
private Long latest_consume_free_time;
private ActivePermission active_permission;
private OwnerPermission owner_permission;*/
}
package com.wuban.tron.explore.domain;
import lombok.Data;
@Data
public class TronBlockHeader {
private BlockHeaderRawData raw_data;
private String witness_signature;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
import java.util.List;
/**
* <core>波场区块服务响应结果类</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class TronResponseArrayData {
private List<TronResponseData> block;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
import java.util.List;
/**
* <core>波场区块服务响应结果类</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class TronResponseData {
private String blockID;
private TronBlockHeader block_header;
private List<Transactions> transactions;
}
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-09
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Address {
/**
* 账户地址
*/
private String address;
/**
* 余额
*/
private Long balance;
public static Address getInstance() {
return Address.builder()
.address("")
.balance(0L)
.build();
}
}
\ No newline at end of file
package com.wuban.tron.explore.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
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-04
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class BlockDayCensus {
/**
*
*/
private Long id;
/**
* 生成区块的平均时间
*/
private Long genBlockAverTime;
/**
* 生成区块总量
*/
private Integer genBlockTotalNum;
/**
* 总交易量
*/
private Integer totalVolume;
/**
* 统计日期
*/
private String censusDate;
private Integer totalBlockBytes;
private Integer averBlockBytes;
/**
*
*/
@JsonIgnore
private Date createTime;
public static BlockDayCensus getInstance() {
return BlockDayCensus.builder()
.id(0L)
.genBlockAverTime(0L)
.genBlockTotalNum(0)
.totalVolume(0)
.censusDate("")
.totalBlockBytes(0)
.averBlockBytes(0)
.createTime(null)
.build();
}
}
\ No newline at end of file
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-03
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class BlockHeader {
/**
*
*/
private Long id;
/**
* 区块ID
*/
private String blockId;
/**
* 区块高度
*/
private Long number;
/**
*
*/
private String txTrieRoot;
/**
*
*/
private String witnessAddress;
/**
* 父hash
*/
private String parentHash;
/**
* 版本号
*/
private Integer version;
/**
* 区块时间戳
*/
private Long timestamp;
/**
*
*/
private String witnessSignature;
/**
* 交易量
*/
private Integer transactionVolume;
/**
* 创建时间
*/
private Date createTime;
/**
* 块大小
*/
private String blockBytes;
public static BlockHeader getInstance() {
return BlockHeader.builder()
.id(0L)
.blockId("")
.number(0L)
.txTrieRoot("")
.witnessAddress("")
.parentHash("")
.version(0)
.timestamp(0L)
.witnessSignature("")
.transactionVolume(0)
.createTime(new Date())
.blockBytes("")
.build();
}
}
\ No newline at end of file
package com.wuban.tron.explore.entity;
import lombok.*;
/**
*
* @author sky
* @date 2020-11-02
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class LastBlock {
/**
* 唯一标识
*/
private Long id;
/**
* 系统已设置的区块高度
*/
private Long curBlockNum;
/**
* 波场最新的区块高度
*/
private Long lastBlockNum;
}
\ No newline at end of file
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-03
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Transaction {
/**
*
*/
private Long id;
/**
* 区块ID
*/
private String blockId;
/**
* 交易ID
*/
private String txId;
/**
* 交易结果
*/
private String contractRet;
/**
* 交易地址FROM
*/
private String ownerAddress;
/**
* 合约数据
*/
private String data;
/**
* 合约地址
*/
private String contractAddress;
/**
* 交易额
*/
private Long amount;
/**
* 交易地址TO
*/
private String toAddress;
/**
*
*/
private String typeUrl;
/**
*
*/
private String type;
/**
*
*/
private String refBlockBytes;
/**
*
*/
private String refBlockHash;
/**
*
*/
private Long expiration;
/**
*
*/
private Long feeLimit;
/**
*
*/
private Long timestamp;
/**
* 创建时间
*/
private Date createTime;
private Long number;
public static Transaction getInstance() {
return Transaction.builder()
.id(0L)
.blockId("")
.txId("")
.contractRet("")
.ownerAddress("")
.data("")
.contractAddress("")
.amount(0L)
.toAddress("")
.typeUrl("")
.type("")
.refBlockBytes("")
.refBlockHash("")
.expiration(0L)
.feeLimit(0L)
.timestamp(0L)
.createTime(new Date())
.number(0L)
.build();
}
}
\ No newline at end of file
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;
/**
* 区块交易hex表
* @author sky
* @date 2020-11-03
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class TransactionHex {
/**
*
*/
private Long id;
/**
*
*/
private String hex;
/**
* 区块ID
*/
private String blockId;
/**
* 交易ID
*/
private String txId;
/**
*
*/
private String signature;
/**
* 创建时间
*/
private Date createTime;
public static TransactionHex getInstance() {
return TransactionHex.builder()
.id(0L)
.hex("")
.blockId("")
.txId("")
.signature("")
.createTime(new Date())
.build();
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
package com.wuban.tron.explore.fetch;
import java.util.List;
/**
* <core>区块数据抓取者服务接口方法</core>
*
* @author sky
* @date 2020/11/04
*/
public interface IBlockDataFetcher<T> {
List<T> fetch();
void send(final List<T> orders) throws InterruptedException;
}
This diff is collapsed.
package com.wuban.tron.explore.param.request;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class CensusRequest {
@NotNull
private String startDate;
private String endDate;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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