背景图

比特币粉尘和空块

最近看了bitcoinj的TransactionOutput类发现了里面的关于粉尘的一些功能。网上搜索关于比特币粉尘的知识,发现了空块攻击和粉尘攻击的一些说明,但是只是简单地进行表述而已。也看到了矿工如何利用各种手段进行作弊,这个可能就是区块链所不能监控的了。所以我觉得区块链的问题还是很多的。

什么是空块攻击

空块的意思很明确,就是区块中没有交易,其实不管怎么样应该是有一笔交易的,就是挖矿奖励的coinbase交易。但是呢块被接收是经过大量的计算工作量的,所以这个看起来有点不太现实。从经济的角度来说这是不太靠谱,但是这种攻击最大的好处就是不用启动算力攻击。比如说你有全网1%的算力,那么发起空包攻击的概率也是很大的,但是就是这1%的算力也是不小的投入。算力攻击其实就是能控制全网51%的算力,这个时候你可以随意更改区块的信息。我在想以后会不会出现网络攻击,瘫痪大部分网络,在一小片网络中占据算力,从本质上说,区域网内的机器也可以进行挖矿,所以也比较困难。

另外个别情况下偶尔一次,也没有问题,但短期内频繁空块就是攻击了,其效果是使交易内存池变大,交易平均确认时间变长。其实已经有很多矿池消灭了空块的,技术上没有难度的。打包空块并不会比打包满块有优势。但是有ASICBoost专利就不同了,空块有利于ASICBoost专利的实施。

粉尘攻击

如果要想理解粉尘攻击就必须先理解什么是粉尘。任何会消耗其费用三分之一以上的交易输出都不是比特币系统现在想要处理的东西,所以我们称之为“粉尘输出”,并且它们是非标准的。

一个典型的输出是33字节(pubkey hash +操作码),需要输入148字节的消耗,所以我们将它们加在一起以找出用于传输这个数值的总数据量。请注意,这个公式对于任何不是付费地址输出的东西都是错误的,不幸的是,我们必须遵循比特币核心的错误以确保我们被认为是标准。一个更好的公式可以估计满足所有不同脚本类型所需的数据大小,或者只是使用硬编码33。

1
2
3
4
5
6
7
8
9
10
// 这个是根据实时的数据进行的计算。
public Coin getMinNonDustValue(Coin feePerKb) {
final long size = this.unsafeBitcoinSerialize().length + 148;
// 计算交易费
return feePerKb.multiply(size).divide(1000);
}
// 默认是费用的3倍
public Coin getMinNonDustValue() {
return getMinNonDustValue(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(3));
}

上面的这段代码就是用来计算最小的输出,如果小于这个输出值,我们就认为这个输出是粉尘输出。

关于小金额的问题

如果地址上未花费输出比较小,那么很有可能就是使用的时候,这笔钱都不能支付交易费(这就是粉尘判断所不能接受的),这样会损失金额。也可以通过账户不停地将账户的钱转移到大账户里面去,看来不管是何种数字货币,都不能避免零头损失的问题。我们做钱包的应用多少都存在这样的问题。但是以太坊不是基于UTXO,而是基于账户多少能缓解不少的问题。

广播攻击

如果不停地向网络广播大量的垃圾交易会阻塞网络,如果我们的节点能检测出这个交易是非法的,并且停止广播,那么这个问题就不会很严重,但是如果修改了代码,不做这个的检测就会出现大问题。比如说矿池大量发送这样的交易,这就会引起灾难性的后果。

0%