参考:
https://blog.csdn.net/qq_25870633/article/details/81980376
https://www.cnblogs.com/gzhlt/p/10271849.html
为什么会有SPV:
在比特币整个生态圈里,大部分都是普通用户,即只有基本的比特币投资及消费支付需要的用户,他们可能没有矿机,没有高端配置的电脑,那么他们是否也要运行一个全节点程序呢?因为随着时间的推移,目前比特币的主链的区块数据高达 200G ,想想如果是一个手机钱包。,或者个人PC 的钱包,下载主网完整区块的话,存储压力未免过大。这时候就出现了 spv 。
比特币网络里的节点在打包一个区块的时候,会对区块里所有的交易进行验证,并且,一个交易还会得到6至7次区块的确认来确保交易最后的完成。正是如此,在使用简单支付验证时,只要判断出一个交易在主链上的某个区块里出现过,则可以证明该交易之前已被验证过。
【注意】:
这里有个细节需要注意,SPV指的是“支付验证“,而不是“交易验证”。这两种验证有很大区别。
"交易验证”非常复杂,涉及到验证是否有足够余额可供支出、是否存在双花、脚本能否通过等等,通常由运行完全节点的矿工来完成。
“支付验证”则比较简单,只判断用于“支付”的那笔交易是否已经被验证过,并得到了多少的算力保护(多少确认数)。
简单的说,交易验证就是要检验这个交易是否合法;支付验证就是验证这笔交易是否已经存在
【考虑这样一种情况】:SPV的目标是验证某个支付是否真实存在,并得到了多少个确认
A收到来自B的一个通知,B声称他已经从某某账户中汇款一定数额的钱给了A。去中心方式下,没有任何人能证明B的可靠。接到这一通知,A如何能判断B所说的是真的呢?
在比特币系统中,这一通知是以一个固定格式的“交易"来实现的,该交易中包含B的汇款账户、B的签名、汇给A的金额以及A的地址。
如果A想本人亲自验证这笔交易,首先,A要遍历区块链账本,定位到B的账户上,这样才能查看B所给的账户上是否曾经有足够的金额;接下来,A要遍历后续的所有账本,看B是否已经支出了这个账户上的钱给别人(是否存在双花欺骗);然后还要验证脚本来判断B是否拥有该账户的支配权。这一过程要求A必须得到完整的区块链才行。
但是,如果A只想知道这笔支付是否已经得到了验证(如果验证了就发货),他可以依赖比特币系统来快速验证。即,检查发生此项支付的那笔交易是否已经收录于区块链中,并得到了多少个确认。
SPV的特点:
SPV 节点一般会与临近节点的连接中设置 BoomFilter ,(该Boomfilter 只接收包含钱包 公钥地址的交易),当邻近节点看到一个TX与SPV节点的 BoomFilter condition 符合的话,他就会用 merkleblock 消息给该SPV节点发送一个 区块;【merkleblock:包含了 BlockHead 和一个连接到该 TX 的Merkle Root 的一个Merkle 路径】;SPV 节点可以利用该merkle路径把TX和包含TX的区块联系起来,并用BlockHead来校验包含该TX的Block是在BlockChiain上的且已经过了6个确认的。这两个验证可以证明该TX是存在于区块链上的。
总之SPV只需要接收小于 1KB的BlockHead 和 merkle 路径数据
spv 校验过程:
- 从网络上获取并保存最长链的所有block header至本地;
- 计算该交易的hash值tx_hash;
- 定位到包含该tx_hash所在的区块,验证block header是否包含在已知 的最长链中;
- 从区块中获取构建merkle tree所需的hash值;
- 根据这些hash值计算merkle_root_hash;
- 若计算结果与block header中的merkle_root_hash相等,则交易真实存 在。
- 根据该block header所处的位置,确定该交易已经得到多少个确认。
【简单的讲,其实SPV就做了两件事】:
1、找到要验证的这笔交易在哪个区块;
2、确定这个交易是否被6次确认过了。
比方说想验证上面的H(K)交易是否支付完成:
首先,节点从网络上获取需要验证的交易的认证路径,在节点上生成对应的一个路径,该路径的值就是图中蓝色标示的节点。在路径确认的情况下,节点只需要计算H(KL)、H(IJKL)、H(IJKLMNOP),H(ABCDEFGHIJKLMNOP)的两次hash值,这样得到的一个merkle根的副本。前面讲过spv节点保存了整个区块链的所有去块头,所以只要拿这个副本和去块头中的merkle根比较。如果存在就能证明该交易支付成功。
SPV的使用场景:
1、轻钱包中的支付校验
2、侧链的双向挂钩中,主链和侧链需要通过对某笔特定的交易做SPV验证,以确保该笔交易确实发生过支付,好使得一方锁定资产,一方转移资产
如:(比特币的侧链)
a】当用户要想侧链转移BTC时,首先在主链上创建一笔交易【一笔特殊的交易】,待转移的BTC被发往一个特殊的输出,这些BTC在主链上被锁定。
b】 等待一段确认其,使得上述交易获得足够的工作量确认 【如: 6个确认】
c】 用户在侧链中也创建交易来提取BTC 【其实严格来说这时候在侧链中不能是BTC了,而是比例兑换的侧链的token】,需要在这笔交易的输入指明 上述主链被锁定的输出,并提供足够的SPV证明。
d】等待一段竞争期,防止双花
e】BTC就这样在侧链上流通了 【严格来说应该是比例兑换的侧链token】
f】当用户想让BTC返回主链时,采用类似的动作。<现在侧链创建交易,待返回的BTC【侧链的token】被发往一个特殊输出,等待一段时间确认期后,在主链用足够的对侧链输出的SPV证明来解锁最早被锁定的输出。等待一段竞争期,珠帘的BTC被解锁,恢复流通>
SPV的神奇:
Merkle树是一种哈希二叉树,它是一种用做快速归纳和校验大规模数据完整性的数据结构。SPV充分利用了Merkle树的这个特点,SPV节点在验证交易是否存在时不保存所有交易也不会下载整个区块,仅仅只是保存区块头。它使用认证路径或者Merkle路径来验证交易存在于区块中,而不必下载区块中所有的交易
可以看出,当区块大小由16笔交易(4KB)急剧增加至65,535笔交易(16MB)时,Merkle的搜索路径长度增长却极其缓慢。这样一来,只需要一个区块头部结构,再加一个这样的搜索路径的开销,一个节点就能花费很小的代价快速定位一个交易。
区块头部只有80字节。按照每小时6个的出块速度,每年产出52560个区块。当只保存区块头部时,每年新增的存储需求约为4兆字节,100年后累计的存储需求仅为400兆,即使用户使用的是最低端的设备,正常情况下也完全能够负载。
安全性
【一】:spv由于没有全部的交易记录,不能验证某个交易不存在,这个漏洞会被针对spv节点的拒绝服务或者双重支付攻击利用。
参考这段话:Wallets operating in SPV mode are only able to validate the block headers they download and not the filters. This makes a “false-negative” attack possible, whereby a malicious peer that knows a wallet is waiting for a particular transaction could send the wallet a fake filter which does not include the transaction, resulting in the wallet not downloading the block and so not becoming aware of the transactions existence.
A “false-positive” scenario is not possible. If a malicious node provides a fake filter which includes a non-existent transaction, the wallet will simply download the full block, compare it to the filter and discover that the filter is not genuine.
【二】:spv节点需要随机链接多个节点,增加与至少一个可靠节点相连接的概率,但是这种随机链接的需求也会容易受到网络分区和sybil攻击。
【三】:SPV因为没有保存全部区块的节点信息,需要和其他节点配合才能进行验证,所以SPV节点存在被诱导连入了一个虚假的网络中的情况,存在被恶意攻击的可能。
如果客户端仅从单个完整节点下载区块链,则该完整节点将再次成为单点故障或危害。这个完整的节点可以将客户端与网络的其余部分隔离开来,并向客户端提供区块链的虚假“视图”
【四】:隐私泄漏。SPV钱包仅向SPV钱包拥有的密钥请求来自完整节点的交易,整个节点链接地址和关联交易,使得比特币用户的匿名化变得微不足道。虽然已经尝试用Bloom过滤器来修复SPV隐私,但这种尝试在很大程度上是无效的。如果没有通过诸如Tor的匿名网络发送交易请求,则完整节点不仅会通过一些方式得到SPV钱包相关的特定地址,还会得到SPV钱包的IP地址