← 主题目录全部档案 →

转账、确认与手续费

一笔钱如何到账,为什么要等确认,何时需要手续费。

按议题整理 · 中文阅读 · 58 条发言。英文及完整讨论可回到对应档案查看。

到账、确认与交易重播

10 条
中本聪SN-0068按 IP 地址发送是即时的。按比特币地址发送而收款方当时不在线的话,可能要过 30 分钟以上才能看到。

按 IP 地址发送是即时的。按比特币地址发送而收款方当时不在线的话,可能要过 30 分钟以上才能看到。

另外,收款方要先与区块链同步才能看到收到的交易。也就是说底部状态栏至少要显示 33000 区块,比如 "x connections 33200 blocks x transactions"。

其他参与者原话sirius-m原帖 ↗

一笔交易的区块数,指的是这笔交易之后,整个网络生成的新区块数量。链上每个新区块,都意味着新比特币归其创建者。你交易列表里的一条 "generated" 交易,表示的就是你生成了一个区块。"区块"这个概念,第一眼看不明白,你并非第一个。

中本聪回应

如果状态显示 "x confirmations" 会不会更清楚,比如:

2/unconfirmed

3/unconfirmed

4/unconfirmed

5/unconfirmed

6 confirmations

7 confirmations

8 confirmations

每个区块实质上意味着又一个节点确认了它认同截至该处为止的全部交易。

中本聪SN-1085如果客户端收到的新区块里没有你的交易,Bitcoin 会自动重播它。重播大约要一个小时。不过它是不屈不挠的。它会永远不厌其烦…

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

如果客户端收到的新区块里没有你的交易,Bitcoin 会自动重播它。重播大约要一个小时。不过它是不屈不挠的。它会永远不厌其烦地骚扰网络,直到你的交易进了区块。

中本聪SN-1323我相信支付处理公司可以把「快速分发交易 + 足够好的校验」作为一种服务提供,在大约 10 秒或更短时间内完成。

我相信支付处理公司可以把「快速分发交易 + 足够好的校验」作为一种服务提供,在大约 10 秒或更短时间内完成。

网络节点只接受收到的第一版交易,纳入它正在尝试生成的区块。当你广播一笔交易时,如果别人同时广播了一笔双重支出,这就是一场看谁先传播到最多节点的竞赛。谁有一点先发优势,就会以几何级数在网络上扩散得更快,拿下大多数节点。

粗略的估算例子:

1 0

4 1

16 4

64 16

80% 20%

所以双重支出哪怕只晚一秒,都处于巨大劣势。

支付处理器会与许多节点保持连接。收到一笔交易后,它会立刻向外广播,同时监控网络中是否出现双重支出。只要它连接的任一监听节点收到冲突交易,支付处理器就会把原交易标记为有问题。双重支出交易很难广泛传播而不被其中一个节点发现。攻击者必须等监听阶段结束后再行动,可到那时,支付处理器广播的交易已经到达大多数节点,或者在传播速度上遥遥领先,攻击者几乎不可能再争取到足够多的剩余节点。

中本聪SN-1325我没说滴水不漏,我说的是足够好。实际操作中的损失会远低于信用卡。
其他参与者原话llama原帖 ↗

这是个好开端,但仍然不是滴水不漏。

中本聪回应

我没说滴水不漏,我说的是足够好。实际操作中的损失会远低于信用卡。

其他参与者原话llama(续)原帖 ↗

(比如拒绝在售货机处转发该交易的消息)

中本聪回应

不,售货机连的是一个大服务商(即支付处理器),它向众多商户提供这项服务。可以想成一个有了新业务的信用卡处理机构。它们会拥有许多连接良好的网络节点。

中本聪SN-1731如果交易一开始没有立刻发出去,比如你当时没连网,重发最长可能要等 2 小时。长期来看,它确实会锲而不舍地一直发。

如果交易一开始没有立刻发出去,比如你当时没连网,重发最长可能要等 2 小时。长期来看,它确实会锲而不舍地一直发。

未来版本我会把这个时长缩短。

你得先下载完整的区块链(当前 71040 个区块)才能看到任何确认。收款方也一样。

中本聪SN-2551没错。你不需要重新广播你的交易它也能工作。

没错。你不需要重新广播你的交易它也能工作。

当任何节点断开一个分叉时,它会把分叉里的全部交易倒回交易池,以便加入新链。整个网络都在保证把你的交易重新整合进去。你唯一会看到的就是确认数从 0 重新开始计数。

在某些类型的分叉里,你的交易本来就已经进了两条分叉,所以无论哪边赢你都没事。

中本聪SN-2844正如你想明白的那样,根本问题在于:交易没有至少 1 个确认之前,我们并不该计数、也不该花费。0/unconfirmed 交易…

正如你想明白的那样,根本问题在于:交易没有至少 1 个确认之前,我们并不该计数、也不该花费。0/unconfirmed 交易就是彻头彻尾的二等公民。它们至多是「收到了什么东西」的提示,把它们计入余额或花出去都为时过早。

我做了改动,让它们以浅色显示,金额放在方括号里如 [+1.23],不计入余额、不可用于花费。这并不适用于你发出的交易——你无条件地信任它们,因是你写的。

我并未用 (+1.23),因会计里圆括号表示负数。我希望方括号的区分足够明显,让人明白是什么意思。

JSON-RPC 接口如果需要,仍能通过指定 0 个确认看到 0/unconfirmed。

我已把改动上传到 SVN rev 158。我很快会发 0.3.13 RC。

如果你的钱包里有这类交易,在升级到 0.3.13(很快会来)之前,不要发出任何支付。

如果你已经发出过这类交易,或者你就是它们的创建者,那么用 theymos 的补丁,或者做下面这个改动,从而用它把你的干净交易发到一个新钱包,清理干净。

把:

if (pcoin->GetDepthInMainChain() < 1 && pcoin->GetDebit() <= 0)

continue;

改成:

if (pcoin->GetDepthInMainChain() < 1)

continue;

中本聪SN-2875在你的节点拥有一条回溯到区块链的交易路径之前,交易不会被接受、也不会显示为 0/unconfirmed。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

其他参与者原话theymos原帖 ↗

