初链主网上线解读之——抗ASIC

栏目: 编程工具 · 发布时间: 5年前

内容简介:在介绍初链的Truehash算法之前,首先介绍一下什么是ASIC。回首这些年矿机的发展脉络,会发现一条清晰的路径:那么,ASIC为何战胜了CPU/GPU,成为了主流矿机?其中很大一部分原因是CPU/GPU为了方便多样性计算,采用了冯诺依曼架构:

一. ASIC如何规避冯诺依曼瓶颈

在介绍初链的Truehash算法之前,首先介绍一下什么是ASIC。

回首这些年矿机的发展脉络,会发现一条清晰的路径:

CPU->GPU->FPGA->ASIC

那么,ASIC为何战胜了CPU/GPU,成为了主流矿机?其中很大一部分原因是CPU/GPU为了方便多样性计算,采用了冯诺依曼架构:

初链主网上线解读之——抗ASIC

冯诺依曼架构大致分三个部分,内存、控制单元、计算单元。运算程序与所运算的数据都写在内存中,执行计算时候向计算单元传输。 传输带宽所带来的计算瓶颈,我们称之为冯诺依曼瓶颈。

我们将集成电路可以简单的看作多个场效应管的结合。CPU的能耗和有多少个场效应晶体管参与工作有关,还和频率是正相关的。一个指令在CPU中的执行,要不要调度运算器,要不要访问外存,要不要回写,在不在L1中都会在调动晶体管数目上产生差别。

在挖矿效能上,少不了一个重要的指标: 每瓦Hash

在CPU中,一些不相干的指令,如:Fetch指令和decode占据了大头,而执行Hash的过程才占据不到10%。这就是完成同样功能,ASIC很省电,而CPU很费电的原因:ASIC不需要执行无关的指令,它将运算程序直接写死在计算单元里,只需要计算Hash即可。专心做一件事并做到最好,完美规避冯诺依曼瓶颈,这就是ASIC的优势!

二. 抵制ASIC,意义何在

既然ASIC这么强大,那么使用ASIC不好吗,为什么要抵制它?

让我们从数字货币的源头去寻找,比特币的白皮书,第6章,第一段:

每个区块的第一笔交易进行特殊化处理,该交易产生一枚由该区块创造者拥有的新的电子货币。这样就增加了节点支持该网络的激励,并在没有中央集权机构发行货币的情况下,提供了一种将电子货币分配到流通领域的一种方法。这种将一定数量新货币持续增添到货币系统中的方法,非常类似于耗费资源去挖掘金矿并将黄金注入到流通领域。此时,CPU的时间和电力消耗就是消耗的资源。

这一章表述地非常明白,挖矿的本质就是 没有中央集权背景下的印钞和分发货币 。挖矿是一种公平的派发货币的过程。

有了以上基础,我们开始进入——初链的Truehash算法。

三. 初链Truehash算法

从 BTC 之后,很多区块链开发者一直在尝试各种不同的抗 ASIC 挖矿算法。从最终结果来看,这些尝试无疑都是失败的。在新一代公链中,初链研究团队作为PoW的捍卫者和拯救者,独创了本质上抗ASIC的挖矿算法,可以实现算法的随机切换,使得再强大的ASIC也无法绕过冯诺依曼瓶颈,从而保护普通矿工的权益。

根本上抗 ASIC 的算法,需要满足以下几点:

  1. 设 S 为一个算法集合,所有实现了 S 的算法,不能绕开冯诺依曼瓶颈。

  2. 每 T 个区块切换一次算法,切换方式必须满足可验证性和随机性。

  3. 算法切换不依赖手动调整。

在普通挖矿算法中,将 blockheade, nonce等信息经过 padding等运算之后,会形成一个向量 v(nonce)。

我们再来看一下初链的truehash算法,它首先检测dataset的状态:

