Skip to content

Commit c6a183f

Browse files
author
建平
committed
交易池和UTXO系统调试完成
1 parent 93e8f45 commit c6a183f

6 files changed

Lines changed: 98 additions & 37 deletions

File tree

README.md

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ blockchain.addBlock({
725725
2. 普通交易必须遵守余额规则
726726
3. 系统交易仍然需要验证签名,确保其合法性
727727

728-
## 交易池和UTXO
728+
## 交易池和UTXO(0.0.6)
729729

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

@@ -965,6 +965,29 @@ void Blockchain::updateUTXOPool(const Block& block) {
965965
966966
### 阶段总结
967967
968+
本阶段用例在链上添加了2个数据
969+
970+
- 交易池
971+
- UTXO池
972+
973+
事实上,UTXO在链上是永久驻留,其记录了每笔交易的结果(财富属于谁)
974+
975+
- 每次交易发生,该次交易的发起方的历史UTXO都被清除,并生成一个新的代表余额的UTXO;
976+
- 每次交易发生,该次交易的接收方将添加一个新的UTXO(所以某个钱包如果只接收不支出,则UTXO会越来越多
977+
978+
而Transaction Pool只是缓存未完成交易
979+
980+
- 当链上新增一个块时,会检查链上未完成交易,并将所有未完成交易计入此块的交易。
981+
- 对该块挖矿(工作量证明)
982+
- 针对该块更新UTXO(即将交易池中未完成交易完成)
983+
- 清空交易池
984+
985+
所以在此例中,交易池不是必须的。
986+
987+
988+
989+
示例程序流程
990+
968991
- 创建三个钱包(构造时生成秘钥对),获取钱包公钥作为身份识别
969992
- 创建链,生成一个0块。id为0,空交易,前置块Hash为0
970993
- 链上注册钱包,公钥到钱包的映射
@@ -1013,28 +1036,28 @@ void Blockchain::updateUTXOPool(const Block& block) {
10131036
10141037
- 使用Bob的钱包对此次交易签名,==注,此签名没有写入交易==(果然需要写入)
10151038
- 通过链操作获取Bob拥有的UTXO
1016-
- 遍历Bob所有UTXO,并构造“交易输入”加入此次交易
1039+
- 遍历Bob所有UTXO,并构造==“交易输入”==加入此次交易
10171040
- utxo的交易ID(此utxo生成时的交易)
10181041
- utxo的输出index(感觉无用的字段,其总是为0)
10191042
- 交易签名写入此“交易输入”
1020-
- 构造向Charlie的“交易输出”写入交易
1043+
- 构造向Charlie的==“交易输出”==写入交易
10211044
- 通过链操作获取Bob的余额,并判断是否满足本次交易,如果满足
10221045
- 计算本交易如果成功,则Bob余额是多少
1023-
- 构造一个向Bob写入上述余额的“交易输出”
1046+
- 构造一个向Bob写入上述余额的==“交易输出”==
10241047
- ==创建交易==3(Charlie向Alice转2.5块,注意,这里没有创建交易输入和输出)
10251048
10261049
- 使用Charlie的钱包对此次交易签名,==注,此签名没有写入交易==(果然需要写入)
10271050
10281051
- 通过链操作获取Charlie拥有的UTXO
1029-
- 遍历Charlie所有UTXO,并构造“交易输入”加入此次交易
1052+
- 遍历Charlie所有UTXO,并构造“交易输入”加入此次交易(==交易的输入是发起者所有的UTXO==)
10301053
- utxo的交易ID(此utxo生成时的交易)
10311054
- utxo的输出index(感觉无用的字段,其总是为0)
10321055
- 交易签名写入此“交易输入”
1033-
- 构造向Alice的“交易输出”写入交易
1056+
- 构造向Alice的“交易输出”写入交易(==接受者的交易输出==)
10341057
- 通过链操作获取Charlie的余额,并判断是否满足本次交易,如果满足
10351058
- 计算本交易如果成功,则Charlie余额是多少
1036-
- 构造一个向Charlie写入上述余额的“交易输出”
1037-
- 通过链操作将交易加入交易池(transactionPool_)
1059+
- 构造一个向Charlie写入上述余额的“交易输出”(==发起者的交易输出==,这里其实是统计发起者的余额)
1060+
- ==通过链操作将交易加入交易池(transactionPool_)==
10381061
- 在transactions_中查找交易,如果找到返回失败
10391062
- 验证交易
10401063
- 验证签名(前文提到,交易签名要写入交易)
@@ -1053,16 +1076,29 @@ void Blockchain::updateUTXOPool(const Block& block) {
10531076
- ==块添加到链上==
10541077
- ==更新UTXO池==(链操作,入参是块)
10551078
- 遍历交易
1056-
- 遍历交易输入(这里无)
1057-
- 2025.05.20 2:21 不行了,先睡了,不然明天就废了
1058-
- 遍历交易输出(这里3个)
1059-
- 生成一个UTXO(交易ID,序号(0),金额,拥有者ID)
1079+
- 遍历交易输入
1080+
- 如前文(这里包括了发起者所有的UTXO,==通过向链上的UTXO系统获取==,即它可能有多个),此次遍历将在链上删除所有这些UTXO,即发起方链上原有的所有UTXO将被删除(下文会计算并重构一个余额UTXO)
1081+
- ~~2025.05.20 2:21 不行了,先睡了,不然明天就废了~~
1082+
- 遍历交易输出(这里2个,一个是本次交易的接收方新增一个UTXO,一个是本次交易发送方重新构建一个余额UTXO)
1083+
- 生成一个UTXO(交易ID,序号(本次交易的输出序号,这里可以是0和1),金额,拥有者ID)
10601084
- UTXO加入==utxoPool_==(chain上总池)
10611085
- 第一级map key为交易ID
1062-
- 第二级map key为utxo的输出index(这里永远为0吧?)
1086+
- 第二级map key为utxo的输出index(这里永远为0吧?,这里明显可以为1
10631087
- 清空交易池中已确认的交易
10641088
- 遍历之前合并的交易(该交易被加入块)
10651089
- ==transactionPool_== 中删除所以交易(这里transactionPool_为空,所以无操作)
1090+
- 通过链上操作获取各个钱包的余额并显示
1091+
- ==开始第二轮交易==
1092+
- 交易4:Alice sends 7.5 coins to Charlie(生成一个交易,链上获取Alice UTXO,用Alice钱包给交易签名,将Alice所有UTXO加入交易输入,给Charlie添加交易输出,给Alice添加交易余额)
1093+
- 交易5:Charlie sends 3 coins to Bob(生成一个交易,链上获取Charlie UTXO,用Alice钱包给交易签名,将Charlie 所有UTXO加入交易输入,给Bob添加交易输出,给Charlie 添加交易余额)
1094+
- 将交易4和5加入链上未处理交易(==验证交易,通过才允许加入==)
1095+
- 在链上添加一个块(生成块<构造成员,生成merkleroot,计算hash>,挖矿,添加到链上,更新UTXO池<入参是块>,清空交易池中已确认交易)
1096+
- 通过链上操作获取各个钱包的余额并显示
1097+
- 打印链信息
1098+
1099+
1100+
1101+
10661102
10671103
# 遗留
10681104

block.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Block::Block(int index, const std::vector<Transaction>& transactions, const std:
1313
, previousHash_(previousHash)
1414
, nonce_(0)
1515
{
16-
std::cout << "Block::Block create" << std::endl;
16+
std::cout << "Block::Block create" << index_ << std::endl;
1717
auto now = std::chrono::system_clock::now();
1818
auto now_c = std::chrono::system_clock::to_time_t(now);
1919
timestamp_ = std::ctime(&now_c);

blockchain.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void Blockchain::addBlock(const std::vector<Transaction>& transactions) {
4747
updateUTXOPool(*newBlock);
4848

4949
// 清空交易池中已确认的交易
50+
std::cout << "\n clearTransactionPool: " << allTransactions.size() << std::endl;
5051
for (const auto& tx : allTransactions) {
5152
std::cout << " removeTransaction: " << tx.getTransactionId() << std::endl;
5253
transactionPool_.removeTransaction(tx.getTransactionId());
@@ -64,29 +65,30 @@ std::vector<Transaction> Blockchain::getPendingTransactions() const {
6465

6566
void Blockchain::updateUTXOPool(const Block& block) {
6667
// 处理区块中的每个交易
68+
std::cout << "\n updateUTXOPool: " << block.getTransactions().size() << std::endl;
6769
for (const auto& tx : block.getTransactions()) {
6870
// 移除已使用的UTXO
69-
std::cout << "updateUTXOPool: " << tx.getTransactionId() << std::endl;
70-
std::cout << " inputs: " << tx.getInputs().size() << std::endl;
71+
std::cout << " updateUTXOPool: " << tx.getTransactionId() << std::endl;
72+
std::cout << " inputs: " << tx.getInputs().size() << std::endl;
7173
for (const auto& input : tx.getInputs()) {
7274
utxoPool_.removeUTXO(input.getTxId(), input.getOutputIndex());
73-
std::cout << " removeUTXO: " << input.getTxId() << ", " << input.getOutputIndex() << std::endl;
75+
std::cout << " removeUTXO: " << input.getTxId() << ", " << input.getOutputIndex() << std::endl;
7476
}
7577

7678
// 添加新的UTXO
77-
std::cout << " outputs: " << tx.getOutputs().size() << std::endl;
79+
std::cout << " outputs: " << tx.getOutputs().size() << std::endl;
7880
for (size_t i = 0; i < tx.getOutputs().size(); ++i) {
79-
std::cout << " addUTXO: " << tx.getTransactionId() << ", " << i << std::endl;
81+
std::cout << " addUTXO: " << tx.getTransactionId() << ", " << i << std::endl;
8082
const auto& output = tx.getOutputs()[i];
8183
UTXO utxo(tx.getTransactionId(), i, output.getAmount(), output.getOwner());
8284
utxoPool_.addUTXO(utxo);
83-
std::cout << " addUTXO: " << utxo.getTxId() << ", " << utxo.getOutputIndex() << std::endl;
85+
// std::cout << " addUTXO: UTXO: " << utxo.getTxId() << ", " << utxo.getOutputIndex() << ", " << utxo.getAmount() << ", " << utxo.getOwner() << std::endl;
8486
}
8587
}
8688
}
8789

8890
double Blockchain::getBalance(const std::string& address) const {
89-
std::cout << "getBalance: " << address << std::endl;
91+
// std::cout << "getBalance: " << address << std::endl;
9092
return utxoPool_.getBalance(address);
9193
}
9294

@@ -110,6 +112,7 @@ bool Blockchain::isChainValid() const {
110112

111113
// 验证交易(包括余额检查)
112114
bool Blockchain::validateTransaction(const Transaction& tx) const {
115+
std::cout << "Blockchain::validateTransaction: " << tx.getTransactionId() << std::endl;
113116
// 检查签名
114117
if (!tx.verifySignature()) {
115118
std::cout << "Transaction signature verification failed" << std::endl;

main.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ int main() {
4747
std::cout << "\nCreating first group of transactions..." << std::endl;
4848

4949
// Alice sends 10 coins to Bob
50+
51+
std::cout << "\nAlice sends 10 coins to Bob" << std::endl;
5052
Transaction tx1(alicePublicKey, bobPublicKey, 10.0);
51-
std::cout << "tx1: " << tx1.getTransactionId() << std::endl;
53+
std::cout << "\ntx1: " << tx1.getTransactionId() << std::endl;
5254
auto aliceUTXOs = blockchain.getUTXOsForAddress(alicePublicKey);
5355
std::cout << "aliceUTXOs: " << aliceUTXOs.size() << std::endl;
5456
std::string tx1Signature = aliceWallet->sign(tx1.getTransactionId());
@@ -59,29 +61,31 @@ int main() {
5961
}
6062
tx1.addOutput(TransactionOutput(10.0, bobPublicKey));
6163
if (blockchain.getBalance(alicePublicKey) > 10.0) {
62-
std::cout << "addOutput alicePublicKey: " << blockchain.getBalance(alicePublicKey) - 10.0 << std::endl;
64+
std::cout << "addOutput alicePublicKey balance: " << blockchain.getBalance(alicePublicKey) - 10.0 << std::endl;
6365
tx1.addOutput(TransactionOutput(blockchain.getBalance(alicePublicKey) - 10.0, alicePublicKey));
6466
}
6567

6668
// Bob sends 5 coins to Charlie
69+
std::cout << "\nBob sends 5 coins to Charlie" << std::endl;
6770
Transaction tx2(bobPublicKey, charliePublicKey, 5.0);
68-
std::cout << "tx2: " << tx2.getTransactionId() << std::endl;
71+
std::cout << "\ntx2: " << tx2.getTransactionId() << std::endl;
6972
auto bobUTXOs = blockchain.getUTXOsForAddress(bobPublicKey);
7073
std::cout << "bobUTXOs: " << bobUTXOs.size() << std::endl;
7174
std::string tx2Signature = bobWallet->sign(tx2.getTransactionId());
7275
tx2.setSignature(tx2Signature);
7376
for (const auto& utxo : bobUTXOs) {
74-
std::cout << "addInput utxo: " << utxo.getTxId() << ", " << utxo.getOutputIndex() << std::endl;
7577
tx2.addInput(TransactionInput(utxo.getTxId(), utxo.getOutputIndex(), tx2Signature));
7678
}
7779
tx2.addOutput(TransactionOutput(5.0, charliePublicKey));
7880
if (blockchain.getBalance(bobPublicKey) > 5.0) {
79-
std::cout << "addOutput bobPublicKey: " << blockchain.getBalance(bobPublicKey) - 5.0 << std::endl;
81+
std::cout << "addOutput bobPublicKey balance: " << blockchain.getBalance(bobPublicKey) - 5.0 << std::endl;
8082
tx2.addOutput(TransactionOutput(blockchain.getBalance(bobPublicKey) - 5.0, bobPublicKey));
8183
}
8284

8385
// Charlie sends 2.5 coins to Alice
86+
std::cout << "\nCharlie sends 2.5 coins to Alice" << std::endl;
8487
Transaction tx3(charliePublicKey, alicePublicKey, 2.5);
88+
std::cout << "\ntx3: " << tx3.getTransactionId() << std::endl;
8589
auto charlieUTXOs = blockchain.getUTXOsForAddress(charliePublicKey);
8690
std::cout << "charlieUTXOs: " << charlieUTXOs.size() << std::endl;
8791
std::string tx3Signature = charlieWallet->sign(tx3.getTransactionId());
@@ -92,19 +96,20 @@ int main() {
9296
}
9397
tx3.addOutput(TransactionOutput(2.5, alicePublicKey));
9498
if (blockchain.getBalance(charliePublicKey) > 2.5) {
95-
std::cout << "addOutput charliePublicKey: " << blockchain.getBalance(charliePublicKey) - 2.5 << std::endl;
99+
std::cout << "addOutput charliePublicKey balance: " << blockchain.getBalance(charliePublicKey) - 2.5 << std::endl;
96100
tx3.addOutput(TransactionOutput(blockchain.getBalance(charliePublicKey) - 2.5, charliePublicKey));
97101
}
98102

99103
// Add transactions to pool
100-
std::cout << "addTransactionToPool tx1" << std::endl;
104+
std::cout << "\naddTransactionToPool tx1" << std::endl;
101105
blockchain.addTransactionToPool(tx1);
102-
std::cout << "addTransactionToPool tx2" << std::endl;
106+
std::cout << "\naddTransactionToPool tx2" << std::endl;
103107
blockchain.addTransactionToPool(tx2);
104-
std::cout << "addTransactionToPool tx3" << std::endl;
108+
std::cout << "\naddTransactionToPool tx3" << std::endl;
105109
blockchain.addTransactionToPool(tx3);
106110

107111
// Add block (includes transactions from pool)
112+
std::cout << "\nmain: addBlock" << std::endl;
108113
blockchain.addBlock({});
109114

110115
// Print balances
@@ -117,34 +122,49 @@ int main() {
117122
std::cout << "\nCreating second group of transactions..." << std::endl;
118123

119124
// Alice sends 7.5 coins to Charlie
125+
std::cout << "\nAlice sends 7.5 coins to Charlie" << std::endl;
120126
Transaction tx4(alicePublicKey, charliePublicKey, 7.5);
127+
std::cout << "\ntx4: " << tx4.getTransactionId() << std::endl;
121128
aliceUTXOs = blockchain.getUTXOsForAddress(alicePublicKey);
129+
std::cout << "aliceUTXOs: " << aliceUTXOs.size() << std::endl;
122130
std::string tx4Signature = aliceWallet->sign(tx4.getTransactionId());
131+
tx4.setSignature(tx4Signature);
123132
for (const auto& utxo : aliceUTXOs) {
133+
std::cout << "addInput utxo: " << utxo.getTxId() << ", " << utxo.getOutputIndex() << std::endl;
124134
tx4.addInput(TransactionInput(utxo.getTxId(), utxo.getOutputIndex(), tx4Signature));
125135
}
126136
tx4.addOutput(TransactionOutput(7.5, charliePublicKey));
127137
if (blockchain.getBalance(alicePublicKey) > 7.5) {
138+
std::cout << "addOutput alicePublicKey balance: " << blockchain.getBalance(alicePublicKey) - 7.5 << std::endl;
128139
tx4.addOutput(TransactionOutput(blockchain.getBalance(alicePublicKey) - 7.5, alicePublicKey));
129140
}
130141

131142
// Charlie sends 3 coins to Bob
143+
std::cout << "\nCharlie sends 3 coins to Bob" << std::endl;
132144
Transaction tx5(charliePublicKey, bobPublicKey, 3.0);
145+
std::cout << "\ntx5: " << tx5.getTransactionId() << std::endl;
133146
charlieUTXOs = blockchain.getUTXOsForAddress(charliePublicKey);
147+
std::cout << "charlieUTXOs: " << charlieUTXOs.size() << std::endl;
134148
std::string tx5Signature = charlieWallet->sign(tx5.getTransactionId());
149+
tx5.setSignature(tx5Signature);
135150
for (const auto& utxo : charlieUTXOs) {
151+
std::cout << "addInput utxo: " << utxo.getTxId() << ", " << utxo.getOutputIndex() << std::endl;
136152
tx5.addInput(TransactionInput(utxo.getTxId(), utxo.getOutputIndex(), tx5Signature));
137153
}
138154
tx5.addOutput(TransactionOutput(3.0, bobPublicKey));
139155
if (blockchain.getBalance(charliePublicKey) > 3.0) {
156+
std::cout << "addOutput charliePublicKey balance: " << blockchain.getBalance(charliePublicKey) - 3.0 << std::endl;
140157
tx5.addOutput(TransactionOutput(blockchain.getBalance(charliePublicKey) - 3.0, charliePublicKey));
141158
}
142159

143160
// Add transactions to pool
161+
std::cout << "\naddTransactionToPool tx4" << std::endl;
144162
blockchain.addTransactionToPool(tx4);
163+
std::cout << "\naddTransactionToPool tx5" << std::endl;
145164
blockchain.addTransactionToPool(tx5);
146165

147166
// Add block
167+
std::cout << "\nmain: addBlock" << std::endl;
148168
blockchain.addBlock({});
149169

150170
// Print balances

transaction.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ Transaction::Transaction(const std::string& from, const std::string& to, double
2525
, to_(to)
2626
, amount_(amount)
2727
{
28+
std::cout << "Transaction::Transaction: " << from_ << " " << to_ << " " << amount_ << std::endl;
2829
transactionId_ = calculateTransactionId();
29-
std::cout << "Transaction::Transaction: " << transactionId_ << std::endl;
3030
}
3131

3232
Transaction Transaction::createSystemTransaction(const std::string& to, double amount) {
@@ -37,11 +37,13 @@ Transaction Transaction::createSystemTransaction(const std::string& to, double a
3737
}
3838

3939
void Transaction::addInput(const TransactionInput& input) {
40+
std::cout << "Transaction::addInput: " << transactionId_ << " input: " << input.getTxId() << " " << input.getOutputIndex() << std::endl;
4041
inputs_.push_back(input);
4142
transactionId_ = calculateTransactionId();
4243
}
4344

4445
void Transaction::addOutput(const TransactionOutput& output) {
46+
std::cout << "Transaction::addOutput: " << transactionId_ << " output: " << output.getAmount() << " " << output.getOwner() << std::endl;
4547
outputs_.push_back(output);
4648
transactionId_ = calculateTransactionId();
4749
}
@@ -50,7 +52,7 @@ bool Transaction::verifySignature() const {
5052
if (from_ == "SYSTEM") return true;
5153

5254
// 验证签名
53-
std::cout << "Transaction::verifySignature: " << transactionId_ << " signature: " << signature_ << std::endl;
55+
// std::cout << "Transaction::verifySignature: " << transactionId_ << " signature: " << signature_ << std::endl;
5456
Wallet::verify(transactionId_, signature_, from_);
5557
// 这里需要实现具体的签名验证逻辑
5658
return !signature_.empty();

utxo.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,25 @@ UTXO::UTXO(const std::string& txId, int outputIndex, double amount, const std::s
88
, owner_(owner)
99
, spent_(false)
1010
{
11-
std::cout << "UTXO::UTXO create" << "txId: " << txId_ << ", outputIndex: " << outputIndex_ << ", amount: " << amount_ << ", owner: " << owner_ << ", spent: " << spent_ << std::endl;
11+
std::cout << " UTXO::UTXO create" << "txId: " << txId_ << ", outputIndex: " << outputIndex_ << ", amount: " << amount_ << ", owner: " << owner_ << ", spent: " << spent_ << std::endl;
1212
}
1313

1414
UTXOPool::UTXOPool() {
1515
}
1616

1717
void UTXOPool::addUTXO(const UTXO& utxo) {
18-
std::cout << "UTXOPool::addUTXO: " << utxo.getTxId() << ", " << utxo.getOutputIndex() << std::endl;
18+
std::cout << " UTXOPool::addUTXO: " << utxo.getTxId() << ", " << utxo.getOutputIndex() << std::endl;
1919
utxos_[utxo.getTxId()][utxo.getOutputIndex()] = utxo;
2020
}
2121

2222
void UTXOPool::removeUTXO(const std::string& txId, int outputIndex) {
23-
std::cout << "removeUTXO: " << txId << ", " << outputIndex << std::endl;
23+
std::cout << " removeUTXO: " << txId << ", " << outputIndex << std::endl;
2424
auto txIt = utxos_.find(txId);
2525
if (txIt != utxos_.end()) {
26-
std::cout << "removeUTXO: " << txId << ", " << outputIndex << " found" << std::endl;
26+
std::cout << " removeUTXO: " << txId << ", " << outputIndex << " found" << std::endl;
2727
txIt->second.erase(outputIndex);
2828
if (txIt->second.empty()) {
29-
std::cout << "removeUTXO: " << txId << ", " << outputIndex << " erased" << std::endl;
29+
std::cout << " removeUTXO: " << txId << ", " << outputIndex << " erased" << std::endl;
3030
utxos_.erase(txIt);
3131
}
3232
}

0 commit comments

Comments
 (0)