ArtForz 已经在免手续费运行了,他占全网算力的 20-30%。不过,最初发送这些坏交易的人已经删掉了自己的钱包,网络也忘掉了这些历史交易,因此基于此的交易无法确认。

中本聪回应

在你的节点拥有一条回溯到区块链的交易路径之前,交易不会被接受、也不会显示为 0/unconfirmed。

你钱包里的任何交易也都捆绑着抵达区块链所需的全部未记录交易。如果你有一笔显示为 0/unconfirmed 的交易,那么它依赖的所有先前未记录交易你都有,你重播自己的交易时也会一并重播它们。

如果免手续费的区块已经生成、却没起作用,那我需要看看哪里出了问题。这是一段很少被用到的代码。它们本应被记录进每一个持有依赖交易的节点的钱包里。

其他参与者原话theymos原帖 ↗

最初发送这些坏交易的人已经删掉了自己的钱包

中本聪回应

叹气……为什么要删除钱包,而不是把它移到一边、留个旧副本以防万一?永远不要删除钱包。

其他参与者原话tcatm原帖 ↗

已经在跑了。3 小时内应该能出一个块。

中本聪回应

收集重播交易恐需要一段时间。如果你能接受入站连接会更有帮助,这样你能听到更多节点。就算你 3 小时内出了块,也请至少连续跑上几天。

中本聪SN-2885确保你的节点保持在线,这样它才能持续重播交易 b412a0。从 29/09/2010 16:41 起就未见它重播过了。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

确保你的节点保持在线,这样它才能持续重播交易 b412a0。从 29/09/2010 16:41 起就未见它重播过了。

中本聪SN-2847那更多是 SelectCoins 层面的事。

那更多是 SelectCoins 层面的事。

SVN rev 161 有一个改进:递归判断你自己的未确认交易能否被花费。这是必需的,因你应该能立刻花掉自己的找零。

新的递归判定是:0/unconfirmed 能花费,条件是它是你的,而且它的所有依赖要么已进区块、要么也是你的。

这是一个 Windows 构建:

http://www.bitcoin.org/download/bitcoin-0.3.13.2-win32-setup.exe

如果你已经有 0/unconfirmed 交易、而且可能已经花过它,这个版本是个改进。如果你是某笔 0/unconfirmed 交易的原始创建者,你仍然需要用 theymos 的补丁。

手续费与交易优先级

22 条
中本聪SN-0290超大交易有一笔小额手续费。生成包含该交易的区块的节点会得到这笔费用。

超大交易有一笔小额手续费。生成包含该交易的区块的节点会得到这笔费用。

同一笔钱之后再次转出时,不会再次产生这笔费用。如果你的钱包里全是挖矿所得,又想一次全部转出,就必须在一笔很大的交易中,合并数百份每份 50 个比特币的挖矿奖励。完成这次合并后,以后再转出这笔资金时,交易里只需要一个输入项。

中本聪SN-0294几乎所有交易都是免费的。如果一笔交易必须把 500 多笔你收到的最大额付款加总才能凑够金额,它就超过了最大尺寸限制。超限交易…
其他参与者原话theymos原帖 ↗

发送方客户端会多发一些比特币来覆盖费用吗(这样收款方拿到的正是他期望的数额)?

中本聪回应

会。

其他参与者原话SmokeTooMuch原帖 ↗

为什么我们还需要费用?我以为"无费用"正是比特币的优点之一呢 ?!

中本聪回应

几乎所有交易都是免费的。如果一笔交易必须把 500 多笔你收到的最大额付款加总才能凑够金额,它就超过了最大尺寸限制。超限交易加一笔小额费用仍可发出。

平均规模的交易,以及最大到 500 倍于平均规模的交易,都是免费的。

只有发送真正巨大的交易时手续费才会登场,即便这样,算下来也大约只有金额的 0.002%。这并非从系统里抽走的钱,它只是流向其他节点。如果你为付这笔费而难过,你随时可以反客为主自己运行一个节点,说不定哪天你自己就捞到一笔 0.44 的费用。

中本聪SN-0296对。否则我们无法给比特币设 2100 万的有限上限,因为生成永远需要某个最低回报。几十年后当回报变得太小,手续费将成为节点的…

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

对。否则我们无法给比特币设 2100 万的有限上限,因为生成永远需要某个最低回报。几十年后当回报变得太小,手续费将成为节点的主要补偿。我相信 20 年后,要么交易量非常大,要么就没有交易量。

中本聪SN-1361通常要超过 25,000 BTC。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

通常要超过 25,000 BTC。

中本聪SN-0998忘了说微支付的好话了。虽然我认为 Bitcoin 目前对更小额的微支付不实用,但随着存储和带宽成本持续下降,它最终会变得实用…

忘了说微支付的好话了。虽然我认为 Bitcoin 目前对更小额的微支付不实用,但随着存储和带宽成本持续下降,它最终会变得实用。如果 Bitcoin 大规模流行,到那时也许已经是这样了。它们变得更实用的另一条路,是我实现 client-only 模式、网络节点合并为更少数量的专业服务器农场。无论你需要多小面额的微支付,最终都会实用。我想 5 到 10 年后,带宽和存储都会显得微不足道。

我并不是说网络对 DoS 攻击免疫。我认为大多数 P2P 网络都可以被用各种方式 DoS。(顺便说一句,我看到唱片公司想对所有文件共享网络发动 DoS,只是不想触犯反黑客/反滥用法律。)

如果我们开始被大量来回的垃圾交易 DoS,你就需要开始支付 0.01 的最低手续费了。0.1.5 其实有过设置它的选项,但我为了减少困惑把它拿掉了。免费交易是件好事,只要大家不滥用,我们可以一直这样。

这就引出一个问题:如果每笔交易有 0.01 的最低手续费,如果只是最低的 0.01,我们要不要自动加上?每次都问一遍会烦死人。如果你有 50.00、发送 10.00,收款方得到 10.00,你剩 39.99。我认为应该自动加上。跟其他许多服务自动附加的费用比,这算微不足道。

其他参与者原话FreeMoney原帖 ↗

多打包交易会拖慢你的哈希速率吗?

中本聪回应

不,完全不。

中本聪SN-1001我不知道怎么实现这个。给区块创建者的手续费用了一个特殊技巧,让手续费不占任何额外空间。如果每笔手续费都是一笔交易,那手续费的…

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

