比特币的”支票“、”找零“、按长计算手续费机制、与账户管理机制

这是一篇专业科普均适用的文章,所以放到极客论道里。

想到写此文的原因是因为Multibit的找零BUG,需要解释一下为什么会产生这么一个BUG。

本文为原创,全部知识来自于3个月来对比特币源代码的苦读。结论来自于自己的思考。

1 比特币交易的”支票“

”支票“这个词不敢说是首创,但绝对是原创。因为我从未看到谁提过这个概念。

比特币的最小存储单元,不是钱包,也不是账户,而是”支票“。

为什么要用”支票“呢?这要从支付的本质说起。

当一个账户付款的时候,必须先要确认它的余额是否够支付的。

现在的银行系统,每一次消费之前,银行要计算一下你的账户余额,就是用全部的收入减去全部的支出。如果一个账户开了10年,收入支出会上千上万笔,计算量会越来越大。银行用的是超级服务器集群,计算量再大都受得了;比特币钱包都是装在个人电脑里,如果每个客户端每次交易都要全部从头算一遍,这种计算方法会把电脑全部搞崩溃。

所以,比特币开发团队非常有智慧地发明了一个机制:支票和找零机制。

一定是先有收入,后有支出。(原初收入来自挖矿收入,所以叫coinbase)

所以,只要拿出以前的单笔收入证明(支票),其收入金额大于支出额;或者多笔收入证明,其收入总和大于支出额,这这笔支付交易就是有效的。这样验证方的电脑工作量就非常小:验证是否有之前的这笔收入支票,这笔收入支票是否被花掉过。

因为每笔收入(支票)只能用一次,所以收入和支出之间就会产生差额,这个差额通过”找零“机制返还给支出者——很简单,自己指定一个地址,把支付之后剩余的钱放进这个地址。

所以,比特币交易的每一笔收入,就相当于一个支票。好比你收到1张1万的支票,今天要花费100元,那么就生成2张支票,一张100元,开给对方,一张9900元,开给自己,1万的这一张标明”已使用“,从此作废。

2 交易的结构与灵活性

一个交易(transaction)由多笔输入支票和输出支票构成。输入可以来自多个地址,输出也可以打给多个地址,输入和输出的地址是可以重复的。

这种设计的初衷,是考虑到比特币记账空间是稀缺资源(既占用网络流量,又占用CPU计算,又占用硬盘存储),一定要把交易信息最大程度压缩。

这样的一个设计,兼容度特别强,如果用编程术语来说,叫”泛型“。因为它涵盖了太多的可能性:

将一个支票转移到另外一个地址。(保持匿名性,或者基于账户安全需要)

用一个支票支付给一个地址,余额找零会自己的地址。(最常见的支付方式)

用一个支票支付给多个地址。(例如老板发工资)(例如为了隐私保密,把大额账户打散到多个小额账户)

用同一个地址的多个支票凑在一起做一笔支付。(大额支付)

用多个地址的多个支票凑在一起做一笔支付(例如AA制)。

用多个地址的多个支票支付给多个地址(还是比如老板发工资,用自己的多笔收入支付给多个员工的地址)(未来手续费高了之后,还有一种应用:搭伙交易。就是把多笔完全不相干的支付放到一个交易里,这样可以节省手续费)

将自己的多个支票整合为一个支票。

将自己的多个地址的余额整合入一个地址。

另外,比特币还支持多私钥账户(三方共管账户)和多种签名方式,因为不是本文主题,就不展开讨论了。

作为对照,我们看到,银行系统现在只支持最基本的交易方式:一个账户支付到一个账户。

3 按长计算手续费与账户管理机制

由于前面提到的,比特币的记账空间是稀缺资源,所以比特币的协议约定,每一个block最多只能存储1M的数据。矿工挖矿,自然希望收入最大化,即用哪些交易填满这1M,收入最高。因而,交易手续费的计算单位,不是交易额,也不是交易笔数,而是字节数。比特币协议设定的手续费计算单位是千字节(当然如果矿工够狡猾,可以把单位做的更小),当前约定的是每千字节手续费最低为万分之一比特币。