func (m *Minerva) CheckDataSetState(blockNum uint64) bool{
    dataset := m.dataset
    if dataset.dateInit == 0{
        //如果blockNum(区块数)小于12000
        if blockNum <= UPDATABLOCKLENGTH{
            //初始化truehashTable
            m.truehashTableInit(dataset.evenDataset)
            dataset.dataset = &dataset.evenDataset
        }else{
            //重点,在这里开始进行数据集的置换
            bn := (blockNum / UPDATABLOCKLENGTH -1 ) * UPDATABLOCKLENGTH + STARTUPDATENUM + 1
            in :=  (blockNum / UPDATABLOCKLENGTH) % 2
            //如果 blockNum > UPDATABLOCKLENGTH 则改变 lookutable 生成奇数或偶数集
            if in == 0{
                //设置dataset的偶数数据集
                dataset.dataset =  &dataset.evenDataset
                //标志位初始化
                dataset.oddFlag = 0
                dataset.evenFlag = 0
            }else{
                //设置dataset的奇数数据集
                dataset.dataset =  &dataset.oddDataset
                dataset.oddFlag = 0
                dataset.evenFlag = 0
            }
            //更新LookupTBL
            m.updateLookupTBL( bn, *dataset.dataset)
        }
        dataset.dateInit = 1
    }

    if blockNum %UPDATABLOCKLENGTH >= STARTUPDATENUM {
        //开始更新 lookuptable
        in :=  (blockNum / UPDATABLOCKLENGTH) % 2
        //将 lookutable 进行奇偶切换
        if in == 0{
            //是偶数,将dadaset设置为奇数
            if dataset.oddFlag == 0 {
                //更新LookupTBL
                res := m.updateLookupTBL(blockNum, dataset.oddDataset[:])
                if res {
                    //更新成功,将dataset奇数标志位设为1
                    dataset.oddFlag = 1
                }else{
                    //更新失败
                    return false
                }
            }
        }else{
            //是奇数,将dadaset设置为偶数
            if dataset.evenFlag == 0 {
                res := m.updateLookupTBL(blockNum, dataset.evenDataset[:])
                if res {
                    dataset.evenFlag = 1
                }else{
                    return false
                }
            }
        }
    }

    if blockNum %UPDATABLOCKLENGTH == 1{
        in :=  (blockNum / UPDATABLOCKLENGTH) % 2
        //改变 lookutable,生成数据集
        if in == 0{
            //设置偶数数据集
            dataset.dataset = &dataset.evenDataset
            dataset.evenFlag = 0
        }else{
            //设置奇数数据集
            dataset.dataset = &dataset.oddDataset
            dataset.oddFlag = 0
        }
    }
    return true
}

这段函数涉及到的主要有truehashTable(truehash表),evenDataset(偶数集),oddDataSet(奇数集),实现的功能是:进行条件检测,来生成区块或置换dataset数据集。

这里UPDATABLOCKLENGTH = 12000

如果区块数小于等于12000个,那么则初始化truehash表,生成区块。

如果区块数大于12000个,那么开始进行dataset数据集的更换。

dataset数据集的改变,显然影响到了truehash算法的改变。接下来进入到truehash函数

// 计算这个nonce的工作量
digest, result := truehashFull(*m.dataset.dataset, hash, nonce)

看函数里面的实现:

func fchainmining( plookup []uint64, header []byte, nonce uint64) ([]byte, []byte){
    var seed [64]byte
    output := make([]byte, DGSTSIZE)
    val0 := uint32(nonce & 0xFFFFFFFF) //产生0~4294967295的一位数
    val1 := uint32(nonce >> 32)

    for  k:= 3; k >= 0; k-- {
        seed[k] = byte(val0) & 0xFF
        val0 >>= 8
    }
    for k := 7; k >= 4; k-- {
        seed[k] = byte(val1) & 0xFF
        val1 >>= 8
    }

    dgst := make([]byte, DGSTSIZE)

    for k := 0; k < HEADSIZE; k++   {
        seed[k+8] = header[k]
    }


    sha512 := makeHasher(sha3.New512())
    var sha512_out [64]byte

    sha512(sha512_out[:],seed[:])
    byteReverse(sha512_out[:])
    var permute_in [32]uint64

    for k := 0; k < 8; k++  {
        for x := 0; x < 8; x++  {
            var sft int= x * 8
            val := (uint64(sha512_out[k*8+x]) << uint(sft))
            permute_in[k] += val
        }
    }
    for k := 1; k < 4; k++  {
        for x := 0; x < 8; x++ {
            permute_in[k * 8 + x] = permute_in[x]
        }
    }

    scramble(permute_in[:], plookup[:])

    var dat_in [256]byte
    for k := 0; k < 32; k++ {
        val := permute_in[k]
        for x := 0; x < 8; x++  {
            dat_in[k * 8 + x] = byte(val & 0xFF)
            val = val >> 8
        }
    }

    for k := 0; k < 64; k++ {
        var temp byte
        temp = dat_in[k * 4];
        dat_in[k * 4] = dat_in[k * 4 + 3];
        dat_in[k * 4 + 3] = temp;
        temp = dat_in[k * 4 + 1];
        dat_in[k * 4 + 1] = dat_in[k * 4 + 2];
        dat_in[k * 4 + 2] = temp;
    }

    //用sha256生成随机hash
    sha256 := makeHasher(sha3.New256())

    sha256(output, dat_in[:])
    // reverse byte
    for k := 0; k < DGSTSIZE; k++   {
        dgst[k] = output[k];
    }

    return  dgst, dgst
}