其他参与者原话bytemaster原帖 ↗

这个问题唯一的解法是让交易广播「不再免费」。也就是说,你想让我把交易纳入区块,就得付钱给我。净结果是每个客户端要向它发送交易的那些客户端付费,而不只是向最终把它打进区块的人付费。这样,经济规律接管一切,谁也别想搭交易广播系统的便车。

中本聪回应

我不知道怎么实现这个。给区块创建者的手续费用了一个特殊技巧,让手续费不占任何额外空间。如果每笔手续费都是一笔交易,那手续费的交易自己的手续费又怎么办?

中本聪SN-2101我想不出实现它的办法。所有手续费都会是额外的交易。那手续费的交易自己的手续费又怎么办?

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

我想不出实现它的办法。所有手续费都会是额外的交易。那手续费的交易自己的手续费又怎么办?

中本聪SN-2294-paytxfee 允许你在交易里附带手续费。如果交易确认变慢了,你可以用 "-paytxfee=0.01" 来获得优先。你…

不,不是这么回事。

-paytxfee 允许你在交易里附带手续费。如果交易确认变慢了,你可以用 "-paytxfee=0.01" 来获得优先。你发出的每笔交易都会多花 0.01。没有理由设得比 0.01 更高。

它只是放在那里以防万一。多半用不上,真用上了再细说也不迟。

中本聪SN-2710另一个选项是降低每个区块允许的免费交易数量,超过之后才要求手续费。节点每个区块只接受一定 KB 的免费交易,超过后就开始要求…

另一个选项是降低每个区块允许的免费交易数量,超过之后才要求手续费。节点每个区块只接受一定 KB 的免费交易,超过后就开始要求至少 0.01 手续费。

这个门槛应该比现在更低。

我认为门槛永远不该是 0。我们应该始终允许至少一些免费交易。

中本聪SN-2714目前,付不付手续费由 -paytxfee 开关手动控制。让软件自动检查最近区块的大小、判断是否该付手续费,相当容易。我们离触…

目前,付不付手续费由 -paytxfee 开关手动控制。让软件自动检查最近区块的大小、判断是否该付手续费,相当容易。我们离触及门槛还远得很,暂时不需要。而且先看看手动控制的效果如何,本来就是个好主意。

就算到了门槛也没什么大不了。免费交易只是要花更久才进区块。

我粗略统计了 74000-78000 附近的 4000 个区块。这不包括区块奖励交易:

平均每区块 2 笔交易、每小时 17 笔、每天 400 笔。

平均每区块交易字节 428 字节,即每笔交易 214 字节。

现在的门槛是每区块 200KB,约合每区块 1000 笔交易。我认为应该降到每区块 50KB。那仍然是平均每区块交易量的 100 多倍。

门槛将来很容易调整。到时候我们能决定调高。先保持较低作为断路器、按需调高是好主意。如果现在就触及门槛,那几乎肯定是某种洪水攻击而不是真实使用。保持较低门槛有助于在这种情况下限制浪费的磁盘空间。

中本聪SN-2731出事的那个是什么版本?发布版,还是自己构建的?什么操作系统?

出事的那个是什么版本?发布版,还是自己构建的?什么操作系统?

你是用 IP 发的还是用 Bitcoin 地址发的?

你发 49.99 时,它有没有提示你付 0.01 手续费?

GetMinFee 有过一个改动,但我看不出它怎么会导致这个。它只在区块变得巨大时才开始生效。

区块数不同的原因,是 0.3.11 里把显示数字减了 1,因那样更合理。

中本聪SN-2732我猜我知道发生了什么。双击那笔挖矿交易。它里面很可能带了一笔低于 0.01 的手续费。

我猜我知道发生了什么。双击那笔挖矿交易。它里面很可能带了一笔低于 0.01 的手续费。

有人一直在付 0.00000010 的手续费。我觉得用 -paytxfee 你连这个都设不出来,得改代码才行。你生成的区块价值 50.00000010,因此当你试图把整笔发出去时,只剩 0.00000010 当找零,这就触发了灰尘垃圾的 0.01 手续费。

除了这个边角案例它通常无害。我应该给 CreateTransaction 加个特例来处理这种情况。

中本聪SN-2735修复在 SVN rev 151。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

修复在 SVN rev 151。

下次升级后,你就能把卡住的 0.01(实际是 0.01000010)发出去了。

中本聪SN-2715我已在 SVN rev 157 里实现了这个改动。
中本聪原话中本聪原帖 ↗

现在的门槛是每区块 200KB,约合每区块 1000 笔交易。我认为应该降到每区块 50KB。那仍然是平均每区块交易量的 100 多倍。

中本聪回应

我已在 SVN rev 157 里实现了这个改动。

我之前把门槛设得那么高,是为了让很大的交易也不必支付手续费。对于由一笔笔 50 BTC 挖矿奖励组成的交易,这个门槛大约相当于 26,000 BTC。尽管当时挖矿比现在容易 100 倍,也只有极少数人达到过这个手续费门槛。新门槛下,转出挖矿所得时大约到 11,000 BTC 才会触发手续费,而且主要只有挖矿所得才容易遇到这种情况。如果你的比特币是买来的,它们通常来自金额更大的交易,离手续费门槛还很远,除非你分几百笔交易买入。即使真的达到门槛,也只需要付一次手续费,就能把这些零碎款项合并起来。

中本聪SN-2851它随区块填满逐步抬高手续费要求:

它随区块填满逐步抬高手续费要求:

<50KB 免费

50KB 0.01

250KB 0.02

333KB 0.03

375KB 0.04

以此类推。

这是典型的定价机制。前 50KB 卖完后,价格涨到 0.01。250KB 卖完后,涨到 0.02。到了某个价格,只要你愿意出价比其他客户高,你几乎总能挤进去。

只附上最低的 0.01 就已经大有帮助。

中本聪SN-2853没错,这个开关应该更动态、按 KB 付费。只是更难想清楚该怎么解释。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

没错,这个开关应该更动态、按 KB 付费。只是更难想清楚该怎么解释。

中本聪SN-2868能请几个人跑一下这个特别构建吗?它会特赦那些灰尘垃圾交易,从而暂时解决 0/unconfirmed 问题。我们其实只需要一个…

