// nexa.go package nexa import ( //"database/sql" "encoding/binary" "encoding/hex" "encoding/json" //"log" //"math" "math/big" "strings" "fmt" "pool/internal/msg" "pool/internal/server/coin" "pool/internal/server/dbif" "pool/internal/stratum" "pool/internal/utility" "time" _ "github.com/mattn/go-sqlite3" "go.uber.org/zap" ) const SERVER_NEXA_VERSION string = "nexa v2.0i" type NexaBlockHeader struct { Header [32]byte Nonce [16]byte } func NexaBlockHeaderToBytes(h NexaBlockHeader) []byte { out := make([]byte, 49) for i := 0; i < 32; i++ { out[i] = h.Header[i] } out[32] = 0x10 for i := 0; i < 16; i++ { out[33+i] = h.Nonce[i] } return out } type NexaBlockHeader12 struct { Header [32]byte Nonce [12]byte } func NexaBlockHeaderToBytes12(h NexaBlockHeader12) []byte { out := make([]byte, 45) for i := 0; i < 32; i++ { out[i] = h.Header[i] } out[32] = 0x0c for i := 0; i < 12; i++ { out[33+i] = h.Nonce[i] } return out } type ServerNexaContext struct { ServerCtx *coin.ServerContext logg *zap.Logger NexaJob msg.NexaStratumJob } var logg *zap.Logger var ServerNexaCtx ServerNexaContext type Notify_msg_nexa struct { ID interface{} `json:"id"` Method string `json:"method"` Params [5]interface{} `json:"params"` } type Notify_msg_nexa_gpu struct { Jsonrpc string `json:"jsonrpc"` ID interface{} `json:"id"` Method string `json:"method"` Params [4]interface{} `json:"params"` } func handle_submit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) { var submit_item coin.BlockMsg /*var user_blk_item coin.UserBlockMsg*/ var pool_blk_item coin.PoolBlkMsg var blk_detail_height int64 var blk_detail_hash string var blk_detail_success bool var blk_detail_miner_diff float64 var blk_detail_pool_diff float64 if miner.Authorized != true { miner.ErrOthers = miner.ErrOthers + 1 stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNAUTH_WORKER) stratum.Send_reconnect_msg(miner) return false, false, false } var new_found bool = false var ack stratum.Submit_ack ack.ID = id ack.Result = true //logg.Warn("[server]", zap.String("user", miner.User), zap.String("miner", miner.Miner)) //logg.Debug("[server]", zap.Float64("id", id), zap.String("job_id", job_id)) //logg.Debug("[server]", zap.String("nonce2", nonce2), zap.String("ntime", ntime), zap.String("nonce", nonce)) //stratum.UpdateJobs(miner) v, ok := miner.Jobs.Load(job_id) if ok { job := v.(msg.NexaStratumJob) if job.Height < miner.CurHeight-1 { ack.Result = false stratum.Handle_exception(miner, id, stratum.MINER_ERR_STALED_JOB) miner.ErrStaleds = miner.ErrStaleds + 1 return false, false, false } //logg.Debug("[server]", zap.Uint64("ntime", nt), zap.Uint64("mintime", uint64(job.Mintime)), zap.Uint64("jobtime", jt_reverse)) /*if nt < uint64(job.Mintime) { ack.Result = false util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_OLD) } else if nt > jt_reverse+uint64(600) { ack.Result = false util.Handle_exception(miner, id, util.MINER_ERR_TIME_TOO_NEW) } else */{ if (miner.LastNonce != nonce) || (miner.LastHeader != job.Header) { miner.LastHeader = job.Header miner.LastNonce = nonce job.Nonce = nonce job.Extranonce2 = nonce2 logg.Debug("[server]", zap.Uint32("height", job.Height), zap.String("target", job.Target)) phb, _ := hex.DecodeString(job.Header) // 区块头 []byte nb, _ := hex.DecodeString(nonce) // nonce []byte var calc_hash []byte if miner.Protocol == "yxminer" { var header NexaBlockHeader for i := 0; i < 32; i++ { header.Header[i] = phb[i] } for i := 0; i < 16; i++ { header.Nonce[i] = nb[i] } submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes(header)) calc_hash = BuildPowHash(header) } else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" { var header NexaBlockHeader12 for i := 0; i < 32; i++ { header.Header[i] = phb[i] } for i := 0; i < 12; i++ { header.Nonce[i] = nb[i] } submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes12(header)) calc_hash = BuildPowHash12(header) } else { var header NexaBlockHeader for i := 0; i < 32; i++ { header.Header[i] = phb[i] } for i := 0; i < 16; i++ { header.Nonce[i] = nb[i] } submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes(header)) calc_hash = BuildPowHash(header) } logg.Debug("[server]", zap.String("hash in", submit_item.Header)) //calc_hash, header := util.BuildBlockHash(&(job), true, Build_PowHash) logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/) submit_target := new(big.Int) //submit_target.SetBytes(common.Reverse(calc_hash)) //hashs, _ := utility.ReverseS(hex.EncodeToString(calc_hash)) //hashb, _ := hex.DecodeString(hashs) //submit_target.SetBytes(hashb) submit_target.SetBytes(calc_hash) /*logg.Debug("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.Target.Bytes()))) if submit_target.Cmp(miner.Target) > 0 {*/ //calc_diff := Target2Diff(common.Reverse(calc_hash)) calc_diff := utility.Target2Diff(calc_hash) //log.Printf("diff,calc_diff:%f difficulty:%f ", calc_diff, miner.Difficulty) logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff)) //logg.Debug("[server]", zap.String("target", miner.Target.String()), zap.Any("bytes", miner.Target.Bytes())) //logg.Info("[server]", zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff), zap.String("target", hex.EncodeToString(miner.Target.Bytes()))) //if calc_diff < miner.Difficulty { if calc_diff < job.JobDifficulty { //gpu protocol handler /*for i := 0; i < 8; i++ { temp_nonce := header.Nonce[8+i] header.Nonce[8+i] = header.Nonce[i] header.Nonce[i] = temp_nonce } submit_item.Header = hex.EncodeToString(NexaBlockHeaderToBytes(header)) calc_hash = BuildPowHash(header) logg.Debug("[server]", zap.String("hash in", hex.EncodeToString(NexaBlockHeaderToBytes(header))))*/ //logg.Debug("[server]", zap.String("calc_hash", hex.EncodeToString(calc_hash)) /*, zap.String("merkle root", hex.EncodeToString(merkle_root))*/) //submit_target = new(big.Int) /*submit_target.SetBytes(calc_hash) calc_diff = utility.Target2Diff(calc_hash) logg.Warn("[server]", zap.String("user", miner.User+"."+miner.Miner), zap.Float64("target diff", miner.Difficulty), zap.Float64("submit diff", calc_diff)) if calc_diff < miner.Difficulty { */ ack.Result = false miner.ErrLowDiffs = miner.ErrLowDiffs + 1 stratum.Handle_exception(miner, id, stratum.MINER_ERR_LOW_DIF_SHARE) return false, false, false //} } //logg.Warn("[server]", zap.String("pow", hex.EncodeToString(submit_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes()))) //submit_target.Text(16) /*if submit_target.Cmp(miner.ServerTarget) <= 0 {*/ //log.Println("[server]server_target", miner.ServerTargetS) //stb, _ := hex.DecodeString(miner.ServerTargetS) stb, _ := hex.DecodeString(job.Target) //logg.Info("[server]", zap.String("target", job.Target)) //server_diff := Target2Diff(common.Reverse(stb)) server_diff := utility.Target2Diff(utility.Reverse(stb)) //log.Printf("[server]server_diff %f", server_diff) //logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff)) //logg.Debug("[server]", zap.String("ServerTargetS", miner.ServerTargetS)) network_target := new(big.Int) network_target.SetBytes(stb) logg.Info("[server]", zap.Float64("calc_diff", calc_diff), zap.Float64("miner.Difficulty", miner.Difficulty), zap.Float64("server_diff", server_diff)) logg.Debug("[server]", zap.String("submit_target", hex.EncodeToString(submit_target.Bytes())), zap.String("network_target", hex.EncodeToString(network_target.Bytes())), zap.String("target", hex.EncodeToString(miner.ServerTarget.Bytes())), zap.Int("cmp", network_target.Cmp(submit_target))) submit_item.Hash = hex.EncodeToString(calc_hash) submit_item.Target = hex.EncodeToString(miner.Target.Bytes()) submit_item.Submit_target = hex.EncodeToString(calc_hash) submit_item.Height = int64(job.Height) submit_item.Pow = hex.EncodeToString(calc_hash) submit_item.Net_target = hex.EncodeToString(network_target.Bytes()) /*user_blk_item.Height = int64(job.Height) user_blk_item.Hash = hex.EncodeToString(calc_hash) user_blk_item.Pow = hex.EncodeToString(calc_hash) user_blk_item.Net_target = hex.EncodeToString(network_target.Bytes())*/ pool_blk_item.Height = int64(job.Height) pool_blk_item.Hash = hex.EncodeToString(calc_hash) pool_blk_item.Pow = hex.EncodeToString(calc_hash) pool_blk_item.Net_target = hex.EncodeToString(network_target.Bytes()) blk_detail_height = int64(job.Height) blk_detail_hash = hex.EncodeToString(calc_hash) blk_detail_success = false blk_detail_miner_diff = miner.Difficulty blk_detail_pool_diff = miner.Server.RefDifficulty if ack.Result == true { /*if miner.CurHeight != 0 && miner.CurHeight == job.Height { return }*/ //if true { if (calc_diff >= server_diff) || (network_target.Cmp(submit_target) >= 0) { miner.Server.SubIdx++ Produce_block_submit(miner /*header,*/, &job, submit_item.Hash, miner.Server.SubIdx) miner.SubmitIndex++ miner.Submits = miner.Submits + 1 //miner.CurHeight = job.Height new_found = true } } } else { miner.LastHeader = job.Header miner.LastNonce = nonce ack.Result = false stratum.Handle_exception(miner, id, stratum.MINER_ERR_DUP_SHARE) miner.ErrDuplicates = miner.ErrDuplicates + 1 return false, false, false } } } else { ack.Result = false stratum.Handle_exception(miner, id, stratum.MINER_ERR_NOT_FOUND_JOB) miner.ErrStaleds = miner.ErrStaleds + 1 return false, false, false } miner.LastJobId = job_id ack.Error = nil body, err := json.Marshal(ack) if err != nil { logg.Error("[server]", zap.String("Marshal", err.Error())) miner.ErrOthers = miner.ErrOthers + 1 stratum.Handle_exception(miner, id, stratum.MINER_ERR_UNKNOWN) return false, false, false } var body_string = string(body) + "\n" err = stratum.Conn_tx(miner.Conn, []byte(body_string)) if err != nil { //miner.Server.Miners.Delete(miner.MinerId) } if miner.ZlogInit { miner.Zlog.Info().Msg(body_string) } logg.Debug("[server]", zap.String("tx", body_string)) miner.TxLock.Lock() miner.Status = coin.MINER_STATUS_RUNNING miner.TxLock.Unlock() if ack.Result { miner.Accepts += miner.Difficulty miner.M5Accepts += miner.Difficulty miner.VarDiffOpt.SubmitShares += miner.Difficulty } else { miner.Rejects += miner.Difficulty } now := time.Now() if miner.Server.Config.Diff.Filter == "kalman" { if ack.Result { share_interval := now.Sub(miner.LastSubmitime).Seconds() mhs := miner.Difficulty * share_interval diff_next, kalman_p := miner.DiffHandler.Handler(miner.Difficulty, share_interval) mhs_est := diff_next * miner.Server.Config.Diff.DiffAdjustInterval ratio := diff_next / miner.Difficulty if ratio > 0 { if now.Sub(miner.StartSubmitTime).Seconds() > 180 { if ratio >= 2 { //miner.DifficultyNext = math.Ceil(diff_next*100) / 100 miner.DifficultyNext = diff_next * 10000000 / 10000000 } else if ratio <= 0.5 { //miner.DifficultyNext = math.Ceil(diff_next*100) / 100 miner.DifficultyNext = diff_next * 10000000 / 10000000 } else { } } else { //miner.DifficultyNext = math.Ceil(diff_next*100) / 100 miner.DifficultyNext = diff_next * 10000000 / 10000000 /*if ratio >= 1.1 { miner.DifficultyNext = math.Ceil(diff_next*100) / 100 } else if ratio <= 0.8 { miner.DifficultyNext = math.Ceil(diff_next*100) / 100 } else { }*/ } } if miner.DifficultyNext > 0.0 { if miner.DifficultyNext < miner.VarDiffOpt.MinDiff { miner.DifficultyNext = miner.VarDiffOpt.MinDiff } else if miner.DifficultyNext > miner.VarDiffOpt.MaxDiff { miner.DifficultyNext = miner.VarDiffOpt.MaxDiff } } //miner.VarDiffOpt.LastCalcTime = now if miner.Server.Config.Diff.Dbg { coin.New_diff_into_db(miner.User, miner.Miner, fmt.Sprint(miner.MinerIndex), miner.Difficulty, diff_next, kalman_p, share_interval, mhs, mhs_est) } //log.Println("diff adjust", ratio, diff_next, miner.Difficulty, miner.DifficultyNext) } } else { // submit time < DiffAdjustInterval,then up adjust diff if now.Sub(miner.LastSubmitime).Seconds() < miner.Server.Config.Diff.DiffAdjustInterval { if ack.Result { if miner.VarDiffOpt.Uptimes++; miner.VarDiffOpt.Uptimes >= coin.DIFFICULTY_WAIT_TIMES { coin.VarAdjustDifficulty(miner, coin.UP_DIFF) miner.VarDiffOpt.LastCalcTime = now } } } else { miner.VarDiffOpt.Uptimes = 0 } // submit time > 2 * DiffAdjustInterval,then down adjust diff if now.Sub(miner.LastSubmitime).Seconds() > miner.Server.Config.Diff.DiffAdjustInterval*2 { if ack.Result { if miner.VarDiffOpt.Downtimes++; miner.VarDiffOpt.Downtimes >= coin.DIFFICULTY_WAIT_TIMES { coin.VarAdjustDifficulty(miner, coin.DOWN_DIFF) miner.VarDiffOpt.LastCalcTime = now } } } else { miner.VarDiffOpt.Downtimes = 0 } } if ack.Result { miner.LastSubmitime = now miner.VarDiffOpt.LastSubmitTime = now } var duration float64 = float64(now.Sub(miner.StartSubmitTime)) / 1000000000 if duration < 1 { duration = 1 } diffOneShareHashesAvg := uint64(0x00000000FFFFFFFF) miner.AverageHashrate = miner.Accepts * float64(diffOneShareHashesAvg) / duration / 1000000 var m5_duration float64 = float64(now.Sub(miner.M5SubmitTime)) / 1000000000 if m5_duration >= float64(time.Minute*5)/1000000000 { miner.M5SubmitTime = now miner.M5Hashrate = miner.M5Accepts * float64(diffOneShareHashesAvg) / m5_duration / 1000000 logg.Info("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate)) miner.M5Accepts = 0 } //logg.Warn("[server]", zap.Float64("Accepts", miner.Accepts), zap.Float64("Rejects", miner.Rejects)) //logg.Info("[server]", zap.Float64("TargetShares", miner.VarDiffOpt.TargetShares), zap.Float64("MinShares", miner.VarDiffOpt.MinShares), zap.Float64("MaxShares", miner.VarDiffOpt.MaxShares), zap.Float64("SubmitShares", miner.VarDiffOpt.SubmitShares)) //logg.Warn("[server]", zap.Float64("reject rate", miner.Rejects/(miner.Accepts+miner.Rejects)), zap.Float64("Hashrate(MH/S)", miner.AverageHashrate)) logg.Warn("[server]", zap.Float64("M5Accepts", miner.M5Accepts), zap.Float64("M5Hashrate(MH/S)", miner.M5Hashrate)) //logg.Info("[server]", zap.Float64("LastCalcTime", float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000)) //calc acutal submit shares period of time, then compare with target shares and adjust diff if miner.Server.Config.Diff.Filter == "kalman" { } else { if float64(now.Sub(miner.VarDiffOpt.LastCalcTime))/1000000000 >= miner.VarDiffOpt.AdjustTime { coin.VarAdjustDifficulty(miner, coin.UPDATE_DIFF) miner.VarDiffOpt.LastCalcTime = now } } if new_found { //util.StaleAllJobs(miner) /*user_blk_item.User = miner.User user_blk_item.Miner = miner.Miner user_blk_item.Index = fmt.Sprint(miner.MinerIndex) user_blk_item.Submit = "y" user_blk_item.Success = false user_blk_item.Accepts = miner.Accepts user_blk_item.Rejects = miner.Rejects user_blk_item.Reward = 0 user_blk_item.Fee = 0 user_blk_item.Nonce = nonce user_blk_item.SubIdx = miner.Server.SubIdx dbif.NotifyUsersBlkStatsDb2(miner, &user_blk_item)*/ pool_blk_item.Submit = "y" pool_blk_item.Success = false pool_blk_item.Accepts = miner.Accepts pool_blk_item.Rejects = miner.Rejects pool_blk_item.Reward = 0 pool_blk_item.Fee = 0 pool_blk_item.Nonce = nonce pool_blk_item.SubIdx = miner.Server.SubIdx dbif.NotifyPoolBlkStatsDb2(miner.Server, &pool_blk_item) } if ack.Result { submit_item.Success = false if new_found { submit_item.Submit = "y" submit_item.SubIdx = miner.Server.SubIdx } else { submit_item.Submit = "n" submit_item.SubIdx = -1 } submit_item.Accepts = miner.Accepts submit_item.Total_accepts = miner.Accepts submit_item.Rejects = miner.Rejects submit_item.Total_rejects = miner.Rejects submit_item.Reward = 0 submit_item.Fee = 0 submit_item.Nonce = nonce //dbif.NotifyMinerDb2(miner, &submit_item) dbif.NotifyBlkDetailDb(miner, blk_detail_height, blk_detail_hash, blk_detail_success, blk_detail_miner_diff, blk_detail_pool_diff, nonce, submit_item.SubIdx) return true, new_found, true } return false, false, true } func Produce_block_submit(miner *coin.MinerObj /*header NexaBlockHeader,*/, job *msg.NexaStratumJob, PowHash string, SubIdx int64) { var nm msg.BlockNexaMsg nm.Id = job.Id nm.Header = job.Header nm.Nonce = job.Nonce nm.Pow = PowHash nm.SubIdx = SubIdx nm.User = miner.User nm.Miner = miner.Miner nm.Index = fmt.Sprint(miner.MinerIndex) body, err := json.Marshal(nm) if err != nil { logg.Error("[server]", zap.String("failed to Marshal job", err.Error())) return } blk := string(body) //Add Height heightb := utility.Uint32ToByte(job.Height) heights := hex.EncodeToString(heightb) blk += heights var Height uint32 = utility.ByteToUint32(heightb) logg.Warn("[server]", zap.Uint32("Height", Height)) //Add SubmitIndex indexb := utility.Uint32ToByte(miner.SubmitIndex) indexs := hex.EncodeToString(indexb) blk += indexs var SubmitIndex uint32 = utility.ByteToUint32(indexb) logg.Info("[server]", zap.Uint32("SubmitIndex", SubmitIndex)) logg.Info("[server]", zap.String("blk", blk)) if miner.Server.PubCh == nil { miner.Server.PubCh = utility.InitZmqPub(miner.Server.Config.Zmq.Pub) } if miner.Server.PubCh != nil { //miner.Server.PubCh.SendChan <- [][]byte{[]byte("blknexa"), []byte(blk)} err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blknexa"), []byte(blk)}) if err != nil { miner.Server.PubCh.Destroy() miner.Server.PubCh = nil logg.Info("[server]", zap.String("blk", err.Error())) } else { logg.Info("[server]", zap.String("blk", "sent")) } } } // server-->miner func nexa_parse_miner_notify(miner *coin.MinerObj, msg msg.NexaStratumJob) int { if miner.NexaJob.Height != msg.Height { miner.Job.IsClean = true } miner.NexaJob = msg miner.NexaJob.Extranonce1 = miner.Job.Extranonce1 miner.Job.Extranonce2_size = msg.Extranonce2_size //miner.Server.Logg.Info("[server]", zap.Int32("miner.Version", miner.Version), zap.Int32("msg.Version", msg.Version)) return 1 } func Init(server *coin.ServerContext) { ServerNexaCtx.ServerCtx = server logg = server.Logg logg.Info("[server]", zap.String("server_nexa_version", SERVER_NEXA_VERSION)) coin.Init_diff_db() } func Start() { } func Stop() { coin.DiffStop() } func InitMiner(miner *coin.MinerObj) { be1 := make([]byte, 8) binary.LittleEndian.PutUint64(be1, (miner.Server.Extranonce1 /* + 0x81000000*/)) miner.Job.Extranonce1 = hex.EncodeToString(be1) miner.NexaJob.Extranonce1 = miner.Job.Extranonce1 miner.Server.Extranonce1++ target, err := utility.DiffToTarget(miner.Difficulty) if err != nil { logg.Error("[server]", zap.String("DiffToTarget", err.Error())) return } miner.Target = target logg.Debug("[target]", zap.String("target", hex.EncodeToString(target.Bytes())), zap.Float64("diff", miner.Difficulty)) server_target := new(big.Int) t_bytes, err := hex.DecodeString(miner.NexaJob.Target) if err != nil { logg.Error("[server]", zap.String("DecodeString", err.Error())) return } //server_target.SetBytes(common.Reverse(t_bytes)) server_target.SetBytes(t_bytes) miner.ServerTarget = server_target miner.ServerTargetS = miner.Server.SJob.Target miner.NexaJob = miner.Server.NexaJob } func Handle_subscribe_nexa(miner *coin.MinerObj, id float64, extranonce1 string) { miner.TxLock.Lock() var result [3]interface{} //result[0] = results result[0] = nil if miner.Protocol == "yxminer" { result[1] = extranonce1 } else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" { var result2 [2]interface{} var result3 [2]interface{} var result4 [2]interface{} result3[0] = "mining.set_difficulty" if miner.Protocol == "WildRig" { result3[1] = extranonce1[:8] } else { result3[1] = miner.Difficulty } result4[0] = "mining.notify" //result4[1] = extranonce1 result4[1] = extranonce1[:8] result2[0] = result3 result2[1] = result4 result[0] = result2 result[1] = extranonce1[:8] //result[0] = fmt.Sprintf("[[%s,%.2f],[%s,%s]]", "mining.set_difficulty", miner.Difficulty, "mining.notify", extranonce1) } else { result[1] = extranonce1 } //result[1] = miner.Job.Extranonce1 miner.Server.Logg.Debug("[server]", zap.Uint64("extra2", miner.Job.Extranonce2_size)) if miner.Job.Extranonce2_size == 0 { result[2] = 4 } else { if miner.Protocol == "yxminer" { result[2] = miner.Job.Extranonce2_size } else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" { result[2] = 4 } else { result[2] = miner.Job.Extranonce2_size } } if extranonce1 == "" { miner.TxLock.Unlock() stratum.Handle_exception(miner, id, stratum.MINER_ERR_NOT_SUBSCRIBED) return } var body []byte var err error if miner.Protocol == "yxminer" { var ack stratum.Subscribe_reply ack.ID = id ack.Result = result ack.Error = nil body, err = json.Marshal(ack) if err != nil { miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error())) miner.TxLock.Unlock() return } } else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" { var ack stratum.SubscribeGpu_reply ack.Jsonrpc = "2.0" ack.ID = id ack.Result = result ack.Error = nil body, err = json.Marshal(ack) if err != nil { miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error())) miner.TxLock.Unlock() return } } else { var ack stratum.Subscribe_reply ack.ID = id ack.Result = result ack.Error = nil body, err = json.Marshal(ack) if err != nil { miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error())) miner.TxLock.Unlock() return } } var body_string = string(body) + "\n" miner.Server.Logg.Debug("[server]", zap.String("tx", body_string)) err = stratum.Conn_tx(miner.Conn, []byte(body_string)) if err != nil { //delete(miner.Server.Miners, miner.MinerId) //miner.Server.Miners.Delete(miner.MinerId) } miner.Status = coin.MINER_STATUS_SUBSCRIBED miner.TxLock.Unlock() if miner.ZlogInit { miner.Zlog.Info().Msg(body_string) } } func HandleMinerSubscribe(miner *coin.MinerObj, id float64, extranonce1 string, msg string) { if strings.Contains(msg, "YxMiner") { miner.Protocol = "yxminer" } else if strings.Contains(msg, "BzMiner") { miner.Protocol = "bzminer" } else if strings.Contains(msg, "lolMiner") { miner.Protocol = "lolminer" } else if strings.Contains(msg, "Rigel") { miner.Protocol = "Rigel" } else if strings.Contains(msg, "WildRig") { miner.Protocol = "WildRig" } else { miner.Protocol = "standard" } Handle_subscribe_nexa(miner, id, extranonce1) } func HandleMinerAuth(miner *coin.MinerObj) { } func HandleMinerSubmit(miner *coin.MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool) { if miner.Protocol == "yxminer" { } else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" { nonce = nonce2 + nonce } else { } accept_ok, submit_ok, handle_ok := handle_submit(miner, id, miner_user, job_id, nonce2, ntime, nonce) return accept_ok, submit_ok, handle_ok } func SetDifficulty(miner *coin.MinerObj) { if miner.Protocol == "yxminer" { stratum.Set_difficulty(miner) } else { stratum.Set_difficulty_nexa(miner) } } func NexaNotify(miner *coin.MinerObj) { miner.TxLock.Lock() if !((miner.Status == coin.MINER_STATUS_AUTHORIZED) || (miner.Status == coin.MINER_STATUS_RUNNING)) { miner.TxLock.Unlock() return } miner.TxLock.Unlock() if miner.DifficultyNext > -1 { ratio := miner.DifficultyNext / miner.Difficulty if ratio > 1.1 || ratio < 0.9 { miner.Difficulty = miner.DifficultyNext miner.DifficultyNext = -1 if miner.Protocol == "yxminer" { stratum.Set_difficulty(miner) } else { stratum.Set_difficulty_nexa(miner) } logg.Info("[gbt]", zap.Float64("update Diff", miner.Difficulty)) } else { miner.DifficultyNext = -1 } } miner.TxLock.Lock() //log.Println("[server]extra1, id", miner.Job.Extranonce1, miner.Job.Job_id, miner.MinerId) var params [5]interface{} idb := make([]byte, 4) binary.BigEndian.PutUint32(idb, miner.JobId) miner.Job.Job_id = hex.EncodeToString(idb) params[0] = miner.Job.Job_id params[1] = miner.NexaJob.Header //params[3] = miner.NexaJob.Height if miner.Protocol == "yxminer" { params[2] = miner.NexaJob.NBits params[3] = miner.NexaJob.CurTime } else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" { params[2] = miner.NexaJob.Height params[3] = miner.NexaJob.NBits } else { params[2] = miner.NexaJob.NBits params[3] = miner.NexaJob.CurTime } miner.CurHeight = miner.NexaJob.Height if miner.Reconnect { params[4] = true miner.Reconnect = false } else { params[4] = miner.Job.IsClean } miner.NexaJob.JobDifficulty = miner.Difficulty miner.Jobs.LoadOrStore(miner.Job.Job_id, miner.NexaJob) /*var entry coin.JobListEntry entry.Job_id = miner.Job.Job_id entry.Ts = time.Now() miner.LockForJobs.Lock() miner.JobList.PushFront(entry) var removes string = "" if miner.JobList.Len() > int(coin.LOCAL_JOBS_TOTAL_SIZE) { e := miner.JobList.Back() entry := e.Value.(coin.JobListEntry) removes = entry.Job_id miner.JobList.Remove(e) } miner.LockForJobs.Unlock() if len(removes) > 0 { miner.Jobs.Delete(removes) }*/ stratum.AddAndUpdateJob(miner) stratum.UpdateJobs(miner) //miner.LastJobId = miner.Job.Job_id miner.JobId++ var body []byte var err error if miner.Protocol == "yxminer" { var msg Notify_msg_nexa msg.ID = nil msg.Method = "mining.notify" msg.Params = params body, err = json.Marshal(msg) if err != nil { miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error())) miner.TxLock.Unlock() return } } else if miner.Protocol == "bzminer" || miner.Protocol == "lolminer" || miner.Protocol == "Rigel" || miner.Protocol == "WildRig" { var msg Notify_msg_nexa_gpu msg.ID = nil msg.Method = "mining.notify" var params4 [4]interface{} params4[0] = params[0] params4[1] = params[1] params4[2] = params[2] params4[3] = params[3] msg.Params = params4 msg.Jsonrpc = "2.0" body, err = json.Marshal(msg) if err != nil { miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error())) miner.TxLock.Unlock() return } } else { var msg Notify_msg_nexa msg.ID = nil msg.Method = "mining.notify" msg.Params = params body, err = json.Marshal(msg) if err != nil { miner.Server.Logg.Error("[server]", zap.String("Marshal", err.Error())) miner.TxLock.Unlock() return } } var body_string = string(body) + "\n" err = stratum.Conn_tx(miner.Conn, []byte(body_string)) if err != nil { //delete(miner.Server.Miners, miner.MinerId) //miner.Server.Miners.Delete(miner.MinerId) } miner.Server.Logg.Debug("[server]", zap.String("tx", body_string)) miner.TxLock.Unlock() if miner.ZlogInit { miner.Zlog.Info().Msg(body_string) } } func Notify(miner *coin.MinerObj) { NexaNotify(miner) } func HandleJobMsg(server *coin.ServerContext, Msg []byte) { var result msg.NexaStratumJob server.Logg.Warn("[server]", zap.String("receive", "job")) if err := json.Unmarshal(Msg, &result); err != nil { server.Logg.Error("[server]", zap.String("Unmarshal", err.Error())) return } server.NexaJob = msg.NexaStratumJob(result) logg.Debug("[gbt]", zap.String("Target", server.NexaJob.Target)) server.NexaJob.Extranonce2_size = 8 server.SJob.Extranonce2_size = 8 logg.Debug("[gbt]", zap.Uint32("Height", server.NexaJob.Height), zap.String("Target", server.NexaJob.Target), zap.String("Header", server.NexaJob.Header) /*, zap.Uint64("Timastamp", server.NexaJob.CurTime)*/) targetb, _ := hex.DecodeString(server.NexaJob.Target) logg.Debug("[gbt]", zap.Uint64("Id", server.NexaJob.Id), zap.Float64("network diff", utility.Target2Diff(utility.Reverse(targetb)))) server.NetHight = uint64(server.NexaJob.Height) server.NetTarget = server.NexaJob.Target server.Miners.Range(func(k, v interface{}) bool { m, ok := v.(*(coin.MinerObj)) if ok { server.Logg.Info("[server]", zap.String("lock", "start")) m.TxLock.Lock() status := m.Status cmd := nexa_parse_miner_notify(m, server.NexaJob) m.TxLock.Unlock() server.Logg.Info("[server]", zap.String("lock", "end")) var need_notify bool = true if time.Now().Sub(m.ConnSetupTime) >= time.Duration(coin.CONN_EXPIRED_TIME)*time.Second { if (status != coin.MINER_STATUS_RUNNING) && (status != coin.MINER_STATUS_AUTHORIZED) { //m.Conn.Close() need_notify = false } } if need_notify { switch cmd { case 0: //extranonce 1 and extranonce2 size //TODO case 1: //notify NexaNotify(m) } } } return true }) } func IsMhsLow(miner *coin.MinerObj) bool { if miner.Mhs5M < 1 { return true } return false } func GetBlockInterval() int { return 180 }