Skip to content

Releases: Zeratal/BlockChain

v0.0.7_3

25 May 17:14

Choose a tag to compare

共识机制(块同步)

v0.0.7_2: 添加UTXO更新功能

25 May 04:14

Choose a tag to compare

增添UTXO的同步和共识机制

v0.0.7_1

22 May 18:15

Choose a tag to compare

网络通讯进阶,多进程,多消息交互

v0.0.7_0

21 May 18:03

Choose a tag to compare

p2p互联第一个版本。这个用例其实启用了3个线程但其工作在一个进程,所以共用了一个控制台,所有打印在一个窗口,也无法分别输入

交易池和UTXO(0.0.6)

20 May 14:42

Choose a tag to compare

交易池和UTXO(0.0.6)

我来帮您实现交易池(Transaction Pool)和UTXO(Unspent Transaction Output)模型。这是区块链系统中非常重要的两个组件。

主要的变更:

  1. UTXO模型:
  • 创建了UTXO类来表示未花费的交易输出
  • 实现了UTXOPool类来管理所有UTXO
  • 提供了查询余额、选择UTXO等功能
  1. 交易池:
  • 创建了TransactionPool类来管理待处理的交易
  • 实现了交易的验证、添加、移除等功能
  • 使用互斥锁保证线程安全
  1. 交易结构更新:
  • 添加了TransactionInputTransactionOutput
  • 更新了Transaction类以支持UTXO模型
  • 实现了更安全的交易验证机制
  1. 区块链更新:
  • 集成了UTXO池和交易池
  • 更新了区块添加逻辑,支持UTXO模型
  • 实现了余额查询的新方法

主要改进:

  1. 更好的安全性:UTXO模型可以防止双重支付
  2. 更高的效率:交易池可以缓存待处理交易
  3. 更准确的余额计算:基于UTXO而不是简单的加减
  4. 更好的并发支持:使用互斥锁保护共享资源

使用示例:

// 创建交易
Transaction tx(fromAddress, toAddress, amount);

// 选择UTXO
auto utxos = utxoPool.selectUTXOs(fromAddress, amount);

// 添加输入
for (const auto& utxo : utxos) {
    tx.addInput(TransactionInput(utxo.getTxId(), utxo.getOutputIndex(), signature));
}

// 添加输出
tx.addOutput(TransactionOutput(amount, toAddress));
if (totalInput > amount) {
    tx.addOutput(TransactionOutput(totalInput - amount, fromAddress)); // 找零
}

// 添加到交易池
blockchain.addTransactionToPool(tx);

UTXO和交易池的概念和实现。

UTXO (Unspent Transaction Output) 模型

UTXO是比特币等区块链系统中使用的一种交易模型。它的核心思想是:

  1. 基本概念
  • 每个交易输出(UTXO)代表一定数量的加密货币
  • 每个UTXO只能被使用一次
  • 交易必须使用已有的UTXO作为输入,并创建新的UTXO作为输出
  1. UTXO类的实现
class UTXO {
    std::string txId_;        // 交易ID
    int outputIndex_;         // 输出索引
    double amount_;           // 金额
    std::string owner_;       // 所有者地址
    bool spent_;             // 是否已花费
};
  1. UTXOPool的功能
  • 管理所有未花费的交易输出
  • 提供余额查询
  • 选择UTXO进行交易
class UTXOPool {
    // 存储结构:交易ID -> (输出索引 -> UTXO)
    std::map<std::string, std::map<int, UTXO>> utxos_;
    
    // 主要方法
    void addUTXO(const UTXO& utxo);                    // 添加UTXO
    void removeUTXO(const std::string& txId, int outputIndex);  // 移除UTXO
    double getBalance(const std::string& address);      // 查询余额
    std::vector<UTXO> selectUTXOs(const std::string& address, double amount);  // 选择UTXO
};

交易池 (Transaction Pool)

