β

基于Java语言构建区块链(六)—— 交易(Merkle Tree)

Harries Blog™ 97 阅读

基于Java语言构建区块链(六)—— 交易(Merkle Tree)

文章 的主要思想和内容均来自 https ://jeiwan.cc/posts/ build ing-blockchain-in-go-part-6/

引言

在这一系列文章的最开始部分,我们提到过区块链是一个 分布式 数据库 。那时候,我们决定跳过”分布式”这一环节,并且聚焦于” 数据 存储”这一环节。到目前为止,我们几乎实现了区块链的所有组成部分。在本篇文章中,我们将会涉及一些在前面的文章中所忽略的一些机制,并且在下一篇文章中我们将开始研究区块链的分布式特性。

前面各个部分内容:

  1. 基本原型
  2. 工作量证明
  3. 持久化 & 命令行
  4. 交易(UTXO)
  5. 地址(钱包)

UTXO池

在持久化 & 命令行 这篇文章中,我们研究了比特币核心存储区块的方式。当中我们提到过与区块相关的数据存储在 blocks 这个数据桶中,而交易数据则存储在 chainstate 这个数据桶中,让我们来回忆一下, chainstate 数据桶的数据结构:

  • ‘c’ + 32-byte transaction hash -> unspent transaction output record for that transaction

    某笔交易的UTXO记录

  • ‘B’ -> 32-byte block hash: the block hash up to which the da tab ase represents the unspent transaction outputs

    数据库所表示的UTXO的区块Hash

从那篇文章开始,我们已经实现了比特币的交易机制,但是我们还没有用到 chainstate 数据桶去存储我们的交易输出。所以,这将是我们现在要去做的事情。

chainstate不会去存储交易数据。相反,它存储的是 UTXO 集,也就是未被花费的交易输出集合。除此之外,它还存储了”数据库所表示的UTXO的区块Hash”,我们这里先暂且忽略这一点,因为我们还没有用到区块高度(这一点我们会在后面的文章进行实现)。

那么,我们为什么需要 UTXO 池呢?

一起来看一下我们前面实现的 find UnspentTransactions 方法:

/**
  * 查找钱包地址对应的所有未花费的交易
  *
  * @param pubKeyHash 钱包公钥Hash
  * @return
  */
 private Transaction[] findUnspentTransactions(byte[] pubKeyHash) throws Exception {
     Map<String, int[]> allSpentTXOs = this.getAllSpentTXOs(pubKeyHash);
     Transaction[] unspentTxs = {};

     // 再次遍历所有区块中的交易输出
     for (BlockchainIterator blockchainIterator = this.getBlockchainIterator(); blockchainIterator.hashNext(); ) {
         Block block = blockchainIterator.next();
         for (Transaction transaction : block.getTransactions()) {

             String txId = Hex.encodeHexString(transaction.getTxId());

             int[] spentOutIndexArray = allSpentTXOs.get(txId);

             for (int outIndex = 0; outIndex < transaction.getOutputs().length; outIndex++) {
                 if (spentOutIndexArray != null && ArrayUtils.contains(spentOutIndexArray, outIndex)) {
                     continue;
                 }

                 // 保存不存在 allSpentTXOs 中的交易
                 if (transaction.getOutputs()[outIndex].isLockedWithKey(pubKeyHash)) {
                     unspentTxs = ArrayUtils.add(unspentTxs, transaction);
                 }
             }
         }
     }
     return unspentTxs;
 }
作者:Harries Blog™
追心中的海,逐世界的梦

发表评论