当前位置:首页 > 热门币 > 正文内容

Java创建比特币交易,技术原理与实践指南

eeo2026-05-25 05:25:07热门币20
摘要:

比特币作为全球首个去中心化数字货币,其交易核心是“数字签名”与“UTXO(未花费交易输出)模型”,通过Java实现比特币交易创建,需要理解比特币交易结构、密钥管理、签名算法等核心概念,本文将结合技术原...

比特币作为全球首个去中心化数字货币,其交易核心是“数字签名”与“UTXO(未花费交易输出)模型”,通过Java实现比特币交易创建,需要理解比特币交易结构、密钥管理、签名算法等核心概念,本文将结合技术原理与代码实践,详细介绍如何用Java从零开始构建一笔合法的比特币交易。

比特币交易的核心概念

UTXO模型

比特币不采用传统账户余额模式,而是基于UTXO(Unspent Transaction Output)模型,每一笔交易消耗(输入)之前交易未被使用的输出(UTXO),并生成新的输出(可能包含找零),用户A有一笔“输入”(来自之前交易的UTXO),现在想向用户B转账1 BTC,若该UTXO价值2 BTC,则交易需包含两个输出:用户B的1 BTC(目标输出)和用户A的1 BTC(找零输出)。

交易结构

一笔标准比特币交易包含以下字段:

  • 版本号:交易协议版本(如2)。
  • 输入列表(TxIn):包含输入的UTXO引用(前一笔交易的哈希与输出索引)、解锁脚本(ScriptSig,用于证明所有权)。
  • 输出列表(TxOut):包含输出金额(以“聪”为单位,1 BTC=1亿聪)和锁定脚本(ScriptPubKey,定义谁能花费该输出)。
  • 锁定时间:交易生效的区块高度或时间戳(通常为0,立即生效)。

密钥与签名

比特币交易所有权通过数字签名证明,发送方需用私钥对交易数据进行签名,接收方通过公钥验证签名合法性,常见的签名算法是ECDSA(椭圆曲线数字签名算法),基于secp256k1曲线。

Java开发环境准备

依赖库

推荐使用以下Java库简化比特币开发:

  • BitcoinJ:最流行的Java比特币库,提供交易构建、密钥管理、网络交互等功能。
  • Bouncy Castle:加密库,用于ECDSA签名等操作。

在Maven项目中添加依赖:

<dependencies>
    <!-- BitcoinJ核心库 -->
    <dependency>
        <groupId>org.bitcoinj</groupId>
        <artifactId>bitcoinj-core</artifactId>
        <version>0.16.1</version>
    </dependency>
    <!-- Bouncy Castle加密库 -->
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.70</version>
    </dependency>
</dependencies>

Java创建比特币交易的完整流程

步骤1:生成或加载密钥对

比特币交易的所有权由私钥控制,私钥通过WIF(Wallet Import Format)或Base58编码表示,使用BitcoinJ生成密钥对:

import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.params.TestNet3Params; // 测试网参数
public class KeyGeneration {
    public static void main(String[] args) {
        // 使用测试网(实际开发中用MainNetParams)
        NetworkParameters params = TestNet3Params.get();
        // 生成新密钥对
        ECKey key = new ECKey();
        // 私钥(WIF格式)
        String privateKeyWIF = key.getPrivateKeyAsWiF(params);
        System.out.println("Private Key (WIF): " + privateKeyWIF);
        // 公钥(压缩格式)
        String publicKey = key.getPublicKeyAsHex();
        System.out.println("Public Key: " + publicKey);
        // 地址(测试网以m或n开头)
        String address = key.toAddress(params).toString();
        System.out.println("Address: " + address);
    }
}

步骤2:获取未花费的UTXO(输入来源)

交易需要消耗已有的UTXO,需通过区块链查询接口获取,BitcoinJ提供了Wallet类管理UTXO,但实际开发中需连接比特币节点或使用区块链浏览器API(如BlockCypher、Blockchain.com)。

