BTC离线生成地址以及btc离线签名(亲测)

废话不多说,说了你们也不看,直接上代码吧

maven依赖

<!-- https://mvnrepository.com/artifact/org.bitcoinj/bitcoinj-core -->
<dependency>
    <groupId>org.bitcoinj</groupId>
    <artifactId>bitcoinj-core</artifactId>
    <version>0.15.8</version>
</dependency>

生成地址,私钥 ,公钥以及助记词

 /**
     * 创建钱包地址
     *
     * @return
     */
    public static Map newaddress() {
        NetworkParameters networkParameters = MainNetParams.get() ;
        DeterministicSeed seed = new DeterministicSeed(new SecureRandom(), 128, "", Utils.currentTimeSeconds());
        Wallet wallet;
        String mnemonics = "";
        String privateKey = "";
        String publicKey = "";
        String address = "";
        String pwd = "";
        try {
            wallet = Wallet.fromSeed(networkParameters, seed);
            //私钥
            privateKey = wallet.currentReceiveKey().getPrivateKeyAsWiF(networkParameters);
            //助记词
            mnemonics = wallet.getKeyChainSeed().getMnemonicCode().toString();
            publicKey = Hex.toHexString(ECKey.publicKeyFromPrivate(wallet.currentReceiveKey().getPrivKey(), true));
            //地址
            address = wallet.currentReceiveAddress().toBase58();
        } catch (Exception e) {
            logger.error("比特币地址创建失败,原因"+e);
            return null;
        }
        Map resultMap = new LinkedHashMap();
        resultMap.put("mnemonics", mnemonics);
        resultMap.put("privateKey", privateKey);
        resultMap.put("publicKey", publicKey);
        resultMap.put("address", address);
        return resultMap;
    }

获取余额

public static double getBalance(String address){
        double balance = 0.0 ;
        try {
            String url = "https://chain.api.btc.com/v3/address/" + address;
            String request = HttpUtils.getRequest(url);
            JSONObject data = JSONObject.parseObject(request);
            JSONObject jsonObject = data.getJSONObject("data");
            Double bal = jsonObject.getDouble("balance");
            return bal ;
        }catch (Exception e){
            return 0.0 ;
        }
    }

获取未消费地址(utxo)

   /***
     * 获取未消费列表
     * @param address :地址
     * @return
     */
    public static List<UTXO> getUnspent(String address) {
        List<UTXO> utxos = Lists.newArrayList();
        String host = isMainNet ? "blockchain.info" : "testnet.blockchain.info";
        String url = "https://insight.bitpay.com/api/addr/"+address+"/utxo";
        try {
            String httpGet = HttpUtils.getRequest(url, null);//
            if (StringUtils.equals("No free outputs to spend", httpGet)) {
                return utxos;
            }
            JSONArray unspentOutputs = JSONObject.parseArray(httpGet) ;
            List<Map> outputs = JSONObject.parseArray(unspentOutputs.toJSONString(), Map.class);
            if (outputs == null || outputs.size() == 0) {
                System.out.println("交易异常,余额不足");
            }
            for (int i = 0; i < outputs.size(); i++) {
                Map outputsMap = outputs.get(i);
                String address2 = outputsMap.get("address").toString();
                String tx_hash = outputsMap.get("txid").toString();
                String tx_output_n = outputsMap.get("vout").toString();
                String script = outputsMap.get("scriptPubKey").toString();
                String value = outputsMap.get("height").toString();
                UTXO utxo = new UTXO(Sha256Hash.wrap(tx_hash), Long.valueOf(tx_output_n), Coin.valueOf(Long.valueOf(value)),
                        0, false, new Script(Hex.decode(script)));
                utxos.add(utxo);
            }
            return utxos;
        } catch (Exception e) {
            logger.error("【BTC获取未消费列表】失败,"+ e);
            return null;
        }

    }

