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

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

内容简介:在介绍初链的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 


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

查看所有标签

猜你喜欢:

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

像计算机科学家一样思考Python (第2版)

像计算机科学家一样思考Python (第2版)

[美] 艾伦 B. 唐尼 / 赵普明 / 人民邮电出版社 / 2016-7 / 49.00

本书以培养读者以计算机科学家一样的思维方式来理解Python语言编程。贯穿全书的主体是如何思考、设计、开发的方法,而具体的编程语言,只是提供了一个具体场景方便介绍的媒介。 全书共21章,详细介绍Python语言编程的方方面面。本书从基本的编程概念开始讲起,包括语言的语法和语义,而且每个编程概念都有清晰的定义,引领读者循序渐进地学习变量、表达式、语句、函数和数据结构。书中还探讨了如何处理文件和......一起来看看 《像计算机科学家一样思考Python (第2版)》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具