交易池是一个临时存储待处理交易的容器,主要功能包括:

  1. 基本概念
  • 存储等待被打包进区块的交易
  • 提供交易验证功能
  • 管理交易的添加和移除
  1. TransactionPool的实现
class TransactionPool {
    std::map<std::string, Transaction> transactions_;  // 存储交易
    mutable std::mutex mutex_;                         // 线程安全锁
    
    // 主要方法
    bool addTransaction(const Transaction& transaction, const UTXOPool& utxoPool);
    void removeTransaction(const std::string& txId);
    std::vector<Transaction> getTransactions() const;
};
  1. 交易验证流程
bool TransactionPool::isValidTransaction(const Transaction& transaction, const UTXOPool& utxoPool) const {
    // 验证签名
    if (!transaction.verifySignature()) return false;
    
    // 验证余额
    if (!utxoPool.hasEnoughFunds(transaction.getFrom(), transaction.getAmount())) return false;
    
    // 验证金额
    if (transaction.getAmount() <= 0) return false;
    
    // 验证发送者和接收者
    if (transaction.getFrom() == transaction.getTo()) return false;
    
    return true;
}

工作流程

  1. 创建交易
// 1. 选择UTXO
auto utxos = utxoPool.selectUTXOs(fromAddress, amount);

// 2. 创建交易输入
for (const auto& utxo : utxos) {
    tx.addInput(TransactionInput(utxo.getTxId(), utxo.getOutputIndex(), signature));
}

// 3. 创建交易输出
tx.addOutput(TransactionOutput(amount, toAddress));
// 如果有找零
if (totalInput > amount) {
    tx.addOutput(TransactionOutput(totalInput - amount, fromAddress));
}
  1. 交易处理
// 1. 添加到交易池
blockchain.addTransactionToPool(tx);

// 2. 挖矿时从交易池获取交易
auto pendingTransactions = transactionPool.getTransactions();

// 3. 交易确认后更新UTXO池
void Blockchain::updateUTXOPool(const Block& block) {
    for (const auto& tx : block.getTransactions()) {
        // 移除已使用的UTXO
        for (const auto& input : tx.getInputs()) {
            utxoPool_.removeUTXO(input.getTxId(), input.getOutputIndex());
        }
        
        // 添加新的UTXO
        for (size_t i = 0; i < tx.getOutputs().size(); ++i) {
            const auto& output = tx.getOutputs()[i];
            UTXO utxo(tx.getTransactionId(), i, output.getAmount(), output.getOwner());
            utxoPool_.addUTXO(utxo);
        }
    }
}

这种设计的优点:

  1. 防止双重支付
  2. 提高交易验证效率
  3. 支持并行处理
  4. 更好的隐私保护
  5. 更准确的余额计算

主程序更新:

  1. 交易创建流程:
  • 现在每个交易都需要选择UTXO作为输入

  • 添加了交易输入和输出的处理

  • 实现了找零机制

  1. 交易池集成:
  • 交易先添加到交易池

  • 挖矿时从交易池获取待处理交易

  • 交易确认后从交易池中移除

  1. 余额查询:
  • 使用UTXO池来查询余额

  • 不再使用钱包的余额缓存

  1. 输出信息:
  • 添加了交易输入和输出的详细信息

  • 显示UTXO的使用情况

  • 显示找零信息

  1. 本地化:
  • 将所有输出信息改为中文

  • 优化了输出格式

主要改进:

  1. 更安全的交易机制

  2. 更准确的余额计算

  3. 更好的交易追踪

  4. 更清晰的输出信息

阶段总结

本阶段用例在链上添加了2个数据

  • 交易池
  • UTXO池

