diff --git a/stratum/api.go b/stratum/api.go index b6216c5..13e395c 100644 --- a/stratum/api.go +++ b/stratum/api.go @@ -40,9 +40,9 @@ func (s *StratumServer) StatsIndex(w http.ResponseWriter, r *http.Request) { if t := s.currentBlockTemplate(); t != nil { stats["height"] = t.height - stats["diff"] = t.difficulty + stats["diff"] = t.diffInt64 roundShares := atomic.LoadInt64(&s.roundShares) - stats["variance"] = float64(roundShares) / float64(t.difficulty) + stats["variance"] = float64(roundShares) / float64(t.diffInt64) stats["prevHash"] = t.prevHash[0:8] stats["template"] = true } diff --git a/stratum/blocks.go b/stratum/blocks.go index 37d592d..9222b34 100644 --- a/stratum/blocks.go +++ b/stratum/blocks.go @@ -5,12 +5,14 @@ import ( "encoding/binary" "encoding/hex" "log" + "math/big" "github.com/sammy007/monero-stratum/cnutil" ) type BlockTemplate struct { - difficulty int64 + difficulty *big.Int + diffInt64 int64 height int64 reservedOffset int prevHash string @@ -49,7 +51,8 @@ func (s *StratumServer) fetchBlockTemplate() bool { log.Printf("New block to mine on %s at height %v, diff: %v, prev_hash: %s", r.Name, reply.Height, reply.Difficulty, reply.PrevHash) } newTemplate := BlockTemplate{ - difficulty: reply.Difficulty, + diffInt64: reply.Difficulty, + difficulty: big.NewInt(reply.Difficulty), height: reply.Height, prevHash: reply.PrevHash, reservedOffset: reply.ReservedOffset, diff --git a/stratum/miner.go b/stratum/miner.go index 3d25522..983687c 100644 --- a/stratum/miner.go +++ b/stratum/miner.go @@ -161,8 +161,13 @@ func (m *Miner) processShare(s *StratumServer, cs *Session, job *Job, t *BlockTe return false } - hashDiff := util.GetHashDifficulty(hashBytes).Int64() // FIXME: Will return max int64 value if overflows - block := hashDiff >= t.difficulty + hashDiff, ok := util.GetHashDifficulty(hashBytes) // FIXME: Will return max int64 value if overflows + if !ok { + log.Printf("Bad hash from miner %v@%v", m.id, cs.ip) + atomic.AddInt64(&m.invalidShares, 1) + return false + } + block := hashDiff.Cmp(t.difficulty) >= 0 if block { _, err := r.SubmitBlock(hex.EncodeToString(shareBuff)) @@ -177,7 +182,7 @@ func (m *Miner) processShare(s *StratumServer, cs *Session, job *Job, t *BlockTe blockFastHash := hex.EncodeToString(hashing.FastHash(convertedBlob)) now := util.MakeTimestamp() roundShares := atomic.SwapInt64(&s.roundShares, 0) - ratio := float64(roundShares) / float64(t.difficulty) + ratio := float64(roundShares) / float64(t.diffInt64) s.blocksMu.Lock() s.blockStats[now] = blockEntry{height: t.height, hash: blockFastHash, variance: ratio} s.blocksMu.Unlock() @@ -189,7 +194,7 @@ func (m *Miner) processShare(s *StratumServer, cs *Session, job *Job, t *BlockTe // Immediately refresh current BT and send new jobs s.refreshBlockTemplate(true) } - } else if hashDiff < cs.endpoint.config.Difficulty { + } else if hashDiff.Cmp(cs.endpoint.difficulty) < 0 { log.Printf("Rejected low difficulty share of %v from %v@%v", hashDiff, m.id, cs.ip) atomic.AddInt64(&m.invalidShares, 1) return false diff --git a/stratum/stratum.go b/stratum/stratum.go index 670706e..b4958e9 100644 --- a/stratum/stratum.go +++ b/stratum/stratum.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "log" + "math/big" "net" "sync" "sync/atomic" @@ -42,6 +43,7 @@ type blockEntry struct { type Endpoint struct { config *pool.Port + difficulty *big.Int instanceId []byte extraNonce uint32 targetHex string @@ -132,6 +134,7 @@ func NewEndpoint(cfg *pool.Port) *Endpoint { log.Fatalf("Can't seed with random bytes: %v", err) } e.targetHex = util.GetTargetHex(e.config.Difficulty) + e.difficulty = big.NewInt(e.config.Difficulty) return e } diff --git a/util/util.go b/util/util.go index 775264a..b4bfdc5 100644 --- a/util/util.go +++ b/util/util.go @@ -31,10 +31,15 @@ func GetTargetHex(diff int64) string { return targetHex } -func GetHashDifficulty(hashBytes []byte) *big.Int { +func GetHashDifficulty(hashBytes []byte) (*big.Int, bool) { diff := new(big.Int) diff.SetBytes(reverse(hashBytes)) - return diff.Div(Diff1, diff) + + // Check for broken result, empty string or zero hex value + if diff.Cmp(new(big.Int)) == 0 { + return nil, false + } + return diff.Div(Diff1, diff), true } func ValidateAddress(addy string, poolAddy string) bool { diff --git a/util/util_test.go b/util/util_test.go index 07d4d45..c7cb2b4 100644 --- a/util/util_test.go +++ b/util/util_test.go @@ -2,7 +2,6 @@ package util import ( "encoding/hex" - "math/big" "testing" ) @@ -23,11 +22,19 @@ func TestGetTargetHex(t *testing.T) { func TestGetHashDifficulty(t *testing.T) { hash := "8e3c1865f22801dc3df0a688da80701e2390e7838e65c142604cc00eafe34000" hashBytes, _ := hex.DecodeString(hash) - diff := new(big.Int) - diff.SetBytes(reverse(hashBytes)) - shareDiff := GetHashDifficulty(hashBytes) + shareDiff, ok := GetHashDifficulty(hashBytes) - if shareDiff.String() != "1009" { + if !ok && shareDiff.String() != "1009" { t.Error("Invalid diff") } } + +func TestGetHashDifficultyWothBrokenHash(t *testing.T) { + hash := "" + hashBytes, _ := hex.DecodeString(hash) + shareDiff, ok := GetHashDifficulty(hashBytes) + + if ok || shareDiff != nil { + t.Error("Must be no result and not ok") + } +}