能请几个人跑一下这个特别构建吗?它会特赦那些灰尘垃圾交易,从而暂时解决 0/unconfirmed 问题。我们其实只需要一个放行它们的区块,就能清理掉以前的交易。如果你用它生成了区块,请回帖。

这些只有二进制包。linux 版只有 64 位。

http://www.bitcoin.org/download/bitcoin-0.3.13.1-specialbuild-win32.zip

http://www.bitcoin.org/download/bitcoin-0.3.13.1-specialbuild-linux64.tar.gz

SHA1 fb7c66270281ed058c570627cf7baff0bdc16e5d bitcoin-0.3.13.1-specialbuild-win32.zip

SHA1 9fc44ea5f2109618073e2cfd887e2cc266eb31a9 bitcoin-0.3.13.1-specialbuild-linux64.tar.gz

linux 64 位版包含对 cpuid 4 路 128 位 SSE2 自动检测的修改(针对 64 位模式下的 AMD),如果你愿意测试看看是否更好。

中本聪SN-3198感谢你们把灌水测试限制在测试网。

感谢你们把灌水测试限制在测试网。

0.3.15 版组合了多项功能,帮助合法交易在洪水攻击期间插队。关键在于 Gavin 的想法:按依赖的年龄给交易排优先级。每一枚币都有权按一定频率转手。等得越久,累积的优先级越高。优先级 = sum(valuein * age) / txsize。手续费仍然优先于优先级,而优先级决定同一费率层内的处理顺序。

为支持优先级功能,SelectCoins 只在万不得已、只剩下你自己的 0 确认交易时才使用它们。这有助于避免你快速转手自己的币,除非你真是通过快速转手全部币来强行做到的。

中本聪SN-3200你应该至少保留一些优先级,以防下一个区块到来之前网络被淹没。
其他参与者原话ByteCoin原帖 ↗

当然,如果网络没有被垃圾交易淹没、你也不太在意当前这笔交易被耽搁,那么优先使用你的 0 确认交易恐更划算,这样可以把较高优先级的币「省」下来,留到网络真的被淹没时用。

中本聪回应

你应该至少保留一些优先级,以防下一个区块到来之前网络被淹没。

只要所有依赖的交易都至少有 1 个确认,如果交易一开始优先级不够,依赖交易会随着时间推移老化,直到它够为止。

其他参与者原话ByteCoin(续)原帖 ↗

当然,像我上面说的那样往交易里塞入约 1,000 个刚周转过的 BTC 来抬高优先级,这种钻空子的手法依然有效!

中本聪回应

或者管理你在每笔交易上花费多少优先级。软件得预知你未来的计划,才能知道应该现在花掉优先级还是留到以后。不过我觉得我们不需要做到这么细。正常用户和攻击者之间的差异足够大。

优先级不必包办一切。一旦确认有洪水攻击,你能加上 -paytxfee=0.01。希望有了优先级机制,你在此之前发出的交易最坏也只是慢,而不是卡死。

中本聪SN-3633我正在做的就是类似的事。优先级就是你描述的这个概念更正式化的版本。
其他参与者原话creighto原帖 ↗

或许在最近实现的年龄优先级规则之外,还应加一条无手续费交易的最小年龄规则。换句话说,或许能定一条生成规则:免费交易务必埋深 3 个区块之后才能再次免费转账。这样真实用户在必要时仍可立即花掉新资金,同时仍然能不计成本地重新调配自己的资金。我认为这会显著抑制目前正在进行的垃圾交易攻击。

中本聪回应

我正在做的就是类似的事。优先级就是你描述的这个概念更正式化的版本。

其他参与者原话FreeMoney原帖 ↗

按现状,3.15 有不少免费交易空间,这些空间优先给 [年龄]*[金额]/[大小] 最高的交易,对吧?划出一部分自由空间要求 [年龄]*[金额]/[大小] > C 是否合理?

也许能把 C 设成让一笔标准的 1 BTC 交易能进下一个区块的主免费区。而 .1 BTC 的要等约 10 个区块才能进。再让允许 [年龄]*[金额]/[大小] < C 的区域每次放行十来笔交易。

中本聪回应

是的,就像这样。不要求优先级的区域是 3K,每区块约十来笔交易。

我刚上传了 SVN r185,对免费交易设置了最低优先级要求。交易洪水由反复重花的币构成,因此它们反复依赖自己的 0 确认交易。0 确认交易优先级为 0,这类免费交易只能一次等一笔交易先进区块。

0.3.15 版在使用 0 确认依赖写交易时,只在别无选择的情况下才用,因此普通用户通常不会遇到这个问题。

我认为这是在把默认手续费设为 0.01 之外的一个好折中。要求免费交易只能这么频繁地周转币,并不算过分。你用免费交易,就是在接受施舍,而同一批币能用施舍的频率总得有个上限。

我们一直说免费交易可能会处理得慢一些。加上 -paytxfee=0.01 能帮你确保交易快速通过。

中本聪SN-3132感谢 m0mchil 持续跟进更新!
其他参与者原话m0mchil原帖 ↗

更新到 SVN 186

中本聪回应

感谢 m0mchil 持续跟进更新!

GPU 矿工们,请尽快升级,终结免费交易滥用!这个版本带有新的基于优先级的免费交易垃圾限制。

其他参与者原话m0mchil原帖 ↗

刚更新到 SVN 181,并修正了 getwork 补丁:在用新交易重建区块之间等待 60 秒。这其实是原版客户端的行为,补丁里误漏掉了。修复了每个 getwork 请求都占满 CPU 的问题(在最近大量交易垃圾攻击下变得很明显)。请升级。

中本聪回应

在 SVN 184 之前,把交易编译进区块用的是 n^2 算法。新的高效单遍算法要快上几个数量级。(O(n) 对比 O(n^2)/2,n=200 时约莫快 10 到 100 倍)

中本聪SN-3810有一个面向遥远未来的可能设计:

不是 locktime。

有一个面向遥远未来的可能设计:

你有意写一笔双重支出。用同样的输入和输出再写一遍,但这次带上手续费。当你的双重支出进入区块时,第一笔支出就失效了。收款方其实不会察觉,因在新交易生效的那一刻,旧交易就失效了,新交易直接取而代之。

