Java 获取BTC(比特币)充值交易

版权声明:“假装、是个有灵魂的程序员” —— Go Big Or Go Home https://blog.csdn.net/u011663149/article/details/85296858

前言:

   需求:从公链拉取所有交易进行原始交易解析,匹配本地钱包地址根据交易确认数进行充值的确认。

   方案:

  •     初始化区块信息(高度、块hash等)持久化到数据库
  •     根据区块hash从主链获取交易txs
  •     解析txs对比充值钱包地址,存储充值信息、Unspent交易信息
  •     更新数据库里的区块信息
  •     进行线程的循环调用即可

1.初始化区块信息到数据库

@Order(value = 1)
@Service
public class BtcoinChargeServiceImpl implements  CommandLineRunner {
	
	private Logger LOG = LoggerFactory.getLogger("btcoin");
	
	private static final String RECHARSTATE = "0";
	private static final String CURRENTTYPE = "BTC";
 

   //初始化区块信息
	@Override
	public void run(String... arg0) throws Exception {
        //从数据读取信息进行判断
		CoinBlockInfo blockInfo = blockMapper.selectByCoinType("BTC");
		if (null == blockInfo || blockInfo.getBlockHeight() == 0) {
			int blockCount = (int) btcService.getBlockCount();
			String blockHash = btcService.getBlockHash(blockCount).toString();
			LOG.info("=== [BTC] init block height is : {} and block hash is :{} start !! ===", blockCount, blockHash);
			CoinBlockInfo blockInfos = new CoinBlockInfo();
			blockInfos.setBlockHeight(blockCount); //高度
			blockInfos.setBlockHash(blockHash);//块Hash
			blockInfos.setCoinType(CURRENTTYPE);
			blockInfos.setCreateTime(new Date());
			blockInfos.setRemark("first record");
			boolean res = blockMapper.insert(blockInfos) > 0 ? true : false;
			if (res)
				LOG.info("=== [BTC] init block success !!");
		}
	}
 
}

  2.  区块hash从主链获取交易txs并进行解析

//比特币充值交易信息

@Service
public class BtcoinChargeServiceImpl implements BtcoinChargeService{
	
	private Logger LOG = LoggerFactory.getLogger("btcoin");
	
	private static final String RECHARSTATE = "0";
	private static final String CURRENTTYPE = "BTC";
 
	
	//对比确认次数
	public int confirm = 9;
	
 
	
	@Transactional(rollbackFor = CoinException.class)
	@Override
	public Object rechargeRecordFromBlockTx(List<UserAccount> userList) throws CoinException {
		Map<Object, Object> result = new HashMap<Object, Object>();
		try {
			// current block from mysql
			CoinBlockInfo blockInfo = blockMapper.selectByCoinType("BTC");
			int parseBlockCount = blockInfo.getBlockHeight(); 
			int blockCount = (int) btcService.getBlockCount(); 
			String blockHash = null;
			if (parseBlockCount > 0) {
				LOG.info("=== [BTC] the current BTC block height is {}, and the processing block height is {}. ===", blockCount, parseBlockCount);
				if (blockCount > parseBlockCount) {
					int current = parseBlockCount + 1;
					if ((blockCount - parseBlockCount) >= confirm) {
						try {
							blockHash = btcService.getBlockHash(current).toString();
							//LOG.info("=== [BTC] scan block [\theight:{}\t], [\thash:{}\t] begins !!! ===", current, blockHash);
							if (parseTransactionInfo(userList, blockHash, current)) {
								 LOG.info("=== [BTC] end of scan block [\theight:{}\t], [\thash:{}\t] !!! ===", current, blockHash);
								/* current height */
								blockInfo.setBlockHeight(current);
								blockInfo.setBlockHash(blockHash);
								blockInfo.setUpdateTime(new Date());
								if (blockMapper.updateByPrimaryKeySelective(blockInfo) > 0 ? true : false) {
									LOG.info("=== [BTC-LOCAL] current block height: {}, previous block height: {} ===", current, parseBlockCount);
								}
								current++;
							} /*else {
								break;
							}*/
						} catch (CoinException e) {
							LOG.info("=== [BTC] getting block information failed through block height.reason:{} ===", e.getMessage(), e);
							throw new CoinException(e.getMessage());
						}
					}
			 
				}
			}
		} catch (CoinException e) {
			LOG.info("=== com.wallet.bit.service.btc.impl.BtcoinChargeServiceImpl.rechargeRecordFromBlockTx(List<UserAccount>):{} ===", e.getMessage(), e);
			throw new CoinException(e.getMessage());
		}
		return result;
	}

