网络、共识与扩容
节点怎样找到彼此、验证历史、处理分歧并应对规模增长。
按议题整理 · 中文阅读 · 74 条发言。英文及完整讨论可回到对应档案查看。
分叉、工作量与时间规则
21 条
软件没有办法自动判断一条链比另一条好,唯一的判据就是累计工作量最大。按这个设计,不管要回退多远,它都必须切到更长的链上。
这条发言承接前面的讨论,可通过下方入口查看完整上下文。
软件没有办法自动判断一条链比另一条好,唯一的判据就是累计工作量最大。按这个设计,不管要回退多远,它都必须切到更长的链上。
唯一的例外是我加的手动检查点。要不是有它们,它可以把重组一路做到第一个区块。
这就是我最后在 SVN rev 139 里做的。
我们需要触发一次重组,把无效链断开。
那是个麻烦的办法。
我们需要触发一次重组,把无效链断开。
这段代码很少有机会得到测试,而且相当复杂,所以简单安全的做法最好。
我的想法是这样。(还没测试过)它检查主链上的所有区块。发现坏的,就把那条链的 bnChainWork 全部置 0,让它无法再成为最佳链,并把最佳链工作量降为分叉点处的值,这样分叉点之后的任何新区块都会触发重组。(不真正做一次重组,它改不了 pindexBest)
这还不完善。它仍需要收到一个有效区块来触发重组。
也许可以在检查之后主动调用 AddToBlockIndex 或 Reorganize,但那需要更细致的推敲。我大概应该把 AddToBlockIndex 里设置新的最佳区块的那部分代码拆出来。我最后很可能用那个做法,而非下面的代码。
bool CTxDB::LoadBlockIndex()
{
...
// Verify blocks in the main chain
vector<CBlockIndex*> vChain;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
vChain.push_back(pindex);
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("LoadBlockIndex() : block.ReadFromDisk failed");
if (!block.CheckBlock())
{
bnBestChainWork = pindex->pprev->bnChainWork;
foreach(CBlockIndex* pindex2, vChain)
pindex2->bnChainWork = 0;
}
}
return true;
}没错,可能还有人在用拨号调制解调器或卫星锅上网。更罕见的是既有上述某一种接入方式,又有那条断了的有线网络的人,但只要这一群体…
没错,可能还有人在用拨号调制解调器或卫星锅上网。更罕见的是既有上述某一种接入方式,又有那条断了的有线网络的人,但只要这一群体大到值得在意,一百万人里总会有一个多线接入的极客。
ISP 断网影响的只是你所在的局部地区。如果你和周边其他地区的通信还在,那大概只有世界的 1/1000 或更少。这一小片里的区块生成会变成每几个小时一个区块。
我支持那个监控方案:监测收到区块的频率是否降得过低。它能覆盖很大范围的可能性。
如何衡量网络参与者的影响力
creighto:我同意这个想法。几个小时之后,客户端应该有可能察觉到收到区块的频率是否下降到了不太可能仅由偶然因素造成的程…
creighto:我同意这个想法。几个小时之后,客户端应该有可能察觉到收到区块的频率是否下降到了不太可能仅由偶然因素造成的程度。它就能知道自己是否已听不到整个网络正常运转的「嗡嗡声」。
其他参与者原话knightmb原帖 ↗有意思的信息。也就是说,除了一些双重支付问题,只要区块链分离不超过 100 个区块左右(或 16 小时以上),
实际上,分割很可能极不对称。把世界从正中间劈开很难。更可能的情形是一个国家对世界其他地方,比方说 1:10 的分割。那样的话,少数派分叉要花 10 倍的时间生成 100 个区块,约 7 天。而且客户端会非常容易地察觉自己听到的区块太少了、一定出了问题。
其他参与者原话knightmb原帖 ↗网络分裂持续的时间有没有硬编码的上限?意思是,如果我有一个从公共网络分离出去的小网络,在里面花了些币,几天后回来同步到公共网络(除了碰巧发生的币生成),交易应该都没问题?
没有时间限制。只要你没有花少数派分叉里生成的币、没有花你收到的别人的双重支付,你的交易随时可以在之后进入另一条链。
你看错代码了。适用的是这段:
你看错代码了。适用的是这段:
bool CBlock::CheckBlock() const
{
...
// Check timestamp
if (nTime > GetAdjustedTime() + 2 * 60 * 60)
return error("CheckBlock() : block timestamp too far in the future");
...
bool CBlock::AcceptBlock()
{
...
// Check timestamp against prev
if (nTime <= pindexPrev->GetMedianTimePast())
return error("AcceptBlock() : block's timestamp is too early");时间戳最多允许到未来 2 小时。它可以早于前一个区块的时间戳,但必须大于最近 11 个区块时间戳的中位数。这样做的原因是:如果前一个区块的时间戳超前太多,就像刚才发生的那样,时间可以在下一个区块被纠正回来。
我把锁定点设在当时最新区块之前约 200 个区块的位置。区块链当时是一条干净的直线,没有分叉,被锁的区块只有一个已知版本。
下载链接已在 bitcoin.org 上。所有人都应升级到这个版本。
下载链接已在 bitcoin.org 上。所有人都应升级到这个版本。
- 新增一个简单的安全防护,把区块链锁定到当前时点。
- 精简了 addr 消息以节省带宽,现在有充足的节点可连。
- 西班牙语翻译,作者 milkiway。
- 法语翻译,作者 aidos。
有了这个安全防护,即使有人真的掌握了全网 50% 以上的 CPU 算力,也无法试图回退、重做昨天之前的区块链。(前提是你装了这个更新)
从现在起我大概会在每个版本里放一个检查点。一旦软件已经确认了被广泛接受的区块链是什么样,就没有必要留下「几个月后翻案」这种人们不需要的非零可能性。
很难想象互联网会被分割得密不透风。那得是一个国家刻意地、彻底地把自己与世界其他地方隔绝开来。
很难想象互联网会被分割得密不透风。那得是一个国家刻意地、彻底地把自己与世界其他地方隔绝开来。
任何能同时接入两侧的节点都会自动把区块链数据传过去,比如有人用拨号调制解调器或卫星电话绕过封锁。只需要一个节点就能做到。任何想继续做生意的人都有动力这么做。
如果网络被分割后又重新合并,较短分叉里那些不在较长分叉中的交易会被重新放回交易池,有资格进入未来的区块。它们的确认数将从头开始。
如果有人利用网络分裂进行双重支付,让同一笔钱在两边分别被花掉,那么较短分叉上的那笔交易会失效,回到“0 次确认/未确认”状态,并一直保持在那里。
想利用分割来双重支付并不容易。如果一侧无法与另一侧通信,你要怎么把花费分别放到两侧?如果有办法,那很可能别人也在用同样的办法把区块链数据传过去。
你通常能知道自己是不是在较小的一侧。比如,如果你的国家把自己与世界隔绝,世界其他地方就是较大的一侧。如果你在较小的一侧,就应假设什么都没有被确认。
对我来说,第二个版本将是巨大的开发和维护麻烦。在升级网络的同时保持向后兼容已经够难了,再来一个版本把事情锁死就更难。如果第二…
对我来说,第二个版本将是巨大的开发和维护麻烦。在升级网络的同时保持向后兼容已经够难了,再来一个版本把事情锁死就更难。如果第二个版本搞砸了,用户体验会让两者都蒙羞,尽管它至少能让用户更明白紧跟官方版本的重要性。如果有人准备分叉出第二个版本,我不得不大张旗鼓地声明使用少数派版本的种种风险。这个设计的规则是:一旦有分歧,多数派版本获胜——这对少数派版本可能相当难看,我不想展开,而且只要只有一个版本,我就不必面对它。
我知道,大多数开发者都不喜欢自己的软件被分叉,但在这个案例里我有实实在在的技术理由。
其他参与者原话gavinandresen原帖 ↗我欣赏交易内置脚本的灵活性,但我那邪恶的小脑瓜立刻开始想滥用它的办法。我可以在 TxOut 脚本里编码各种有趣的信息,如果未被 hack 的客户端验证后忽略这些交易,它就成了一个有用的隐蔽广播通信信道。
在它流行起来、有人觉得"把最新的 Lady Gaga 视频用上百万笔交易灌进支付网络发给所有朋友"很好玩之前,这确实是个很酷的特性……
这正是手续费存在的原因之一。必要的话我们还有别的办法。
其他参与者原话laszlo原帖 ↗Satoshi,这个设计你做了多久了?它看起来深思熟虑,不是那种没经过大量头脑风暴和讨论、坐下来就写代码的东西。每个人都在用显而易见的问题找它的漏洞,但它一直站得住脚。
从 2007 年开始。某一刻我确信存在一种完全不需要信任的做法,从此欲罢不能地一直想下去。工作量里设计远多于编码。
幸运的是,到目前为止被提出的问题,都是我以前考虑过并做了规划的。
出块间隔与网络延迟的权衡
其他参与者原话Suggester原帖 ↗Satoshi,我算了一下,我这台新式 core 2 duo 大约要连续不停工作 20 小时才能生成 ฿50.00!老电脑就更没指望了。人们喜欢尽快"拥有"点什么的感受,有没有办法让生成更可分割?比如,不是每 20 小时生成 ฿50,而是每 2 小时生成 ฿5?
我考虑过,但没有切实可行的办法做更小的增量。区块生成频率,是在"尽快确认交易"与"网络延迟"之间的平衡。
算法的目标是平均每小时 6 个区块。如果改成每个区块奖励 5 个比特币、每小时生成 60 个区块,区块数量会变成原来的 10 倍,初始区块下载也要花 10 倍时间。反正也行不通:那样区块平均间隔仅剩 1 分钟,网络变大后就太接近广播延迟了。
它一直在不断延长。如果停下来,攻击者就会有时间追上。别担心,空区块并不大。
若干名拜占庭将军,每人有一台电脑,想通过暴力破解密码来攻击国王的 wi-fi。他们已经得知,密码长度为某个确定的字符数。他们…
若干名拜占庭将军,每人有一台电脑,想通过暴力破解密码来攻击国王的 wi-fi。他们已经得知,密码长度为某个确定的字符数。他们一旦触发网络生成一个数据包,就必须在有限时间内破解密码,侵入并擦除日志,以免被发现。只有大多数将军同时攻击,他们才有足够的 CPU 算力及时破解密码。
他们并不特别在乎何时攻击,只要达成一致就行。他们决定,任何有意愿的人都可以宣布一个攻击时间,我们称之为“计划”,最先听到的计划就是正式计划。问题在于,网络不是即时的,如果两名将军几乎同时宣布不同计划,有些人可能先听到一个,另一些人则先听到另一个。
他们用工作量证明链来解决这个问题。每名将军收到自己最先听到的计划后,就让电脑求解一道基于哈希的困难工作量证明题,并把计划纳入哈希。工作量证明的难度足够高,即使所有人同时计算,预计也要 10 分钟,才会有一个人找到答案,并向网络广播。收到答案后,每个人都会调整自己的工作量证明计算,把第一个答案纳入哈希,这样找到的下一个工作量证明就会接在第一个后面。如果有人原本在为另一个计划计算,就会切换到这个计划,因为它的工作量证明链现在更长。
大约两小时后,这个计划应该已经通过哈希,纳入一条包含 12 个工作量证明的链。每名将军只要验证工作量证明链的难度,就能估算每小时投入了多少并行 CPU 算力,并看出,要在规定时间内生成它,必然需要大多数电脑参与。至少,大多数人一定看到了这个计划,因为工作量证明就证明他们为它做过计算。如果工作量证明体现的 CPU 算力足够破解密码,他们就可以放心地在约定时间发动攻击。
我会尽量加快进度,尽快发布源代码,供大家参考,帮助澄清这些实现方面的问题。
我会尽量加快进度,尽快发布源代码,供大家参考,帮助澄清这些实现方面的问题。
Ray Dillinger(Bear)写道:
引用的来信Ray Dillinger来源 ↗一个币被花出去时,买方和卖方都会为一份(盲化的)交易记录加上数字签名。
只有买方签名,而且没有盲化。
引用的来信Ray Dillinger来源 ↗如果有人双重支付,就可以解除交易记录的盲化,揭露作弊者的身份。
这里不使用身份,也不依靠事后追索。一切都靠事前预防。
引用的来信Ray Dillinger来源 ↗这是通过一种相当标准的切分选择算法实现的,买方用秘密份额回应若干项挑战
没有挑战,也没有秘密份额。基本交易就是第 2 节图中所示的样子:一个能通过上一笔交易公钥验证的签名(买方的),以及一个新的公钥(卖方的),下一次花费时必须满足这个公钥的验证要求。
引用的来信Ray Dillinger来源 ↗他们在工作时,也可能收到与自己尝试延长的链一样长的链,其中最后几个“环节”与自己正在处理的链并不相同。他们会忽略这些链。
对,如果长度相等,就保留最先收到的那条来打破平局。
引用的来信Ray Dillinger来源 ↗如果其中包含双重支付,他们就创建一笔证明双重支付的“交易”,将其加入池 A,广播出去,然后继续工作。
不需要这样报告“双重支付证明”。如果同一条链包含了两次支付,那么这个区块就无效,会被拒绝。
如果一个区块没有足够的工作量证明,也一样。该区块无效,会被拒绝。没有必要就此传播报告。每个节点都能看出这一点,在转发之前就将它拒绝。
如果有两条竞争的链,各自包含同一笔交易的不同版本,一个试图把钱给某人,另一个试图把同一笔钱给别人,那么判断哪次支付有效,就是整个工作量证明链的作用。
我们不是在“留意”双重支付,以便发出警报并抓住作弊者。我们只是裁定哪次支付有效。交易接收方必须等待几个区块,确保这个裁定有时间完成。想作弊的人尽可以尝试同时进行双重支付,最终也只会在几个区块之内,让其中一次支付有效,其他的无效。一旦主链中已经有一次支付,之后任何双重支付都会立即被拒绝。
即使更早的支付尚未上链,只要它已经在所有节点的池中,那些已有第一次支付的节点就都会拒绝第二次支付。
引用的来信Ray Dillinger来源 ↗如果新链被接受,他们就放弃添加当前环节,将池 L 中的所有交易放回池 A(连同开始工作以来收到或创建的交易),从池 A 中删除那些已经属于新链某个环节的交易记录,然后重新开始工作,尝试延长新链。
对。每当有新交易到来时,他们也会刷新,所以 L 基本上随时都包含 A 中的所有内容。
引用的来信Ray Dillinger来源 ↗使用 CPU 密集型数字签名算法,为包含新区块 L 的链签名。
这是 Hashcash 式的 SHA-256 工作量证明(零的部分原像),不是签名。
引用的来信Ray Dillinger来源 ↗有没有一种机制,确保这条“链”不会完全由最快的 3 或 4 个节点添加的环节组成?因为广播的交易记录很容易漏掉那 3 或 4 个节点,如果漏掉了,而这些节点继续主导这条链,那笔交易可能永远不会被加入。
如果你把它想成 CPU 密集型数字签名,可能就会以为这是一场争先完成耗时操作的竞赛,最快的总会获胜。
工作量证明是 Hashcash 式的 SHA-256 碰撞查找。这是一个无记忆过程,每秒进行数百万次哈希,每次都有很小的概率找到一个答案。最快的 3 或 4 个节点的优势,只会与它们占总 CPU 算力的比例相称。任何人在任何时刻找到答案的概率,都与其 CPU 算力成正比。
系统会有手续费,因此节点有动力尽可能接收并纳入所有交易。当生成的币总量达到预定上限时,节点最终将只靠手续费获得报酬。
引用的来信Ray Dillinger来源 ↗此外,向链上添加一个环节所需的工作量,应该随着前一周添加到该链的环节数而变化(同样呈指数变化),从而严格控制币的生成速度(以及通货膨胀)。
对。
引用的来信Ray Dillinger来源 ↗要让它能够扩展,就需要币的合并机制。需要有一种“可证明”的交易,让某人作废十个单枚的币,再创建一个面额为十的新币,等等。
每笔交易都是这样的。见第 9 节,金额的合并与拆分。
Satoshi Nakamoto
Hal Finney 写道:
Hal Finney 写道:
引用的来信Hal Finney来源 ↗我认为,节点必须为每条候选链分别保存一个待处理交易列表。 ……也可以问……平均而言,一个节点必须同时跟踪多少条候选链?
好在只需要为当前最佳分支保留一个待处理交易池。当最佳分支收到新区块时,ConnectBlock 会从待处理交易池中移除该区块的交易。如果另一个分支变得更长,就沿着主分支调用 DisconnectBlock,直到分叉点,把区块交易放回待处理交易池,然后在新分支上调用 ConnectBlock,再次移除两个分支中共有的交易。预计这样的重组会很少见,而且深度很浅。
有了这个优化,候选分支实际上不构成什么负担。它们只保存在磁盘上,除非有一天成为主链,否则无需理会。
引用的来信Hal Finney来源 ↗或者,正如 James 之前提出的,如果网络广播可靠,却依赖一种可能很慢的泛洪算法,会怎样影响性能?
广播很可能几乎完全可靠。如今 TCP 传输几乎不会丢失,而广播协议有重试机制,过一段时间会从其他节点获取数据。如果实际广播速度比预期慢,可能就需要增加区块之间的目标时间,以免浪费资源。我们希望区块通常能在远少于生成它所需的时间内传播完毕,否则节点会花太多时间计算过时的区块。
我计划做一次自动化测试,让计算机随机互相发送付款,并随机丢弃数据包。
引用的来信Hal Finney来源 ↗
- 比特币系统被证明对社会有用且有价值,因此节点运营者觉得自己的努力是在为世界作出有益贡献(类似各种“@Home”计算项目,人们自愿贡献计算资源来支持公益)。
在这种情况下,我觉得单纯的利他主义就足以让网络正常运行。
如果我们能解释清楚,从自由意志主义的角度看,它会很有吸引力。不过,我更擅长写代码,不太擅长文字表达。
Satoshi Nakamoto
James A. Donald 写道:
James A. Donald 写道:
引用的来信James A. Donald来源 ↗仅仅每个人都知道 X 还不够。我们还需要每个人都知道每个人都知道 X,并且每个人都知道每个人都知道每个人都知道 X ——正如拜占庭将军问题中那样,这是分布式数据处理中的经典难题。
工作量证明链是拜占庭将军问题的一种解决方案。我试着放在那个情境下重新表述一下。
若干位拜占庭将军各有一台电脑,想通过暴力破解密码来攻击国王的 wi-fi。他们已得知密码的长度是特定的字符数。一旦他们触发网络生成一个数据包,就必须在有限时间内破解密码,侵入并清除日志,否则就会被发现并惹上麻烦。只有大多数人同时发起攻击,他们的 CPU 算力才足以迅速破解密码。
他们并不特别在意何时攻击,只要大家达成一致就行。他们决定,谁愿意都可以宣布一个时间,而最先听到的时间就是正式攻击时间。问题在于网络并非即时传输;如果两位将军几乎同时宣布不同的攻击时间,有些人可能先听到一个,另一些人先听到另一个。
他们用工作量证明链来解决这个问题。每位将军收到自己最先听到的攻击时间后,就让电脑去求解一个极难的工作量证明问题,其哈希包含这个攻击时间。工作量证明难度很高,预计他们所有人同时计算 10 分钟,才会有一个人找到答案。一旦某位将军找到工作量证明,就将它广播到网络,所有人都会更改当前的工作量证明计算,把这个工作量证明纳入正在计算的哈希。如果有人之前在另一个攻击时间上工作,就会切换到这个时间,因为它的工作量证明链现在更长了。
两小时后,某个攻击时间应该已经被纳入一条由 12 个工作量证明构成的哈希链。每位将军只需验证这条工作量证明链的难度,就能估算每小时有多少并行 CPU 算力投入其中,并看出,要在给定时间内产生这么多工作量证明,必定需要大多数电脑参与。他们必定都看到了这个时间,因为工作量证明就是他们为此工作的证据。如果工作量证明链展示的 CPU 算力足以破解密码,他们就可以放心地在约定时间发起攻击。
你所问到的所有同步、分布式数据库和全局视图问题,都是通过工作量证明链解决的。
James A. Donald 写道:
James A. Donald 写道:
引用的来信James A. Donald来源 ↗好,假设一个节点把一批交易纳入了自己的工作量证明,这些交易全都是诚实、合法的单次支付;另一个节点把另一批交易纳入自己的工作量证明,这些也同样都是诚实、合法的单次支付,而两个证明大约在同一时间生成。
接下来会发生什么?
它们都会广播自己的区块。所有节点都会收到并保留两者,但只在最先收到的那个区块上继续工作。假设恰好一半先收到一个,另一半先收到另一个。
不久后,所有交易都会传播完毕,让每个人都拥有完整的交易集合。两边工作的节点都会尝试补入自己这一边缺少的交易。当下一个工作量证明被找到时,无论该节点此前在计算哪个区块,那个分支都会变得更长,平局就此打破。无论是哪一边,新区块都会包含另一半交易,因此不管哪种情况,该分支都会包含所有交易。即使出现了连续两次分裂这种不太可能的情况,第二次分裂的两边也都会包含完整的交易集合。
交易多等一个或几个周期才进入区块,并不是什么问题。
Satoshi Nakamoto
James A. Donald 写道:
James A. Donald 写道:
引用的来信James A. Donald来源 ↗核心概念是,许多实体保存着关于谁拥有哪些比特币的完整而一致的信息。
但保持一致性很棘手。我不清楚,如果有人把一笔交易报告给一位维护者,另一个人又把另一笔交易传给另一位维护者,会发生什么。只有把交易纳入所有历史交易的全网共同视图后,才能知道它是否有效;而只有过了一段时间,又有许多新交易到来之后,才可能知道这个关于所有历史交易的全网共同视图,是否真的是全网共同接受的。
你是否解释过该怎么做,只是我没理解,还是说你确信能做到,但对细节还不太明确?
工作量证明链解决了同步问题,也解决了如何在无需信任任何人的情况下,知道全网共同视图是什么的问题。
交易会很快传播到整个网络,因此如果同一笔交易的两个版本几乎同时被报告,领先的那个版本在抢先到达更多节点方面会占很大优势。节点只接受最先看到的版本,拒绝后到的版本,所以较早的交易会有多得多的节点努力将其纳入下一个工作量证明。实际上,每个节点都是通过把自己最先看到的那笔交易纳入工作量证明的计算,来为自己的看法投票。
如果两笔交易确实在完全相同的时间到达,支持它们的节点也正好各占一半,那么结果就是随机的:哪笔先进入工作量证明,哪笔就被判定为有效。
当一个节点找到工作量证明时,新区块会传播到整个网络,所有人都将它加入链中,并开始计算它之后的下一个区块。之前收到另一笔交易的节点会停止尝试把它纳入区块,因为按照已接受的链,它现在已经无效。
工作量证明链本身就足以证明,它来自全网共同视图。只有网络中的多数节点合力,才有足够的 CPU 算力生成难度如此高的工作量证明链。任何用户收到工作量证明链后,都可以看到网络中的多数节点认可了什么。一旦某笔交易经哈希运算被纳入链中的一环,而后面又接上了几环,它就牢牢地刻进了全网历史。
Satoshi Nakamoto
Hal Finney 写道:
Hal Finney 写道:
引用的来信Hal Finney来源 ↗文中提到,如果一笔广播的交易没有到达所有节点,也没关系,因为它很快就会进入区块链。这是怎样发生的——如果创建“下一个”区块的节点(第一个找到 hashcash 碰撞的节点)没收到这笔交易,随后又有几个区块由同样没收到这笔交易的节点添加上去,会怎么样?所有收到它的节点,是否都会一直保留这笔交易,希望等自己足够幸运,成为找到下一个碰撞的节点时,把它纳入区块?
是的,节点会把交易保留在工作集中,直到它们进入一个区块。如果一笔交易到达了 90% 的节点,那么每次找到新区块时,它就有 90% 的概率被纳入其中。
引用的来信Hal Finney来源 ↗或者举个例子,如果一个节点保留着两条或更多条链,等着看哪条增长最快,这时链 A 收到一个区块,其中包含对链 B 中某个币的双重支付,会怎么样?会不会检查这种情况?(如果有人双重支付,而两组不同的节点分别听到了使用同一个币的两笔不同交易,就可能出现这种情况。)
不需要检查这种情况。哪个分支最终领先,其中的交易就有效,另一个分支中的交易就无效。如果有人这样尝试双重支付,总会有且只有一次支付变得有效,其他的都无效。
交易接收方通常需要等待大约一小时或更久,让这类潜在冲突有时间得到解决。他们仍然可以立即把币再次花出去,但在发货等操作之前应该等待。
引用的来信Hal Finney来源 ↗我也不完全理解,一个能调集比所有诚实参与者更多算力的强大攻击者,究竟如何实现双重支付或取消交易。我知道他可以创建新区块,把它们接起来,形成最长链,但他怎么能删除或添加链上的旧交易?攻击者发出新区块时,诚实节点不能进行一致性检查,确认没有任何内容被删除吗?如果能进一步解释这种攻击,会更有助于判断攻击者从中得到的收益,与单纯使用自己的算力诚实地铸造新币相比如何。
攻击者不是在末尾添加区块。他必须回头重做包含自己交易的区块,以及之后的所有区块,还包括他做这些工作时网络继续添加到末尾的所有新区块。他是在改写历史。一旦他的分支更长,它就成为新的有效分支。
这涉及一个关键点。即使所有在场的人都看到了这些小动作,也无法利用这个事实。
必须始终严格地把最长链视为有效链。在场的节点可能记得,一个分支先出现,后来被另一个取代,但它们无法向不在场的节点证明这一点。不能让节点分成几个小派别:一派坚持自己认为最早的分支,一派先看到了另一个分支,还有一派后来才加入,根本没看到发生了什么。基于 CPU 算力的工作量证明投票必须拥有最终决定权。让所有人保持一致的唯一办法,就是无论发生什么,都相信最长链始终有效。
引用的来信Hal Finney来源 ↗至于支付交易,币的接收方需要进行哪些检查?她需要追溯这个币的完整转手历史,确认列表中的每笔交易确实都已链接到“时间戳”区块链中吗?还是只需要检查最近的一笔?
接收方只需要沿交易历史往回验证,追溯到区块链中足够久远的位置,通常只需要追溯 2 笔交易的深度。再早的所有交易都可以丢弃。
引用的来信Hal Finney来源 ↗时间戳节点会不会检查交易,确保某个币的上一笔交易已经在链上,从而保证链上的所有交易都代表有效的币?
对,正是如此。节点收到一个区块时,会根据已有区块中的先前交易,检查其中每笔交易的签名。区块中的交易,只能依赖于先前区块或同一区块中的有效交易。交易 C 可以依赖于同一区块中的交易 B,而 B 又依赖于更早区块中的交易 A。
引用的来信Hal Finney来源 ↗抱歉问了这么多问题,但正如我说的,这的确是一个很有前景而且很新颖的想法,我很期待看到这个概念进一步发展。如果能更侧重流程来描述这个想法,提供各种对象(币、区块、交易)的数据结构细节、消息中包含的数据,以及对系统中各种可能事件的处理步骤作出算法描述,都会很有帮助。你提到正在编写一个实现,但我认为下一步如果能给出更正式的系统文字描述,会很有帮助。
感谢你的提问。实际上,我做这件事的顺序有点反过来了。我必须先写出全部代码,才能确信自己能解决每一个问题,然后才写论文。我想,发布代码所需的时间应该比写出详细规范更短。你自行补全的那些细节,绝大多数假设已经是对的了。
Satoshi Nakamoto
节点连接与网络发现
30 条
好,如果重新下载真的过不了区块 1698,那我们就进入更陌生的领域了。
好,如果重新下载真的过不了区块 1698,那我们就进入更陌生的领域了。
是,恐怕他的杀毒软件、甚至路由器或防火墙在对某个字节序列做模式匹配并加以拦截。
拿到 knightmb 的 blk*.dat 试试能否让他跨过那个点,会很有启发。
也许你只是运气不好,摊上一个没有反向解析的出口节点。
也许你只是运气不好,摊上一个没有反向解析的出口节点。
IRC 服务器的响应看起来并不像是为此把你断开。它本该在那之后输出 IRC SENDING: NICK,但它并未,于是超时了。
我看到问题了。IRC 代码在等一些特定短语来判断服务器何时准备好接收你的 NICK,但它并未在找那一条特定的短语。我会修。
我不确定是否真的必须等服务器查完主机名才能发 nick。
第一次用 TOR,还得靠种子节点,花了多久才连上?
你在连接自己。全部 21 次连接尝试都是对版本 31300(0.3.13)的节点。并非每个人都有 0.3.13。
你在连接自己。全部 21 次连接尝试都是对版本 31300(0.3.13)的节点。并非每个人都有 0.3.13。
IRC 看起来在正常工作。它应该尚有别的节点可试。
我可能需要做些修改,确保它在断开后不会立刻再次尝试连接自己。不过我看不出这是怎么发生的,它应该重置 nLastTry、把自己排到队列末尾,但日志里没有体现。
你能把 addr.dat 移走试试。也许它里面有什么不对。
你在用 -addnode 吗?
这无关紧要,因为你也同样连不上 sourceforge 去下载软件。
引用 · 发言者未注明但到时就没有 IRC 服务器可以用来引导入网了。
这无关紧要,因为你也同样连不上 sourceforge 去下载软件。
如果你之前连接过网络,就不再需要 IRC 来引导了。就算没连接过,你也可以从种子节点引导。从 0.3.0 起,IRC 就已完全不是必需的了。
- 即使已有 8 条入站连接,也始终维持 8 条出站连接
SVN rev 125:
- 即使已有 8 条入站连接,也始终维持 8 条出站连接
- 出站连接限制为每个 a.b.?.? 段一条
- 新增 -maxconnections=# 开关
我加了(目前未写进文档的)开关 -maxconnections=#。除非你的路由器撑不住大量连接,否则不要用它;需要的话试试 -maxconnections=30。
-maxconnections 我没怎么测过,有人能帮忙测测吗?
我希望你最好不要放出 1000 节点连接版的构建。跑这个的人不用太多,我们就得再发一个专门限制入站连接数的版本。
在 0.3.0 里,改到 8 这个变更只进了 Windows 版,其他版本仍是 15。
好问题。如果你要让超过 8 个局域网节点连到一个网关节点,那最好把网关节点配置成可以接受入站连接。否则,网关节点已有 8 个…
好问题。如果你要让超过 8 个局域网节点连到一个网关节点,那最好把网关节点配置成可以接受入站连接。否则,网关节点已有 8 个或更多连接时,就不会再尝试增加出站连接。当它连着的外部节点来来去去时,它不会建立新的出站连接去补位。如果你能接受入站连接就没问题,那会有很多别的节点来连你。
每个人都必须连到同一个 IRC 服务器和频道,才能彼此找到。
我在 RC4 里把最大对外连接数从 15 降到了 8。
我在 RC4 里把最大对外连接数从 15 降到了 8。
15 远超冗余所需。8 仍然有充足的冗余。
随着节点升级到这个版本,接受入站连接的节点获得的连接数会减半。
如果有人想要 8 条以上连接,可以在防火墙上开放 8333 端口。
我们可以做的一件事是把对外连接数从 15 降到 10,甚至 5。当初选 15 很随意。它只需要足够支撑冗余和消息的快速指数传…
感谢就此的反馈。
我们可以做的一件事是把对外连接数从 15 降到 10,甚至 5。当初选 15 很随意。它只需要足够支撑冗余和消息的快速指数传播。10 仍然绰绰有余。5 应该也行。10 是个整十数,用户容易看出,连接数停在这里是程序有意设定的。
实现 UPnP 会有帮助,这样接受入站的节点会更多。你的连接数 = 接受入站节点数与只出不进节点数之比 × 15。我们需要鼓励更多人接受入站连接。
我会实现一个功能:达到一定数量后停止接受入站连接。
你运行的是哪个版本?
有人知道 BitTorrent 这类典型 P2P 软件能到多少连接吗?
Freenode 太显眼了,正处在所有那些用户和版主聚集的正中央。Laszlo 的方案对我们合适得多。
Freenode 太显眼了,正处在所有那些用户和版主聚集的正中央。Laszlo 的方案对我们合适得多。
我发布了改用 irc.lfnet.org 而非 freenode 的 0.3.0.RC2,如果你想开始切换的话:
我们试试改用 Laszlo 的 irc.lfnet.org 而不是 freenode。这是 RC2,里面唯一的改动就是这个:
这条发言承接前面的讨论,可通过下方入口查看完整上下文。
我们试试改用 Laszlo 的 irc.lfnet.org 而不是 freenode。这是 RC2,里面唯一的改动就是这个:
(下载链接见下方)
我们需要更多关于出了什么事的细节,MadHatter。
我们需要更多关于出了什么事的细节,MadHatter。
0.2 和 0.3 都有不靠 IRC 的备用连接方式,只是连得慢一些。
0.2 只要曾经连接过,不用 IRC 也能找到其他节点,但全新安装不靠 IRC 就无法第一次发现网络。
0.3 不靠 IRC 也能完成初始节点发现。必要时它可以完全不依赖 IRC 运转,但有 IRC 作冗余更好。
大家怎么看,0.3 版要做这个切换吗?
SVN 版本现在先用 IRC,失败则回退到一份硬编码的种子节点列表。现在种子节点已经够多,到下个发布时其中许多应该还在运行。…
SVN 版本现在先用 IRC,失败则回退到一份硬编码的种子节点列表。现在种子节点已经够多,到下个发布时其中许多应该还在运行。它只短暂连上一个种子节点取回地址列表就断开,所以你的连接数会有一阵掉回零。那时请耐心点。只有第一次连接才慢。
这意味着 TOR 用户不再需要 -addnode,它会自动连上。
3) 按比特币地址发送的话,没什么。
Bitcoin 有自己的分布式地址目录,用的是 "addr" 消息。是时候把当前长期运行的静态节点编成种子列表写进代码了。我…
Bitcoin 有自己的分布式地址目录,用的是 "addr" 消息。是时候把当前长期运行的静态节点编成种子列表写进代码了。我可以加一段代码,让新节点不优先保持与种子节点的连接——连上、取列表、就走,这样不会给它们添负担。
你们怎么看,我该继续把种子加进去吗?
它仍会先试 IRC。IRC 的优点是列出当前在线的节点——它们必须保持连接才能留在列表上——缺点是单点故障。"addr" 系统没有单点故障,但只能告诉你最近见过哪些节点,所以连接会慢一点,因为你试的一些节点已经下线。两者结合让我们两全其美、总体更稳健。
有人愿意志愿运行一台 IRC 服务器,以防 freenode 哪天厌倦了我们吗?
目前,它总是假定入站端口是 8333,所以就算你从别的端口号转发的,它也会让其他 bitcoin 节点去连 router:8…
目前,它总是假定入站端口是 8333,所以就算你从别的端口号转发的,它也会让其他 bitcoin 节点去连 router:8333。
我不急着修这个,因为我想不出多个入站连接端口能带来什么好处。你提供了一个入站端口,就已经为网络尽了一份力。同一个人开两个入站端口,对冗余毫无帮助。
如果你有很多台计算机,更合理的做法是在大部分机器上用 -connect 开关在本地互联。
感谢 soultcer 与 Freenode 的工作人员沟通。很高兴知道当前规模没问题,而且他们现在知道我们是谁了。他们对 …
感谢 soultcer 与 Freenode 的工作人员沟通。很高兴知道当前规模没问题,而且他们现在知道我们是谁了。他们对 TOR 这样的项目都很支持,所以希望他们对我们大概也会友好。我们不想赖着不走。等我们规模太大时,同样地,我们也大到不再需要 IRC,到时我们会离开。
我们需要 IRC 只是因为没有人有静态 IP。早期有一些稳定的支持者,但他们的 IP 都是地址池分配的,每隔几天就变。IRC 本来就只是临时方案。Bitcoin 内建的 addr 系统才是主要方案。
Bitcoin 可以从任何 bitcoin 节点获取 IP 列表。在这个意义上,每个节点都是一台目录服务器。
当静态 IP 节点足够多,我们有较大把握认为至少会有一个持续运行到当前版本不再使用时,我们就可以预编一份种子列表。
你觉得种子列表该怎么编?从已经稳定了一段时间的当前连接 IP 里挑选,可以吗?
顺便说一句,如果我们想靠部署独立的目录服务器软件来补充,我建议用 IRC 行吗?IRC 是个很好的目录服务器(我听说它还有别的用途),有成熟的 IRC 服务器实现,谁都能运行。Bitcoin 的 IRC 客户端实现也已经过彻底测试。
节点一旦有 15 条连接就不再主动发起连接。如果你能接受入站连接,那么从连向你的节点那里可以收到远超此数的连接,否则你就封顶…
节点一旦有 15 条连接就不再主动发起连接。如果你能接受入站连接,那么从连向你的节点那里可以收到远超此数的连接,否则你就封顶在 15。
我不知道有什么理由要 15 条连接。也许应该是 10。
由于只能向外连接的节点现在大部分时间大概都在 15 条上下,你的连接数应该会逐渐稳定在一个均衡水平。45 意味着每 1 个接受入站的节点对应 3 个只出不进的节点。
连接数不再是衡量网络规模的好指标了。应该有人定期通过 IRC 连到 chat.freenode.net 的 bitcoin 频道数一数用户数。那给出的是网络节点总数(TOR 节点除外)。
区块生成速度又一次超过了目标。大约 5 天后的下次调整,难度又要上一个台阶。
目前还没有实现这个功能的端口设置。这是尚未实现的功能。你只能把 NAT 的端口转发设到其中一台计算机。(我之前说过 NAT …
目前还没有实现这个功能的端口设置。这是尚未实现的功能。你只能把 NAT 的端口转发设到其中一台计算机。(我之前说过 NAT 端口转换什么的,但那行不通,其他节点不知道要连到那个端口)
如果愿意,作为一个小优化,你可以让其余计算机这样运行:
bitcoin -connect=<第一台计算机的 IP>
这样它们的全部网络通信都经由第一台计算机,而不必各自单独连到网上取同样的信息。这能节省带宽,不过它本来就不占用多少带宽,故除非你有海量计算机,否则影响不大。
为了在第一台宕机时保有冗余,可以让两台向外连接、其余连接到这两台。头两台正常运行,其余这样运行:
bitcoin -connect=<IP1> -connect=<IP2>
bitcoin -addnode=1.2.3.4 告诉 bitcoin 要连接的一个节点
有命令行选项:
bitcoin -addnode=1.2.3.4 告诉 bitcoin 要连接的一个节点
bitcoin -connect=1.2.3.4 只连接指定节点
这些选项可以叠加使用,比如
bitcoin -connect=(先试这个) -connect=(下一个) ...
-connect 可以指定不可路由的 IP,比如 192.168.x.x,所以如果你有一个服务器集群,想让一台连接外部世界、其余都连到那一台,也能做到。
特别是,如果你打算一直通过 TOR 连接,就需要 -addnode,因为 IRC 服务器封禁所有 TOR 出口节点。通过 TOR 连接可以用:
bitcoin -proxy=127.0.0.1:9050 -addnode=212.159.72.216
只要连接数不少于 1,挖矿速度就一样。
只要连接数不少于 1,挖矿速度就一样。
更多的连接,只是增加冗余而已。如果你只有一条连接,而那个节点速度慢、正忙,或者只与你一人相连,那该如何是好?多几条连接,能让你更确信自己与网络保持着良好的连通。实践中,这从没成为过问题,网络的连接非常充分。有 2、3 条连接,你就没有问题。
我看出发生什么了。不知怎么回事,你所有的套接字都失效了。你没有与网络通信,但因为还有 8 个僵死连接,程序以为仍然在线,就继…
我看出发生什么了。不知怎么回事,你所有的套接字都失效了。你没有与网络通信,但因为还有 8 个僵死连接,程序以为仍然在线,就继续生成区块。如果你的区块编号连续,中间没有穿插别人的区块,就能判断出现了这种情况,例如:
2/unconfirmed
3/unconfirmed
4/unconfirmed
5/unconfirmed
6 blocks
7 blocks
像这样连续 6 个区块都只有你一个人找到,是不大可能的。
你退出并重新启动后,程序连接到网络,下载了你缺席期间网络找到的 45 个区块。由于你的区块没有立即广播到网络,网络就没有包含它们,继续向前了。
听起来你在 Wine 上遇到的也是完全相同的问题。显然, Linux 上的套接字处理存在某种问题,无论用哪种方式都会影响它。
我会开始研究。如果最终找不到问题的根源,就得做某种机制,监测是否一直没有消息,并断开连接。目前你唯一能采取的临时办法,就是更频繁地退出并重新启动。
除了一个节点连接,你的所有节点连接都在同一时间失效,剩下的那个也不久后失效了。IRC 仍在工作,所以并不是你断开了互联网。
我在想,区块状态是不是应该一直显示“#/unconfirmed”,直到成熟(先是 119/unconfirmed,然后是 120 blocks)。这个数字对区块的意义,不如对交易那么大。
我觉得不把自己生成的区块算作确认,会是一种改进。缺点是不同节点显示的状态数字会不一致。状态数字也不再与区块成熟倒计时相对应。较轻量的选择是:只有当所有确认都来自自己时,才作特殊处理。
引用 New Liberty Standard 的文字New Liberty Standard来源 ↗我刚丢了 6 组正在成熟的币!我原本有 10 组比特币正在成熟。最后一组大约在 0:22 生成。在 bitcoin 卡住之前,它到了 2/unconfirmed。到了 10:10,0:22 生成的那组比特币仍然只有 2/unconfirmed。因为你告诉我不会丢币,我就关闭并重新启动了 bitcoin。好的一面是,它关闭和启动都很顺利。但不幸的是,区块更新后,我丢了 6 组比特币。其中四组还未确认,但两组已经确认。现在它们没有留下任何痕迹。也许既然你已经提供了“Show Generated Coins”选项,就可以把生成失败的比特币重新显示出来。我只是不喜欢这些比特币就这样凭空消失。我目前仍在运行 Linux 构建,但过去 24 小时生成的 10 组比特币中有 6 组就这样消失,让 Wine 版本突然显得有吸引力得多。我附上了 debug.log。
引用 New Liberty Standard 的文字New Liberty Standard来源 ↗Linux 构建在过去 20 小时内生成了相当数量的比特币,而且我相信你对数据库错误的解释,所以一切都表明,我今后会一直运行 Linux 构建。 Linux 构建唯一有点烦人的地方,是我的电脑风扇从 50% 变成了 100%。:-P 我知道可以限制 CPU,所以如果它实在让我心烦,而且我能接受生成更少的比特币,也许我会那样做。或者,我只是需要开始多听点音乐……
……
在还有未确认项的时候关闭程序, 没有风险。 当你创建交易或新区块时,它会立即 向网络广播。此后,不断增加的 #/confirmed 数字只是用来观察结果。 在这段时间里, 你的节点不会做任何事情来促进 它被接受。
太好了,我一直期待着开发 Linux 版本。
太好了,我一直期待着开发 Linux 版本。
如果连接 Freenode 的隐藏服务,他们会告诉你,由于滥用,那边也已经禁止 TOR,然后把你踢下线。你可以按一个分为几步的流程,在 unix 上运行一个密码工具,再发邮件申请可以登录的账号,但这就变得相当复杂了。不知道我们能不能只申请一个账号,然后大家共用?我猜 IRC 服务器大概会限制每个账号同时只能有一个登录会话,或者某位管理员可能不愿意看到同一个账号有十几个登录。
除了 IRC 那部分,代理测试得怎么样?因为你以前连接过,addr.dat 里有已知节点地址,但没有 IRC 告诉你哪些在线,找到它们就要很久。除了你以外,通常还有 1 到 3 个节点能接收传入连接,已经知道你的现有节点最终也会连接你。你得到了多少连接,花了多久?我想,要知道是否成功通过 TOR 建立了传出连接,需要在 debug.log 中搜索“connected”。
如果一开始就要通过 TOR 连接,而不先正常连接一次来获得种子节点,就必须知道一个能够接收传入连接的现有节点地址,并像这样指定种子节点: bitcoin -proxy=127.0.0.1:9050 -addnode=<ip of a node>
如果某些能接收传入连接的节点愿意把自己的 IP 写进程序,就可以自动获得种子节点。或者可以在 Wiki 页面上公布一些 IP 种子地址并附上说明。
另一种办法是重新到处寻找不封禁 TOR 节点的 IRC 服务器。或者找个人架设一个。IRC 服务器封禁 TOR,是因为上面有真正的文字聊天……如果有一个服务器只放机器人和杂项内容,就不会在乎了。大概应该在论坛或邮件列表上问问,看有没有人知道这样的服务器。
另一个问题是 TOR 用户无法接收传入连接,而我们能接收的节点本来就很少。如果所有人都转用 TOR,就没有节点可以连接了。
我们缺少能够接收传入连接的节点。最近一般只有 2 到 4 个。需要向大家强调在路由器上设置端口转发的重要性。每个点对点文件共享程序都有相关说明。我们应该在 bitcoin.sourceforge.net 首页放一段文字,敦促大家设置端口转发来接收传入连接,并链接到一个介绍各种路由器设置方法的网站。
引用 Martti Malmi 的文字Martti Malmi来源 ↗我已经把目前移植好的内容上传到 svn/branches。Util、script、db 和头文件现在都能完整编译,net.cpp 能部分编译,所以还有工作要做。
Linux 没有与 _beginthread 直接对应的函数,所以我改用了 Boost 线程。
我没能通过 Tor SOCKS 代理连上。这可能是因为 Freenode 的 Tor 政策要求连接他们的隐藏服务:http://freenode.net/irc_servers.shtml#tor
引用中本聪此前的文字中本聪来源 ↗heapchk() 只是一个没在用的 MSVCRT 调试功能。在 Linux 上可以让它什么也不做。OpenSSL 在 Linux 上会自动使用 /dev/urandom 提供随机种子,所以 RandAddSeedPerfmon 也可以什么都不做。
在我们充分完成离线测试之前,别让它连接网络。如果你有两台电脑,先断开互联网,用“bitcoin -connect=<ip>”让它们互连,一台 windows,一台 linux。-connect 允许连接 192.168.x.x 这样的不可路由地址。如果它发出某种我们还没想到要检查的畸形垃圾数据,或者以其他方式干扰网络,我们可不想因此损害网络的可靠性声誉。
等你有能编译、可供测试的版本时,我有时间做些测试。我可以把它加入目前正在针对已有改动运行的压力测试。
引用 Martti Malmi 的文字Martti Malmi来源 ↗我在 util.h 中加了一个 #ifdef,用 Linux 的 gettimeofday 替换 QueryPerformanceCounter。更新到 wxWidgets 2.9 后,一些 Unicode/ANSI 错误没有改代码就解决了。目前我在 Linux 上遇到的唯一编译错误,来自 util.h 中的 heapchk()。
引用中本聪此前的文字中本聪来源 ↗我修复了遇到的一些不可移植的内容: QueryPerformanceCounter printf 格式字符串中的 %I64d Sleep CheckDiskSpace
如果你知道还有其他应该由我修复的不可移植内容,请告诉我。
我想把 debug.log 和 db.log 移到数据文件所在的目录(%appdata%\Bitcoin),而不再放到碰巧作为当前目录的位置。
Hal Finney 写道:
Hal Finney 写道:
引用的来信Hal Finney来源 ↗听起来不错。我还想在多台机器上运行多个币/区块生成器,全部放在同一个 NAT 地址后面。我还没试过,所以不知道当前软件能不能做到。
当前版本可以正常运行。它们会各自通过互联网建立连接,而传入连接只会到达 8333 端口所映射的那台主机。
作为一项优化,我会增加一个“-connect=1.2.3.4”开关,让程序只连接指定地址。你可以让额外节点连接主节点,仅由主节点连接互联网。目前其实无关紧要,因为在网络规模变得很大之前,所需带宽都微乎其微。
引用的来信Hal Finney来源 ↗顺便说一句,我不记得我们有没有谈过这个,但前几天有人提到了安全时间戳。你希望能够证明某个文档在过去的特定时间已经存在。在我看来,比特币这一串区块非常适合做这个。
确实,比特币就是一个为交易服务的分布式安全时间戳服务器。只需几行代码,就能创建一笔交易,在其中额外加入任何需要加时间戳的内容的哈希。我应该增加一条命令,用这种方式为文件加时间戳。
引用的来信Hal Finney来源 ↗
正是如此。
Satoshi Nakamoto
看来0.1.3确实解决了这个问题。之前僵尸节点越来越多,我发出的消息几乎收不到回复。现在,发出4条 inventory 消息…
看来0.1.3确实解决了这个问题。之前僵尸节点越来越多,我发出的消息几乎收不到回复。现在,发出4条 inventory 消息,就能收到4条 getdata 消息。
你有没有遇到过显示“未被接受”的区块?如果节点当时无法广播,这个连接问题可能会导致生成的区块不被接受。等状态超过5左右,就可以放心认为它已经被接受了。
可惜,我所在的地方无法接收传入连接,这让事情更困难了。最初一两天,网络主要靠你的节点接收传入连接,才得以持续运转。
如果愿意,你可以向我的比特币地址付款,不过这样你看不到完整的转账过程: 1NSwywA5Dvuyw89sfs3oLPvLiDNGf48cPD
你也可以运行 findstr /c:"version message" debug.log,然后从列表靠近末尾的已连接用户中随便找一个,试着给他付款。那些以端口8333结尾的节点可以接收连接。
我刚想到一件事。迟早会有人对暴力搜索比特币地址感兴趣,找一个开头几个字符对应自己名字的地址,有点像挑一个能拼出某个词的电话号码。纯属巧合,我这个地址里正好有我的姓名首字母。
Satoshi
引用 Hal Finney 的来信Hal Finney来源 ↗谢谢,Satoshi,这个新版本似乎运行得好多了。我有8个连接,看 debug.log,似乎有不少活动。我看到你给我付了一笔款,谢谢!告诉我你的地址,我也试着给你付一笔。如果我理解得没错,我昨天成功生成了一个区块,这些币就快成熟了。
Hal
我想我已经修复了与“select failed: 10038”(WSAENOTSOCK 错误)有关的问题。select 出错…
我想我已经修复了与“select failed: 10038”(WSAENOTSOCK 错误)有关的问题。select 出错本身不是大问题,但它导致通信线程阻塞在一个套接字上;这个套接字本该处于非阻塞模式,却没有正确设置。这个问题以前一直没有暴露,是因为只要 select 没有失败,只有在有数据可读时才会调用 receive。
如果不修复这个问题,你的节点有时就会停止通信。连接仍会建立,但不会传送数据。生成的区块很可能不会被接受,因为你无法把它们广播出去,其他节点会把你的分支甩在后面。这就是没有网络连接时 Generate(生成比特币)不运行的原因。
这也可能是 bitcoin.exe 无法退出的原因。关闭程序时没有理由等待通信线程,因此我把它改成只等待消息处理线程。以后我会再做更彻底的强制关闭处理。
看起来你的节点的通信线程刚刚又被这个问题阻塞了。这次它运行了几个小时才出问题。
随信附上 0.1.3 版 exe。
James A. Donald 写道:
James A. Donald 写道:
引用的来信James A. Donald来源 ↗引用的中本聪旧文中本聪来源 ↗幸好,只需要为当前最佳分支保留一个待处理交易池。
这要求我们知道,也就是说,一个诚实、行为正常、通信和数据存储运转良好的对等节点知道,当前最佳分支是什么——
我的意思是,一个节点只需要为自己掌握的最佳分支保留待处理交易池,也就是它目前认为最好的那个分支。它会尝试在这个分支上构建区块,而它需要交易池也仅仅是为了这一点。
引用的来信James A. Donald来源 ↗引用的中本聪旧文中本聪来源 ↗广播大概会几乎完全可靠。
我们不能假设每条消息至少到达一次,而必须设计一种机制,使信息能够到达,即使承载信息的消息经常无法到达。
我想,我已经解决了对等网络的广播机制。
每个节点向其邻居发送一份清单,列出自己拥有的新区块和新交易的哈希。邻居请求其中自己尚未拥有的条目。如果某个条目超时后仍未到达,就向另一个拥有它的邻居请求。因为所有或大多数邻居最终都应该拥有每个条目,所以即使与某个邻居通信出了问题,也能从其他任意邻居那里获取,逐个尝试就好。
这种清单—请求—数据的机制会带来一点延迟,但它能避免多余的数据块进入发送队列,节省带宽,因此总体上反而能提高传输速度。
引用的来信James A. Donald来源 ↗你已经有了这样一种设计的概要和提案,这是很大的进步,但难点都藏在细节里。
我相信,在过去一年半的编写过程中,我已经想清楚了所有这些细节,而且它们确实很多。论文没有涵盖具体功能细节,但源代码很快就会发布。我已经把主要文件发给你了。(目前可按请求提供,很快会完整发布)
Satoshi Nakamoto
下载、验证与存储
13 条
这是个好优化。下次更新 SVN 时我会加上。
这是个好优化。下次更新 SVN 时我会加上。
更一般地,我们还可以考虑这个:
dbenv.set_lk_max_objects(10000);
dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
dbenv.set_flags(DB_AUTO_COMMIT, 1);
+ dbenv.set_flags(DB_TXN_NOSYNC, 1);
ret = dbenv.open(strDataDir.c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
之后我们依赖 CDB::Close() 里的 dbenv.txn_checkpoint(0, 0, 0) 在钱包写入后刷盘。
看起来你倾向于认定什么都有问题,把情况想得比实际更糟。
看起来你倾向于认定什么都有问题,把情况想得比实际更糟。
写区块索引是轻量工作。构建交易索引时,每个区块都需要多得多的随机访问。我怀疑慢就慢在读取所有前序交易输入上。读缓存对此会有帮助。最好由 DB 来做。也许它有设置缓存内存大小的选项。
引用 · 发言者未注明1) 比特币应该在程序启动时就打开数据库而不只是环境,并在程序关闭时关闭数据库。
它已经这么做了。见 CDB。(比如)CTxDB 对象的生命周期只是为了支持数据库事务,以及关闭时判断数据库是否还有人在用。
引用 · 发言者未注明而且,比特币还强制执行一次数据库检查点操作,把日志里的全部事务写入主数据库。
如果它真在那么做,会慢得多。它本该只是一分钟一次或 500 区块一次:
if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
nMinutes = 1;
dbenv.txn_checkpoint(0, nMinutes, 0);或许应该加上这个:
if (!fReadOnly)
dbenv.txn_checkpoint(0, nMinutes, 0);
引用 · 发言者未注明2) 对于初始区块下载,应该每处理 N 条记录才提交一次事务,而不是每条记录都提交一次。我建议 N=1000。
事务提交意味着刷盘吗?这让我很意外。我以为包在事务里的数据库操作会像其他数据库操作一样被记日志。很多数据库应用几乎每一对操作都得包进事务,比如把钱从一个账户挪到另一个。(借记 a,贷记 b)我无法想象它们还被要求自己把操作攒成批。
在下面两种情况下,情况 1 刷一次盘、情况 2 刷两次吗?
情况 1:
write
write
write
write
checkpoint
情况 2:
begin transaction
write
write
commit transaction
begin transaction
write
write
commit transaction
checkpoint
扭曲我们的数据库用法不会是正确的路子。出路在于 BDB 设置和缓存。
尽管说了这么多,当前的下一步是:
尽管说了这么多,当前的下一步是:
引用 · 发言者未注明应该有人用不同的 Berkeley DB 设置做实验,看看有没有能让下载显著加快的配置。如果真发现了什么,我们再落实细节。
具体来说,我推测,增加读缓存可能会很有帮助。
其他参与者原话jgarzik原帖 ↗IRC 上又来了一个新用户,这次是 Linux,下载速度是每 4 秒 1 个区块——估计总下载时间要 4 天左右。
那就是出了更具体的问题。那不是正常初始下载时间。没有更多细节就无法诊断。如果是下载慢造成的,10-20 分钟后下一次区块广播本该让它切换到更快的来源,它提速了吗?debug.log 里可能有线索。他们的网络连接有多快?是一直慢,还是只在某处变慢?
其他参与者原话jgarzik(续)原帖 ↗我们把创世区块到区块 74000 的哈希硬编码(编译)进了比特币,因此没理由不能从任何地方自动下载区块数据库的压缩包,解包、验证,然后开始运行。
74000 检查点不足以保护你,而且如果下载已经超过 74000 就毫无作用。-checkblocks 能做更多,但仍然容易被绕过。你终究得信任压缩包的提供者。
如果真有一个「验证」步骤,那耗时和现在正常的初始下载一样长——瓶颈是建索引,不是数据下载。
其他参与者原话jgarzik原帖 ↗想必某个时候会出现只下载区块头的轻量客户端,但区块头仍会有数十万个……
每个区块头 80 字节,不需要建索引。也许 1 分钟就够。
引用 · 发言者未注明未压缩的数据,用一个并非为批量数据传输设计的协议(比特币 P2P)。
数据主要是哈希、密钥和签名,不可压缩。
初始下载的速度并不反映协议的批量数据传输速率。真正的制约因素是下载过程中的建索引。
我在一块慢速的 7 年老硬盘上测过,带宽和 CPU 显然不是瓶颈。初始下载用了 1 小时 20 分钟。
我在一块慢速的 7 年老硬盘上测过,带宽和 CPU 显然不是瓶颈。初始下载用了 1 小时 20 分钟。
如果远超这个时间——当然 24 小时肯定算远超——那一定是从很慢的节点下载,或者你的连接比每秒约 15KB(120kbps)慢得多,或者有别的地方出了问题。出现那种情况时,最好能知道瓶颈看起来在哪里。
约莫每 10 分钟最新区块送达时,它都有机会切换到更快的节点。最新区块广播时,它会向其他节点请求接下来的 500 个区块,并从发送最快的一个继续下载。至少,它本该这样工作。
其他参与者原话jgarzik原帖 ↗下载期间你需要 ACID 的哪些性质?
也许只需要更多的读缓存。它必须随机地读遍 blk0001.dat 和 blkindex.dat 来建索引。它不能假设文件比内存小,虽然目前仍是这样。缓存会相当有效,因为所依赖的数据大多是近期的。
应该有人用不同的 Berkeley DB 设置做实验,看看有没有能让下载显著加快的配置。如果真发现了什么,我们再落实细节。
其他参与者原话jgarzik(续)原帖 ↗添加 BDB 记录只是向日志文件追加,直到你执行一次检查点操作。检查点随后更新主数据库文件。
我们每 500 个区块执行一次检查点操作。
花时间的不是下载,而是验证和建立索引。
花时间的不是下载,而是验证和建立索引。
从带宽上说,它比下载一个压缩包更高效。比特币只下载 blk0001.dat 里的数据,目前是 55MB,然后自行构建 blkindex.dat,为 47MB。构建 blkindex.dat 才是全部磁盘活动的来源。
在区块下载期间,它每 500 个区块才把数据库刷一次盘。你可能会看到区块计数在 ??499 和 ??999 处停顿。那就是在刷盘。
自己做验证和建索引,是确保索引数据安全的唯一办法。如果从一个不受信任的来源复制 blk0001.dat 和 blkindex.dat,就无法知道里面的全部内容是否可信。
也许 Berkeley DB 有一些可调的开关,能启用或加大缓存内存。
下一个 SVN 修订里,我会让它只回溯到区块 74000 的最后一个检查点。将来如果要再修问题,随时可以让它至少回溯到问题所…
下一个 SVN 修订里,我会让它只回溯到区块 74000 的最后一个检查点。将来如果要再修问题,随时可以让它至少回溯到问题所在之处。另外,我正在加校验区块索引的代码,也就是说会对工作量证明链做校验。
不过,系统仍无法完全防范你的 blk*.dat 文件中可能存在的问题。用别人 blk 文件的副本,就是在信任那个人。
SVN rev 139 会在加载后对区块链做一次基本检查。
SVN rev 139 会在加载后对区块链做一次基本检查。
有了它,我们本不需要删 blk*.dat,它会自动重组回分叉点。当时没时间把这个功能做扎实。
它可能比我们想要的慢,因为要把所有区块都加载一遍。如果太慢,可以让它只回溯到某个区块号为止。
没什么特别原因。下次我改成 1000。
通过对数据库设置做一些调整,我把初始区块下载速度提高到了原来的约 5 倍。现在下载只要约 30 分钟。
通过对数据库设置做一些调整,我把初始区块下载速度提高到了原来的约 5 倍。现在下载只要约 30 分钟。
数据库默认把每个区块同步写盘,这没有必要。我改了设置,让它把变更缓存在内存里、批量写出。区块仍然是事务性写入的,变更要么完整发生、要么完全不发生,无论哪种情况数据都处于有效状态。
我只在初始区块下载期间启用这个变更。当与最新区块的差距缩小到 2000 个区块以内时,就会停用这些改动,恢复原来的处理速度。
我编了个测试版,想提前用的话:
http://www.bitcoin.org/download/bitcoin-0.3.2.5-win32.zip
http://www.bitcoin.org/download/bitcoin-0.3.2.5-linux.tar.gz
这些二进制也包含 Gavin Andresen 的 JSON-RPC HTTP 认证功能,以及 0.3.2 的其他重要安全改进。
过去 24 小时我跑了一个测试:在初始区块下载期间每 2-60 秒随机杀死并重启它(可怜的家伙),一切正常。
wallet.dat 的处理方式没有任何变化。这个变更只影响 blk*.dat 和不关键的 addr.dat。blk*.dat 万一坏了,随时可以删掉重新下载。
对,下载完全部区块它们就会重新出现。
你有多少个区块?(看状态栏)
这错误我头一回见。
你有多少个区块?(看状态栏)
你应该把 blk*.dat 文件(在 ~/.bitcoin)移到另一个目录,让它重新开始下载区块链。方便的话,能不能把旧的 blk*.dat 文件留一阵子,万一我需要看?
它实际上一次下载 500 个区块,然后计数器随着区块的验证一块一块地累加。
它实际上一次下载 500 个区块,然后计数器随着区块的验证一块一块地累加。
让 bitcoin 下载并验证区块的好处是:你不必信任你下载它们的来源。如果你从某个网站下载 blk*.dat 文件,你就得信任那个网站,因为你在未亲自验证的情况下接受了数据。如果是从你自己的另一台电脑上拷贝 blk*.dat,那没问题。
你的初始区块下载要花多久?
轻客户端与扩容
10 条
太好了!首个纯客户端实现,会真正开始推动一切进入下一阶段。它会开源,还是成为 Google 的专有软件?
这条发言承接前面的讨论,可通过下方入口查看完整上下文。
阅读完整通信正文 · Mike Hearn · 2010-12-30 · Java 简化支付验证客户端的进展
谢谢你提供这些信息。
关于纯客户端节点,我也得出了同样的结论,一直在做的就是这个。我快做完了……区块链下载、解析以及区块和交易验证已经完成,创建支出交易的部分也快完成了。
第一版基本会按你的建议来做,可能再加一项优化:只存储构造区块定位器所需的区块,按指数增大间隔来选取要保留的区块。Android 提供应用私有的本地存储,所以不必存储完整区块链,也能接收新区块……只要保存足够的信息,确保始终能够跟随最长链就行。
顺便说一句,你的代码很容易阅读,是极其宝贵的参考。为此也要谢谢你。
第二版我在考虑,在交易被纳入区块链之前就显示它们。做法是运行经过安全加固、严格限制访问的中继节点,在交易被接纳进内存池时向手机发送消息。Android 为每台手机提供了一条安全、低功耗的后台通道。设备离线时,消息存放在服务器端;收到消息后,手机上的应用会自动启动并处理。
因此,只要中继节点没有被入侵,这个系统应该就足够可信,可以把小额交易立即显示在界面中。它确实引入了一些中心化和单点故障,不过,如果中继机制停止运行或被入侵,影响也只会持续到 10 分钟后下载新区块时为止。
确实,纯客户端程序没必要实现 EvalScript,因为如果不存储整条区块链并建立索引,就无法验证交易是否存在双重支付。我的代码会解析脚本,并依赖脚本采用标准结构,但实际上并不运行它们。
很想看看这个数字的推导过程。从某种意义上说,币的数量是可以任意选择的,因为使用纳比特币(nanocoin)来表示时,发行单位的数量大得近乎无限。
值得实现某种更可靠的自动更新机制,或者制定一份逐步引入这项变化的时间表。哪怕只是为了让人们在判断“比特币值不值得我投入时间和精力”时,能看到一份明确、可靠的扩容计划,也值得这样做。
我担心的不是硬件本身的性能,而是随着不同版本的软件实现出现、不自动更新的节点越来越多,协议逐渐僵化。当然,以纯客户端模式运行的其他实现不会造成问题;不过,SMTP 等系统即使内置了扩展机制,事实证明也无法在全球范围内升级……实现太多,安装实例也太多了。
引用的来信Mike Hearn来源 ↗关于纯客户端节点,我也得出了同样的结论,我正在实现的就是这个。快完成了……区块链下载、解析,以及区块/交易验证都做好了,创建花费交易的功能也快好了。
太好了!首个纯客户端实现,会真正开始推动一切进入下一阶段。它会开源,还是成为 Google 的专有软件?
论文中的简化支付验证,设想的是你直接接收交易,就像现在没人使用的按 IP 地址发送;或者由一个节点按公钥为所有交易建立索引,…
阅读完整通信正文 · Mike Hearn · 2010-12-27 · 关于简化支付验证、发行量与区块大小的问题
如果你也过这个节的话,不管你现在身在何处,都祝你圣诞快乐,Satoshi :-)
我一直在用 Java 实现简化支付验证,希望做出一个能在 Android 手机上运行的客户端。因此,我想了很多关于比特币存储需求和可扩展性的问题,也产生了一些论文没有回答的疑问(也许可以找个时候更新论文,因为我觉得其中一些内容已经过时了)。
具体来说,比特币里有各种没有说明来历的常数,代码和论文都没有解释它们是怎么确定的。例如,发行到 2100 万枚币时就不再增发。这个数字总该有一个由来,可我看不出是什么。
另一个是 10 分钟的目标出块间隔。我理解,选择它是为了让交易有时间在网络中传播。不过,BGP 这样现有的大型点对点网络,能在不到 1 分钟内把新数据传遍全球。
最后一个让我感兴趣的数字,是区块大小的 500kb 上限。根据维基百科,仅 Visa 在 2009 年就处理了 620 亿笔交易。换算下来,平均每秒约 2000 笔,峰值大概是两倍,也就是每秒 4000 笔。目标出块间隔为 10 分钟时,峰值期间一个区块可能需要容纳 240 万笔交易,显然装不进 500kb。这 500kb 是个临时限制,会随着时间推移逐步从官方客户端中移除,还是有更根本的原因?
引用的来信Mike Hearn来源 ↗我一直在做简化支付验证的 Java 实现,希望构建一个能在 Android 手机上运行的客户端。因此,我对比特币的存储需求和可扩展性想了很多,由此产生了一些论文没有回答的问题(也许将来可以出一个新版论文,因为我认为其中一些方面已经过时了)。
论文中的简化支付验证,设想的是你直接接收交易,就像现在没人使用的按 IP 地址发送;或者由一个节点按公钥为所有交易建立索引,你就可以像从邮件服务器下载邮件一样下载它们。
现在,我认为纯客户端节点应该接收完整区块,以便扫描其中属于自己的交易。它们不需要存储区块,也不需要为其建立索引。初次下载时,只需下载区块头,因为程序第一次运行之前不可能收到任何付款(0.3.18 中添加了下载区块头的命令)。从那以后,它们下载完整区块,但只保存区块头。
纯客户端模式的代码大部分已经实现。github 上有一个包含它的功能分支,我也把补丁附在了这封邮件里。
下面是关于它的更多说明:
中本聪引用的旧邮件Satoshi Nakamoto来源 ↗“这是我目前完成的客户端模式实现。纯客户端模式只记录区块头,不使用交易索引。它不能生成币,但仍能发送和接收交易。它还没有完全达到可供最终用户使用的程度,但这没关系,因为只要没有启用 fClient,它就完全不起作用。目前,它主要是作为文档,向重新实现纯客户端的开发者展示哪些代码需要保留、哪些可以省去。
中本聪引用的旧邮件Satoshi Nakamoto来源 ↗在 fClient=true 的情况下,我只测试过仅下载区块头的初次下载过程。
中本聪引用的旧邮件Satoshi Nakamoto来源 ↗说一点背景。CBlockIndex 包含区块头的全部信息,所以要只用区块头运行,我只需像往常一样维护 CBlockIndex 结构。nFile/nBlockPos 为空,因为完整区块没有记录到磁盘上。
中本聪引用的旧邮件Satoshi Nakamoto来源 ↗在不删除 blk*.dat 的情况下顺利切换客户端模式开关的代码,还没有实现。主要只需要让非客户端模式的 LoadBlockIndex 忽略区块位置为空的区块索引项。这样就会把它们作为完整区块重新下载。切换回客户端模式没有问题,它不介意完整区块已经存在。
中本聪引用的旧邮件Satoshi Nakamoto来源 ↗如果初始区块下载耗时太长,我们就需要把客户端模式作为一个选项,让新用户可以快速开始运行。如果能顺利关闭客户端模式,他们以后想开始生成币时,就可以关闭客户端模式,让它下载完整区块。不过,他们最好还是直接使用 getwork 矿工程序加入矿池。
中本聪引用的旧邮件Satoshi Nakamoto来源 ↗重新实现纯客户端时,完全不需要实现 EvalScript,最多只需实现标准交易模板使用的五个操作码。”
引用的来信Mike Hearn来源 ↗具体来说,比特币中有各种来由不明的固定数值,但代码和论文都没有解释它们的来源。例如,发行达到 2100 万枚币后,通胀就会停止。这个数字一定是以某种方式得出的,但我看不出来。
是有根据的估计,而且计算结果恰好是整齐的数字。我想要一个数:如果比特币非常流行,这个数不会太低;如果不流行,也不会太高。
引用的来信Mike Hearn来源 ↗另一个是 10 分钟的目标出块时间。我理解选择它是为了让交易有时间在网络中传播。但现有的大型 P2P 网络,例如 BGP,可以在 <1 分钟内把新数据传播到全世界。
如果传播需要 1 分钟,那么 10 分钟就是一个不错的估计。这样节点只会损失 10% 的工作量(1 分钟/10 分钟)。如果延迟浪费的 CPU 时间占比更大,可能会产生我还没想到的弱点。攻击者不会受到延迟影响,因为他在连接自己生成的区块,所以他会占优势。延迟也会让链更频繁地出现临时分叉。
引用的来信Mike Hearn来源 ↗我感兴趣的最后一个数字,是区块大小的 500kb 限制。根据维基百科,仅 Visa 在 2009 年就处理了 620 亿笔交易。换算下来,平均每秒 2000 笔,所以峰值可能约为两倍,即每秒 4000 笔。按 10 分钟的目标出块时间,峰值时一个区块可能需要容纳 240 万笔交易,这显然装不进 500kb。这个 500kb 是一个会随着时间推移,逐渐从官方客户端中取消的临时限制,还是某种更根本的限制?
等实际使用量更接近限制,并确认一切运行正常后,就可以逐步引入更高的上限。
最终,当我们有了纯客户端实现,区块链大小就不会那么重要。在那之前,所有用户仍必须下载整条区块链才能开始使用,如果能把它控制在合理大小,就很好。
在交易量非常高时,网络节点会整合,会有更多矿池挖矿和 GPU 集群,而用户会运行纯客户端。通过开发来优化并实现并行处理,它可以继续扩展。
无论软件目前的处理能力是多少,它都会自动按摩尔定律的速度增长,大约每年 60%。
它能提前很多个版本就写进去,这样等到到达那个区块号、真正生效时,没有它的旧版本早已被淘汰。
它能分阶段引入,比如:
if (blocknumber > 115000)
maxblocksize = largerlimit
它能提前很多个版本就写进去,这样等到到达那个区块号、真正生效时,没有它的旧版本早已被淘汰。
接近截止区块号时,我能向旧版本发警报,确保它们知道自己务必升级。
+1 theymos。别用这个补丁,它会让你与网络不兼容,让你自己吃亏。
最好尽可能长时间地将 blk*.dat 文件维持在较小的体积。
最好尽可能长时间地将 blk*.dat 文件维持在较小的体积。
长远的解决办法,是让文件大小不再重要。
但目前文件还小,最好维持这一点,好让新用户更快开始使用。等我最终实现纯客户端模式(client-only),文件大小就不太重要了。
手续费还有工作要做。万一发生洪水攻击,你仍然可以通过支付 0.01 手续费插队,把自己的交易送进下一个区块。不过我还没来得及在界面上加这个选项。
无论规模大小,测试网的反应方式都一样,只是浪费的带宽和造成的困扰少得多。
每个用户都是一个网络节点的现状,并非大规模阶段的预期形态。那就像每个 Usenet 用户都跑自己的 NNTP 服务器。这个设…
每个用户都是一个网络节点的现状,并非大规模阶段的预期形态。那就像每个 Usenet 用户都跑自己的 NNTP 服务器。这个设计支持让用户就只做用户。跑一个节点的负担越重,节点就会越少。那少数节点会是大型服务器集群。其余的是只做交易、不挖矿的客户端节点。
其他参与者原话bytemaster原帖 ↗再说,10 分钟才确认付款有效太慢了。它得像今天刷信用卡一样快。
看那个零食机主题,我在里面概述了支付处理服务商如何在大约 10 秒或更短时间内把支付验证得足够好,实际上相当好(欺诈率远低于信用卡)。如果你不信,或者没看懂,抱歉,我没时间说服你。
设计中勾勒了一个不需要完整区块链的轻量客户端。在设计 PDF 里它叫简化支付验证(Simplified Payment Ve…
设计中勾勒了一个不需要完整区块链的轻量客户端。在设计 PDF 里它叫简化支付验证(Simplified Payment Verification)。轻量客户端可以收发交易,只是不能生成区块。它不需要信任某个节点来验证支付,仍能自行验证。
轻量客户端尚未实现,计划是在需要时实现。目前,每个人都运行完整的网络节点。
我预计节点永远不会超过 10 万个,可能更少。它会达到一个均衡:再多节点加入就不值当了。其余的将是轻量客户端,可能数以百万计。
达到均衡规模后,许多节点将以服务器集群的形式运行,由一两个网络节点通过局域网向集群内的其余机器提供数据。
区块验证、轻客户端与托管服务
耗时的主要不是下载本身,而是下载时验证所有区块里的全部签名。
初始区块下载通常要花多久?中途会变慢,还是全程速度差不多?
我想过对链条的大部分做更粗略的检查、只认真验证最后几千个区块。可行,但工作量大,而且还有许多优先级更高的事要做。
简化支付验证(SPV)是为轻量级纯客户端用户准备的:他们只做交易、不生成、不参与节点网络。他们不需要下载区块,只需下载哈希链——目前大约 2MB,验证极快(验证整条链不到一秒)。如果网络变得非常大,比如超过 100,000 个节点,我们就用这个让普通用户不必成为完整节点也能交易。到那个阶段,大多数用户应该开始运行纯客户端软件,只有专业的服务器集群继续运行完整网络节点,有点像 usenet 网络的整合方式。
SPV 尚未实现,也要到很远的将来才会实现,但当前的所有实现都是围绕支持它而设计的。
同时,vekja.net 和 www.mybitcoin.com 这类站点一直在试验基于账户的网站。你在网站上创建账户,把比特币存在那里的账户里,转入转出。在网站注册账户比安装、学习使用软件容易得多,对大多数人也是更熟悉的方式。唯一的缺点是你必须信任该站点,但对零钱数额的微支付和杂项开支来说这没问题。这是很好的入门方式,等金额大了再升级到真正的 bitcoin 软件。
我很乐意回答你的任何问题。如果有时间,我应该写一份常见问题解答,作为论文的补充。
你好,中本聪:
我读了你的比特币论文,觉得很有意思。不过,我觉得有些地方不太好懂——如果你能给出一些例子,可能会更容易理解。
具体来说,我不太清楚区块里包含什么。如果我理解正确,所有交易都会被哈希进一条(或者几条)全局链。如果只有一条链,可以说它记录了‘整个经济的历史’,那要怎样扩展规模呢?假设在全球范围内使用,每小时就会有数百万甚至数十亿笔交易被哈希进这条链。我知道每份工作量证明可以把很多交易装进一个区块,但这仍然意味着要对大量数据做哈希计算。如果有多条链,交易又该如何分配,才能让攻击者依然难以压倒网络?例如,如果有 10 条全局链,攻破系统所需的 CPU 算力就只有原来的 10%。
我也想知道,‘1 个核心 = 1 票’这个假设是否可靠。如果大多数节点都运行在普通电脑上,攻击者似乎很可能通过 FPGA 或定制 ASIC 获得明显更高的性能。你怎么看用专用硬件超越这条链的可能性?
激励那一节我读起来有些困难。特别是,我不清楚,在什么情况下,运行节点的动机会从铸造新币转为收取手续费(比特币的主要意义之一,不就是把交易成本降到零吗?)。我猜系统里有某个人负责管理——例如,你以某种方式决定 2400 万枚币是合适的数量,然后分发某种规则文件,规定‘在这个时间戳之后铸造的币,必须有 N+1 个零比特的前缀’,再由诚实节点执行这些规则。
你是怎样决定 v1 的通胀安排的?2400 万枚币这个数字是怎么来的?这些币有哪些面额?你提到了拆分和合并价值的方法,但我还不清楚它如何运作。例如,比特币的数量总是整数,还是也可以有不足一枚的比特币?
问题真不少 :) 不过,真正具有革命性的想法很少见。我上一次对一种新货币方案这么兴奋,还是发现 Ripple 的时候。如果你对 Ripple 有什么看法,我也很想听听。
谢谢——mike
Mike,你好,
我很乐意回答你的任何问题。如果有时间,我应该写一份常见问题解答,作为论文的补充。
全世界只有一条链。
现有的 Visa 信用卡网络,每天在全球处理约 1500 万笔网上购物。凭借现有硬件,比特币已经可以扩展到远超这个规模,而成本只需其中一小部分。它实际上不会碰到规模上限。如果你有兴趣,我可以详细说明它如何应对极大的规模。
根据摩尔定律,我们可以预期硬件速度在 5 年后变为 10 倍,在 10 年后变为 100 倍。即使比特币以疯狂的速度普及,我也认为计算机速度的增长会超过交易数量的增长。
我预计近期不需要手续费,但如果运行节点的负担变得过重,就可以运行一种只处理附带手续费的交易的节点。节点所有者自行决定能接受的最低手续费。目前,这样的节点什么也赚不到,因为没人附带手续费;但如果足够多的节点这么做,用户附带手续费就会更快得到接受,不附带则会更慢。市场最终确定的手续费应该很低。如果一个节点要求更高手续费,就会放弃所有手续费更低的交易。尽可能处理更多付费交易,它就能增加业务量,也可能赚得更多。不过,这个转变不是由某个掌管系统的人控制的,而是个人各自对市场力量作出反应。
最终,大多数节点可能由配备多张 GPU 显卡的专业人士运行。目前,任何有 PC 的人都可以参与,而不用担心自己用的是什么显卡,这很好,希望还能保持一段时间。如今,越来越多电脑出厂时都配有相当不错的 GPU,所以也许以后我们会转向那种方式。
比特币的一个关键特点是,网络的安全性会随着网络规模和需要保护的价值增加而增强。缺点是,它在起步阶段规模很小时容易受到攻击,不过,能够偷走的价值应该始终低于行窃所需付出的代价。如果有人出于其他动机,想证明某一点,那他们证明的也只是我已经承认的一点。
币的数量和发行时间表,是我根据已有认识作出的估计。这是个艰难的选择,因为网络一旦开始运行,规则就固定下来,我们只能接受它。我想选一个能让价格与现有货币类似的方案,但不知道未来,这很难做到。最后,我选了一个折中的方案。如果比特币一直是小众事物,每单位的价值就会低于现有货币。如果设想它被用于世界商业活动的一部分,那么全世界只有 2100 万个币,每单位价值就会高得多。金额用 64 位整数表示,保留 8 位小数,所以 1 个币在内部表示为 100000000。如果通常的价格变得很小,仍有足够细的精度。例如,如果 0.001 值 1 欧元,改变小数点的显示位置可能更方便:你如果有 1 个比特币,就显示为 1000,而 0.001 则显示为 1。
Ripple 很有意思,因为除了比特币,它是唯一没有把信任集中到中央服务器、而是对信任采取其他处理方式的系统。
Satoshi
早在网络接近这么大的规模之前,用户就可以安全地使用简化支付验证(第 8 节)检查双重支付,这只需要保存区块头链,大约每天 1…
引用的来信James A. Donald来源 ↗Satoshi Nakamoto 写道:
引用的中本聪旧文中本聪来源 ↗我一直在开发一种新的电子现金系统,它完全采用点对点方式,无需可信第三方。
我们非常、非常需要这样的系统,但按我对你的方案的理解,它似乎无法扩展到所需的规模。
可转让的工作量证明代币要有价值,就必须具有货币价值。要有货币价值,就必须在一个非常大的网络中转让—— 例如类似 bittorrent 的文件交换网络。
要及时发现并拒绝一次双重支付,就必须掌握交易中那些币的大部分过往交易;如果直接实现,就要求每个对等节点掌握大部分过往交易,或者最近发生的大部分过往交易。如果数亿人都在交易,就需要很大的带宽——每个人都必须知道全部交易,或其中相当大的一部分。
早在网络接近这么大的规模之前,用户就可以安全地使用简化支付验证(第 8 节)检查双重支付,这只需要保存区块头链,大约每天 12KB。只有尝试生成新币的人才需要运行网络节点。起初,大多数用户都会运行网络节点,但随着网络增长到一定程度,这项工作会越来越多地交给拥有专用硬件服务器群的专业人员。一个服务器群只需要在网络中运行一个节点,局域网里的其他机器都连接这个节点。
带宽要求可能没有你想的那么难以承受。一笔典型交易大约是 400 字节(ECC 非常紧凑)。每笔交易需要广播两次,所以我们按每笔交易 1KB 算。Visa 在 2008 财年处理了 370 亿笔交易,平均每天 1 亿笔。这么多交易需要 100GB 的带宽,相当于 12 张 DVD 或 2 部高清电影的大小,按当前价格计算,带宽费用约为 $18。
如果网络达到那么大的规模,也需要好几年,到那时,在互联网上传送 2 部高清电影大概就不算什么大事了。
Satoshi Nakamoto
目录与阅读顺序由本站整理;原话保留各自日期与上下文。文中软件版本、费用和设置属于当时的历史语境。