diff --git a/cnutil/cnutil.go b/cnutil/cnutil.go index 6326954..ae4e30e 100644 --- a/cnutil/cnutil.go +++ b/cnutil/cnutil.go @@ -5,7 +5,9 @@ package cnutil // #include // #include "src/cnutil.h" import "C" -import "unsafe" +import ( + "unsafe" +) func ConvertBlob(blob []byte) []byte { output := make([]byte, 76) @@ -18,25 +20,16 @@ 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) []byte { +func Hash(blob []byte, fast bool, height int) []byte { output := make([]byte, 32) if fast { C.cryptonight_fast_hash((*C.char)(unsafe.Pointer(&blob[0])), (*C.char)(unsafe.Pointer(&output[0])), (C.uint32_t)(len(blob))) } else { - C.cryptonight_hash((*C.char)(unsafe.Pointer(&blob[0])), (*C.char)(unsafe.Pointer(&output[0])), (C.uint32_t)(len(blob))) + C.cryptonight_hash((*C.char)(unsafe.Pointer(&blob[0])), (*C.char)(unsafe.Pointer(&output[0])), (C.uint32_t)(len(blob)), (C.int)(height)) } return output } func FastHash(blob []byte) []byte { - return Hash(append([]byte{byte(len(blob))}, blob...), true) + return Hash(append([]byte{byte(len(blob))}, blob...), true, 0) } diff --git a/cnutil/src/cnutil.cpp b/cnutil/src/cnutil.cpp index 462d2db..dc74dc0 100644 --- a/cnutil/src/cnutil.cpp +++ b/cnutil/src/cnutil.cpp @@ -18,10 +18,3 @@ 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); -} diff --git a/cnutil/src/cnutil.h b/cnutil/src/cnutil.h index fbe7033..3a11d57 100644 --- a/cnutil/src/cnutil.h +++ b/cnutil/src/cnutil.h @@ -6,9 +6,8 @@ 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); +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); #ifdef __cplusplus diff --git a/cnutil/src/main.cc b/cnutil/src/main.cc index 3879181..d3e5b1c 100644 --- a/cnutil/src/main.cc +++ b/cnutil/src/main.cc @@ -26,17 +26,9 @@ 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) { +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, 0); + crypto::cn_slow_hash(input, len, output, variant, 0, height); } extern "C" void cryptonight_fast_hash(const char* input, char* output, uint32_t len) { diff --git a/rpc/rpc.go b/rpc/rpc.go index ffffda3..d1716e0 100644 --- a/rpc/rpc.go +++ b/rpc/rpc.go @@ -47,6 +47,11 @@ type GetInfoReply struct { Status string `json:"status"` } +type ValidateAddressReply struct { + IsValid bool `json:"isvalid"` + IsMine bool `json:"ismine"` +} + type JSONRpcResp struct { Id *json.RawMessage `json:"id"` Result *json.RawMessage `json:"result"` @@ -97,6 +102,10 @@ func (r *RPCClient) SubmitBlock(hash string) (*JSONRpcResp, error) { return r.doPost(r.Url.String(), "submitblock", []string{hash}) } +func (r *RPCClient) ValidateAddress(addr string) (*JSONRpcResp, error) { + return r.doPost(r.Url.String(), "validateaddress", []string{addr}) +} + func (r *RPCClient) doPost(url, method string, params interface{}) (*JSONRpcResp, error) { jsonReq := map[string]interface{}{"jsonrpc": "2.0", "id": 0, "method": method, "params": params} data, _ := json.Marshal(jsonReq) diff --git a/stratum/handlers.go b/stratum/handlers.go index 7632fc5..97c934c 100644 --- a/stratum/handlers.go +++ b/stratum/handlers.go @@ -5,8 +5,6 @@ import ( "regexp" "strings" "sync/atomic" - - "../util" ) var noncePattern *regexp.Regexp @@ -18,11 +16,16 @@ func init() { } func (s *StratumServer) handleLoginRPC(cs *Session, params *LoginParams) (*JobReply, *ErrorReply) { - address, id := extractWorkerId(params.Login) - if !s.config.BypassAddressValidation && !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"} - } + + _, id := extractWorkerId(params.Login) + + /* + r := s.rpc() + if !s.config.BypassAddressValidation && !util.ValidateAddress(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"} + } + */ t := s.currentBlockTemplate() if t == nil { diff --git a/stratum/miner.go b/stratum/miner.go index ee188a7..214ca6d 100644 --- a/stratum/miner.go +++ b/stratum/miner.go @@ -68,7 +68,18 @@ func (cs *Session) getJob(t *BlockTemplate) *JobReplyData { } job.submissions = make(map[string]struct{}) cs.pushJob(job) - reply := &JobReplyData{JobId: job.id, Blob: blob, Target: cs.endpoint.targetHex} + majorVersion, err := strconv.ParseInt(blob[0:2], 16, 32) + if err != nil { + panic("Failed to get major version") + } + variant := majorVersion - 6 + reply := &JobReplyData{ + JobId: job.id, + Blob: blob, + Target: cs.endpoint.targetHex, + Height: t.height, + Variant: variant, + } return reply } @@ -151,7 +162,7 @@ func (m *Miner) processShare(s *StratumServer, cs *Session, job *Job, t *BlockTe hashBytes, _ = hex.DecodeString(result) } else { convertedBlob = cnutil.ConvertBlob(shareBuff) - hashBytes = cnutil.Hash(convertedBlob, false) + hashBytes = cnutil.Hash(convertedBlob, false, int(t.height)) } if !s.config.BypassShareValidation && hex.EncodeToString(hashBytes) != result { diff --git a/stratum/proto.go b/stratum/proto.go index 0be91c6..db2036d 100644 --- a/stratum/proto.go +++ b/stratum/proto.go @@ -45,9 +45,11 @@ type JobReply struct { } type JobReplyData struct { - Blob string `json:"blob"` - JobId string `json:"job_id"` - Target string `json:"target"` + Blob string `json:"blob"` + JobId string `json:"job_id"` + Target string `json:"target"` + Height int64 `json:"height"` + Variant int64 `json:"variant"` } type StatusReply struct { diff --git a/stratum/stratum.go b/stratum/stratum.go index 9e49de0..acb2dba 100644 --- a/stratum/stratum.go +++ b/stratum/stratum.go @@ -79,6 +79,11 @@ 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{}) diff --git a/util/util.go b/util/util.go index fc28939..11679ca 100644 --- a/util/util.go +++ b/util/util.go @@ -2,11 +2,11 @@ package util import ( "encoding/hex" + "encoding/json" "math/big" "time" - "unicode/utf8" - "../cnutil" + "../rpc" ) var Diff1 = StringToBig("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") @@ -42,16 +42,23 @@ func GetHashDifficulty(hashBytes []byte) (*big.Int, bool) { return diff.Div(Diff1, diff), true } -func ValidateAddress(addy string, poolAddy string) bool { - if len(addy) != len(poolAddy) { +func ValidateAddress(r *rpc.RPCClient, addr string, checkIsMine bool) bool { + rpcResp, err := r.ValidateAddress(addr) + if err != nil { return false } - prefix, _ := utf8.DecodeRuneInString(addy) - poolPrefix, _ := utf8.DecodeRuneInString(poolAddy) - if prefix != poolPrefix { - return false + var reply *rpc.ValidateAddressReply + if rpcResp.Result != nil { + err = json.Unmarshal(*rpcResp.Result, &reply) + if err != nil { + return false + } + if checkIsMine { + return reply.IsMine + } + return reply.IsValid } - return cnutil.ValidateAddress(addy) + return false } func reverse(src []byte) []byte {