说起来容易,实现起来难。要写出一个能正确构造双重支出的客户端、在钱包里管理两个版本直到其中之一被选中、处理好所有边角情况,工作量不小。现有代码里的每一个假设都是「你不会试图写双重支出」。

比特币矿工侧也需要一些改动,让交易池有可能接受双重支出,但只严格限于输入输出匹配且手续费更高的情况。目前,双重支出从不被交易池接受,因此每个节点都在用它见到的第一笔交易进块来作证。

收款地址与支付方式

11 条
中本聪SN-0176端口转发是把一个端口指向一台计算机。它告诉路由器由哪台计算机处理发往该端口的连接。所以收款的就是那台机器。

端口转发是把一个端口指向一台计算机。它告诉路由器由哪台计算机处理发往该端口的连接。所以收款的就是那台机器。

如果没设置端口转发,入站连接不会到达任何一台计算机,向该 IP 发送时只会提示无法连接收款方,什么也发不出去。按 IP 发送时,你其实仍是发到一个比特币地址:你的计算机连上那个 IP,向它索取一个新的比特币地址,把交易直接交给它,并确认它收到且接受。

应该有人把自己的静态 IP 贴出来,让大家试试按 IP 发送,顺便白送那个人一些钱。

比特币地址里有 32 位校验和,所以你不会不小心打错一个无效地址。

如果 4) 你发给了某个已抛弃或丢失 wallet.dat 的收款人,钱就丢了。这里有个微妙之处:既然流通中的总钱数变少了,每个人剩下的钱都会略微升值,即"自然通缩"。

中本聪SN-0366不是,每笔生成的交易都用一个新的、一次性的地址。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

其他参与者原话NewLibertyStandard原帖 ↗

生成的比特币是用主 Bitcoin 窗口当前显示的那个地址加密的吗?

中本聪回应

不是,每笔生成的交易都用一个新的、一次性的地址。

什么都不用主窗口里的地址,它只是放在那儿方便你复制。0.2.5 在它旁边加了个 "New..." 按钮,每次使用前都能轻松换新。

中本聪SN-0309在销售点用会很不错。收银机在屏幕上显示一个编码了比特币地址和金额的二维码,你用手机拍下来。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

在销售点用会很不错。收银机在屏幕上显示一个编码了比特币地址和金额的二维码,你用手机拍下来。

中本聪SN-0536生成一个新的比特币地址,只在你自己的电脑上占用一点磁盘空间(大约 500 字节)。就像生成一个新的 PGP 私钥,只是 CP…

生成一个新的比特币地址,只在你自己的电脑上占用一点磁盘空间(大约 500 字节)。就像生成一个新的 PGP 私钥,只是 CPU 消耗更小,因为它是 ECC。地址空间实际上无限。它不伤害任何人,所以想生成多少就生成多少。

中本聪SN-0316瞧,我们完全可以照同样的方式做,比如:
其他参与者原话Karmicads原帖 ↗
中本聪回应

瞧,我们完全可以照同样的方式做,比如:

http://127.0.0.1:8330/?to=;amount=

Bitcoin 可以像在 8332 上应答 JSON-RPC 那样,在本地回环的 8330 端口上应答,给出 HTTP 应答。

其他参与者原话DataWraith原帖 ↗

bitcoin 链接应该更像 mailto: 而不是 magnet:,恕我直言。

中本聪回应

我想我们能办到。

虽然 Bitcoin 有可能在 HTTP 应答里呈现 HTML 界面、直接把事情办了,但作为用户,我会疑惑:是某个网站想骗我,还是我真的在和自己的 Bitcoin 服务器对话?

HTTP 应答可以只是一段带 JavaScript 的 HTML,等价于后退按钮,把浏览器送回原页面。然后 Bitcoin 弹出发送比特币对话框,目标比特币地址和金额已经填好。工作方式就像 mailto: 链接弹出一个已填好地址的新邮件。

127.0.0.1 回环对机器上的任何用户都可访问,没有按用户隔离,但这没关系,因为它只提供"预填对话框字段"的便利功能。你仍然得按发送。我们要确保发送按钮不处于选中状态,免得你正在敲空格或回车时它跳到前台。

中本聪SN-0495你生成的比特币地址会永久保留。必须保留一个比特币地址,才能证明发往它的东西归你所有。如果你能删除一个比特币地址而有人向它发了…

SheriffWoody:

你生成的比特币地址会永久保留。必须保留一个比特币地址,才能证明发往它的东西归你所有。如果你能删除一个比特币地址而有人向它发了款,钱就丢了。它们每个只有大约 500 字节。

sirius-m:

上千个自有地址完全不成问题。如果你已经生成了 50000 BTC,那你其实已经有 1000 个自有地址了,每生成 50 个就有一个。它们是隐藏的,不在 UI 里显示。

加一小段代码、给同一个 IP 持续返回同一个地址,是个好主意。我是这样用 C++ 做的:在对方使用之前,一直给同一个 IP 返回同一个密钥(即比特币地址):

// Keep giving the same key to the same ip until they use it

if (!mapReuseKey.count(pfrom->addr.ip))

mapReuseKey[pfrom->addr.ip] = GenerateNewKey();

...sends the key mapReuseKey[pfrom->addr.ip]

……之后……

// Received something with this key

mapReuseKey.erase(pfrom->addr.ip);

如果不方便知道何时收到过款,就每 20 分钟清一次缓存的密钥。

我想给 getnewaddress 加一个参数:若该地址在多少天内无收款就过期。

中本聪SN-0670现在的按 IP 发送没什么用:它连接到那个 IP,所以你为了匿名想用 TOR,可那样它就完全可能被窃听、被中间人攻击。

现在的按 IP 发送没什么用:它连接到那个 IP,所以你为了匿名想用 TOR,可那样它就完全可能被窃听、被中间人攻击。

未来按 IP 发送的计划是做成比特币地址加 IP 的形式,比如:

1auaDZCFYqaGx4FKS5WenNfurk2SkoDu4h1.2.3.4

1auaDZCFYqaGx4FKS5WenNfurk2SkoDu4hdomain.com

我需要分隔符字符的建议。":" 是个候选,但 IPv6 里也有 :,可能造成混淆。最好是 url 参数里允许的字符。

