美文网首页
矿池&CPU挖矿

矿池&CPU挖矿

作者: hukun | 来源:发表于2018-05-02 18:27 被阅读0次

    由于对区块链的喜爱,个人最近对矿池以及挖矿做了一点点研究。

    首先先说下对于矿池的主要结构,如图


    1525254093070.jpg

    pool

    pool为矿池的中心服务器,用来跟链与miner通信的。
    运行pool程序的电脑上必须要有一个ETH或者OF的全节点。
    他的主要功能包括两个
    一:更新工作

    func updateWork() {
        for true {
            currWorkNew, err := callArray("eth_getWork", []interface{}{})
            if err == nil {
    
                if currWorkNew.Result == nil {
                    time.Sleep(time.Millisecond * 200)
                    continue
                }
    
                if currHash == currWorkNew.Result[0].(string) {
                    //logInfo.Println("新的任务跟当前任务一致")
                    time.Sleep(time.Millisecond * 200)
                    continue
                }
    
                currWork = currWorkNew
                currHash = currWork.Result[0].(string)
    
            } else {
                currWork = nil
                logError.Println("update work error: ", err)
            }
    
            //fmt.Println("Current work", currWork.Result[0])
            time.Sleep(time.Millisecond * 200)
        }
    }
    

    二、提交工作

    func submitWork(params []interface{}) (*ResponseBool, error) {
        result, err := callBool("eth_submitWork", params)
        return result, err
    }
    

    miner

    miner为矿工方,主要用来挖矿,挖矿算法这里用的是eth公开的算法,我加以个人想法优化的。
    首先是更新工作

    // 更新区块
    func updatePendingBlock() {
    
        var (
            //threads     int = runtime.NumCPU()
            currHashNew int64
            //difficulty    uint64
        )
    
        for true {
            time.Sleep(time.Millisecond * 500)
            //var pend sync.WaitGroup
            currWorkNew, err := callArray("ofbank_getWork", []interface{}{})
            //fmt.Println(currWorkNew)
            //logInfo.Println(currWorkNew)
            if err != nil {
                logInfo.Println("new work info", currWorkNew)
                logError.Println("get new work error: ", err)
            } else {
    
                if currWorkNew.Result == nil {
                    fmt.Println("获取的任务为空")
                    continue
                }
    
                currHashNew, err = strconv.ParseInt(currWorkNew.Result[2].(string), 0, 64)
                if err != nil {
                    logError.Println("get difficulty error: ", err,currHashNew)
                    continue
                }
                if currHash == currHashNew {
                    continue
                }
    
                if mining {
                    abort <- struct{}{}
                }
    
                currHash = currHashNew
                currWork = currWorkNew
    
                fmt.Println("开始工作",currHash,currWork.Result[0])
    
                go sealWork(currWorkNew, abort)
    
            }
    
        }
    
    }
    

    这里在获取工作后,执行sealWork,这里有一个终止的通道,用来停止之前的工作,以免做无用功。

    func sealWork(currWork *ResponseArray, abort chan struct{}) {
    
        var (
            blockDifficulty int64
            err             error
            threads         int = runtime.NumCPU()
        )
        //fmt.Println(currWork)
        blockDifficulty, err = strconv.ParseInt(currWork.Result[2].(string), 0, 64)
        if err != nil {
            logError.Printf("seal work error: %+v", err)
            mining = false
            return
        }
    
        myBlock := &block{
            //number:      number,
            difficulty:  big.NewInt(blockDifficulty),
            hashNoNonce: common.HexToHash(currWork.Result[0].(string)),
        }
    
        var stop = make(chan struct{}, threads)
        var l = sync.Mutex{}
    
        var th = 0
        mining = true
        for i := 0; i < threads; i++ {
            th++
            //fmt.Println("第",th,"线程")
    
            go func() {
                currNonce, md := hasher.Search(myBlock, stop, 0)
    
                l.Lock()
                th--
                if th < 0 {
                    th = 0
                }
                l.Unlock()
    
                myBlock.nonce = currNonce
                myBlock.mixDigest = common.BytesToHash(md)
    
                if hasher.Verify(myBlock) {
    
                    if mining {
                        // 挖矿中
                        l.Lock()
                        mining = false
                        l.Unlock()
    
                        submitTask := make([]interface{}, 3)
    
                        // nonce 必须为偶数位长度
                        nonceStr := strconv.FormatUint(currNonce, 16)
                        if len(nonceStr)%2 != 0 {
                            nonceStr = "0" + nonceStr
                        }
                        submitTask[0] = fmt.Sprintf("0x%s", nonceStr)
                        submitTask[1] = currWork.Result[0].(string)
                        //submitTask[1] = currWork.Result[0]
                        submitTask[2] = common.BytesToHash(md).Hex()
    
                        fmt.Println("提交工作")
    
                        abort <- struct{}{}
                        submitWork(submitTask)
                    }
                }
            }()
        }
    
    L:
        for {
            select {
            case <-abort:
                l.Lock()
                var t = th - 1
                mining = false
                currWork = nil
                currHash = 0
                for i := 0; i < t; i ++ {
                    th--
                    stop <- struct{}{}
                }
                l.Unlock()
                break L
            }
        }
    }
    

    然后是sealWork方法,这里根据CPU核心数创建线程,以达到最大CPU利用率。
    在算到相应的工作后,向pool提交工作,等待下个工作。

    使用攻略

    简单写下windows系统下的使用攻略:
    在有全节点的电脑上执行pool.exe 即可。

    1525256636299.jpg

    然后在查看当前电脑的IP地址,这里可以自行百度,有很多种方法,

    然后在挖矿的电脑上执行miner.exe程序,


    1525256671691.jpg

    在这里输入刚刚查到的ip地址,回车,就可以了。

    demo下载地址
    demo里面有可执行程序.

    相关文章

      网友评论

          本文标题:矿池&CPU挖矿

          本文链接:https://www.haomeiwen.com/subject/zkicrftx.html