m2pool-core/internal/server/monero/monero.go

757 lines
21 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package monero
import (
"crypto/rand"
"strings"
//"database/sql"
"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_MONERO_VERSION string = "monero v0.1a"
type ServerMoneroContext struct {
ServerCtx *coin.ServerContext
logg *zap.Logger
Sha3xJob msg.Sha3xStratumJob
RandomxVM *RandomXValidator
}
var logg *zap.Logger
var ServerMoneroCtx ServerMoneroContext
type MoneroNotify_params_msg struct {
Id string `json:"id"`
JobId string `json:"job_id"`
SeedHash string `json:"seed_hash"`
Blob string `json:"blob"`
Height uint32 `json:"height"`
Target string `json:"target"`
NextSeedHash string `json:"next_seed_hash"`
Algo string `json:"algo"`
}
type Monero_msg struct {
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params MoneroNotify_params_msg `json:"params"`
}
// 辅助函数:反转每个字节的小端 hex
func reverseHexBytes(s string) string {
if len(s)%2 != 0 {
s = "0" + s
}
res := ""
for i := len(s); i > 0; i -= 2 {
res += s[i-2 : i]
}
return res
}
func calc_target(diff uint64) string {
difficulty := new(big.Int)
difficulty.SetString(fmt.Sprintf("%d", diff), 10)
// 2^256 - 1
max := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
// target = (2^256 - 1) / difficulty
target := new(big.Int).Div(max, difficulty)
// 转为32字节 hex大端
targetHexBE := fmt.Sprintf("%064x", target)
return targetHexBE
}
func calc_diff(hash string) uint64 {
be := reverseHexBytes(hash)
target_be := new(big.Int)
target_be.SetString(be, 16)
max := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
difficulty := new(big.Rat).SetFrac(max, target_be)
// Convert *big.Rat to *big.Float, then to uint64
diffFloat := new(big.Float).SetRat(difficulty)
result, _ := diffFloat.Uint64()
return result
}
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
// fmt.Println("提交job_id:", job_id)
var keys []string
miner.Jobs.Range(func(k, v interface{}) bool {
if key, ok := k.(string); ok {
keys = append(keys, key)
}
return true // 继续遍历
})
// fmt.Println("目前任务所有key:", keys)
v, ok := miner.Jobs.Load(job_id)
if ok {
job := v.(msg.MoneroStratumJob)
if uint32(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
}
if (miner.LastNonce != nonce) || (miner.MoneroJob.BlocktemplateBlob != job.BlocktemplateBlob) {
miner.MoneroJob.BlocktemplateBlob = job.BlocktemplateBlob
miner.LastNonce = nonce
job.Nonce = nonce
if miner.ZlogInit {
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
}
var calc_hash []byte
var completeHeader []byte
nonceByte, err := hex.DecodeString(nonce)
if err != nil {
fmt.Println(err)
return false, false, false
}
headerByte, err := hex.DecodeString(job.BlockhashingBlob)
if err != nil {
fmt.Println(err)
return false, false, false
}
calc_hash, completeHeader, err = ServerMoneroCtx.RandomxVM.BuildPowHash(headerByte, nonceByte)
if err != nil {
fmt.Println("calc_hash error:", err)
return false, false, false
}
job.CompleteHeader = completeHeader
if miner.ZlogInit {
miner.Zlog.Info().Msg("hash in " + submit_item.Header + " calc_hash " + hex.EncodeToString(calc_hash) + " " + miner.User + "." + miner.Miner)
}
submit_target := new(big.Int)
submit_target.SetBytes(calc_hash)
calc_diff := utility.MoneroTarget2Diff(calc_hash)
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " target diff " + fmt.Sprintf("%f", (miner.Difficulty)) + " submit diff " + fmt.Sprintf("%f", (calc_diff)))
}
if calc_diff < float64(job.Difficulty) {
ack.Result = false
miner.ErrLowDiffs = miner.ErrLowDiffs + 1
stratum.Handle_exception(miner, id, stratum.MINER_ERR_LOW_DIF_SHARE)
return false, false, false
}
stb, _ := hex.DecodeString(job.Target)
server_diff := utility.MoneroTarget2Diff(utility.Reverse(stb))
network_target := new(big.Int)
network_target.SetBytes(stb)
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " calc_diff " + fmt.Sprintf("%f", (calc_diff)) + " miner.Difficulty " + fmt.Sprintf("%f", (miner.Difficulty)) + " server_diff " + fmt.Sprintf("%f", (server_diff)))
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " submit_target " + hex.EncodeToString(submit_target.Bytes()) + " network_target " + hex.EncodeToString(network_target.Bytes()) + " target " + hex.EncodeToString(miner.ServerTarget.Bytes()) + " cmp " + fmt.Sprintf("%d", (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())
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 = float64(job.Difficulty)
blk_detail_pool_diff = miner.Server.RefDifficulty
if ack.Result == 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
new_found = true
}
if new_found && float64(miner.Server.MoneroJob.Difficulty) <= calc_diff {
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)
}
}
} else {
miner.LastHeader = job.BlocktemplateBlob
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 {
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit 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)
}
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 = diff_next * 10000000 / 10000000
} else if ratio <= 0.5 {
miner.DifficultyNext = diff_next * 10000000 / 10000000
} else {
}
} else {
miner.DifficultyNext = diff_next * 10000000 / 10000000
}
}
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
}
}
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)
}
}
} else {
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
}
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(0xFFFFFFFFFFFFFFFF)
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
miner.M5Accepts = 0
}
if miner.ZlogInit {
miner.Zlog.Info().Msg(miner.User + "." + miner.Miner + " handle_submit M5Accepts " + fmt.Sprintf("%f", (miner.M5Accepts)) + " M5Hashrate(MH/S) " + fmt.Sprintf("%f", (miner.M5Hashrate)))
}
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 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.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 contractBlockTemplateBlob(miner *coin.MinerObj, nonceHex string) (string, error) {
blockTemplateStr := miner.MoneroJob.BlocktemplateBlob
block, err := hex.DecodeString(blockTemplateStr)
if err != nil {
return "", err
}
if len(block) < 43 {
return "", fmt.Errorf("blocktemplate blob too short: %d", len(block))
}
// nonce 是 4 字节 hex直接解码成 bytes
nonceBytes, err := hex.DecodeString(nonceHex)
if err != nil {
return "", fmt.Errorf("invalid nonce hex: %v", err)
}
if len(nonceBytes) != 4 {
return "", fmt.Errorf("nonce must be 4 bytes, got %d", len(nonceBytes))
}
// 覆盖 nonce 区域 (39~42)
copy(block[39:43], nonceBytes)
return hex.EncodeToString(block), nil
}
func Produce_block_submit(miner *coin.MinerObj /*header Sha3xBlockHeader,*/, job *msg.MoneroStratumJob, PowHash string, SubIdx int64) {
var nm msg.BlockMoneroMsg
blockBlob, err := contractBlockTemplateBlob(miner, job.Nonce)
if err != nil {
fmt.Println(err)
return
}
nm.Id = job.Id
nm.Header = blockBlob
nm.Nonce = job.Nonce
nm.Pow = PowHash
nm.SubIdx = SubIdx
nm.User = miner.User
nm.Miner = miner.Miner
nm.Height = job.Height
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
}
// JSON主体
blk := string(body)
// 高度uint32 → 4字节 → hex编码8字符
heightHex := fmt.Sprintf("%08x", job.Height)
// Indexuint32 → 4字节 → hex编码8字符
indexHex := fmt.Sprintf("%08x", miner.MinerIndex)
// 拼接最终消息
msg := blk + heightHex + indexHex
// fmt.Println(msg)
logg.Info("[server]", zap.String("final_msg", msg))
if miner.Server.PubCh == nil {
miner.Server.PubCh = utility.InitZmqPub(miner.Server.Config.Zmq.Pub)
}
if miner.Server.PubCh != nil {
// fmt.Println(msg)
err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blkmonero"), []byte(msg)})
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"))
}
}
}
// var start_job_id uint64 = 0
// server-->miner
func parse_miner_notify(miner *coin.MinerObj, msg msg.MoneroStratumJob) int {
if miner.MoneroJob.Height != msg.Height {
miner.Job.IsClean = true
}
miner.MoneroJob = msg
miner.MoneroJob.JobId = msg.JobId
return 1
}
func Init(server *coin.ServerContext) {
ServerMoneroCtx.ServerCtx = server
ServerMoneroCtx.RandomxVM = &RandomXValidator{}
logg = server.Logg
logg.Info("[server]", zap.String("server_sha3x_version", SERVER_MONERO_VERSION))
coin.Init_diff_db()
}
func Start() {
}
func Stop() {
coin.DiffStop()
}
func InitMiner(miner *coin.MinerObj) {
miner.MoneroJob = miner.Server.MoneroJob
// miner.MoneroJob.Extranonce1 = miner.Job.Extranonce1
server_target := new(big.Int)
t_bytes, err := hex.DecodeString(miner.MoneroJob.Target)
if err != nil {
logg.Error("[server]", zap.String("DecodeString", err.Error()))
return
}
//server_target.SetBytes(common.Reverse(t_bytes))
miner.MoneroJob = ServerMoneroCtx.ServerCtx.MoneroJob
server_target.SetBytes(t_bytes)
miner.ServerTarget = server_target
miner.ServerTargetS = miner.Server.SJob.Target
miner.CurHeight = uint32(miner.MoneroJob.Height)
}
func Handle_subscribe_sha3x(miner *coin.MinerObj, id float64, extranonce1 string) {
}
func HandleMinerSubscribe(miner *coin.MinerObj, id float64, extranonce1 string, msg string) {
}
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) {
//nonce_str, _ := stratum.ReverseHexStringByByte(nonce)
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) {
stratum.Set_difficulty(miner)
}
func MoneroNotify(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
stratum.Set_difficulty(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 msg Monero_msg
msg.Params.Id = miner.Session
msg.Params.SeedHash = miner.MoneroJob.SeedHash
msg.Params.JobId = miner.MoneroJob.JobId
msg.Params.Blob = miner.MoneroJob.BlockhashingBlob
msg.Params.Height = uint32(miner.MoneroJob.Height)
miner.MoneroJob.Difficulty = uint64(miner.Difficulty)
msg.Params.NextSeedHash = ""
msg.Params.Algo = "rx/0"
//target_s, _ := stratum.ReverseHexStringByByte(miner.Sha3xJob.Target)
//msg.Params.Target = target_s[48:]
target_new, _ := utility.MoneroDiffToTarget(miner.Difficulty)
target_str := fmt.Sprintf("%064x", target_new.Bytes())
target_strr, strerr := stratum.ReverseHexStringByByte(target_str)
if strerr != nil {
println("ReverseHexStringByByte", strerr.Error())
}
//println("target=", target_str, "r=", target_strr)
msg.Params.Target = target_strr[48:]
miner.CurHeight = uint32(miner.MoneroJob.Height)
// miner.MoneroJob.JobDifficulty = miner.Difficulty
miner.Jobs.LoadOrStore(miner.MoneroJob.JobId, miner.MoneroJob)
stratum.AddAndUpdateJob(miner)
stratum.UpdateJobs(miner)
miner.JobId++
var body []byte
var err error
msg.Jsonrpc = "2.0"
msg.Method = "job"
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.TxLock.Unlock()
if miner.ZlogInit {
miner.Zlog.Info().Msg(body_string)
}
}
func Notify(miner *coin.MinerObj) {
MoneroNotify(miner)
}
func formatUint64ToHexWithPadding(val uint64) string {
hexStr := fmt.Sprintf("%016x", val)
if len(hexStr) < 64 {
paddingLen := 64 - len(hexStr)
hexStr += string(make([]byte, paddingLen))
for i := len(hexStr) - paddingLen; i < 64; i++ {
hexStr = hexStr[:i] + "0" + hexStr[i+1:]
}
}
return hexStr
}
func formatWideTargetTo32BytesTarget(wide_target string) string {
if len(wide_target) > 64 {
panic("任务中的wide_target错误")
}
// 去掉前缀 0x 或 0X
wide_target = strings.TrimPrefix(wide_target, "0x")
wide_target = strings.TrimPrefix(wide_target, "0X")
wide_target = fmt.Sprintf("%0*s%s", 64-len(wide_target), "", wide_target)
return wide_target
}
var last_seed string = ""
func randomxJobId() string {
// 生成4个字节
bytes := make([]byte, 4)
_, err := rand.Read(bytes)
if err != nil {
panic(err)
}
// 转成 hex 字符串
hexStr := hex.EncodeToString(bytes)
return hexStr
}
func HandleJobMsg(server *coin.ServerContext, Msg []byte) {
var result msg.MoneroStratumJob
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
}
result.Target = calc_target(result.Difficulty)
// 上个模板 seed_hash 和本次 seed_hash 不一致时,重置 randomx 虚拟机
if result.SeedHash != last_seed {
fmt.Println("开始创建新的 randomx vm, 本次 seed_hash", result.SeedHash)
seedBytes, err := hex.DecodeString(result.SeedHash)
if err != nil {
panic(err)
}
// 如果已有旧 VM先释放
if ServerMoneroCtx.RandomxVM != nil {
ServerMoneroCtx.RandomxVM.Destroy()
}
// 创建新 VM
vm, err := NewRandomXValidator(seedBytes)
if err != nil {
panic(err)
}
ServerMoneroCtx.RandomxVM = vm
last_seed = result.SeedHash
}
server.MoneroJob = msg.MoneroStratumJob(result)
logg.Debug("[gbt]", zap.String("Target", server.MoneroJob.Target))
logg.Debug("[gbt]", zap.Uint64("Id", server.MoneroJob.Id), zap.Float64("network diff", float64(server.MoneroJob.Difficulty)))
server.NetHight = uint64(server.MoneroJob.Height) // 当前server中的全网高度
server.NetTarget = result.Target // 当前server中的全网target
server.Miners.Range(func(k, v interface{}) bool {
if v != nil {
m, ok := v.(*(coin.MinerObj))
if ok {
if m != nil {
server.Logg.Info("[server]", zap.String("lock", "start"))
m.TxLock.Lock()
status := m.Status
cmd := parse_miner_notify(m, server.MoneroJob)
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
MoneroNotify(m)
}
}
}
}
}
return true
})
}
func IsMhsLow(miner *coin.MinerObj) bool {
if miner.Mhs5M < 1 {
return true
}
return false
}
func GetBlockInterval() int {
return 3600
}