我想用 SSL 做连接,用比特币地址的公钥作为证书。这样你就能确定自己连上的正是你想要的对方,并且安全加密。比特币地址不用于交易,只用于认证。一个新生成的比特币地址会通过 SSL 连接发来。

既然经过了认证,允许 IP 地址是域名就安全了。需要留意的是:如果用了代理,要用 socks4a 而不是 DNS 查询。

中本聪SN-0679SirArthur 关于普通在线商家的观点很有道理,而那正是按 IP 发送选项更适合的场景。这种情况下,商家在静态 IP 上…

SirArthur 关于普通在线商家的观点很有道理,而那正是按 IP 发送选项更适合的场景。这种情况下,商家在静态 IP 上有自己的服务器、自己的域名和 SSL 证书。

我们可以不按 IP 连接,而是通过 SSL 连接一个域名,用现有的 CA 基础设施来认证你连上的确实是该域名的所有者。

用户发送到 domain.com(或 www.domain.com 也行)。那会非常自然,用户可以看到并核实自己输入的正是他要付款的对象。

SSL 也让 TOR 用户的安全得到保障。

问题是,我认为商家仍会更愿意用比特币地址,好确切知道这笔付款对应什么订单。你根本不能指望用户在备注栏里填对内容来标识交易。只有当我们有了 mailto 式的链接、能把订单号预填进备注栏,这才接近实用——但那样的话,链接里放一个比特币地址也照样行。

只在 domain.com 上开一个开放的比特币服务器、让用户把身份不明的付款发过去,责任太大了。普通用户不习惯"必须标识付款"这个概念。商家会收到太多空白付款,一周之后跟一句"我付过钱了,我的东西呢?!"

付款流程里确实有一个步骤:接收方在接受之前验证订单。如果不包含有效的订单号,它可以拒绝付款并返回错误消息。不过这需要把定制代码与比特币服务器做相当深度的集成。

中本聪SN-0318但既然链接已经替你把字都打好了,我看不出用域名地址代替比特币地址有什么好处。用比特币地址,用户无法发出一笔身份不明的付款。在…

http://127.0.0.1:8330/?to=domain.com&amount=200.00&comment=order_12345

http://127.0.0.1:8330/?to=1.2.3.4&amount=200.00

但既然链接已经替你把字都打好了,我看不出用域名地址代替比特币地址有什么好处。用比特币地址,用户无法发出一笔身份不明的付款。在拿到一个正确的比特币地址之前,他们根本无法付款。

按域名发送的好处是你可以直观地核实钱发给了谁。

一个更关键的问题是:如果浏览器不被允许连接 127.0.0.1 怎么办:

http://bitcointalk.org/index.php?topic=63.msg1589#msg1589

而且如果真是这样,那个包含 127.0.0.1 的 freenet 链接示例又怎么说?

中本聪SN-2098结果是反正没人喜欢那种转账方式,因此它没得到什么开发关注。

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

没实现。

结果是反正没人喜欢那种转账方式,因此它没得到什么开发关注。

中本聪SN-2773最好默认禁用按 IP 收款,除非你明确打算用它。这是一大片无人使用的攻击面,没有必要默认开放。

最好默认禁用按 IP 收款,除非你明确打算用它。这是一大片无人使用的攻击面,没有必要默认开放。

在商店场景下,你通常只想让顾客通过你的自动化系统付款,它只发放与特定订单和账户关联的 bitcoin 地址。随机、无身份的支付自愿发到服务器的 IP 地址上,没有任何用处。

总的来说,按 IP 发送的实用场景有限。如果不经代理直连,中间人风险或许能容忍,但没有隐私。如果你用隐私代理,中间人风险则高得不可接受。如果我们费劲实现了 SSL,通常只大商家才愿意花功夫拿 CA 证书,而这些场景大多仍然用 bitcoin 地址更好。

我已把这个改动上传到 SVN rev 156。启用的开关是 "-allowreceivebyip"。

用这个版本的发送方会得到错误 "Recipient is not accepting transactions sent by IP address"。旧版本的发送方会得到 "Transfer was not accepted"。

我给开关用了不同的名字,因 "-allowiptransactions" 听起来像包含发送。如果这个开关有更好的名字,我们能再改。

商家如何正确记账

15 条
中本聪SN-0116如 riX 所说,这才是正路。软件可以在每次收款时按需生成新的比特币地址。"请发送 X 个比特币至 [一次性比特币地址] 以…

如 riX 所说,这才是正路。软件可以在每次收款时按需生成新的比特币地址。"请发送 X 个比特币至 [一次性比特币地址] 以完成订单"。服务器收到该地址上的这笔金额,就可以触发自动发货或给店主发邮件。

加命令行支持是高优先级。只是要有时间写代码。

中本聪SN-0664我加了几个与标签相关的函数,帮助管理每个用户的多个地址。新增或更名的函数:

我加了几个与标签相关的函数,帮助管理每个用户的多个地址。新增或更名的函数:

getreceivedbyaddress -- 单个地址收到的金额

getreceivedbylabel -- 带此标签的所有地址收到的金额

listreceivedbyaddress -- 列出地址及其收到的金额

listreceivedbylabel -- 列出标签及其收到的金额

setlabel -- 为完整性补充的其他标签函数

getlabel

getaddressesbylabel

为保持一致,我把 getamountreceived 更名为 getreceivedbyaddress、getallreceived 更名为 listreceivedbyaddress。旧名字仍在,以免破坏现有代码,但已弃用。

思路是:只要你在调用 getnewaddress 时提供用户名,就能用 "bylabel" 函数取得该用户在所有地址上的收款总额。你可以随意更换他的地址,不必操心追踪他所有旧地址。

自动更换用户收款地址的好办法:就在显示他当前地址之前,检查它是否收到过任何东西,如果有就换成新地址:

// Get a new address whenever the current one has received anything

if (strAddr == "" || getreceivedbyaddress(strAddr) > 0)

strAddr = getnewaddress(strUsername); // Label the address with username

Display(strAddr); // Display their current receiving address

// Get total received by all the user's addresses

getreceivedbylabel(strUsername, 0) // unconfirmed

getreceivedbylabel(strUsername, 1) // available balance

