【区块链】我实现了 UTXO 自动选择算法(最小手续费策略)
作者:ZFJ_张福杰
博客:https://zfj1128.blog.csdn.net
日期:2025-05-05
关键词:区块链、交易、交易签名、UTXO、手续费
前言
在做钱包或交易系统时,大多数人关注的是"签名、广播、链上交互",但真正影响用户体验的手续费往往被忽略了。
🤔 为什么同样一笔转账,手续费差别可以很大?
答案很直接:
🤗 UTXO 选择策略(Coin Selection)决定了你的手续费
在这里,我结合自己的web3项目经验和自己的理解,完整讲清楚我实现的一套UTXO 自动选择算法:
🤑 以"最小手续费"为目标的 UTXO 自动选择算法

一、UTXO是什么?
在 Bitcoin 中,没有"账户余额"的概念,而是:
UTXO(Unspent Transaction Output)
举个例子:
你的钱包里可能是这样:
| UTXO | 金额 |
|---|---|
| U1 | 0.2 BTC |
| U2 | 0.5 BTC |
| U3 | 1.0 BTC |
当你要转:
0.7 BTC
你需要"拼出"这笔钱,比如:
- 1.0(单个)
- 0.5 + 0.2(两个)
这一步,就是 UTXO 选择
二、手续费是怎么被影响的?
1. 误解
很多人误解:
❌ 手续费跟金额有关
实际上:
手续费 ≈ 交易大小 × 费率
2. 决定因素
那交易大小由什么决定的呢?
最关键因素是:
- 输入数量(UTXO 数量)
- 输出数量(包括找零)
3. 方案对比
| 方案 | 输入数 | 交易体积 | 手续费 |
|---|---|---|---|
| 用 1 个大 UTXO | 1 | 小 | 低 |
| 用 3 个小 UTXO | 3 | 大 | 高 |
结论:
UTXO 越多 → 交易越大 → 手续费越高
三、核心设计思路
目标:最小手续费
我们要实现的算法目标非常明确:
在满足转账金额的前提下,最小化交易体积(从而降低手续费)
这其实是一个:
组合优化问题(类似背包问题)
我没有走"暴力穷举最优解"(性能不可控),而是设计了一套:
工程可用 + 接近最优的策略
Step 1:优先单 UTXO 命中
是否存在一个 UTXO:
👉🏻 ≥ 目标金额 + 预估手续费
如果有:
👉🏻 直接选它(最优解)
Step 2:大额优先(减少输入数)
如果没有单个满足:
👉🏻 按金额从大到小排序:
text
[1.0, 0.5, 0.2]
然后逐个加入,直到满足金额。
👉🏻 这样做的核心目标: 尽量减少输入数量
Step 3:控制输入上限
为了防止极端情况(几十个小 UTXO):
👉🏻 我们可以加限制:
输入数量 ≤ N(例如 3 或 5)
👉🏻 避免: 手续费失控
Step 4:找零(Change Output)
如果:
👉🏻 输入总额 > 转账金额
就必须生成:
👉🏻 找零输出
⚠️ 关键点:
- 找零会增加交易大小
- 也会影响手续费
👉🏻 所以我的策略是: 尽量减少找零 or 让找零接近合理值
四、核心伪代码实现(Dart)
dart
class Utxo {
final int value; // satoshi
Utxo(this.value);
}
List<Utxo> selectUtxos(List<Utxo> utxos, int target) {
// 按金额从大到小排序
utxos.sort((a, b) => b.value.compareTo(a.value));
// 1. 单个UTXO命中
for (var u in utxos) {
if (u.value >= target) {
return [u];
}
}
// 2. 贪心组合
List<Utxo> selected = [];
int total = 0;
for (var u in utxos) {
selected.add(u);
total += u.value;
if (total >= target) {
break;
}
}
return selected;
}
五、补充逻辑
上面只是代码"骨架",真正工程实现必须补这些:
1. 手续费估算
你必须预估:
- 每个 input 大小(约 148 bytes)
- 每个 output 大小(约 34 bytes)
2. 动态费率(sat/vByte)
从网络获取当前推荐费率
3. dust 检测
如果找零太小(dust):
- 不生成找零
- 直接作为手续费
4. UTXO 合并策略(进阶)
在低费率时主动合并小 UTXO:
- 减少未来成本
六、进阶优化
如果这个做个,或者在面试的时候回答了,那就是面试加分了。
1. Branch and Bound(类似 Bitcoin Core)
更接近最优解:
- 枚举组合
- 剪枝优化
2. 精确匹配(Exact Match)
如果能刚好凑齐:
- 不需要找零
- 最省手续费
3. 隐私优化
避免暴露:
- 全部资产
- UTXO 结构
七、总结
👉🏻 UTXO 选择不是"凑金额",而是"优化交易成本"
大多数钱包做到的是:
👉🏻 "能转账"
但真正优秀的钱包会做到:
👉🏻 让用户用最少的钱完成交易
👉🏻 面试官问:你做过 UTXO 选择吗?
我们可以这样说:
我实现了一套以最小手续费为目标的 UTXO 选择算法,优先单UTXO命中,其次采用大额优先的贪心策略减少输入数量,并结合手续费估算、找零优化和dust处理,在性能与最优解之间做了工程平衡
关于作者(ZFJ_张福杰)
- 官网:https://zfjsafe.com
- 博客:https://zfj1128.blog.csdn.net
- Github:https://github.com/zfjsyqk
- Gitee:https://gitee.com/zfj1128
- 打赏:https://zfjsafe.com/paycode