事实上,UTXO在链上是永久驻留,其记录了每笔交易的结果(财富属于谁)

  • 每次交易发生,该次交易的发起方的历史UTXO都被清除,并生成一个新的代表余额的UTXO;
  • 每次交易发生,该次交易的接收方将添加一个新的UTXO(所以某个钱包如果只接收不支出,则UTXO会越来越多

而Transaction Pool只是缓存未完成交易

  • 当链上新增一个块时,会检查链上未完成交易,并将所有未完成交易计入此块的交易。
  • 对该块挖矿(工作量证明)
  • 针对该块更新UTXO(即将交易池中未完成交易完成)
  • 清空交易池

所以在此例中,交易池不是必须的。

示例程序流程

  • 创建三个钱包(构造时生成秘钥对),获取钱包公钥作为身份识别

  • 创建链,生成一个0块。id为0,空交易,前置块Hash为0

  • 链上注册钱包,公钥到钱包的映射

  • 创建三个系统交易(初始交易,准备给钱包充值)

    • 初始化交易(系统,钱包ID,金额)
    • 系统交易特殊签名
    • 给交易插入一个“交易输出”(金额,钱包ID)
    • 更新交易Hash值(每次给交易添加输入输出都要更新Hash)
  • 将以上交易列表加入链(生成块)

    • 合并新交易和待处理交易(==transactionPool_==无)
    • ==生成块==
      • 初始化块index,交易列表,前块的hash值
      • 获取时间戳
      • 创建MerkleTress生成merkleRoot_
      • 计算hash值
    • ==挖矿(更新hash值)==
    • ==块添加到链上==
    • ==更新UTXO池==(链操作,入参是块)
      • 遍历交易
        • 遍历交易输入(这里无)
        • 遍历交易输出(这里3个)
          • 生成一个UTXO(交易ID,序号(0),金额,拥有者ID)
          • UTXO加入==utxoPool_==(chain上总池)
            • 第一级map key为交易ID
            • 第二级map key为utxo的输出index(这里永远为0吧?)
    • 清空交易池中已确认的交易
      • 遍历之前合并的交易(该交易被加入块)
        • ==transactionPool_== 中删除所以交易(这里transactionPool_为空,所以无操作)
  • 检查初始余额

    • 通过链操作获取各钱包余额。
      • ==utxoPool_==中获取余额
        • 遍历2层map,找到所有者地址和请求钱包地址一致的utxo,累计金额
  • ==开始正常交易==

  • ==创建交易1==(Alice向Bob转10块,注意,这里没有创建交易输入和输出)

  • 使用alice的钱包对此次交易签名,==注,此签名没有写入交易==(果然需要写入)

  • 通过链操作获取Alice拥有的UTXO

  • 遍历Alice所有UTXO,并构造“交易输入”加入此次交易

    • utxo的交易ID(此utxo生成时的交易)
    • utxo的输出index(感觉无用的字段,其总是为0)
    • 交易签名写入此“交易输入”
  • 构造向Bob的“交易输出”写入交易

  • 通过链操作获取Alice的余额,并判断是否满足本次交易,如果满足

    • 计算本交易如果成功,则Alice余额是多少
    • 构造一个向Alice写入上述余额的“交易输出”
  • ==创建交易2==(Bob向Charlie转5块,注意,这里没有创建交易输入和输出)

  • 使用Bob的钱包对此次交易签名,==注,此签名没有写入交易==(果然需要写入)

  • 通过链操作获取Bob拥有的UTXO

  • 遍历Bob所有UTXO,并构造==“交易输入”==加入此次交易

    • utxo的交易ID(此utxo生成时的交易)
    • utxo的输出index(感觉无用的字段,其总是为0)
    • 交易签名写入此“交易输入”
  • 构造向Charlie的==“交易输出”==写入交易

  • 通过链操作获取Bob的余额,并判断是否满足本次交易,如果满足

    • 计算本交易如果成功,则Bob余额是多少
    • 构造一个向Bob写入上述余额的==“交易输出”==
  • ==创建交易==3(Charlie向Alice转2.5块,注意,这里没有创建交易输入和输出)

  • 使用Charlie的钱包对此次交易签名,==注,此签名没有写入交易==(果然需要写入)

  • 通过链操作获取Charlie拥有的UTXO

  • 遍历Charlie所有UTXO,并构造“交易输入”加入此次交易(==交易的输入是发起者所有的UTXO==)

    • utxo的交易ID(此utxo生成时的交易)
    • utxo的输出index(感觉无用的字段,其总是为0)
    • 交易签名写入此“交易输入”
  • 构造向Alice的“交易输出”写入交易(==接受者的交易输出==)

  • 通过链操作获取Charlie的余额,并判断是否满足本次交易,如果满足

    • 计算本交易如果成功,则Charlie余额是多少
    • 构造一个向Charlie写入上述余额的“交易输出”(==发起者的交易输出==,这里其实是统计发起者的余额)
  • ==通过链操作将交易加入交易池(transactionPool_)==

    • 在transactions_中查找交易,如果找到返回失败
    • 验证交易
      • 验证签名(前文提到,交易签名要写入交易)
      • 验证发送者有足够余额(这里利用入参传进来的utxo池)
      • 验证交易金额大于0
      • 验证交易双方不是一个地址
    • 添加到交易池
  • 往链上增加一个块(无需携带新的交易,链会检查之前加入的未完成交易)

    • 合并新交易和待处理交易(==transactionPool_==有,transactions无)
    • ==生成块==
      • 初始化块index,交易列表,前块的hash值
      • 获取时间戳
      • 创建MerkleTress生成merkleRoot_
      • 计算hash值
    • ==挖矿(更新hash值)==
    • ==块添加到链上==
    • ==更新UTXO池==(链操作,入参是块)
      • 遍历交易
        • 遍历交易输入
          • 如前文(这里包括了发起者所有的UTXO,==通过向链上的UTXO系统获取==,即它可能有多个),此次遍历将在链上删除所有这些UTXO,即发起方链上原有的所有UTXO将被删除(下文会计算并重构一个余额UTXO)
        • 2025.05.20 2:21 不行了,先睡了,不然明天就废了
        • 遍历交易输出(这里2个,一个是本次交易的接收方新增一个UTXO,一个是本次交易发送方重新构建一个余额UTXO)
          • 生成一个UTXO(交易ID,序号(本次交易的输出序号,这里可以是0和1),金额,拥有者ID)
          • UTXO加入==utxoPool_==(chain上总池)
            • 第一级map key为交易ID
            • 第二级map key为utxo的输出index(这里永远为0吧?,这里明显可以为1)
    • 清空交易池中已确认的交易
      • 遍历之前合并的交易(该交易被加入块)
        • ==transactionPool_== 中删除所以交易(这里transactionPool_为空,所以无操作)
  • 通过链上操作获取各个钱包的余额并显示

  • ==开始第二轮交易==

  • 交易4:Alice sends 7.5 coins to Charlie(生成一个交易,链上获取Alice UTXO,用Alice钱包给交易签名,将Alice所有UTXO加入交易输入,给Charlie添加交易输出,给Alice添加交易余额)

  • 交易5:Charlie sends 3 coins to Bob(生成一个交易,链上获取Charlie UTXO,用Alice钱包给交易签名,将Charlie 所有UTXO加入交易输入,给Bob添加交易输出,给Charlie 添加交易余额)

  • 将交易4和5加入链上未处理交易(==验证交易,通过才允许加入==)

  • 在链上添加一个块(生成块<构造成员,生成merkleroot,计算hash>,挖矿,添加到链上,更新UTXO池<入参是块>,清空交易池中已确认交易)

  • 通过链上操作获取各个钱包的余额并显示

  • 打印链信息

v0.0.4

15 May 16:53

Choose a tag to compare

添加钱包系统,包括密钥生成、签名和验证功能。

Full Changelog: v0.0.2...v0.0.4

v0.0.2

15 May 09:32

Choose a tag to compare

简单的交易结构和Merkle树

Full Changelog: v0.0.1...v0.0.2

v0.0.1

15 May 09:23

Choose a tag to compare

Basic blockchain demo code, including initializing the chain, adding blocks to the chain, and verification.

Full Changelog: https://github.com/Zeratal/BlockChain/commits/v0.0.1