假设我们已获取一个UTXO:

  • 交易哈希a3b2c1d4...(前一笔交易的ID)
  • 输出索引0(该交易的第1个输出)
  • 金额50000000聪(0.5 BTC)
  • 锁定脚本:目标地址的锁定脚本(如76a914...88ac

步骤3:构建交易输入(TxIn)

输入需引用UTXO,并包含解锁脚本(ScriptSig)证明所有权,解锁脚本通常由“签名+公钥”组成:

import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
public class TxInBuilder {
    public static TransactionInput createTxIn(
            Sha256Hash txHash, int outputIndex, ECKey key, TransactionOutput utxo) {
        // 创建输入(引用UTXO)
        TransactionInput txIn = new TransactionInput(
            null, // 交易上下文(可为null)
            utxo.getValue(), // 输入金额(从UTXO获取)
            new ScriptBuilder() // 解锁脚本
                .op(ScriptOpCodes.OP_0) // OP_0表示签名
                .data(key.sign(utxo.getOutPointFor().hash)) // 签名
                .data(key.getPubKey()) // 公钥
                .build(),
            utxo.getOutPointFor() // 引用的UTXO
        );
        return txIn;
    }
}

步骤4:构建交易输出(TxOut)

输出包含目标地址和金额,锁定脚本定义谁能花费(如P2PKH:Pay-to-Public-Key-Hash):

import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Address;
import org.bitcoinj.script.ScriptBuilder;
public class TxOutBuilder {
    public static TransactionOutput createTxOut(
            NetworkParameters params, long amount, Address toAddress) {
        // 锁定脚本:目标地址的P2PKH脚本
        Script scriptPubKey = new ScriptBuilder()
            .op(ScriptOpCodes.OP_DUP)
            .op(ScriptOpCodes.OP_HASH160)
            .data(toAddress.getHash160())
            .op(ScriptOpCodes.OP_EQUALVERIFY)
            .op(ScriptOpCodes.OP_CHECKSIG)
            .build();
        // 创建输出
        return new TransactionOutput(null, amount, scriptPubKey);
    }
}

步骤5:组装完整交易并签名

将输入、输出组合为交易,并对输入进行签名(确保交易合法性):

import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.script.Script;
public class TransactionBuilder {
    public static Transaction createAndSignTransaction(
            NetworkParameters params,
            List<TransactionInput> txIns,
            List<TransactionOutput> txOuts,
            ECKey signingKey) {
        // 创建交易
        Transaction tx = new Transaction(params);
        txIns.forEach(tx::addInput);
        txOuts.forEach(tx::addOutput);
        // 设置版本和锁定时间
        tx.setVersion(2);
        tx.setLockTime(0);
        // 对输入进行签名(ECDSA)
        for (int i = 0; i < txIns.size(); i++) {
            TransactionInput txIn = txIns.get(i);
            Script scriptSig = new ScriptBuilder()
                .data(signingKey.sign(tx.hashForSignature(i, txIn.getOutput().getScript(), Transaction.SigHash.ALL, false)))
                .data(signingKey.getPubKey())
                .build();
            txIn.setScriptSig(scriptSig);
        }
        return tx;
    }
}

步骤6:序列化交易并广播

交易构建完成后,需序列化为字节流(十六进制字符串)才能广播到比特币网络:

import org.bitcoinj.core.Utils;
public class TransactionBroadcast {
    public static void main(String[] args) {
        // 假设已构建好交易tx
        Transaction tx = ...; // 步骤5中的交易对象
        // 序列化为十六进制字符串
        String txHex = Utils.HEX.encode(tx.bitcoinSerialize());
        System.out.println("Raw Transaction: " + txHex);
        // 广播交易(需连接比特币节点或使用第三方API)
        // BitcoinJ的PeerGroup.broadcastTransaction(tx)
        // 或通过Blockchain.com的广播接口
    }
}

完整代码示例

将上述步骤整合为完整示例(测试网环境):

import org.bitcoinj.core.*;
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import java.util.Arrays;
import java.util.List;
public
    币安交易所

    币安交易所是国际领先的数字货币交易平台,低手续费与BNB空投福利不断!

扫描二维码推送至手机访问。

版权声明:本文由e-eo发布,如需转载请注明出处。

本文链接:http://www.e-eo.com/post/27491.html

分享给朋友: