m2pool_core/internal/server/nexa/nexa.go

930 lines
30 KiB
Go

// 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
}