ASIC芯片的特性

ASIC 芯片在当今算力领域很受关注,它的主要优势是具有强大的计算能力,比主流计算机的计算能力强很多。例如在专业的挖矿场景里,ASIC 芯片可以快速地进行复杂运算。不过,它在内存访问性能方面表现得较为普通,和在算力上的突出优势相比,内存访问的效率是它的短板之一。

科技在不断发展,对芯片的性能要求也在逐渐提高。ASIC 芯片虽然具有惊人的算力,但是其内存访问存在性能瓶颈,这就限制了它在某些特定场景中的应用,无法全面满足在多任务并发情况下对内存进行快速读写的需求。

伪随机顺序机制

在挖矿的计算过程里,存在一种伪随机顺序的实现方式。有一个种子节点以及 seed 值,通过运算把得数放置在第一个位置,接着后面每个位置的值是由前一个位置取哈希而得到的。比如读取 A 位置的数,依据取值运算就能得出下一次要读取的 B 位置。

这种方式模拟出了随机顺序,使得计算过程变得更难以预测。然而,这种方法存在一些问题,要是没有保存数组的话,每次读取不同位置的数都得从开头开始进行计算,这就增加了计算的复杂度以及时间成本。

矿工的内存策略

部分矿工会留存部分内存区域的内容,这与比特币主要进行哈希运算存在差异。他们借助 ASIC 芯片以及内存访问的特性,尝试依照类似普通计算机对资源的配对比例的方式来进行优化。例如依据实际的运算状况,有针对性地保存关键数据。

这种策略是矿工为了提高效率而采取的,在一定程度上对计算和验证的流程进行了改善。但是,它存在弊端,因为验证的区域和求解的区域几乎是一样大的,如果不保存数组,计算的复杂度就会急剧增加,从而影响到挖矿的整体效率。

以太坊的数据集设计

以太坊使用了两个不同大小的数据集,其中一个是 16M 的 cache,另一个是 1G 的 DAG。这种设计有助于轻节点进行验证,因为轻节点只需保留 16M 的 cache 即可,而矿工则需要保存 1G 的大数据集。轻节点只有在需要时才会临时计算元素,而矿工则可以直接访问内存。

这种设计把不同参与方的需求充分考虑到了。轻节点因为资源有限,所以保存小数据集就能降低存储压力;而矿工拥有专业硬件,能够承担起保存大数据集所带来的存储和访问需求,从而保证了整个系统的运行效率。

数据读取与运算过程

以太坊求解时,先依据 block 及 nonce 算出初始哈希值,接着将其映射到大数据集中去读取数。之后按照伪随机顺序,从大数据集中读取 128 个数,在读取过程中,不仅要计算当前位置的元素,还要读取相邻元素。最后算出哈希值,并与挖矿难度目标阈值进行比较。

def mkcache(cache_size, seed):
    o = [hash(seed)]
    for i in range(1, cache_size):
        o.append(hash(o[-1]))
    return o

每次 nonce 进行更替时,第一次映射的位置会发生改变。这个改变需要反复循环 64 次,通过这样的循环可以得到哈希值并与阈值进行比较。这样的过程保证了挖矿的难度,同时也体现了随机性,避免了单一手段对挖矿机制进行破解。

def calc_dataset_item(cache, i):
    cache_size = cache.size
    mix = hash(cache[i % cache_size] ^ i)  
    for j in range(256):
        cache_index = get_int_from_item(mix)  # 自定义函数,原代码是没有的
        mix = make_item(mix, cache[cache_index % cache_size])  # 自定义函数,原代码是没有的
    return hash(mix)

轻节点与矿工的差异

def calc_dataset(full_size, cache):
	return [calc_dataset_item(cache, i) for i in range(full_size)]

轻节点与矿工在内存使用以及运算方式方面存在明显差异。轻节点并未保存大数据集,它需要从 cache 中重新生成所用到的元素,通过临时计算来满足验证的需求。然而,矿工则必须在内存中存储 1G 的大数据集,通过直接访存来提升运算速度。

以太坊进行这样的设计,其目的是要平衡整个网络在资源利用和安全验证这两方面的情况。然而,对于这样的设计所产生的效果到底怎样,以及能否在长期内满足不断增长的挖矿以及验证方面的需求,还需要进行更进一步的观察以及研究。

def hashimoto_full(header, nonce, full_size, dataset):
	mix = hash(header, nonce)
	for i in range(64):
		dataset_index = get_int_from_item(mix) % full_size
		mix = make_item(mix, dataset[dataset_index])
		mix = make_item(mix, dataset[dataset_index + 1])
	return hash(mix)
	
def hashimoto_light(header, nonce, full_size, cache):
	mix = hash(header, nonce)
	for i in range(64):
		dataset_index = get_int_from_item(mix) % full_size
		mix = make_item(mix, calc_dataset_item(cache, dataset_index))
		mix = make_item(mix, calc_dataset_item(cache, dataset_index + 1))
	return hash(mix)

这种内存访问机制以及与之相关的设计是否是以太坊挖矿的最佳方案?大家可以点赞、分享本文,并且在评论区表达自己的看法!