Skip to content

Commit

Permalink
Adding support for JobIDs, and LRU cache to accept shares for stale h…
Browse files Browse the repository at this point in the history
…eaders
  • Loading branch information
Djadih committed Nov 8, 2023
1 parent 9e8f34b commit 7b2c36a
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 55 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/J-A-M-P-S/structs v1.1.0
github.com/dominant-strategies/go-quai v0.22.0
github.com/gorilla/mux v1.8.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/robfig/cron v1.2.0
gopkg.in/redis.v3 v3.6.4
)
Expand Down
11 changes: 3 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,6 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dominant-strategies/bn256 v0.0.0-20220930122411-fbf930a7493d h1:hkL13khTTS48QfWmjRFWpuzhOqu6S0cjpJOzPoBEDb4=
github.com/dominant-strategies/bn256 v0.0.0-20220930122411-fbf930a7493d/go.mod h1:nvtPJPChairu4o4iX2XGrstOFpLaAgNYhrUCl5bSng4=
github.com/dominant-strategies/go-quai v0.13.0-rc.0 h1:aZpS8S8KF9N9S7zagdfLMegWmp+sFSXjFuaQtWeFO/g=
github.com/dominant-strategies/go-quai v0.13.0-rc.0/go.mod h1:LQ/o4Mrx1YV/4TJK2o3fKuJIx811LpirNCk1FrrxkTQ=
github.com/dominant-strategies/go-quai v0.14.0-rc.0 h1:5GODoCKo4AaC4kt0WccYNeYDRj8o/8n0G3yUsii499E=
github.com/dominant-strategies/go-quai v0.14.0-rc.0/go.mod h1:LQ/o4Mrx1YV/4TJK2o3fKuJIx811LpirNCk1FrrxkTQ=
github.com/dominant-strategies/go-quai v0.15.0-rc.0 h1:lfrmmSEr8KImBwY719N6LDKwVZXNY2w8U5ocYEsOpvU=
github.com/dominant-strategies/go-quai v0.15.0-rc.0/go.mod h1:LQ/o4Mrx1YV/4TJK2o3fKuJIx811LpirNCk1FrrxkTQ=
github.com/dominant-strategies/go-quai v0.21.2 h1:UTzVvsx/bxrdVmNgyAm7Y/R9eOVWvAW8Ou78Q5/9Md0=
github.com/dominant-strategies/go-quai v0.21.2/go.mod h1:LQ/o4Mrx1YV/4TJK2o3fKuJIx811LpirNCk1FrrxkTQ=
github.com/dominant-strategies/go-quai v0.22.0 h1:5G0jxGfQZZFHtsoPdBDO6oZHzJFnscxjFCjQTUYXDE0=
github.com/dominant-strategies/go-quai v0.22.0/go.mod h1:LQ/o4Mrx1YV/4TJK2o3fKuJIx811LpirNCk1FrrxkTQ=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
Expand Down Expand Up @@ -174,6 +166,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hnlq715/golang-lru v0.4.0 h1:gyo/wIvLE6Upf1wucAfwTjpR+BQ5Lli2766H2MnNPv0=
github.com/hnlq715/golang-lru v0.4.0/go.mod h1:RBkgDAtlu0SgTPvpb4VW2/RQnkCBMRD3Lr6B9RhsAS8=
Expand Down Expand Up @@ -511,6 +505,7 @@ gopkg.in/bsm/ratelimit.v1 v1.0.0-20170922094635-f56db5e73a5e/go.mod h1:KF9sEfUPA
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
Expand Down
1 change: 1 addition & 0 deletions proxy/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type BlockTemplate struct {
Target *big.Int
Difficulty *big.Int
Height []*big.Int
JobID uint
}

