Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unified nicehash+eth-proxy #417

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"hashrateExpiration": "3h",

"healthCheck": true,
"debug": false,
"maxFails": 100,

"stratum": {
Expand Down
1 change: 1 addition & 0 deletions proxy/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Proxy struct {

MaxFails int64 `json:"maxFails"`
HealthCheck bool `json:"healthCheck"`
Debug bool `json:"debug"`

Stratum Stratum `json:"stratum"`
}
Expand Down
23 changes: 19 additions & 4 deletions proxy/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (s *ProxyServer) handleGetWorkRPC(cs *Session) ([]string, *ErrorReply) {
if t == nil || len(t.Header) == 0 || s.isSick() {
return nil, &ErrorReply{Code: 0, Message: "Work not ready"}
}
return []string{t.Header, t.Seed, s.diff}, nil
return []string{t.Header, t.Seed, s.diff, util.ToHex(int64(t.Height))}, nil
}

// Stratum
Expand All @@ -63,18 +63,31 @@ func (s *ProxyServer) handleSubmitRPC(cs *Session, login, id string, params []st
return false, &ErrorReply{Code: -1, Message: "Invalid params"}
}

stratumMode := cs.stratumMode()
if stratumMode == NiceHash {
for i := 0; i <= 2; i++ {
if params[i][0:2] != "0x" {
params[i] = "0x" + params[i]
}
}
}

if !noncePattern.MatchString(params[0]) || !hashPattern.MatchString(params[1]) || !hashPattern.MatchString(params[2]) {
s.policy.ApplyMalformedPolicy(cs.ip)
log.Printf("Malformed PoW result from %s@%s %v", login, cs.ip, params)
return false, &ErrorReply{Code: -1, Message: "Malformed PoW result"}
}
t := s.currentBlockTemplate()
exist, validShare := s.processShare(login, id, cs.ip, t, params)
exist, validShare := s.processShare(login, id, cs.ip, t, params, stratumMode != EthProxy)
ok := s.policy.ApplySharePolicy(cs.ip, !exist && validShare)

if exist {
log.Printf("Duplicate share from %s@%s %v", login, cs.ip, params)
return false, &ErrorReply{Code: 22, Message: "Duplicate share"}
// see https://github.com/sammy007/open-ethereum-pool/compare/master...nicehashdev:patch-1
if !ok {
return false, &ErrorReply{Code: 23, Message: "Invalid share"}
}
return false, nil
}

if !validShare {
Expand All @@ -85,7 +98,9 @@ func (s *ProxyServer) handleSubmitRPC(cs *Session, login, id string, params []st
}
return false, nil
}
log.Printf("Valid share from %s@%s", login, cs.ip)
if s.config.Proxy.Debug {
log.Printf("Valid share from %s@%s", login, cs.ip)
}

if !ok {
return true, &ErrorReply{Code: -1, Message: "High rate of invalid shares"}
Expand Down
64 changes: 46 additions & 18 deletions proxy/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,74 @@ import (
"strconv"
"strings"

"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common"
"github.com/hackmod/ethereum-ethash"

"github.com/sammy007/open-ethereum-pool/util"
)

var hasher = ethash.New()

func (s *ProxyServer) processShare(login, id, ip string, t *BlockTemplate, params []string) (bool, bool) {
var (
maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
)

func (s *ProxyServer) processShare(login, id, ip string, t *BlockTemplate, params []string, stratum bool) (bool, bool) {
nonceHex := params[0]
hashNoNonce := params[1]
mixDigest := params[2]
nonce, _ := strconv.ParseUint(strings.Replace(nonceHex, "0x", "", -1), 16, 64)
shareDiff := s.config.Proxy.Difficulty

var result common.Hash
if stratum {
hashNoNonceTmp := common.HexToHash(params[2])

_, mixDigestTmp, hashTmp := hasher.Compute(t.Height, hashNoNonceTmp, nonce)
params[1] = hashNoNonceTmp.Hex()
params[2] = mixDigestTmp.Hex()
hashNoNonce = params[1]
result = hashTmp
} else {
hashNoNonceTmp := common.HexToHash(hashNoNonce)
_, mixDigestTmp, hashTmp := hasher.Compute(t.Height, hashNoNonceTmp, nonce)

// check mixDigest
if (mixDigestTmp.Hex() != mixDigest) {
return false, false
}
result = hashTmp
}

// Block "difficulty" is BigInt
// NiceHash "difficulty" is float64 ...
// diffFloat => target; then: diffInt = 2^256 / target
shareDiffCalc := util.TargetHexToDiff(result.Hex()).Int64()
shareDiffFloat := util.DiffIntToFloat(shareDiffCalc)
if shareDiffFloat < 0.0001 {
log.Printf("share difficulty too low, %f < %d, from %v@%v", shareDiffFloat, t.Difficulty, login, ip)
return false, false
}

h, ok := t.headers[hashNoNonce]
if !ok {
log.Printf("Stale share from %v@%v", login, ip)
return false, false
}

share := Block{
number: h.height,
hashNoNonce: common.HexToHash(hashNoNonce),
difficulty: big.NewInt(shareDiff),
nonce: nonce,
mixDigest: common.HexToHash(mixDigest),
}

block := Block{
number: h.height,
hashNoNonce: common.HexToHash(hashNoNonce),
difficulty: h.diff,
nonce: nonce,
mixDigest: common.HexToHash(mixDigest),
if s.config.Proxy.Debug {
log.Printf("Difficulty pool/block/share = %d / %d / %d(%f) from %v@%v", shareDiff, t.Difficulty, shareDiffCalc, shareDiffFloat, login, ip)
}

if !hasher.Verify(share) {
// check share difficulty
shareTarget := new(big.Int).Div(maxUint256, big.NewInt(shareDiff))
if (result.Big().Cmp(shareTarget) > 0) {
return false, false
}

if hasher.Verify(block) {
// check target difficulty
target := new(big.Int).Div(maxUint256, big.NewInt(h.diff.Int64()))
if result.Big().Cmp(target) <= 0 {
ok, err := s.rpc().SubmitBlock(params)
if err != nil {
log.Printf("Block submission failure at height %v for %v: %v", h.height, t.Header, err)
Expand Down
10 changes: 8 additions & 2 deletions proxy/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ type JSONRpcReq struct {
Params json.RawMessage `json:"params"`
}

type JSONStratumReq struct {
Method string `json:"method"`
Params interface{} `json:"params"`
Id interface{} `json:"id"`
}

type StratumReq struct {
JSONRpcReq
Worker string `json:"worker"`
Expand All @@ -23,9 +29,9 @@ type JSONPushMessage struct {

type JSONRpcResp struct {
Id json.RawMessage `json:"id"`
Version string `json:"jsonrpc"`
Version string `json:"jsonrpc,omitempty"`
Result interface{} `json:"result"`
Error interface{} `json:"error,omitempty"`
Error interface{} `json:"error"`
}

type SubmitReply struct {
Expand Down
23 changes: 23 additions & 0 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ type ProxyServer struct {
sessionsMu sync.RWMutex
sessions map[*Session]struct{}
timeout time.Duration
// Extranonce
Extranonces map[string]bool
}

type jobDetails struct {
JobID string
SeedHash string
HeaderHash string
Height string
}

type staleJob struct {
SeedHash string
HeaderHash string
}

type Session struct {
Expand All @@ -44,6 +58,14 @@ type Session struct {
sync.Mutex
conn net.Conn
login string

stratum int
subscriptionID string
Extranonce string
ExtranonceSub bool
JobDetails jobDetails
staleJobs map[string]staleJob
staleJobIDs []string
}

func NewProxy(cfg *Config, backend *storage.RedisClient) *ProxyServer {
Expand All @@ -64,6 +86,7 @@ func NewProxy(cfg *Config, backend *storage.RedisClient) *ProxyServer {

if cfg.Proxy.Stratum.Enabled {
proxy.sessions = make(map[*Session]struct{})
proxy.Extranonces = make(map[string]bool)
go proxy.ListenTCP()
}

Expand Down
Loading