BTC网络
比特币采用了基于国际互联网(Internet)的P2P(peer-to-peer)网络架构。P2P是指位于同一网络中的每台计算机都彼此对等,各个节点共同提供网络服务,不存在任何“特殊”节点。每个网络节点以“扁平(flat)”的拓扑结构相互连通。
在P2P网络中不存在任何服务端(server)、中央化的服务、以及层级结构。P2P网络的节点之间交互运作、协同处理:每个节点在对外提供服务的同时也使用网络中其他节点所提供的服务。P2P网络也因此具有可靠性、去中心化,以及开放性。
早期的国际互联网就是P2P网络架构的一个典型用例:IP网络中的各个节点完全平等。当今的互联网架构具有分层架构,但是IP协议仍然保留了扁平拓扑的结构。在比特币之外,规模最大也最成功的P2P技术应用是在文件分享领域:Napster是该领域的先锋,BitTorrent是其架构的最新演变。
节点类型及角色
尽管比特币P2P网络中的各个节点相互对等,但是根据所提供的功能不同,各节点可能具有不同的角色。每个比特币节点都是路由、区块链数据库、挖矿、钱包服务的功能集合。一个全节点(full node)包括如图8-1所示的四个功能:钱包,矿工,完整的区块链数据库和网络路由
每个节点都参与全网络的路由功能,同时也可能包含其他功能。每个节点都参与验证并传播交易及区块信息,发现并维持与对等节点的连接。
一些节点保有一份完整的、最新的区块链拷贝,这样的节点被称为“全节点”。全节点能够独立自主地校验所有交易,而不需借由任何外部参照。另外还有一些节点只保留了区块链的一部分,它们通过一种名为“简易支付验证(SPV)”的方式来完成交易验证。这样的节点被称为“SPV节点”,又叫“轻量级节点”。
挖矿节点通过运行在特殊硬件设备上的工作量证明(proof-of-work)算法,以相互竞争的方式创建新的区块。一些挖矿 节点同时也是全节点,保有区块链的完整拷贝;还有一些参与矿池挖矿的节点是轻量级节点,它们必须依赖矿池服务器维护的全节点进行工作。
用户钱包也可以作为全节点的一部分,这在桌面比特币客户端中比较常见。当前,越来越多的用户钱包都是SPV节点, 尤其是运行于诸如智能手机等资源受限设备上的比特币钱包应用;而这正变得越来越普遍。
比特币传播网络
虽然比特币P2P网络服务于各种各样的节点类型的一般需求,但是对于比特币挖掘节点的专门需求,它显示出太高的网络延迟。
比特币传播网络是一种尝试最小化矿工之间传输块的延迟的网络。原始的比特币传播网络是由核心开发商Matt Corallo于2015年创建的,以便能够以非常低的延迟在矿工之间快速同步块。该网络由世界各地的亚马逊Web服务基础架构上托管的几个专门的节点组成,并且连接大多数矿工和采矿池。
原始的比特币传播网络在2016年被替换为Fast Internet Bitcoin Relay Engine or FIBRE,也由核心开发商Matt Corallo创建。 FIBER是一种基于UDP的中继网络,可以中继节点网络内的块。 FIBER实现了compact block,以进一步减少传输的数据量和网络延迟。
康奈尔大学研究的另一个中继网络(仍在提案阶段)是 Falcon。 Falcon使用“直通路由”而不是“存储转发”来减少延迟,通过传播块的部分,而不是等待直到接收到完整的块。
传播网络不是比特币的P2P网络的替代品。相反,它们是覆盖网络,在具有特殊需求的节点之间提供额外的连接像高速公路不是农村道路的替代品,而是交通繁忙的两点之间的快捷方式,您仍然需要小路连接高速公路。
网络发现
当新的网络节点启动后,为了能够参与协同运作,它必须发现网络中的其他比特币节点。新的网络节点必须发现至少一个网络中存在的节点并建立连接。由于比特币网络的拓扑结构并不基于节点间的地理位置,因此各个节点之间的地理信息完全无关。在新节点连接时,可以随机选择网络中存在的比特币节点与之相连。
节点通常采用TCP协议、使用8333端口(该端口号通常是比特币所使用的,除8333端口外也可以指定使用其他端口) 与已知的对等节点建立连接。在建立连接时,该节点会通过发送一条包含基本认证内容的version消息开始“握手”
保持连接
节点必须持续进行两项工作:在失去已有连接时发现新节点,并在其他节点启动时为其提供帮助。节点启动时只需要一个连接,因为第一个节点可以将它引荐给它的对等节点,而这些节点又会进一步提供引荐。一个节点,如果连接到大量的其他对等节点,这既没必要,也是对网络资源的浪费。
在启动完成后,节点会记住它最近成功连接的对等节点;因此,当重新启动后它可以迅速与先前的对等节点网络重新建立连接。如果先前的网络的对等节点对连接请求无应答,该节点可以使用种子节点进行重启动。
用户可以通过提供 -connect= 选项来指定一个或多个IP地址,从而达到覆盖自动节点管理功能并指定IP地址列表的目的。如果采用此选项,节点只连接到这些选定的节点IP地址,而不会自动发现并维护对等节点之间的连接。
如果已建立的连接没有数据通信,所在的节点会定期发送信息以维持连接。如果节点持续某个连接长达90分钟没有任何通信,它会被认为已经从网络中断开,网络将开始查找一个新的对等节点。因此,比特币网络会随时根据变化的节点及网络问题进行动态调整,不需经过中心化的控制即可进行规模增减的有机调整。
全节点
全节点是指维持包含全部交易信息的完整区块链的节点。更加准确地说,这样的节点应当被称为完整区块链节点”。
完整区块链节点保有完整的、最新的包含全部交易信息的比特币区块链拷贝,这样的节点可以独立地进行建立并校验区块链,从第一区块(创世区块)一直建立到网络中最新的区块。完整区块链节点可以独立自主地校验任何交易信息,而不需要借助任何其他节点或其他信息来源。完整区块节点通过比特币网络获取包含交易信息的新区块更新,在验证无误后将此更新合并至本地的区块链拷贝之中。
运行完整区块链节点可以给您一种纯粹的比特币体验:不需借助或信任其他系统即可独立地对所有交易信息进行验证。 辨别您是否在运行全节点是十分容易的:只需要查看您的永久性存储设备(如硬盘)是否有超过20GB的空间被用来存储完整区块链即可。如果您需要很大的磁盘空间、并且同步比特币网络耗时2至3天,那么您使用的正是全节点。这就是摆脱中心化管理、获得完全的独立自由所要付出的代价。
交换“库存清单”,同步本地账本
一个全节点连接到对等节点之后,第一件要做的事情就是构建完整的区块链。如果该节点是一个全新节点,那么它就不包含任何区块链信息,它只知道静态植入在客户端软件中的创世区块。新节点需要下载从0号区块(创世区块)开始的数十万区块的全部内容,才能跟网络同步、并重建全区块链。
同步区块链的过程从发送version消息开始,这是因为该消息中含有的BestHeight字段标示了一个节点当前的区块链高度(区块数量)。节点可以从它的对等节点中得到版本消息,了解双方各自有多少区块,从而可以与其自身区块链所拥有的区块数量进行比较。对等节点们会交换一个getblocks消息,其中包含他们本地区块链的顶端区块哈希值(指纹)。如果某个对等节点识别出它接收到的哈希值并不属于顶端区块,而是属于一个非顶端区块的旧区块,那么它就能推断出:其自身的本地区块链比其他对等节点的区块链更长。
拥有更长区块链的对等节点比其他节点有更多的区块,可以识别出哪些区块们是其他节点需要“补充”的。它会识别出第 一批可供分享的500个区块,通过使用inv(inventory)消息把这些区块的哈希值传播出去。缺少这些区块的节点便可以 通过各自发送的getdata消息来请求得到全区块信息,用包含在inv消息中的哈希值来确认是否为正确的被请求的区块, 从而读取这些缺失的区块。
该节点会追踪记录其每个对等节点连接上“正在传输”(指那些它已经发出了请求但还没有接收到)的区块数量,并且检查该数量有没有超过上限( MAX_BLOCKS_IN_TRANSIT_PER_PEER )。用这种办法,如果一个节点需要更新大量区块,它会在上一请求完成后才发送对新区块的请求,从而允许对等节点控制更新速度,不至于压垮网络。
简易支付验证 (Simplified Payment Verification (SPV) )节点
并非所有的节点都有能力储存完整的区块链。许多比特币客户端被设计成运行在空间和功率受限的设备上,对于这样的设备,通过简化的支付验证(SPV)的方式可以使它们在不必存储完整区块链的情况下进行工作。这种类型的客端被称为SPV客户端或轻量级客户端。
SPV节点只需下载区块头,而不用下载包含在每个区块中的交易信息。由此产生的不含交易信息的区块链,大小只有完整区块链的1/1000。SPV节点不能构建所有可用于消费的UTXO的全貌,这是由于它们并不知道网络上所有交易的完整信息。SPV节点验证交易时所使用的方法略有不同,这个方法需依赖对等节点“按需”提供区块链相关部分的局部视图。
简易支付验证是通过参考交易在区块链中的深度,而不是高度,来验证它们。一个拥有完整区块链的节点会构造一条验证链,这条链是由沿着区块链按时间倒序一直追溯到创世区块的数千区块及交易组成。而一个SPV节点会验证所有区块的链(但不是所有的交易),并且把区块链和有关交易链接起来。
例如,一个全节点要检查第300,000号区块中的某个交易,它会把从该区块开始一直回溯到创世区块的300,000个区块全部都链接起来,并建立一个完整的UTXO数据库,通过确认该UTXO是否还未被支付来证实交易的有效性。SPV节点则不能验证UTXO是否还未被支付。相反地,SPV节点会在该交易信息和它所在区块之间用merkle路径(见“ Merkle 树”章节)建立一条链接。然后SPV节点一直等待,直到序号从300,001到300,006的六个区块堆叠在该交易所在的区块之上,并通过确立交易的深度是在第300,006区块~第300,001区块之下来验证交易的有效性。事实上,如果网络中的其他节点都接受了第300,000区块,并通过足够的工作在该块之上又生成了六个区块,根据代理网关协议,就可以证明该交易不是双重支付。
如果一个交易实际上不存在,SPV节点不会误认为该交易存在于某区块中。SPV节点会通过请求merkle路径证明以及验证区块链中的工作量证明,来证实交易的存在性。可是,一个交易的存在是可能对SPV节点“隐藏”的。SPV节点毫无疑问可以证实某个交易的存在性,但它不能验证某个交易(譬如同一个UTXO的双重支付)不存在,这是因为SPV节点没有一份关于所有交易的记录。
这个漏洞会被针对SPV节点的拒绝服务攻击或双重支付型攻击所利用。为了防御这些攻击,SPV节点需要随机连接到多个节点,以增加与至少一个可靠节点相连接的概率。这种随机连接的需求意味着SPV节 点也容易受到网络分区攻击或Sybil攻击。在后者情况中,SPV节点被连接到虚假节点或虚假网络中,没有通向可靠节点或真正的比特币网络的连接。
在绝大多数的实际情况中,具有良好连接的SPV节点是足够安全的,它在资源需求、实用性和安全性之间维持恰当的平衡。当然,如果要保证万无一失的安全性,最可靠的方法还是运行完整区块链的节点。
总结
完整的区块链节点是通过检查整个链中在它之下的数千个区块来保证这个UTXO没有被支付,从而验证交易。而 SPV节点是通过检查在其上面的区块将它压在下面的深度来验证交易。
隐私风险
由于SPV节点需要读取特定交易从而选择性地验证交易,这样就又产生了隐私风险。与全区块链节点收集每一个区块内的全部交易所不同的是,SPV节点对特定数据的请求可能无意中透露了钱包里的地址信息。例如,监控网络的第三方可以跟踪某个SPV节点上的钱包所请求的全部交易信息,并且利用这些交易信息把比特币地址和钱包的用户关联起来,从而损害了用户的隐私。
在引入SPV节点/轻量级节点后不久,比特币开发人员就添加了一个新功能:Bloom过滤器,用以解决SPV节点的隐私风 险问题。Bloom过滤器通过一个采用概率而不是固定模式的过滤机制,允许SPV节点只接收交易信息的子集,同时不会精确泄露哪些是它们感兴趣的地址。
Bloom过滤器
Bloom过滤器是一个允许用户描述特定的关键词组合而不必精确表述的基于概率的过滤方法。它能让用户在有效搜索关键词的同时保护他们的隐私。在SPV节点里,这一方法被用来向对等节点发送交易信息查询请求,同时交易地址不会被暴露。
Bloom过滤器可以让SPV节点指定交易的搜索模式,该搜索模式可以基于准确性或私密性的考虑被调节。一个非常具体 的Bloom过滤器会生成更准确的结果,但也会显示该用户钱包里的使用的地址;反之,如果过滤器只包含简单的关键 词,更多相应的交易会被搜索出来,在包含若干无关交易的同时有着更高的私密性。
Bloom过滤器如何工作
Bloom过滤器的实现是由一个可变长度(N)的二进制数组(N位二进制数构成一个位域)和数量可变(M)的一组哈希函数组成。这些哈希函数的输出值始终在1和N之间,该数值与二进制数组相对应。并且该函数为确定性函数,也就是说任何一个使用相同Bloom过滤器的节点通过该函数都能对特定输入得到同一个的结果。Bloom过滤器的准确性和私密 性能通过改变长度(N)和哈希函数的数量(M)来调节。
SPV节点和隐私
实现SPV的节点的隐私比整个节点更弱。完整节点接收所有交易,因此不会显示关于它的钱包中是否使用某个地址的信息。 SPV节点接收与其钱包中的地址相关的经过过滤的列表。结果,它减少了所有者的隐私。
bloom过滤器是减少隐私损失的一种方式。没有它们,SPV节点将不得不明确地列出它感兴趣的地址,造成严重的隐私违规。然而,即使使用过滤器,对手监控SPV客户端的流量或直接连接到它的P2P网络中的节点可以随时随地收集足够的信息来了解SPV客户端的钱包中的地址
加密和认证连接
比特币的大多数新用户假设比特币节点的网络通信是加密的。其实,比特币的原始实现就很明显地完成了。虽然这不是完整节点的主要隐私问题,但SPV节点是一个很大的问题。
作为增加比特币P2P网络隐私和安全性的一种方法,有两种解决方案可以通过BIP-150/151提供通信加密:
- Tor传输
- P2P认证和加密
Tor运输
Tor代表洋葱路由网络,是一个软件项目和网络,通过提供匿名,不可追踪和隐私的随机网络路径提供数据的加密和封装。
Bitcoin Core提供了多种配置选项,允许您运行通过Tor网络传输的流量的比特币节点。此外,Bitcoin Core还可以提供Tor隐藏服务,允许其他Tor节点通过Tor直接连接到您的节点。
从Bitcoin Core版本0.12开始,如果能够连接到本地Tor服务,节点将自动提供隐藏的Tor服务。如果您安装Tor并且Bitcoin Core进程作为具有足够权限的用户访问Tor认证cookie的用户运行,则应自动运行。
使用debug标志打开Bitcoin Core对于Tor服务的调试,如下所示:
$ bitcoind --daemon --debug=tor
你应该在日志中看到“tor:ADD_ONION success”,表示Bitcoin Core已经向Tor网络添加了隐藏的服务。
P2P对等认证和加密
BIP-150和BIP-151两种比特币改进方案在比特币P2P网络中增加了对P2P认证和加密的支持。这两个BIP定义了可由兼容的比特币节点提供的可选服务。
BIP-151启用了支持BIP-151的两个节点之间的所有通信的协商加密。
BIP-150提供可选的对等认证,允许节点使用ECDSA和私钥对对方的身份进行身份验证。
BIP-150要求在认证之前,两个节点按照BIP-151建立了加密通信。
截至2017年1月,BIP-150和BIP-151未在Bitcoin Core中实施。但是,这两个提案已由至少一个名为bcoin的替代比特币客户端实施。 BIP-150和BIP-151允许用户运行连接到受信任的完整节点的SPV客户端,使用加密和身份验证来保护SPV客户端的隐私。
此外,可以使用身份验证来创建可信比特币节点的网络,并防止中间人攻击。最后,P2P加密(如果广泛部署)将加强比特币对流量分析和隐私侵权监控的阻力,特别是在互联网使用受到严格控制和监控的极权主义国家。
交易池
交易池与孤立交易池
比特币网络中几乎每个节点都会维护一份未确认交易的临时列表,被称为内存池或交易池。节点们利用这个池来追踪记录那些被网络所知晓、但还未被区块链所包含的交易。例如,保存用户钱包的节点会利用这个交易池来记录那些网络已经接收但还未被确认的、属于该用户钱包的预支付信息。
随着交易被接收和验证,它们被添加到交易池并通知到相邻节点处,从而传播到网络中。
有些节点的实现还维护一个单独的孤立交易池。如果一个交易的输入与某未知的交易有关,如与缺失的父交易相关,该孤立交易就会被暂时储存在孤立交易池中直到父交易的信息到达。
当一个交易被添加到交易池中,会同时检查孤立交易池,看是否有某个孤立交易引用了此交易的输出(子交易)。任何匹配的孤立交易会被进行验证。如果验证有效,它们会从孤立交易池中删除,并添加到交易池中,使以其父交易开始的链变得完整。
对新加入交易池的交易来说,它不再是孤立交易。前述过程重复递归寻找进一步的后代,直至所有的后代都被找到。通过这一过程,一个父交易的到达把整条链中的孤立交易和它们的父级交易重新结合在一起,从而触发了整 条独立交易链进行级联重构。
交易池和孤立交易池(如有实施)都是存储在本地内存中,并不是存储在永久性存储设备(如硬盘)里。更准确的说, 它们是随网络传入的消息动态填充的。节点启动时,两个池都是空闲的;随着网络中新交易不断被接收,两个池逐渐被填充
UTXO池
有些比特币客户端的实现还维护一个UTXO数据库,也称UTXO池,是区块链中所有未支付交易输出的集合。
“UTXO 池”的名字听上去与交易池相似,但它代表了不同的数据集。UTXO池不同于交易池和孤立交易池的地方在于,它在初始 化时不为空,而是包含了数以百万计的未支付交易输出条目,有些条目的历史甚至可以追溯至2009年。UTXO池可能会被安置在本地内存,或者作为一个包含索引的数据库表安置在永久性存储设备中。
区别
交易池和孤立交易池代表的是单个节点的本地视角。取决于节点的启动时间或重启时间,不同节点的两池内容可能有很大差别。相反地,UTXO池代表的是网络的突显共识,因此,不同节点间UTXO池的内容差别不大。此外,交易池和孤立交易池只包含未确认交易,而UTXO池之只包含已确认交易。