获取btc费率

 /**
     * 获取btc费率
     *
     * @return
     */
    public static Long getFeeRate() {
        try {
            String httpGet1 = HttpUtils.getRequest("https://bitcoinfees.earn.com/api/v1/fees/recommended", null);
            Map map = JSON.parseObject(httpGet1, Map.class);
            Long fastestFee = Long.valueOf(map.get("fastestFee").toString());
            return fastestFee;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

获取旷工费用

 /**
     * 获取矿工费用
     * @param amount
     * @param utxos
     * @return
     */
    public static Long getFee(long amount, List<UTXO> utxos) {
        Long feeRate = getFeeRate();//获取费率
        Long utxoAmount = 0L;
        Long fee = 0L;
        Long utxoSize = 0L;
        for (UTXO us : utxos) {
            utxoSize++;
            if (utxoAmount >= (amount + fee)) {
                break;
            } else {
                utxoAmount += us.getValue().value;
                fee = (utxoSize * 148 * 34  + 10) * feeRate;
            }
        }
        return fee;
    }

离线签名

   /**
     * btc交易签名
     * @param fromAddress
     * @param toAddress
     * @param privateKey
     * @param amount
     * @param fee
     * @param utxos
     * @return
     * @throws Exception
     */
    public static String sign(String fromAddress, String toAddress, String privateKey, long amount, long fee, List<UTXO> utxos) throws Exception {
        NetworkParameters networkParameters = isMainNet ? MainNetParams.get() : TestNet3Params.get();
        Transaction transaction = new Transaction(networkParameters);

        String changeAddress = fromAddress;//找零地址
        Long changeAmount = 0L;
        Long utxoAmount = 0L;
        List<UTXO> needUtxos = new ArrayList<UTXO>();
        //获取未消费列表
        if (utxos == null || utxos.size() == 0) {
            throw new Exception("未消费列表为空");
        }
        //遍历未花费列表,组装合适的item
        for (UTXO utxo : utxos) {
            if (utxoAmount >= (amount + fee)) {
                break;
            } else {
                needUtxos.add(utxo);
                utxoAmount += utxo.getValue().value;
            }
        }
        transaction.addOutput(Coin.valueOf(amount), Address.fromBase58(networkParameters, toAddress));
        //消费列表总金额 - 已经转账的金额 - 手续费 就等于需要返回给自己的金额了
        changeAmount = utxoAmount - (amount + fee);
        //余额判断
        if (changeAmount < 0) {
            throw new Exception("utxo余额不足");
        }
        //输出-转给自己(找零)
        if (changeAmount > 0) {
            transaction.addOutput(Coin.valueOf(changeAmount), Address.fromBase58(networkParameters, changeAddress));
        }
        //输入未消费列表项
        DumpedPrivateKey dumpedPrivateKey = DumpedPrivateKey.fromBase58(networkParameters, privateKey);
        ECKey ecKey = dumpedPrivateKey.getKey();
        for (UTXO utxo : needUtxos) {
            TransactionOutPoint outPoint = new TransactionOutPoint(networkParameters, utxo.getIndex(), utxo.getHash());
            transaction.addSignedInput(outPoint, utxo.getScript(), ecKey, Transaction.SigHash.ALL, true);
        }
        byte[] bytes = transaction.bitcoinSerialize();
        String hash = Hex.toHexString(transaction.bitcoinSerialize());
        logger.info("fee:{},utxoAmount:{},changeAmount{}", fee, utxoAmount, changeAmount);
        return hash;
    }

广播交易

public static String publishTx(String Hash){
        HashMap<String, String> map = Maps.newHashMap();
        map.put("rawhex",Hash) ;
        String jsonObject = HttpsUtils.sendPost("https://chain.api.btc.com/v3//tools/tx-publish", map);
        return jsonObject ;
    }

如果帮助到你,请点点关注,谢谢

上一篇:2020年5月21最新比特币/以太坊/柚子等行情分析行情分析


下一篇:币圈交易达人:5.12比特币行情分析减半结束价格是瀑布还是火箭