比特币交易系统实现

核心数据结构

1. 交易结构

1
2
3
4
5
struct Transaction {
id: String,
vin: Vec<TXInput>,
vout: Vec<TXOutput>,
}

2. 交易输出(TXOutput)

1
2
3
4
struct TXOutput {
value: i64, // 以satoshi为单位
script_pub_key: String, // 锁定脚本(接收方地址/公钥)
}

说明:

  • value表示代金券金额
  • script_pub_key定义使用规则

3. 交易输入(TXInput)

1
2
3
4
5
struct TXInput {
txid: String, // 引用的交易ID
vout: i32, // 输出索引
script_sig: String, // 解锁脚本
}

说明:

  • vout指明使用哪个输出作为本次输入
  • 未被引用的输出即为余额

功能实现

1. 创世交易

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
impl Transaction {
fn new_coinbase(to: String, data: String) -> Self {
Transaction {
id: String::new(),
vin: vec![TXInput {
txid: String::new(),
vout: -1,
script_sig: data,
}],
vout: vec![TXOutput {
value: 50 * 100_000_000, // 50 BTC
script_pub_key: to,
}],
}
}
}

2. 余额查询实现

查找未花费交易

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
impl Blockchain {
fn find_unspent_transactions(&self, address: &str) -> Vec<Transaction> {
let mut unspent_txs = Vec::new();
let mut spent_outputs = HashMap::new();

for block in self.iter() {
for tx in block.transactions {
// 记录已花费输出
for input in &tx.vin {
if input.can_unlock_output_with(address) {
spent_outputs.insert((input.txid.clone(), input.vout));
}
}

// 查找未花费输出
for (i, output) in tx.vout.iter().enumerate() {
if !spent_outputs.contains_key(&(tx.id.clone(), i as i32))
&& output.can_be_unlocked_with(address) {
unspent_txs.push(tx.clone());
}
}
}
}

unspent_txs
}
}

计算余额

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
impl Blockchain {
fn get_balance(&self, address: &str) -> i64 {
let mut balance = 0;
let utxos = self.find_unspent_transactions(address);

for tx in utxos {
for output in tx.vout {
if output.can_be_unlocked_with(address) {
balance += output.value;
}
}
}

balance
}
}

余额查询流程

图片1

1. 初始化

  • 创建未花费交易切片
  • 创建已花费输出映射

2. 遍历区块链

  • 获取区块链迭代器
  • 遍历每个区块直到创世块

3. 处理交易

  • 遍历区块中所有交易
  • 记录已花费输出
  • 查找未花费输出

4. 验证所有权

  • 检查输出是否能被地址解锁
  • 确认输出未被后续交易花费

5. 计算最终余额

  • 累加所有未花费输出的值
  • 返回总余额

实现特点

  1. 采用UTXO模型
  2. 支持多输入多输出
  3. 实现基础脚本系统
  4. 提供余额查询功能
  5. 支持新交易创建