kaspad/mining/simulator/mineloop.go
Svarog 047a2c16c4 [NOD-70] Added mining simluator (#228)
* [NOD-70] Added GetBlockTemplate method to rpcclient

* [NOD-70] Basic infrastructure for mining simulator

* [NOD-70] Fix txFees in NewBlockTempalte: include value for fee transaction + don't set fee for coinbase = -totalFees.

* [NOD-70] Added capabilities parameter to Client.GetBlockTemplate call

* [NOD-70] Dirty version of mining simulator complete

* [NOD-70] cleaned up mining simulator

* [NOD-70] Added dockerfile to mining simulator

* [NOD-70] Updated base config path of mining simulator to mining_simulator

* [NOD-70] Remove error return from msgblock.AddTransaction - it never returns one

* [NOD-70] Renamed r -> random

* [NOD-70] Move paths initialization of mining simulator to main

* [NOD-70] Cleaned up mining simulator dockerfile

* [NOD-70] Add '--' to tini argument
2019-03-26 16:37:44 +02:00

108 lines
2.9 KiB
Go

package main
import (
"encoding/hex"
"fmt"
"log"
"math/rand"
"strconv"
"strings"
"sync/atomic"
"time"
"github.com/daglabs/btcd/blockdag"
"github.com/daglabs/btcd/btcjson"
"github.com/daglabs/btcd/dagconfig/daghash"
"github.com/daglabs/btcd/rpcclient"
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/wire"
)
var random = rand.New(rand.NewSource(time.Now().UnixNano()))
func parseBlock(template *btcjson.GetBlockTemplateResult) (*util.Block, error) {
// parse parent hashes
parentHashes := make([]daghash.Hash, len(template.ParentHashes))
for i, parentHash := range template.ParentHashes {
hash, err := daghash.NewHashFromStr(parentHash)
if err != nil {
return nil, fmt.Errorf("Error decoding hash %s: %s", parentHash, err)
}
parentHashes[i] = *hash
}
// parse Bits
bitsInt64, err := strconv.ParseInt(template.Bits, 16, 32)
if err != nil {
return nil, fmt.Errorf("Error decoding bits %s: %s", template.Bits, err)
}
bits := uint32(bitsInt64)
// parse rest of block
msgBlock := wire.NewMsgBlock(wire.NewBlockHeader(template.Version, parentHashes, &daghash.Hash{}, &daghash.Hash{}, uint32(bits), 0))
for i, txResult := range append([]btcjson.GetBlockTemplateResultTx{*template.CoinbaseTxn}, template.Transactions...) {
reader := hex.NewDecoder(strings.NewReader(txResult.Data))
tx := &wire.MsgTx{}
if err := tx.BtcDecode(reader, 0); err != nil {
return nil, fmt.Errorf("Error decoding tx #%d: %s", i, err)
}
msgBlock.AddTransaction(tx)
}
return util.NewBlock(msgBlock), nil
}
func solveBlock(msgBlock *wire.MsgBlock) {
maxNonce := ^uint64(0) // 2^64 - 1
targetDifficulty := util.CompactToBig(msgBlock.Header.Bits)
for i := uint64(0); i < maxNonce; i++ {
msgBlock.Header.Nonce = i
hash := msgBlock.BlockHash()
if daghash.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
break
}
}
}
func mineLoop(clients []*rpcclient.Client) error {
clientsCount := int64(len(clients))
for atomic.LoadInt32(&isRunning) == 1 {
var currentClient *rpcclient.Client
if clientsCount == 1 {
currentClient = clients[0]
} else {
currentClient = clients[random.Int63n(clientsCount)]
}
log.Printf("Next block will be mined by: %s", currentClient.Host())
template, err := currentClient.GetBlockTemplate([]string{"coinbasetxn"})
if err != nil {
return fmt.Errorf("Error getting block template: %s", err)
}
block, err := parseBlock(template)
if err != nil {
return fmt.Errorf("Error parsing block: %s", err)
}
msgBlock := block.MsgBlock()
msgBlock.Header.HashMerkleRoot = *blockdag.BuildHashMerkleTreeStore(block.Transactions()).Root()
msgBlock.Header.IDMerkleRoot = *blockdag.BuildIDMerkleTreeStore(block.Transactions()).Root()
solveBlock(msgBlock)
log.Printf("Found block %s! Submitting", block.Hash())
err = currentClient.SubmitBlock(block, &btcjson.SubmitBlockOptions{})
if err != nil {
return fmt.Errorf("Error submitting block: %s", err)
}
}
return nil
}