如果只是取某个特定用户的余额,比如响应那个用户的页面请求,用 getreceivedbylabel;如果要遍历所有用户,最好用 listreceivedbylabel 拿到完整列表再对照结果扫描。用 getreceivedbylabel 扫描用户是 n 的平方,用 listreceivedbylabel 是 n-log-n(或 n 线性)。

其实只有当你为了"一收到钱就自发采取行动"而轮询、而不是用户打开网页看到余额后告诉你怎么处理时,才真正需要扫描全部用户。没必要轮询得太频繁。如果你要求 1 个确认,反正平均要 10 分钟,每几分钟轮询一次以上毫无意义。

如果你卖的是数字商品和服务——有人免费蹭到也没多大损失、也无法转卖牟利——我认为接受 0 确认没问题。

基本上只有卖黄金或货币时才需要多个确认。

中本聪SN-0543是的,实际上它就是这样。getallreceived 0 就能满足你的要求。(现在它已更名为 listreceivedbya…
其他参与者原话molybdenum原帖 ↗

或者一个可选参数指定该交易之后的最小区块数(getallreceived 1 为当前行为,或直接 getallreceived,getallreceived 5 给偏执狂,getallreceived 0 为即时确认)?

中本聪回应

是的,实际上它就是这样。getallreceived 0 就能满足你的要求。(现在它已更名为 listreceivedbyaddress 0)默认是 1 个确认,但我认为实际上大多数数字商品和服务可以 0 确认。如你所说,如果你需要多于 0 个确认,可以显示两个数字:未确认余额和可用余额,这样他们立刻就能看到交易已经通过。

listreceivedbyaddress [minconf=1] [includeempty=false]

[minconf] 是款项被计入所需的最少确认数。

[includeempty] 是否包含尚未收到任何付款的地址。

返回一个对象数组,包含:

"address" : 接收地址

"label" : 接收地址的标签

"amount" : 该地址收到的总金额

"confirmations" : 所含最近一笔交易的确认数

或者,如果你用用户名给地址贴标签,就用 listreceivedbylabel。

到目前为止,我集中精力于面向 web 商家的函数,无界面挖矿机的远程管理功能还没怎么顾上。

中本聪SN-0782我担心太多程序员会拿它去检查收款。那样永远不可靠。list/getreceivedbyaddress/label 函数才是可…
其他参与者原话lachesis原帖 ↗

不过 listtransactions RPC 方法要是能在下个版本前完成就好了。

中本聪回应

我担心太多程序员会拿它去检查收款。那样永远不可靠。list/getreceivedbyaddress/label 函数才是可靠的做法。

我们不该为了等每个可能的特性都完成而无限期拖延。永远都会有一件事等着做。

中本聪SN-1271这是个 wxWidgets 应用,所以没有 main() 函数。不久之后也许就有了,因为我离让 bitcoind 不依赖 w…

在 init.cpp。

这是个 wxWidgets 应用,所以没有 main() 函数。不久之后也许就有了,因为我离让 bitcoind 不依赖 wxBase 编译已经很近了。(到时候会放在 init.cpp)

我把文件命名成 "main.cpp",抱歉,当时另一个可选名字是 "core.cpp"。现在改太迟了。不过我还是更喜欢 main.cpp。

我们仍然非常缺示例代码,展示使用 JSON-RPC 函数的推荐方式,比如给一个典型的 storefront 网站做基本的账户系统。用 getreceivedbylabel、以用户名做 label,账户存的地址被用过之后就换一个新比特币地址。我在论坛某个地方贴过一段示例代码片段。(搜 getreceivedbylabel 或 getnewaddress)示例代码可以是一个最普通不过的银行网站,可以存款、可以付款。

中本聪SN-1211我一直想鼓励有人写一些示例 Python 代码并发布出来,展示做常规记账事务的推荐方式,但都没下文。要是你不必像现在这样重新…

我一直想鼓励有人写一些示例 Python 代码并发布出来,展示做常规记账事务的推荐方式,但都没下文。要是你不必像现在这样重新发明轮子就好了。搜 getnewaddress,你应该能找到一个我贴过一小段示例伪代码的主题。

中本聪SN-1297我们需要有人写示例代码,最好是 Python 或 Java,展示用 JSON-RPC 接口创建账户系统的推荐方式。大多数卖东…

我们需要有人写示例代码,最好是 Python 或 Java,展示用 JSON-RPC 接口创建账户系统的推荐方式。大多数卖东西的网站都需要类似的东西。一直跟进这里 JSON-RPC 主题的人应该对它该怎么工作有概念。

用户登录自己的账户后,你展示他能汇入资金的比特币地址。展示之前,先检查这个地址是否已被用过,用过就换新的(getnewaddress )。你只需要在数据库里为每个账户保留最新的比特币地址。(我在之前的某个主题里贴过这段的示例代码片段,搜 getnewaddress)

用 getreceivedbylabel 、以用户名做 label,取账户的「贷方」金额。你需要在数据库里记一个「借方」金额。账户当前余额是(贷方 - 借方)。用户花钱时,增加借方。

如果你要求多于 0 个确认,最好同时展示当前余额(0 确认)和可用余额(1 个或以上确认),这样用户能立刻看到付款已被接收。不是所有网站都要等确认,所以「当前 + 可用」双余额应该是可选的。卖数字商品的网站大多 0 确认就够。

一个合适的示例应用是个简单的银行网站:具备以上功能,外加向比特币地址付款的选项。示例代码应该尽可能简单,只带让它成为可用网站的最少东西。

vekja.net 就是这类网站的一个例子。

中本聪SN-1713你需要用 listtransactions 做什么?

你需要用 listtransactions 做什么?

我当初不实现 listtransactions,就是想确保 web 程序员不会用它。人们很容易顺手拿它来盯收到的付款。走那条路没有任何可靠的办法保证什么都不漏。在拿出过硬的示例代码、用 getreceivedbyaddress 和 getreceivedbylabel 指着说「用这个!用这个!别用 listtransactions!」之前,我认为不应该实现 listtransactions。

真要实现的时候,也许一个对抗滥用的办法是把它做成纯文本。不要把字段拆成 comment、confirmations、credit、debit 之类。可以是一个格式化好的字符串,比如 "0/unconfirmed 0:0:0 date comment debit 4 credit 0" 什么的,让程序员难以做错事、去解析它。它只是用来看服务器状态的。不过我猜这对想把内容格式化成 html 表格的 web 界面来说会有点烦。

中本聪SN-2002我已经有了类似东西的开头。大体上和 Gavin 描述的一样。

我已经有了类似东西的开头。大体上和 Gavin 描述的一样。

再补充一些 rpc 接口:

move

从一个内部账户转到另一个。我想空白账户名("")会是你的默认账户。如果你卖东西给某个用户,能执行 move "theiraccount" "" 123.45。

"move" 是这个名字的最佳选择吗?我避开了 "transfer",因它听起来太像发送一笔交易。

我在考虑新增一个 getaccountaddress 函数,而不是重载 getnewaddress:

getaccountaddress

给你一个从 getnewaddress 分配的地址。它会一直返回同一个地址,直到该地址收到东西,从而分配一个新地址。(它会自动完成我前段时间贴的示例代码所做的事)

这些命令能不能让简单场景下不用自建数据库就实现你的网站?

中本聪SN-2005这是一段伪代码,演示怎么使用基于账户的命令。它确实让网站整合容易多了。

这是一段伪代码,演示怎么使用基于账户的命令。它确实让网站整合容易多了。

print "send to " + getaccountaddress(username) + " to fund your account"

print "balance: " + getbalance(username, 0)

print "available balance: " + getbalance(username, 6)

// 如果达成一笔销售,把钱从他们的账户里移出

move(username, "", amount, 6)

// 提现

sendfrom(username, bitcoinaddress, amount, 6)

中本聪SN-3752这样使用 listtransactions 是不安全的。

这样使用 listtransactions 是不安全的。

我知道我一直因为对 listtransactions 迟迟不肯松口而挨批。让我解释一下我为什么犹豫。

交易是动态的。过去的交易或许会失去确认、消失又回来、失效并彻底消失,或者被另一笔双重支出取代。它们的日期或许会变,顺序也或许会变。

程序员自但然地想这样用 listtransactions:从我上次询问之后,把新交易喂给我,我自己记账或保存静态记录。这在一切常规使用中似乎都没问题,但如果你把金额用于任何用途,它就极具被利用的空间:

1) 你怎么知道一笔过去的交易失效并消失了?

