diff --git a/cmd/kaspaminer/mineloop.go b/cmd/kaspaminer/mineloop.go index 13651cbe0..005864597 100644 --- a/cmd/kaspaminer/mineloop.go +++ b/cmd/kaspaminer/mineloop.go @@ -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 diff --git a/rpcclient/mining.go b/rpcclient/mining.go index a00cd46af..e19556cc4 100644 --- a/rpcclient/mining.go +++ b/rpcclient/mining.go @@ -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 +} diff --git a/rpcmodel/rpc_results.go b/rpcmodel/rpc_results.go index 6a5d38887..028900dac 100644 --- a/rpcmodel/rpc_results.go +++ b/rpcmodel/rpc_results.go @@ -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"` diff --git a/server/rpc/handle_get_block_template.go b/server/rpc/handle_get_block_template.go index e6a538bd8..7472c8fe5 100644 --- a/server/rpc/handle_get_block_template.go +++ b/server/rpc/handle_get_block_template.go @@ -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, diff --git a/server/rpc/rpcserverhelp.go b/server/rpc/rpcserverhelp.go index dc4544b68..f6869a166 100644 --- a/server/rpc/rpcserverhelp.go +++ b/server/rpc/rpcserverhelp.go @@ -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",