migration of open-etc-friends-pool for use with Etica/EGAZ
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

136 lines
4.7 KiB

package proxy
import (
"errors"
"log"
"regexp"
"strings"
"github.com/yuriy0803/open-etc-pool-friends/rpc"
"github.com/yuriy0803/open-etc-pool-friends/util"
)
// Allow only lowercase hexadecimal with 0x prefix
var noncePattern = regexp.MustCompile("^0x[0-9a-f]{16}$")
var hashPattern = regexp.MustCompile("^0x[0-9a-f]{64}$")
var workerPattern = regexp.MustCompile("^[0-9a-zA-Z-_]{1,8}$")
// Stratum
func (s *ProxyServer) handleLoginRPC(cs *Session, params []string, id string) (bool, *ErrorReply) {
if len(params) == 0 {
return false, &ErrorReply{Code: -1, Message: "Invalid params"}
}
login := strings.ToLower(params[0])
login = strings.Split(login, ".")[0]
if !util.IsValidHexAddress(login) {
return false, &ErrorReply{Code: -1, Message: "Invalid login"}
}
if !s.policy.ApplyLoginPolicy(login, cs.ip) {
return false, &ErrorReply{Code: -1, Message: "You are blacklisted"}
}
//save for later, too broad right now, bans the ip the wallet comes from, (bad if more then one miner proxies there)
// if !s.policy.ApplyLoginWalletPolicy(login) {
// // check to see if this wallet login is blocked in json file
// return false, &ErrorReply{Code: -1, Message: "You are blacklisted"}
// }
cs.login = login
s.registerSession(cs)
log.Printf("Stratum miner connected %v@%v", login, cs.ip)
return true, nil
}
func (s *ProxyServer) handleGetWorkRPC(cs *Session) ([]string, *ErrorReply) {
t := s.currentBlockTemplate()
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
}
// Stratum
func (s *ProxyServer) handleTCPSubmitRPC(cs *Session, id string, params []string) (bool, *ErrorReply) {
s.sessionsMu.RLock()
_, ok := s.sessions[cs]
s.sessionsMu.RUnlock()
if !ok {
return false, &ErrorReply{Code: 25, Message: "Not subscribed"}
}
return s.handleSubmitRPC(cs, cs.login, id, params)
}
func (s *ProxyServer) handleSubmitRPC(cs *Session, login, id string, params []string) (bool, *ErrorReply) {
if !workerPattern.MatchString(id) {
id = "0"
}
if len(params) != 3 {
s.policy.ApplyMalformedPolicy(cs.ip)
log.Printf("Malformed params from %s@%s %v", login, cs.ip, params)
return false, &ErrorReply{Code: -1, Message: "Invalid params"}
}
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"}
}
go func(s *ProxyServer, cs *Session, login, id string, params []string) {
t := s.currentBlockTemplate()
//MFO: This function (s.processShare) will process a share as per hasher.Verify function of github.com/ethereum/ethash
// output of this function is either:
// true,true (Exists) which means share already exists and it is validShare
// true,false (Exists & invalid)which means share already exists and it is invalidShare or it is a block <-- should not ever happen
// false,false (stale/invalid)which means share is new, and it is not a block, might be a stale share or invalidShare
// false,true (valid)which means share is new, and it is a block or accepted share
// false,false,false (blacklisted wallet attached to share) see json file
// When this function finishes, the results is already recorded in the db for valid shares or blocks.
exist, validShare := s.processShare(login, id, cs.ip, t, params)
ok := s.policy.ApplySharePolicy(cs.ip, !exist && validShare)
// if true,true or true,false
if exist {
log.Printf("Duplicate share from %s@%s %v", login, cs.ip, params)
cs.lastErr = errors.New("Duplicate share")
}
// if false, false
if !validShare {
//MFO: Here we have an invalid share
log.Printf("Invalid share from %s@%s", login, cs.ip)
// Bad shares limit reached, return error and close
if !ok {
cs.lastErr = errors.New("Invalid share")
}
}
//MFO: Here we have a valid share and it is already recorded in DB by miner.go
// if false, true
if s.config.Proxy.Debug {
log.Printf("Valid share from %s@%s", login, cs.ip)
}
if !ok {
cs.lastErr = errors.New("High rate of invalid shares")
}
}(s, cs, login, id, params)
return true, nil
}
func (s *ProxyServer) handleGetBlockByNumberRPC() *rpc.GetBlockReplyPart {
t := s.currentBlockTemplate()
var reply *rpc.GetBlockReplyPart
if t != nil {
reply = t.GetPendingBlockCache
}
return reply
}
func (s *ProxyServer) handleUnknownRPC(cs *Session, m string) *ErrorReply {
log.Printf("Unknown request method %s from %s", m, cs.ip)
s.policy.ApplyMalformedPolicy(cs.ip)
return &ErrorReply{Code: -3, Message: "Method not found"}
}