From 95c758018ad69b09622939c3a998dc8c9ce5ea9e Mon Sep 17 00:00:00 2001 From: Jianping Wu Date: Thu, 21 Mar 2019 19:22:58 -0700 Subject: [PATCH] Displayed error message other than 500 internal error. --- cnutil/cnutil.go | 9 ++++++ cnutil/src/cnutil.cpp | 7 +++++ cnutil/src/cnutil.h | 1 + cnutil/src/main.cc | 7 +++++ config_keva.json | 65 +++++++++++++++++++++++++++++++++++++++++++ config_monero.json | 65 +++++++++++++++++++++++++++++++++++++++++++ pool/pool.go | 1 + rpc/rpc.go | 8 ++++-- stratum/handlers.go | 16 +++++++---- stratum/stratum.go | 20 +++++++++---- util/util.go | 16 ++++++++++- 11 files changed, 201 insertions(+), 14 deletions(-) create mode 100644 config_keva.json create mode 100644 config_monero.json diff --git a/cnutil/cnutil.go b/cnutil/cnutil.go index ae4e30e..3a22cd6 100644 --- a/cnutil/cnutil.go +++ b/cnutil/cnutil.go @@ -20,6 +20,15 @@ func ConvertBlob(blob []byte) []byte { return output } +func ValidateAddress(addr string) bool { + input := C.CString(addr) + defer C.free(unsafe.Pointer(input)) + + size := (C.uint32_t)(len(addr)) + result := C.validate_address(input, size) + return (bool)(result) +} + func Hash(blob []byte, fast bool, height int) []byte { output := make([]byte, 32) if fast { diff --git a/cnutil/src/cnutil.cpp b/cnutil/src/cnutil.cpp index dc74dc0..869d60d 100644 --- a/cnutil/src/cnutil.cpp +++ b/cnutil/src/cnutil.cpp @@ -18,3 +18,10 @@ extern "C" uint32_t convert_blob(const char *blob, size_t len, char *out) { output.copy(out, output.length(), 0); return output.length(); } + +extern "C" bool validate_address(const char *addr, size_t len) { + std::string input = std::string(addr, len); + std::string output = ""; + uint64_t prefix; + return tools::base58::decode_addr(addr, prefix, output); +} \ No newline at end of file diff --git a/cnutil/src/cnutil.h b/cnutil/src/cnutil.h index 3a11d57..6433ec2 100644 --- a/cnutil/src/cnutil.h +++ b/cnutil/src/cnutil.h @@ -6,6 +6,7 @@ extern "C" { #endif uint32_t convert_blob(const char *blob, uint32_t len, char *out); +bool validate_address(const char *addr, uint32_t len); void cryptonight_hash(const char* input, char* output, uint32_t len, int height); void cryptonight_fast_hash(const char* input, char* output, uint32_t len); diff --git a/cnutil/src/main.cc b/cnutil/src/main.cc index d3e5b1c..a94dd65 100644 --- a/cnutil/src/main.cc +++ b/cnutil/src/main.cc @@ -26,6 +26,13 @@ extern "C" uint32_t convert_blob(const char *blob, size_t len, char *out) { return output.length(); } +extern "C" bool validate_address(const char *addr, size_t len) { + std::string input = std::string(addr, len); + std::string output = ""; + uint64_t prefix; + return tools::base58::decode_addr(addr, prefix, output); +} + extern "C" void cryptonight_hash(const char* input, char* output, uint32_t len, int height) { const int variant = input[0] >= 7 ? input[0] - 6 : 0; crypto::cn_slow_hash(input, len, output, variant, 0, height); diff --git a/config_keva.json b/config_keva.json new file mode 100644 index 0000000..45a884a --- /dev/null +++ b/config_keva.json @@ -0,0 +1,65 @@ +{ + "isKeva": true, + "address": "TKj7HMzeLAxd5DSoo35XuCfNH2yWC9y2Xb", + "bypassAddressValidation": false, + "bypassShareValidation": false, + + "threads": 1, + + "estimationWindow": "15m", + "luckWindow": "24h", + "largeLuckWindow": "72h", + + "blockRefreshInterval": "1s", + + "stratum": { + "timeout": "15m", + + "listen": [ + { + "host": "0.0.0.0", + "port": 1111, + "diff": 8000, + "maxConn": 32768 + }, + { + "host": "0.0.0.0", + "port": 3333, + "diff": 16000, + "maxConn": 32768 + }, + { + "host": "0.0.0.0", + "port": 5555, + "diff": 16000, + "maxConn": 32768 + } + ] + }, + + "frontend": { + "enabled": true, + "listen": "0.0.0.0:8082", + "login": "admin", + "password": "", + "hideIP": false + }, + + "upstreamCheckInterval": "5s", + + "upstream": [ + { + "name": "Test", + "host": "127.0.0.1", + "port": 19332, + "timeout": "300s", + "user": "yourusername", + "password": "yourpassword" + } + ], + + "newrelicEnabled": false, + "newrelicName": "MyStratum", + "newrelicKey": "SECRET_KEY", + "newrelicVerbose": false +} diff --git a/config_monero.json b/config_monero.json new file mode 100644 index 0000000..2a12e9d --- /dev/null +++ b/config_monero.json @@ -0,0 +1,65 @@ +{ + "isKeva": false, + "address": "47v4BWeUPFrM9YkYRYk2pkS9CubAPEc7BJjNjg4FvF66Y2oVrTAaBjDZhmFzAXgqCNRvBH2gupQ2gNag2FkP983ZMptvUWG", + "bypassAddressValidation": false, + "bypassShareValidation": false, + + "threads": 1, + + "estimationWindow": "15m", + "luckWindow": "24h", + "largeLuckWindow": "72h", + + "blockRefreshInterval": "1s", + + "stratum": { + "timeout": "15m", + + "listen": [ + { + "host": "0.0.0.0", + "port": 1111, + "diff": 8000, + "maxConn": 32768 + }, + { + "host": "0.0.0.0", + "port": 3333, + "diff": 16000, + "maxConn": 32768 + }, + { + "host": "0.0.0.0", + "port": 5555, + "diff": 16000, + "maxConn": 32768 + } + ] + }, + + "frontend": { + "enabled": true, + "listen": "0.0.0.0:8082", + "login": "admin", + "password": "", + "hideIP": false + }, + + "upstreamCheckInterval": "5s", + + "upstream": [ + { + "name": "Test", + "host": "127.0.0.1", + "port": 18081, + "timeout": "300s", + "user": "yourusername", + "password": "yourpassword" + } + ], + + "newrelicEnabled": false, + "newrelicName": "MyStratum", + "newrelicKey": "SECRET_KEY", + "newrelicVerbose": false +} diff --git a/pool/pool.go b/pool/pool.go index 108106a..a76200d 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -1,6 +1,7 @@ package pool type Config struct { + IsKeva bool `json:"isKeva"` Address string `json:"address"` BypassAddressValidation bool `json:"bypassAddressValidation"` BypassShareValidation bool `json:"bypassShareValidation"` diff --git a/rpc/rpc.go b/rpc/rpc.go index d1716e0..7aa7e70 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -121,9 +121,11 @@ func (r *RPCClient) doPost(url, method string, params interface{}) (*JSONRpcResp } defer resp.Body.Close() - if resp.StatusCode < 200 || resp.StatusCode >= 400 { - return nil, errors.New(resp.Status) - } + /* + if resp.StatusCode < 200 || resp.StatusCode >= 400 { + return nil, errors.New(resp.Status) + } + */ var rpcResp *JSONRpcResp err = json.NewDecoder(resp.Body).Decode(&rpcResp) diff --git a/stratum/handlers.go b/stratum/handlers.go index 97c934c..3d6ec63 100644 --- a/stratum/handlers.go +++ b/stratum/handlers.go @@ -5,6 +5,8 @@ import ( "regexp" "strings" "sync/atomic" + + "../util" ) var noncePattern *regexp.Regexp @@ -17,15 +19,19 @@ func init() { func (s *StratumServer) handleLoginRPC(cs *Session, params *LoginParams) (*JobReply, *ErrorReply) { - _, id := extractWorkerId(params.Login) + address, id := extractWorkerId(params.Login) - /* - r := s.rpc() - if !s.config.BypassAddressValidation && !util.ValidateAddress(r, address, false) { + r := s.rpc() + if !s.config.BypassAddressValidation { + if s.config.IsKeva && !util.ValidateAddress_Keva(r, address, false) { log.Printf("Invalid address %s used for login by %s", address, cs.ip) return nil, &ErrorReply{Code: -1, Message: "Invalid address used for login"} } - */ + if !s.config.IsKeva && !util.ValidateAddress(address, s.config.Address) { + log.Printf("Invalid address %s used for login by %s", address, cs.ip) + return nil, &ErrorReply{Code: -1, Message: "Invalid address used for login"} + } + } t := s.currentBlockTemplate() if t == nil { diff --git a/stratum/stratum.go b/stratum/stratum.go index acb2dba..bf01c69 100644 --- a/stratum/stratum.go +++ b/stratum/stratum.go @@ -13,6 +13,7 @@ import ( "sync/atomic" "time" + "../cnutil" "../pool" "../rpc" "../util" @@ -79,11 +80,6 @@ func NewStratum(cfg *pool.Config) *StratumServer { } log.Printf("Default upstream: %s => %s", stratum.rpc().Name, stratum.rpc().Url) - r := stratum.rpc() - if !cfg.BypassAddressValidation && !util.ValidateAddress(r, cfg.Address, true) { - log.Fatal(cfg.Address + " is either not a valid address or not owned by upstream server") - } - stratum.miners = NewMinersMap() stratum.sessions = make(map[*Session]struct{}) @@ -132,6 +128,7 @@ func NewStratum(cfg *pool.Config) *StratumServer { }() go func() { + var addressedCheck = false for { select { case <-infoTimer.C: @@ -140,6 +137,19 @@ func NewStratum(cfg *pool.Config) *StratumServer { if err != nil { log.Printf("Unable to update info on upstream %s: %v", v.Name, err) } + + if err == nil && !addressedCheck { + addressedCheck = true + r := stratum.rpc() + if !cfg.BypassAddressValidation { + if cfg.IsKeva && !util.ValidateAddress_Keva(r, cfg.Address, true) { + log.Fatal(cfg.Address + " is either not a valid address or not owned by upstream server") + } + if !cfg.IsKeva && !cnutil.ValidateAddress(cfg.Address) { + log.Fatal(cfg.Address + " is not a valid address") + } + } + } } current := stratum.rpc() poll(current) diff --git a/util/util.go b/util/util.go index 11679ca..1f9938b 100644 --- a/util/util.go +++ b/util/util.go @@ -5,7 +5,9 @@ import ( "encoding/json" "math/big" "time" + "unicode/utf8" + "../cnutil" "../rpc" ) @@ -42,7 +44,7 @@ func GetHashDifficulty(hashBytes []byte) (*big.Int, bool) { return diff.Div(Diff1, diff), true } -func ValidateAddress(r *rpc.RPCClient, addr string, checkIsMine bool) bool { +func ValidateAddress_Keva(r *rpc.RPCClient, addr string, checkIsMine bool) bool { rpcResp, err := r.ValidateAddress(addr) if err != nil { return false @@ -61,6 +63,18 @@ func ValidateAddress(r *rpc.RPCClient, addr string, checkIsMine bool) bool { return false } +func ValidateAddress(addy string, poolAddy string) bool { + if len(addy) != len(poolAddy) { + return false + } + prefix, _ := utf8.DecodeRuneInString(addy) + poolPrefix, _ := utf8.DecodeRuneInString(poolAddy) + if prefix != poolPrefix { + return false + } + return cnutil.ValidateAddress(addy) +} + func reverse(src []byte) []byte { dst := make([]byte, len(src)) for i := len(src); i > 0; i-- {