这和支票有什么相干呢?

比特币有趣的地方就在这里。看似不相干的地方,却产生了巨大的关联,并导致后面许多衍生结果。

如果每一笔交易,都是用一个输入支票,打给一个输出支票和一个找零支票,那么是不是有效支票数量从1个变成了2个,支票数量会越来越多?长此以往,每个人的账户里都会有好多个支票。然后,突然有一天,当你要做一笔大的支付时,可能要动用上百上千个支票,才能凑齐。

按照比特币交易协议, 一个最简单的交易:单一输入支票、一个目标支出支票、一个找零支票,大概要占用300个字节。每增加一个输入支票,要增加169个字节,也即,如果输入支票数量达到6个,交易长度就超过了1KB,就需要支付双份手续费了。以后每增加6个输入支票,交易手续费就增加一份。换言之,每一个支票,在花费时,都会产生六万分之一比特币的手续费(做小额生意收比特币的老板们,想不到还有这么一笔隐形成本吧?)。因为都是找零支票,所以金额都会很小,假设每个支票只有万分之一比特币,那么手续费将达到惊人的1/6!即便每个支票是千分之一比特币,手续费也将是1/60,这一点都不比银行转账便宜!

有省钱办法吗?当然有啊。

因为最低计费单位是1KB,不到1KB也收万分之一比特币,而一个普通交易只有300个字节,所以可以用剩余的724字节消灭4个小额支票。即虽然一个支票就够付的了,但是在交易里还是要另外放上4个小额的支票,然后将这4个支票的金额都放到找零支票里。这样一折腾,5进2出,支票的数量就会不断变少,那么前面论述的那笔额外手续费就被化解掉了。

所以,一个好的(或者说负责任的,或者说懂行的)比特币钱包程序,都需要开发小额支票的自动清理机制。不具备这样机制的钱包都是不合格的。我只用过QT钱包,据我观察,QT钱包有这个机制,但不是很完善。

4 账户管理机制的其他考虑

除了节省手续费,账户管理机制还需要考虑到以下用户需求:

4.1 支付灵活性。如果剩余支票过少,同时发生多笔支付就会产生麻烦,因为需要等前一笔支付确认之后,才能确认后一笔支付。而确认一次需要30分钟时间,遇到急事,会让人抓狂的。

4.2 隐私保密。因为单一地址的余额是公开的秘密,谁都可以查到,所以比特币土豪很容易被人肉出来。所以对应的,应当将余额较大的账户,资金分散到多个地址里,这样只有账户持有者知道这些地址属于同一个人,而陌生人很难知道。当然这个机制具体实现要比说的复杂,因为他人很容易从这些账户的交易关联性中找出蛛丝马迹,就像我通过我的提现地址顺藤摸瓜发现了MT控制的6000个币一样。http://www.bit-sky.com/index.php/2013-12-15-15-08-16/2014-01-27-19-39-08/418-mt-gox-6000

4.3 多个收款地址和多个付款地址。为了识别客户,需要给每个客户提供一个不同的收款地址。类似的道理,有时需要给每一个供应商一个专用付款地址,以方便记账(因为供应商提供的收款地址并不一定永远不变)。这背后需要的处理逻辑就复杂多了。这种需求最典型的是交易中心;当然所有的商户都有类似需求。这是一套比特币的财务管理系统。(不知币付宝是如何设计的?)

4.4 钱包文件大小和备份安全性。比如QT钱包每100次支付就会自动生成100个新地址,导致以前的钱包备份文件失效,就是一个相当严重的漏洞.

比特币是一个智慧的宝库,中本聪隐身了,好多玄妙之处我们只能自己挖掘体会了。