[NOD-1093] Add hashMerkleRoot to GetBlockTemplateResult (#776)

* Add hashMerkleRoot field to GetBlockTemplateResult

* Use hashMerkleRoot from template instead of recalculating

* Move ParseBlock from kaspaminer into rpcclient

* Rename ParseBlock to ConvertGetBlockTemplateResultToBlock and wrap errors
This commit is contained in:
Elichai Turkel 2020-06-28 16:53:09 +03:00 committed by GitHub
parent 0a7a4ce7d6
commit d3c6a3dffc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 62 additions and 54 deletions

View File

@ -1,23 +1,17 @@
package main
import (
"encoding/hex"
nativeerrors "errors"
"math/rand"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/kaspanet/kaspad/rpcclient"
"github.com/pkg/errors"
"github.com/kaspanet/kaspad/blockdag"
"github.com/kaspanet/kaspad/rpcmodel"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/daghash"
"github.com/kaspanet/kaspad/wire"
"github.com/pkg/errors"
)
var random = rand.New(rand.NewSource(time.Now().UnixNano()))
@ -104,52 +98,6 @@ func handleFoundBlock(client *minerClient, block *util.Block) error {
return nil
}
func parseBlock(template *rpcmodel.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, errors.Errorf("Error decoding hash %s: %s", parentHash, err)
}
parentHashes[i] = hash
}
// parse Bits
bitsUint64, err := strconv.ParseUint(template.Bits, 16, 32)
if err != nil {
return nil, errors.Errorf("Error decoding bits %s: %s", template.Bits, err)
}
bits := uint32(bitsUint64)
// parseAcceptedIDMerkleRoot
acceptedIDMerkleRoot, err := daghash.NewHashFromStr(template.AcceptedIDMerkleRoot)
if err != nil {
return nil, errors.Errorf("Error parsing acceptedIDMerkleRoot: %s", err)
}
utxoCommitment, err := daghash.NewHashFromStr(template.UTXOCommitment)
if err != nil {
return nil, errors.Errorf("Error parsing utxoCommitment: %s", err)
}
// parse rest of block
msgBlock := wire.NewMsgBlock(
wire.NewBlockHeader(template.Version, parentHashes, &daghash.Hash{},
acceptedIDMerkleRoot, utxoCommitment, bits, 0))
for i, txResult := range template.Transactions {
reader := hex.NewDecoder(strings.NewReader(txResult.Data))
tx := &wire.MsgTx{}
if err := tx.KaspaDecode(reader, 0); err != nil {
return nil, errors.Errorf("Error decoding tx #%d: %s", i, err)
}
msgBlock.AddTransaction(tx)
}
block := util.NewBlock(msgBlock)
msgBlock.Header.HashMerkleRoot = blockdag.BuildHashMerkleTreeStore(block.Transactions()).Root()
return block, nil
}
func solveBlock(block *util.Block, stopChan chan struct{}, foundBlock chan *util.Block) {
msgBlock := block.MsgBlock()
targetDifficulty := util.CompactToBig(msgBlock.Header.Bits)
@ -231,7 +179,7 @@ func solveLoop(newTemplateChan chan *rpcmodel.GetBlockTemplateResult, foundBlock
}
stopOldTemplateSolving = make(chan struct{})
block, err := parseBlock(template)
block, err := rpcclient.ConvertGetBlockTemplateResultToBlock(template)
if err != nil {
errChan <- errors.Errorf("Error parsing block: %s", err)
return

View File

@ -7,8 +7,13 @@ package rpcclient
import (
"encoding/hex"
"encoding/json"
"strconv"
"strings"
"github.com/kaspanet/kaspad/rpcmodel"
"github.com/kaspanet/kaspad/util"
"github.com/kaspanet/kaspad/util/daghash"
"github.com/kaspanet/kaspad/wire"
"github.com/pkg/errors"
)
@ -100,3 +105,55 @@ func (r FutureGetBlockTemplateResult) Receive() (*rpcmodel.GetBlockTemplateResul
func (c *Client) GetBlockTemplate(payAddress string, longPollID string) (*rpcmodel.GetBlockTemplateResult, error) {
return c.GetBlockTemplateAsync(payAddress, longPollID).Receive()
}
// ConvertGetBlockTemplateResultToBlock Accepts a GetBlockTemplateResult and parses it into a Block
func ConvertGetBlockTemplateResultToBlock(template *rpcmodel.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, errors.Wrapf(err, "error decoding hash: '%s'", parentHash)
}
parentHashes[i] = hash
}
// parse Bits
bitsUint64, err := strconv.ParseUint(template.Bits, 16, 32)
if err != nil {
return nil, errors.Wrapf(err, "error decoding bits: '%s'", template.Bits)
}
bits := uint32(bitsUint64)
// parse hashMerkleRoot
hashMerkleRoot, err := daghash.NewHashFromStr(template.HashMerkleRoot)
if err != nil {
return nil, errors.Wrapf(err, "error parsing HashMerkleRoot: '%s'", template.HashMerkleRoot)
}
// parse AcceptedIDMerkleRoot
acceptedIDMerkleRoot, err := daghash.NewHashFromStr(template.AcceptedIDMerkleRoot)
if err != nil {
return nil, errors.Wrapf(err, "error parsing acceptedIDMerkleRoot: '%s'", template.AcceptedIDMerkleRoot)
}
utxoCommitment, err := daghash.NewHashFromStr(template.UTXOCommitment)
if err != nil {
return nil, errors.Wrapf(err, "error parsing utxoCommitment '%s'", template.UTXOCommitment)
}
// parse rest of block
msgBlock := wire.NewMsgBlock(
wire.NewBlockHeader(template.Version, parentHashes, hashMerkleRoot,
acceptedIDMerkleRoot, utxoCommitment, bits, 0))
for i, txResult := range template.Transactions {
reader := hex.NewDecoder(strings.NewReader(txResult.Data))
tx := &wire.MsgTx{}
if err := tx.KaspaDecode(reader, 0); err != nil {
return nil, errors.Wrapf(err, "error decoding tx #%d", i)
}
msgBlock.AddTransaction(tx)
}
block := util.NewBlock(msgBlock)
return block, nil
}

View File

@ -141,6 +141,7 @@ type GetBlockTemplateResult struct {
ParentHashes []string `json:"parentHashes"`
MassLimit int64 `json:"massLimit,omitempty"`
Transactions []GetBlockTemplateResultTx `json:"transactions"`
HashMerkleRoot string `json:"hashMerkleRoot"`
AcceptedIDMerkleRoot string `json:"acceptedIdMerkleRoot"`
UTXOCommitment string `json:"utxoCommitment"`
Version int32 `json:"version"`

View File

@ -716,6 +716,7 @@ func (state *gbtWorkState) blockTemplateResult(s *Server) (*rpcmodel.GetBlockTem
ParentHashes: daghash.Strings(header.ParentHashes),
MassLimit: wire.MaxMassPerBlock,
Transactions: transactions,
HashMerkleRoot: header.HashMerkleRoot.String(),
AcceptedIDMerkleRoot: header.AcceptedIDMerkleRoot.String(),
UTXOCommitment: header.UTXOCommitment.String(),
Version: header.Version,

View File

@ -313,6 +313,7 @@ var helpDescsEnUS = map[string]string{
"getBlockTemplateResult-sigOpLimit": "Number of sigops allowed in blocks",
"getBlockTemplateResult-massLimit": "Max transaction mass allowed in blocks",
"getBlockTemplateResult-transactions": "Array of transactions as JSON objects",
"getBlockTemplateResult-hashMerkleRoot": "The root of the merkle tree of all transaction IDs in this block",
"getBlockTemplateResult-acceptedIdMerkleRoot": "The root of the merkle tree of transaction IDs accepted by this block",
"getBlockTemplateResult-utxoCommitment": "An ECMH UTXO commitment of this block",
"getBlockTemplateResult-version": "The block version",