美文网首页
BTC交易流程

BTC交易流程

作者: shiweigang | 来源:发表于2020-06-16 18:10 被阅读0次

    交易流程图

    image

    交易说明

    交易的创建
    1. 遍历自己地址的可用UTXO是否大于交易的数额amount。

    2. 计算交易费用fee

    3. 如果如果可用UTXO >= fee + amount 则开始组织交易。

      1. 生成输出 一个一个的 TxOut,并添加到数组中 (包含转账地址和找零地址)。

      2. 根据UTXO生成 TxIn,并添加到数组中。

      3. 对 TxIn 数组中的 TxIn 进行逐一签名。

      4. 发送交易信息。

    交易的输入

    每一笔交易都会由一个或一组输入和一个或一组输出组成,除了一种特殊的交易 coinbase,coinbase是bitcoin-core定义的给区块挖出者的奖励,其实也是比特币的产出过程。只有coinbase交易会产生比特币,其他的交易都是比特币的转移。

    一个交易(MsgTx)是由多个Input和多个Output组成的,而在Input中是由指向UTXO的OutPoint,解锁脚本SignatureScript和序列Sequence组成,一笔交易分为三个步骤:
    1. 构建原始交易RawTransaction,该交易包含了输入指向的OutPoint,也包含了完整的Output,但是没有签名,也就是没有设置SignatureScript的内容。

    2. 用私钥对签名构建的RawTransaction进行签名,并将签名构建成完整的解锁脚本,填入对应的Input的SignatureScript字段中。

    3. 将签名后的Transaction发送到P2P网络中。

    对交易进行签名,有几个Input,就要要签名几次,每个签名的原理是一样的,在比特币中,对一笔交易的签名流程是这样的:
    1. 查找该笔交易对应的UTXO

    2. 获得该UTXO对应的锁定脚本

    3. 复制该交易对象,并在复制副本中将该Input的解锁脚本字段的值设置为对应的锁定脚本

    未花费的消费列表

    │    {
    
    │       "output_no": 0,
    
    │       "scriptPubKey": "76a914b73187dbcab54a93d861f1e53b39843f8a8d8ce988ac",
    
    │       "address": "1HhdzZNfAdpdtbGnRNkat9YSc5BN6TKenG",
    
    │       "txid": "ac0472c6a1095ffd2372412ba1c88c291c25b2315fedcdb45d02189fc2436c06",
    
    │       "value": "0.00003499",
    
    │       "satoshis": "3499"
    
    │     }
    

    比特币交易数据解析

    签名的信息

    01000000024a2989e933ed9875f83776ddb4ee105a3ee7363e60e0f53db8a682f82aa52303010000006b483045022071e572d11357a0801ce69741ffde20de49099cd4ddeac19d4ad6697ca766c5fc022100835d7dabdc674e78ca523f09811b7178b3c31d08735909a28975721c6a2d2e34012103be47f412d8e23a3baf591bbe42c5859062b5b0b168567ecd8746ddc1948103fdffffffff0bcdf46d36a33c8d768e25be6b185bc9efad8aca7fad55b5180c9475afe6718f000000006c493046022100ae57aeb9711a6879bc7ddd363feb62aa5aa42b0dca6aa81e1eafc533e4cce0c4022100db46f11ac362e0fe494c65d24fb702c92ebc554690a7447365d38e7aa3613a740121030b7979840ce44d7318f5883aed9d8f5a3c0778326beae0c2117ea8712c7de5aaffffffff0108880200000000001976a9148c2cbf83f9b3034007456580a9072a9304684a4988ac00000000
    

    签名信息解析

    {
    
        "addresses": [
    
            "1DnBD1YD8HhDdneKUUh36TK48pTWVKkWvC"
    
        ],
    
        "block_height": -1,
    
        "block_index": -1,
    
        "confirmations": 0,
    
        "double_spend": false,
    
        "fees": 0,
    
        "hash": "a0b956a450134ede9839c4d9fcf4c31446a24a135c2f8c11a8288eac0ba1a34f",
    
        "inputs": [
    
            {
    
                "age": 0,
    
                "output_index": 1,
    
                "prev_hash": "0323a52af882a6b83df5e0603e36e73e5a10eeb4dd7637f87598ed33e989294a",
    
                "script": "483045022071e572d11357a0801ce69741ffde20de49099cd4ddeac19d4ad6697ca766c5fc022100835d7dabdc674e78ca523f09811b7178b3c31d08735909a28975721c6a2d2e34012103be47f412d8e23a3baf591bbe42c5859062b5b0b168567ecd8746ddc1948103fd",
    
                "script_type": "empty",
    
                "sequence": 4294967295
    
            },
    
            {
    
                "age": 0,
    
                "output_index": 0,
    
                "prev_hash": "8f71e6af75940c18b555ad7fca8aadefc95b186bbe258e768d3ca3366df4cd0b",
    
                "script": "493046022100ae57aeb9711a6879bc7ddd363feb62aa5aa42b0dca6aa81e1eafc533e4cce0c4022100db46f11ac362e0fe494c65d24fb702c92ebc554690a7447365d38e7aa3613a740121030b7979840ce44d7318f5883aed9d8f5a3c0778326beae0c2117ea8712c7de5aa",
    
                "script_type": "empty",
    
                "sequence": 4294967295
    
            }
    
        ],
    
        "outputs": [
    
            {
    
                "addresses": [
    
                    "1DnBD1YD8HhDdneKUUh36TK48pTWVKkWvC"
    
                ],
    
                "script": "76a9148c2cbf83f9b3034007456580a9072a9304684a4988ac",
    
                "script_type": "pay-to-pubkey-hash",
    
                "value": 165896
    
            }
    
        ],
    
        "preference": "low",
    
        "received": "2020-06-15T08:47:43.844912895Z",
    
        "relayed_by": "3.92.56.73",
    
        "size": 341,
    
        "total": 165896,
    
        "ver": 1,
    
        "vin_sz": 2,
    
        "vout_sz": 1
    
    }
    

    签名交易流程

    private BtcTxSignResult signTransaction(String password, Wallet wallet, String to, boolean isFork) {
    
        // 发送到的地址
    
        this.to = to;
    
        // NetworkParameters上下文
    
        this.network = NetParamsService.getNetworkParameters(wallet.chainType);
    
        // 获取私钥信息
    
        byte[] bytes = WalletManager.getBtcPriKey(wallet.keystore, password);
    
        String xprv = new String(bytes, Charset.forName("UTF-8"));
    
        DeterministicKey xprvKey = DeterministicKey.deserializeB58(xprv, network);
    
        BigInteger privateKey = xprvKey.getPrivKey();
    
        ECKey ecKey = ECKey.fromPrivate(privateKey);
    
        // 创建交易信息实体
    
        Transaction tran = new Transaction(network);
    
    
    
        long changeAmount = totalMoney - amount - fee;
    
        LogUtils.eTag("UTXOTransaction", changeAmount + "totalMoney:" + totalMoney + "amount:" + amount + "fee:" + fee);
    
        // 输出地址
    
        tran.addOutput(Coin.valueOf(amount), Address.fromString(network, this.to));
    
        // 找零地址
    
        if (changeAmount > DUST_THRESHOLD) {
    
            tran.addOutput(Coin.valueOf(changeAmount), Address.fromString(network, wallet.getAddress()));
    
        }
    
        // 输入信息
    
        for (UTXO output : getOutputs()) {
    
            TransactionOutPoint transactionOutPoint = new TransactionOutPoint(network, output.getVout(), Sha256Hash.wrap(output.getTxHash()));
    
            //这个添加签名输入的最后一个参数就是添加了SIGHASH_FORKID(0x40)
    
            tran.addSignedInput(transactionOutPoint, Coin.valueOf(new BigDecimal(output.getAmount()).longValue())
    
                    , new Script(NumericUtil.hexToBytes(output.getScriptPubKey())), ecKey, Transaction.SigHash.ALL, true, isFork);
    
        }
    
        // 生产交易hash
    
        String signedHex = NumericUtil.bytesToHex(tran.bitcoinSerialize());
    
        String txHash = NumericUtil.beBigEndianHex(Hash.sha256(Hash.sha256(signedHex)));
    
        return new BtcTxSignResult(signedHex, txHash);
    
    }
    

    获取NetworkParametersNetworkParameters说明

    不同的币种NetworkParameters的里面的两个参数不同
    
        int addressHeader = 0;
    
        case LTC:
    
            return 0x30;
    
        case BCH:
    
        case BTC:
    
        case EOS:
    
            return 0x00;
    
        case DASH:
    
            return 0x4C;
    
        case DOGE:
    
            return 0x1E;
    
        int bip32HeaderP2PKHpriv
    
        case LTC:
    
            return 0x019D9CFE;
    
        case BCH:
    
        case BTC:
    
        case EOS:
    
            return 0x0488ADE4;
    
        case DASH:
    
            return 0x02FE52CC;
    
        case DOGE:
    
            return 0x0488E1F4;
    

    UTXO数据UTXO的定义

    新的交易模块设计:

    /**
    
     * @FileName     : TransactionModule
    
     * @date         : 2020/6/15 10:46
    
     * @author       : Owen
    
     * @description  : 交易相关接口类
    
     */
    
    object TransactionModule {
    
        open class ValidationError : Exception() {
    
            class EmptyValue() : ValidationError()
    
            class InsufficientBalance() : ValidationError()
    
            class NotEnoughForMinimumRequiredBalance() : ValidationError()
    
            class TooFewAmount() : ValidationError()
    
            class MaxAmountLimit() : ValidationError()
    
        }
    
    
    
        /**
    
         * 转账金额处理
    
         */
    
        interface IAmountDelegate {
    
    
    
            val availableBalance: BigDecimal
    
            var inputAmount: BigDecimal
    
    
    
            fun setInputAmount(amount: String)
    
            @Throws
    
            fun validAmount(): Boolean
    
        }
    
    
    
        /**
    
         * 发送到的地址处理
    
         */
    
        interface IAddressDelegate {
    
            fun setToAddress(toAddress: String)
    
            @Throws
    
            fun validAddress(): Boolean
    
        }
    
    
    
        /**
    
         * 转账费用处理
    
         */
    
        interface IFeeDelegate {
    
    
    
            fun loadData()
    
            @Throws
    
            fun validFee(): Boolean
    
    
    
            fun onClear()
    
    
    
        }
    
    
    
        /**
    
         * 广播交易处理
    
         */
    
        interface ISendDelegate {
    
            fun signTransaction()
    
            fun sendTransaction()
    
        }
    
    
    
        /**
    
         * 发送交易流程代理
    
         */
    
        interface ITransactionDelegate {
    
    
    
            fun loadData()
    
            fun setInputAmount(amount: String)
    
            fun setToAddress(toAddress: String)
    
            fun calculateFee()
    
            fun setMemo(memo: String)
    
            fun validTransactionData()
    
            fun sendTransaction()
    
    
    
        }
    
    
    
        class Factory(private val wallet: Wallet) : ViewModelProvider.Factory {
    
            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
    
                val presenter = TransactionPresenter()
    
                when(wallet.chainType){
    
                    CoinEnum.BTC.symbol,
    
                    CoinEnum.BTC.symbol,
    
                    CoinEnum.BTC.symbol,
    
                    CoinEnum.BTC.symbol -> {
    
                    }
    
                    CoinEnum.ETH.symbol -> {
    
    
    
                    }
    
                    CoinEnum.EOS.symbol -> {
    
    
    
                    }
    
    
    
                return presenter as T
    
            }
    
    
    
        }
    
    }
    
    /**
    
     * @FileName     : AmountDelegate
    
     * @date         : 2020/6/15 11:25
    
     * @author       : Owen
    
     * @description  : Amount交易金额代理类
    
     */
    
    class AmountDelegate(balance: String) : TransactionModule.IAmountDelegate {
    
        override val availableBalance: BigDecimal
    
            get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
    
    
    
        override var inputAmount: BigDecimal = BigDecimal.ZERO
    
    
    
        override fun setInputAmount(amount: String) {
    
    
    
        }
    
    
    
        override fun validAmount(): Boolean {
    
            return true
    
        }
    
    }
    
    /**
    
     * @FileName     : TransactionPresenter
    
     * @date         : 2020/6/15 10:56
    
     * @author       : Owen
    
     * @description  : 交易代理实现
    
     */
    
    class TransactionPresenter : ViewModel(), TransactionModule.ITransactionDelegate {
    
        private var memo: String = ""
    
    
    
        private val errorMessage = MutableLiveData<String>()
    
    
    
        var amountDelegate: TransactionModule.IAmountDelegate? = null
    
        var addressDelegate: TransactionModule.IAddressDelegate? = null
    
        var feeDelegate: TransactionModule.IFeeDelegate? = null
    
        var sendDelegate: TransactionModule.ISendDelegate? = null
    
    
    
        override fun loadData() {
    
            feeDelegate?.loadData()
    
        }
    
    
    
        override fun setInputAmount(amount: String) {
    
            amountDelegate?.setInputAmount(amount)
    
        }
    
    
    
        override fun setToAddress(toAddress: String) {
    
            addressDelegate?.setToAddress(toAddress)
    
        }
    
    
    
        override fun calculateFee() {
    
    
    
        }
    
    
    
        override fun setMemo(memo: String) {
    
            this.memo = memo
    
        }
    
    
    
        override fun validTransactionData() {
    
            try {
    
                amountDelegate?.validAmount()
    
                addressDelegate?.validAddress()
    
                feeDelegate?.validFee()
    
                sendTransaction()
    
            } catch (e: TransactionModule.ValidationError) {
    
                when (e) {
    
                    is TransactionModule.ValidationError.EmptyValue -> {
    
                        errorMessage.value = ""
    
                    }
    
                    else -> {
    
                        errorMessage.value = ""
    
                    }
    
                }
    
            }
    
        }
    
    
    
        override fun sendTransaction() {
    
            sendDelegate?.signTransaction()
    
        }
    
    
    
        override fun onCleared() {
    
    
    
        }
    
    }    

    相关文章

      网友评论

          本文标题:BTC交易流程

          本文链接:https://www.haomeiwen.com/subject/ilirxktx.html