里面有众多的移位操作、置换操作,其中用到了加密算法sha256算法,sha512算法,然后通过makeHasher()函数生成随机hash。

还有一个很关键的函数scramble(permute_in[:], plookup[:])

func scramble( permute_in []uint64, plookup []uint64) int{
    var ptbl []uint64
    var permute_out [32]uint64
    for k := 0; k < 64; k++ {

        sf := int(permute_in[0] & 0x7f)
        bs := int(permute_in[31] >> 60)

        ptbl = plookup[bs * 2048 * 32:]

        MatMuliple(permute_in[:], permute_out[:], ptbl[:])
        shift2048(permute_out[:], sf)

        for k := 0; k < 32; k++ {
            permute_in[k] = permute_out[k]
            permute_out[k] = 0
        }
    }
    return 0
}

由此我们可以看到,通过改变dataset集,打乱输入hash运算的数据来实现hash算法的改变。这个数据集极为复杂,那么这个算法集合全部写死在计算单元内的概率将几乎为0。由于算法会 随机切换 ,冯诺依曼瓶颈将无法绕过。

truehash的算法切换原理的总结:每 12000个 PoW区块(生成大概需要83天)换一次dataset数据集。新的dataset数据集信息由上个周期的第 1 – 8192个区块所组成,组成方式通过分析第 11001 - 11256个区块的哈希值所产生。由于区块的hash值不可提前预知,在第 11256个区块出现之前,新算法的信息更是无从得知。从上周期的第 11257个区块,到该算法作废,总共只有 88天的时间,这么短的时间内生产 ASIC没有意义,从而抵制矿机的形成欲望。

四.水果链整合PoW,终结大矿主时代

在目前的矿机生态下,PoW慢链需要避免Selfish Mining Attack和Eclipse Attack等问题。初链TrueChain团队大胆尝试用fPoW协议(FruitChain)替代中本聪的原始PoW协议(Nakamoto PoW),从工程上实现了将水果链整合到PoW中,从而成为fPOW。

fPOW是全新的挖矿设计理念,它采用了水果链(FruitChain)的形象设计。它的亮点如下:

  1. 低难度挖矿:水果的挖矿难度是正常区块挖矿难度的1/600,每个水果记录了若干交易信息,普通挖矿只需要验证交易信息即可,因而无需加入矿池,即可实现挖矿,避免了算力集中(形成矿池)。

  2. 抵御私自挖矿:只要水果是新鲜并且存在的,那么便可获得奖励。

  3. 挖水果获得报酬:挖矿的矿工把挖到的水果接上Block后,会按照计算能力比例分配报酬。

水果链的实现,使得普通挖矿者可以更加公平地参与到挖矿过程中,并获得更加公平地奖励分配,这使初链成为名副其实的去中心化公链,终结了大矿主时代。

作者:weixin_39029194 

原文:https://blog.csdn.net/weixin_39029194/article/details/83281012 


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Music Recommendation and Discovery

Music Recommendation and Discovery

Òscar Celma / Springer / 2010-9-7 / USD 49.95

With so much more music available these days, traditional ways of finding music have diminished. Today radio shows are often programmed by large corporations that create playlists drawn from a limited......一起来看看 《Music Recommendation and Discovery》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换