2) 发生区块链重组时,交易重新确认后很容易被重复计数。

3) 一笔交易或许被 txid 不同的双重支出取代。你会把两笔支出都算进去。

「我只需要看新交易、因之前的交易我已经看过了」这个假设模型不成立。旧交易随时可能改变。

每当你基于收到的支付金额采取行动,你都务必回到比特币那里请求当前余额总额(或使用 move 或 sendfrom),并做好余额可能下降的准备。

现在我们有了账户功能,能更容易地按正确方式做事,因此推出 listtransactions 的时机更成熟了。

中本聪SN-3756那你如何应对我在你引用的那条消息里列出的问题?

这条发言承接前面的讨论,可通过下方入口查看完整上下文。

那你如何应对我在你引用的那条消息里列出的问题?

中本聪SN-3759我说的不是某个 minconf 水平下的正常风险,我说的是这样使用 listtransactions 带来的额外陷阱。

我说的不是某个 minconf 水平下的正常风险,我说的是这样使用 listtransactions 带来的额外陷阱。

中本聪原话中本聪原帖 ↗

2) 发生区块链重组时,交易重新确认后很容易被重复计数。

中本聪回应

楼主的 listtransactions [count=10] [txid] 示例似乎在暗示——而且程序员也很容易假定——只要传入上一次调用 listtransactions 的最后一个 txid,就不会再看到同一笔交易,但事实并非这样。如果你不自己维护一个持久的映射或字典来记录哪些 txid 已经接受过,就很容易把支付重复计数。

一个函数看起来就是为某种显而易见的用法量身定做的,而那种用法却是个不显眼的陷阱——这总说不过去。

其他参与者原话jgarzik原帖 ↗

listtransactions 并没有给这个问题添加任何东西,超出了 listreceivedbyaddress 已经暴露的风险之外。

中本聪回应

假设两笔支出都指向同一地址。getreceivedbyaddress 在任一时刻只会计入其中一笔支出,绝不会两笔都算。

用 listtransactions,两笔都算进去就太容易了。你看到第一笔支出,计入;看到第二笔支出,又计入。总额被重复计算。

中本聪SN-3764只要这个接口的定位是向用户展示最近 N 笔交易历史之类的用途,就没问题——何况现在有了账户功能,用正确的方式做支付检测更容易…
其他参与者原话jgarzik原帖 ↗

关于「 之后的交易」,我同意你和中本聪的看法。我的 listtransactions(现在叫 xlisttransactions)补丁刻意不提供那个功能,从来都没有。

中本聪回应

只要这个接口的定位是向用户展示最近 N 笔交易历史之类的用途,就没问题——何况现在有了账户功能,用正确的方式做支付检测更容易了。

Gavin,listtransactions 能不能加个选项,列出所有账户的交易?

我不确定接口应该是什么样,也许:

listtransactions [count]

不过从命令行做这个会很别扭。

我想不出接口的好方案,问题就在这。也许像 "" 一样来个 "*" 特例。这样人人都得确保没有用户能创建名为 "*" 的账户。

其他参与者原话jgarzik原帖 ↗

当然,用交易来追踪这一点相当容易。

中本聪回应

我不明白用交易追踪这事儿怎么就「相当容易」了。

中本聪SN-3834一个使用 0.3.18 新的基于账户命令的伪代码示例。

一个使用 0.3.18 新的基于账户命令的伪代码示例。

print "send to " + getaccountaddress(username) + " to fund your account"

print "balance: " + getbalance(username, 0)

print "available balance: " + getbalance(username, 6)

// if you make a sale, move the money from their account to your "" account

if (move(username, "", amount, 6, "purchased item"))

SendTheGoods()

// withdrawal

sendfrom(username, bitcoinaddress, amount, 6, "withdrawal by user")

你能用 listtransactions(username) 向他们展示其近期交易列表。

目录与阅读顺序由本站整理;原话保留各自日期与上下文。文中软件版本、费用和设置属于当时的历史语境。

← 选择其他主题全部档案 →

阅读字号

选择适合你的字号,之后阅读会继续使用。