Skip to content

Commit

Permalink
pool: Do not populate/use gentx2.
Browse files Browse the repository at this point in the history
This modifies the pool to report the entire partial header via the first
generation tx field as intended and no longer populates the second
generation tx field since it does not apply to Decred.

Some of the old ASICs hacked the stake version in there, but that is
really not something that should have ever been done because the stratum
"protocol" (which is not actually very well defined) already does not
individually provide all of the information the Decred header
needs nor does it provide an official way to extend it.

Further, the Decred header explicitly provides additional space which
removes the need to create a new coinbase and update the merkle root.

So, in order to address these things, the field that was intended to
serve for the coinbase (generate transaction) was repurposed to contain
the serialized partial header for data after the previous block hash in
the format it is to be hashed.  Therefore, it should be providing the
entire remaining partial header to ensure that any future modifications
to the end of the header are available to miners without modification.

Given that the old ASICs no longer work with the network, this takes the
opportunity to make the change.
  • Loading branch information
davecgh authored and jholdstock committed Oct 12, 2023
1 parent 73a5cd5 commit de6e42e
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 39 deletions.
4 changes: 2 additions & 2 deletions cmd/miner/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ func (m *Miner) process(ctx context.Context) {
continue
}

jobID, prevBlockE, genTx1E, genTx2E, blockVersionE, _, _,
jobID, prevBlockE, genTx1E, blockVersionE, _, _,
cleanJob, err := pool.ParseWorkNotification(notif)
if err != nil {
log.Errorf("parse job notification error: %v", err)
Expand All @@ -380,7 +380,7 @@ func (m *Miner) process(ctx context.Context) {
}

blockHeader, err := pool.GenerateBlockHeader(blockVersionE,
prevBlockE, genTx1E, m.extraNonce1E, genTx2E)
prevBlockE, genTx1E, m.extraNonce1E)
if err != nil {
log.Errorf("generate block header error: %v", err)
m.cancel()
Expand Down
7 changes: 3 additions & 4 deletions pool/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,10 +759,9 @@ func (c *Client) updateWork(cleanJob bool) {
updatedWorkE := buf.String()
blockVersion := updatedWorkE[:8]
prevBlock := updatedWorkE[8:72]
genTx1 := updatedWorkE[72:288]
genTx1 := updatedWorkE[72:360]
nBits := updatedWorkE[232:240]
nTime := updatedWorkE[272:280]
genTx2 := updatedWorkE[352:360]

heightD, err := hex.DecodeString(updatedWorkE[256:264])
if err != nil {
Expand All @@ -779,8 +778,8 @@ func (c *Client) updateWork(cleanJob bool) {
log.Error(err)
return
}
workNotif := WorkNotification(job.UUID, prevBlock, genTx1, genTx2,
blockVersion, nBits, nTime, cleanJob)
workNotif := WorkNotification(job.UUID, prevBlock, genTx1, blockVersion,
nBits, nTime, cleanJob)

c.sendMessage(workNotif)
log.Tracef("Sent a timestamp-rolled current work at "+
Expand Down
7 changes: 3 additions & 4 deletions pool/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,14 +440,13 @@ func testClientMessageHandling(t *testing.T) {

blockVersion := workE[:8]
prevBlock := workE[8:72]
genTx1 := workE[72:288]
genTx1 := workE[72:360]
nBits := workE[232:240]
nTime := workE[272:280]
genTx2 := workE[352:360]

// Send a work notification to the CPU client.
r = WorkNotification(job.UUID, prevBlock, genTx1, genTx2,
blockVersion, nBits, nTime, true)
r = WorkNotification(job.UUID, prevBlock, genTx1, blockVersion, nBits,
nTime, true)
select {
case <-client.ctx.Done():
t.Fatalf("client context done: %v", err)
Expand Down
7 changes: 3 additions & 4 deletions pool/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,18 +543,17 @@ func (h *Hub) processWork(headerE string) {

blockVersion := headerE[:8]
prevBlock := headerE[8:72]
genTx1 := headerE[72:288]
genTx1 := headerE[72:360]
nBits := headerE[232:240]
nTime := headerE[272:280]
genTx2 := headerE[352:360]
job := NewJob(headerE, height)
err = h.cfg.DB.persistJob(job)
if err != nil {
log.Error(err)
return
}
workNotif := WorkNotification(job.UUID, prevBlock, genTx1, genTx2,
blockVersion, nBits, nTime, true)
workNotif := WorkNotification(job.UUID, prevBlock, genTx1, blockVersion,
nBits, nTime, true)
h.endpoint.clientsMtx.Lock()
for _, client := range h.endpoint.clients {
client.sendMessage(workNotif)
Expand Down
57 changes: 32 additions & 25 deletions pool/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"encoding/json"
"fmt"
"math/big"
"strings"

"github.com/decred/dcrd/wire"

Expand Down Expand Up @@ -473,7 +472,9 @@ func ParseSetDifficultyNotification(req *Request) (uint64, error) {
}

// WorkNotification creates a work notification message.
func WorkNotification(jobID string, prevBlock string, genTx1 string, genTx2 string, blockVersion string, nBits string, nTime string, cleanJob bool) *Request {
func WorkNotification(jobID string, prevBlock string, genTx1 string, blockVersion string, nBits string, nTime string, cleanJob bool) *Request {
// The genTx2 parameter is not needed in Decred, so it is left blank.
const genTx2 = ""
return &Request{
Method: Notify,
Params: []interface{}{jobID, prevBlock, genTx1, genTx2, []string{},
Expand All @@ -482,96 +483,102 @@ func WorkNotification(jobID string, prevBlock string, genTx1 string, genTx2 stri
}

// ParseWorkNotification resolves a work notification message into its components.
func ParseWorkNotification(req *Request) (string, string, string, string, string, string, string, bool, error) {
func ParseWorkNotification(req *Request) (string, string, string, string, string, string, bool, error) {
const funcName = "ParseWorkNotification"
if req.Method != Notify {
desc := fmt.Sprintf("%s: notification method is not notify", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

params, ok := req.Params.([]interface{})
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification "+
"parameters", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

jobID, ok := params[0].(string)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification "+
"jobID parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

prevBlock, ok := params[1].(string)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification prevBlock "+
"parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

genTx1, ok := params[2].(string)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification genTx1 "+
"parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

genTx2, ok := params[3].(string)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification genTx2 "+
"parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}
// Note that params[3] which is a second generation transaction is not
// applicable for decred.

// Note that param[4] which is the list of merkle branches is not
// Note that params[4] which is the list of merkle branches is not
// applicable for decred, the final merkle root is already
// included in the block.

blockVersion, ok := params[5].(string)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification "+
"blockVersion parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

nBits, ok := params[6].(string)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification "+
"nBits parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

nTime, ok := params[7].(string)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification "+
"nTime parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

cleanJob, ok := params[8].(bool)
if !ok {
desc := fmt.Sprintf("%s: unable to parse work notification "+
"cleanJob parameter", funcName)
return "", "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
return "", "", "", "", "", "", false, errs.MsgError(errs.Parse, desc)
}

return jobID, prevBlock, genTx1, genTx2, blockVersion,
nBits, nTime, cleanJob, nil
return jobID, prevBlock, genTx1, blockVersion, nBits, nTime, cleanJob, nil
}

// GenerateBlockHeader creates a block header from a mining.notify
// message and the extraNonce1 of the client.
func GenerateBlockHeader(blockVersionE string, prevBlockE string,
genTx1E string, extraNonce1E string, genTx2E string) (*wire.BlockHeader, error) {
genTx1E string, extraNonce1E string) (*wire.BlockHeader, error) {

const funcName = "GenerateBlockHeader"

// Ensure the provide generation tx (partial header) has the minimum
// required length.
const minGenTx1ELen = 288
if len(genTx1E) < minGenTx1ELen {
desc := fmt.Sprintf("%s: genTx1E field length of %d is less than the "+
"required minimum length of %d", funcName, len(genTx1E),
minGenTx1ELen)
return nil, errs.MsgError(errs.Decode, desc)
}

var buf bytes.Buffer
_, _ = buf.WriteString(blockVersionE)
_, _ = buf.WriteString(prevBlockE)
_, _ = buf.WriteString(genTx1E)
_, _ = buf.WriteString(genTx1E[:216])
_, _ = buf.WriteString(extraNonce1E)
_, _ = buf.WriteString(strings.Repeat("0", 56))
_, _ = buf.WriteString(genTx2E)
_, _ = buf.WriteString(genTx1E[224:])
headerE := buf.String()

headerD, err := hex.DecodeString(headerE)
Expand Down

0 comments on commit de6e42e

Please sign in to comment.