type Block struct {
Expand Down
71 changes: 66 additions & 5 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,27 @@ package proxy
import (
"context"
"encoding/json"
"fmt"
"log"
"math/big"
"net"
"net/http"
"strings"
"sync"
"sync/atomic"
"time"

"github.com/dominant-strategies/go-quai-stratum/policy"
"github.com/dominant-strategies/go-quai-stratum/storage"
"github.com/dominant-strategies/go-quai-stratum/util"
"github.com/dominant-strategies/go-quai/common"
"github.com/dominant-strategies/go-quai/consensus"
"github.com/dominant-strategies/go-quai/consensus/progpow"
"github.com/dominant-strategies/go-quai/core/types"
"github.com/dominant-strategies/go-quai/quaiclient/ethclient"
"github.com/gorilla/mux"

"github.com/dominant-strategies/go-quai-stratum/policy"
"github.com/dominant-strategies/go-quai-stratum/storage"
"github.com/dominant-strategies/go-quai-stratum/util"
"github.com/gorilla/mux"
lru "github.com/hashicorp/golang-lru/v2/expirable"
)

const (
Expand All @@ -42,6 +45,9 @@ type ProxyServer struct {
// Channel to receive header updates
updateCh chan *types.Header

// Keep track of previous headers
headerCache *lru.LRU[uint, *types.Header]

// Stratum
sessionsMu sync.RWMutex
sessions map[*Session]struct{}
Expand Down Expand Up @@ -86,7 +92,8 @@ func NewProxy(cfg *Config, backend *storage.RedisClient) *ProxyServer {
nil,
false,
),
updateCh: make(chan *types.Header, c_updateChSize),
updateCh: make(chan *types.Header, c_updateChSize),
headerCache: lru.NewLRU[uint, *types.Header](10, nil, 600*time.Second),
}
proxy.diff = util.GetTargetHex(cfg.Proxy.Difficulty)

Expand Down Expand Up @@ -300,9 +307,63 @@ func (s *ProxyServer) updateBlockTemplate(pendingHeader *types.Header) {
Height: pendingHeader.NumberArray(),
}

if t == nil {
newTemplate.JobID = 0
} else {
newTemplate.JobID = t.JobID + 1
}

s.blockTemplate.Store(&newTemplate)
s.headerCache.Add(newTemplate.JobID, newTemplate.Header)
log.Printf("New block to mine on %s at height %d", common.OrderToString(common.ZONE_CTX), pendingHeader.NumberArray())
log.Printf("Sealhash: %#x", pendingHeader.SealHash())

go s.broadcastNewJobs()
}

func (s *ProxyServer) verifyMinedHeader(jobID uint, nonce []byte) (*types.Header, error) {
header, ok := s.headerCache.Get(jobID)
if !ok {
return nil, fmt.Errorf("Unable to find header for that jobID: %d", jobID)
}
header = types.CopyHeader(header)

header.SetNonce(types.BlockNonce(nonce))
mixHash, _ := s.engine.ComputePowLight(header)
header.SetMixHash(mixHash)

if header.NumberU64(common.ZONE_CTX) != s.currentBlockTemplate().Header.NumberU64(common.ZONE_CTX) {
log.Printf("Stale header received, block number: %d", header.NumberU64(common.ZONE_CTX))
}

powHash, err := s.engine.VerifySeal(header)
log.Printf("Miner submitted a block. Number: %d. Blockhash: %#x", header.NumberU64(common.ZONE_CTX), header.Hash())
if err != nil {
return nil, fmt.Errorf("unable to verify seal of block: %#x. %v", powHash, err)
}

return header, nil
}

func (s *ProxyServer) submitMinedHeader(cs *Session, header *types.Header) error {

_, order, err := s.engine.CalcOrder(header)
if err != nil {
return fmt.Errorf("rejecting header: %v", err)
}

log.Printf("Received a %s block", strings.ToLower(common.OrderToString(order)))

// Send mined header to the relevant go-quai nodes.
// Should be synchronous starting with the lowest levels.
for i := common.HierarchyDepth - 1; i >= order; i-- {
err := s.clients[i].ReceiveMinedHeader(context.Background(), header)
if err != nil {
// Header was rejected. Refresh workers to try again.
cs.pushNewJob(s.currentBlockTemplate())
return fmt.Errorf("rejected header: %v", err)
}
}

return nil
}
75 changes: 33 additions & 42 deletions proxy/stratum.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ package proxy

import (
"bufio"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"math/big"
"net"
"strings"
"strconv"

"github.com/dominant-strategies/go-quai-stratum/util"
"github.com/dominant-strategies/go-quai/common"
"github.com/dominant-strategies/go-quai/core/types"
)

const (
Expand Down Expand Up @@ -166,7 +163,19 @@ func (cs *Session) handleTCPMessage(s *ProxyServer, req *Request) error {
case "mining.submit":
var errorResponse Response

header := s.currentBlockTemplate().Header
jobId, err := strconv.ParseUint(req.Params.([]interface{})[0].(string), 16, 0)
if err != nil {
log.Printf("Error decoding jobID: %v", err)
errorResponse = Response{
ID: req.Id,
Error: map[string]interface{}{
"code": 500,
"message": "Bad jobID",
},
}
return cs.sendMessage(&errorResponse)
}

nonce, err := hex.DecodeString(req.Params.([]interface{})[1].(string))
if err != nil {
log.Printf("Error decoding nonce: %v", err)
Expand All @@ -180,9 +189,18 @@ func (cs *Session) handleTCPMessage(s *ProxyServer, req *Request) error {
return cs.sendMessage(&errorResponse)
}

header.SetNonce(types.BlockNonce(nonce))
mixHash, _ := s.engine.ComputePowLight(header)
header.SetMixHash(mixHash)
header, err := s.verifyMinedHeader(uint(jobId), nonce)
if err != nil {
log.Printf("Unable to verify header: %v", err)
errorResponse = Response{
ID: req.Id,
Error: map[string]interface{}{
"code": 406,
"message": "Bad nonce",
},
}
return cs.sendMessage(&errorResponse)
}

err = s.submitMinedHeader(cs, header)
if err != nil {
Expand Down Expand Up @@ -226,16 +244,17 @@ func (cs *Session) sendTCPError(err error) {
cs.sendMessage(&message)
}

func (cs *Session) pushNewJob(header *types.Header, target *big.Int) error {
// func (cs *Session) pushNewJob(header *types.Header, target *big.Int) error {
func (cs *Session) pushNewJob(template *BlockTemplate) error {
// Update target to worker.
cs.setMining(common.BytesToHash(target.Bytes()))
cs.setMining(common.BytesToHash(template.Target.Bytes()))

notification := Notification{
Method: "mining.notify",
Params: []string{
fmt.Sprintf("%x", header.Number(common.ZONE_CTX)),
fmt.Sprintf("%x", header.Number(common.ZONE_CTX)),
fmt.Sprintf("%x", header.SealHash()),
fmt.Sprintf("%x", template.JobID),
fmt.Sprintf("%x", template.Header.Number(common.ZONE_CTX)),
fmt.Sprintf("%x", template.Header.SealHash()),
"0",
},
}
Expand Down Expand Up @@ -287,7 +306,7 @@ func (s *ProxyServer) broadcastNewJobs() {
bcast <- n

go func(cs *Session) {
err := cs.pushNewJob(t.Header, t.Target)
err := cs.pushNewJob(t)
<-bcast
if err != nil {
log.Printf("Job transmit error to %v@%v: %v", cs.login, cs.ip, err)
Expand All @@ -297,34 +316,6 @@ func (s *ProxyServer) broadcastNewJobs() {
}
}

func (s *ProxyServer) submitMinedHeader(cs *Session, header *types.Header) error {
powHash, err := s.engine.VerifySeal(header)
if err != nil {
return fmt.Errorf("unable to verify seal of block: %#x. %v", powHash, err)
}
log.Printf("Miner submitted a block. Blockhash: %#x", header.Hash())
_, order, err := s.engine.CalcOrder(header)
if err != nil {
return fmt.Errorf("rejecting header: %v", err)
}

// Should be synchronous starting with the lowest levels.
log.Printf("Received a %s block", strings.ToLower(common.OrderToString(order)))

// Send mined header to the relevant go-quai nodes.
// Should be synchronous starting with the lowest levels.
for i := common.HierarchyDepth - 1; i >= order; i-- {
err := s.clients[i].ReceiveMinedHeader(context.Background(), header)
if err != nil {
// Header was rejected. Refresh workers to try again.
cs.pushNewJob(s.currentBlockTemplate().Header, s.currentBlockTemplate().Target)
return fmt.Errorf("rejected header: %v", err)
}
}

return nil
}

func (cs *Session) sendMessage(v any) error {
cs.Lock()
defer cs.Unlock()
Expand Down

0 comments on commit 7b2c36a

Please sign in to comment.