@Data public abstract class Watcher implements Runnable{ private Logger logger = LoggerFactory.getLogger(Watcher.class); private boolean stop = false; //默认同步间隔20秒 private Long checkInterval = 2000L; private Long currentBlockHeight = 0L; private int step = 5; //区块确认数 private int confirmation = 3; private DepositEvent depositEvent; private Coin coin; private WatcherLogService watcherLogService; public void check(){ try { Long networkBlockNumber = getNetworkBlockHeight() - confirmation + 1; if (currentBlockHeight < networkBlockNumber) { long startBlockNumber = currentBlockHeight + 1; currentBlockHeight = (networkBlockNumber - currentBlockHeight > step) ? currentBlockHeight + step : networkBlockNumber; logger.info("replay block from {} to {}", startBlockNumber, currentBlockHeight); List<Deposit> deposits = replayBlock(startBlockNumber, currentBlockHeight); if(deposits != null) { deposits.forEach(deposit -> { depositEvent.onConfirmed(deposit); }); //记录日志 watcherLogService.update(coin.getName(), currentBlockHeight); }else { logger.info("扫块失败!!!"); // 未扫描成功 currentBlockHeight = startBlockNumber - 1; } } else { logger.info("Already latest height: {}, networkBlockHeight: {},nothing to do!", currentBlockHeight, networkBlockNumber); } } catch (Exception e){ e.printStackTrace(); } } public abstract List<Deposit> replayBlock(Long startBlockNumber, Long endBlockNumber); public abstract Long getNetworkBlockHeight(); @Override public void run() { stop = false; long nextCheck = 0; while(!(Thread.interrupted() || stop)) { if (nextCheck <= System.currentTimeMillis()) { try { nextCheck = System.currentTimeMillis() + checkInterval; logger.info("check..."); check(); } catch (Exception ex) { logger.info(ex.getMessage()); } } else { try { Thread.sleep(Math.max(nextCheck - System.currentTimeMillis(), 100)); } catch (InterruptedException ex) { logger.info(ex.getMessage()); } } } } }
//////////////////////////////////////////////////////////
@Component public class BitcoinWatcher extends Watcher{ @Autowired private BitcoinRPCClient rpcClient; @Autowired private AccountService accountService; private Logger logger = LoggerFactory.getLogger(Watcher.class); @Override public List<Deposit> replayBlock(Long startBlockNumber, Long endBlockNumber) { List<Deposit> deposits = new ArrayList<Deposit>(); try { for (Long blockHeight = startBlockNumber; blockHeight <= endBlockNumber; blockHeight++) { String blockHash = rpcClient.getBlockHash(blockHeight.intValue()); //获取区块 Bitcoin.Block block = rpcClient.getBlock(blockHash); List<String> txids = block.tx(); logger.info("获取区块(" + blockHeight + ")交易列表,总交易数:" + txids.size() + ""); //遍历区块中的交易 for(String txid:txids){ Bitcoin.RawTransaction transaction = rpcClient.getRawTransaction(txid); List<Bitcoin.RawTransaction.Out> outs = transaction.vOut(); if(outs != null) { for (Bitcoin.RawTransaction.Out out : outs) { if (out.scriptPubKey() != null) { List<String> addresses = out.scriptPubKey().addresses(); if(addresses != null && addresses.size() > 0) { String address = out.scriptPubKey().addresses().get(0); BigDecimal amount = new BigDecimal(out.value()); if (accountService.isAddressExist(address)) { logger.info("发现充值地址(" + address + "),充值金额:" + amount + " BTC"); Deposit deposit = new Deposit(); deposit.setTxid(transaction.txId()); deposit.setBlockHeight((long) block.height()); deposit.setBlockHash(transaction.blockHash()); deposit.setAmount(amount); deposit.setAddress(address); deposit.setTime(transaction.time()); deposits.add(deposit); } } } } } } } } catch (Exception e){ e.printStackTrace(); return null; } return deposits; } @Override public Long getNetworkBlockHeight() { try { return Long.valueOf(rpcClient.getBlockCount()); } catch (Exception e){ e.printStackTrace(); return 0L; } } }
全部评论