	/*
	* 对钱包地址进行比对处理
	*/
	private boolean parseTransactionInfo(List<UserAccount> userList, String blockHash, int current) throws CoinException {
		Map block = (Map) btcService.getblock(blockHash);
		JSONObject blocks = JSONObject.parseObject(JSON.toJSONString(block));
		if (isError(blocks)) {
			LOG.info("=== [BTC] handling blockTransactions data errors !! ===");
			return false;
		}
		JSONArray txs = JSONArray.parseArray(blocks.getString("tx"));
		LOG.info("=== [BTC] scan block [\theight:{}\t], [\thash:{}\t], [\ttotal transactions:{}\t] begins !!! ===", current, blockHash, txs.size());
		for (int i = 0, len = txs.size(); i < len; i++) {
			String txId = txs.getString(i);
			// deal block
			//LOG.info("=== [BTC] scan block [\theight:{}\t], [\thash:{}\t], [\ttx:{}\t] begins !!! ===", current, blockHash, txId);
			parseBlockInfoByTxId(userList, txId, current);
			// LOG.info("=== [BTC] current blockheight:{},blockhash:{},txhash:{} operation completion!!", current, blockHash, txId);
		}
		return true;
	}
	/**
	 * 处理块信息
	 * @throws CoinException
	 * @Title: parseBlockInfoByTxId @param @param userList @param @param txId @param @throws CoinException 参数 @return void 返回类型 @throws
	 */
	private boolean parseBlockInfoByTxId(List<UserAccount> userList, String txId, int height) throws CoinException {
		try {
			Map transaction = (Map) btcService.getTrawtransaction(txId, 1);
			JSONObject info = JSONObject.parseObject(JSON.toJSONString(transaction));
			Integer confirm = info.getInteger("confirmations");
			Long time = info.getLong("time");
			Long blocktime = info.getLong("blocktime");
			// vin
			JSONArray vins = JSONArray.parseArray(info.getString("vin"));
			double sumvin = 0;
			double sumvout = 0;
			List<String> formAddress = new ArrayList<>();
			for (int z = 0, lenz = vins.size(); z < lenz; z++) {
				JSONObject vin = JSONObject.parseObject(vins.getString(z));
				String txid = vin.getString("txid");
				if (null != txid) {
					Integer vinN = vin.getInteger("vout");
	//				LOG.info("=== [BTC] search vins txid:{} trawtransaction! ===", txid);
					Map parentTransaction = (Map) btcService.getTrawtransaction(txid, 1);
					JSONObject parentInfo = JSONObject.parseObject(JSON.toJSONString(parentTransaction));
					JSONArray vouts = JSONArray.parseArray(parentInfo.getString("vout"));
					for (int j = 0, leg = vouts.size(); j < leg; j++) {
						JSONObject vout = vouts.getJSONObject(j);
						Integer n = vout.getInteger("n");
						if (n == vinN) { // 收款金额
							sumvin += vout.getDouble("value");
							JSONObject scriptPubKey = vout.getJSONObject("scriptPubKey");
							JSONArray addresses = scriptPubKey.getJSONArray("addresses");
							formAddress.add(addresses.getString(0));
						}
					}
				}
			}
			// vout
			JSONArray vouts = JSONArray.parseArray(info.getString("vout"));
			for (int x = 0, lenx = vouts.size(); x < lenx; x++) {
				JSONObject vout = JSONObject.parseObject(vouts.getString(x));
				Integer n = vout.getInteger("n");
				JSONObject scriptPubKey = vout.getJSONObject("scriptPubKey");
				String hex = scriptPubKey.getString("hex");
				String type = scriptPubKey.getString("type");// usdt charge
				if (!type.equals("nulldata")) {
					if (n == 0) { // recharge = 0 , utxo
						JSONArray addresses = scriptPubKey.getJSONArray("addresses");
						String receviceAddr = addresses.getString(0);
						for (UserAccount user : userList) {
							Long userId = user.getUserId();
							String userAddress = user.getUserAddress();
							if (userAddress.equals(receviceAddr)) {
								double amount = vout.getDouble("value");
								if (amount > 0) {
									// count fee
									for (int w = 0, lenw = vouts.size(); w < lenw; w++) {
										JSONObject feevout = JSONObject.parseObject(vouts.getString(x));
										sumvout += feevout.getDouble("value");
									}
									try {
										LOG.info("=== [BTC] handling transaction data entry and storage !!! ===");
										 //记录充值信息处理入库
										 
									} catch (Exception e) {
										LOG.info("=== [BTC] record user recharge exception:{}  ===", e.getMessage(), e);
									}
								}
							}
						}
					}
				}
			}
		} catch (CoinException e) {
			LOG.info("=== com.wallet.bit.service.btc.impl.BtcoinChargeServiceImpl.parseBlockInfoByTxId(List<UserAccount>, String, int):{} ===", e.getMessage(), e);
			throw new CoinException(e.getMessage());
		}
		return false;
	}

  
	
	private boolean isError(JSONObject json) {
		if (json == null || (StringUtils.isNotEmpty(json.getString("error")) && json.get("error") != "null")) {
			return true;
		}
		return false;
	}
	
 
 
}

通过JSON-rpc 进行节点的调用参考:https://blog.csdn.net/u011663149/article/details/87182097

 

没有更多推荐了,返回首页