create git
This commit is contained in:
681
internal/server/coin/coin.go
Normal file
681
internal/server/coin/coin.go
Normal file
@@ -0,0 +1,681 @@
|
||||
// coin.go
|
||||
package coin
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
|
||||
"fmt"
|
||||
"pool/internal/db"
|
||||
"pool/internal/msg"
|
||||
"pool/internal/server/diff"
|
||||
"pool/internal/utility"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/zeromq/goczmq"
|
||||
"go.uber.org/zap"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const JOB_EXPIRED_TIME uint32 = 3600 //job expired time (second)
|
||||
const LOCAL_JOBS_EXPIRED_TIME uint32 = 3600 //300 //local jobs expired time (second)
|
||||
const LOCAL_JOBS_TOTAL_SIZE uint32 = 100 //300 //total local jobs
|
||||
const CONN_EXPIRED_TIME uint32 = 600 //connection expired time
|
||||
|
||||
// miner status
|
||||
// const MINER_STATUS_OFFLINE string = "offline"
|
||||
const MINER_STATUS_CONNECTED string = "connected"
|
||||
const MINER_STATUS_SUBSCRIBED string = "subscribed"
|
||||
const MINER_STATUS_AUTHORIZED string = "authorized"
|
||||
const MINER_STATUS_RUNNING string = "online"
|
||||
const MINER_STATUS_DISCONNECTED string = "offline"
|
||||
const MINER_STATUS_DISABLED string = "disabled"
|
||||
|
||||
const MINER_DURATION_TIME time.Duration = 1
|
||||
const MINER_DIFFICULTY_ADJUST_DURATION time.Duration = 5
|
||||
|
||||
// vardiff
|
||||
const UP_DIFF int = 0
|
||||
const DOWN_DIFF int = 1
|
||||
const UPDATE_DIFF int = 2
|
||||
const DIFFICULTY_WAIT_TIMES int = 6
|
||||
|
||||
const (
|
||||
Low = 0
|
||||
Mid = 1
|
||||
Hign = 2
|
||||
)
|
||||
|
||||
type BindConfig struct {
|
||||
Listen string `json:"listen"`
|
||||
Auth bool `json:"auth"`
|
||||
}
|
||||
|
||||
type DiffConfig struct {
|
||||
StartDifficulty float64 `json:"start_diff"`
|
||||
DiffMin float64 `json:"diff_min"`
|
||||
DiffMax float64 `json:"diff_max"`
|
||||
DiffAdjustInterval float64 `json:"diff_adjust_interval"`
|
||||
DiffAdjustPercentage float64 `json:"diff_adjust_percentage"`
|
||||
DiffAdjustTime float64 `json:"diff_adjust_time"`
|
||||
Filter string `json:"filter"`
|
||||
Dbg bool `json:"dbg"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Coin string `json:"coin"`
|
||||
Host BindConfig `json:"host"`
|
||||
Diff DiffConfig `json:"diff"`
|
||||
Zmq utility.ZmqConfig `json:"zmq"`
|
||||
Redis utility.RedisConfig `json:"redis"`
|
||||
Zaplog zap.Config `json:"zap"`
|
||||
Logrotae utility.LogRotateConfig `json:"logrotate"`
|
||||
}
|
||||
|
||||
type CoinObj struct {
|
||||
Coin string
|
||||
Init func(server *ServerContext)
|
||||
Start func()
|
||||
Stop func()
|
||||
InitMiner func(miner *MinerObj)
|
||||
HandleMinerSubscribe func(miner *MinerObj, id float64, extranonce1 string, msg string)
|
||||
HandleMinerAuth func(miner *MinerObj)
|
||||
HandleMinerSubmit func(miner *MinerObj, id float64, miner_user string, job_id string, nonce2 string, ntime string, nonce string) (bool, bool, bool)
|
||||
SetDifficulty func(miner *MinerObj)
|
||||
Notify func(miner *MinerObj)
|
||||
HandleJobMsg func(server *ServerContext, Msg []byte)
|
||||
IsMhsLow func(miner *MinerObj) bool
|
||||
GetBlockInterval func() int
|
||||
}
|
||||
|
||||
type PoolBlkMsg struct {
|
||||
Height int64
|
||||
Hash string
|
||||
Pow string
|
||||
Net_target string
|
||||
Submit string
|
||||
Success bool
|
||||
Accepts float64
|
||||
Rejects float64
|
||||
Reward float64
|
||||
Fee float64
|
||||
Nonce string
|
||||
SubIdx int64
|
||||
}
|
||||
|
||||
type ServerContext struct {
|
||||
CoinCtx CoinObj
|
||||
DbCtx *db.DbContext
|
||||
|
||||
Config *ServerConfig
|
||||
|
||||
PubCh *goczmq.Sock
|
||||
SubCh *goczmq.Sock
|
||||
|
||||
Listener net.Listener
|
||||
|
||||
MinerType string
|
||||
|
||||
Extranonce1 uint64
|
||||
|
||||
Difficulty float64
|
||||
|
||||
RefDifficulty float64
|
||||
|
||||
Accepts float64
|
||||
Rejects float64
|
||||
AverageHashrate float64
|
||||
|
||||
Miners sync.Map
|
||||
|
||||
MMhs sync.Map
|
||||
|
||||
Started bool
|
||||
|
||||
SLock sync.Mutex
|
||||
ExitFlag bool
|
||||
|
||||
//AlivingChan chan bool
|
||||
//LiveingExpired bool
|
||||
FlagAliving int32
|
||||
FlagAlivingExit int32
|
||||
|
||||
ExitPingChan chan bool
|
||||
ExitJobChan chan bool
|
||||
|
||||
Logg *zap.Logger
|
||||
LogR *lumberjack.Logger
|
||||
|
||||
SJob msg.StratumJob
|
||||
|
||||
//UpdateMap sync.Map
|
||||
|
||||
SyncJobChan chan bool
|
||||
Synced bool
|
||||
|
||||
ExitDbMiners chan bool
|
||||
ExitDbMinersStats chan bool
|
||||
|
||||
ExitDbUser chan bool
|
||||
ExitDbUserStats chan bool
|
||||
|
||||
ExitDbPoolStats chan bool
|
||||
|
||||
NexaJob msg.NexaStratumJob
|
||||
Sha3xJob msg.Sha3xStratumJob
|
||||
MoneroJob msg.MoneroStratumJob
|
||||
Tari_Sha3xJob msg.GbtSendMsg
|
||||
ExitDiffVar chan bool
|
||||
|
||||
RedisClient *redis.Client
|
||||
|
||||
Accepts5M float64
|
||||
Accepts15M float64
|
||||
Accepts30M float64
|
||||
Accepts1h float64
|
||||
Accepts3h float64
|
||||
Accepts6h float64
|
||||
Accepts12h float64
|
||||
Accepts24h float64
|
||||
Accepts48h float64
|
||||
|
||||
Rejects5M float64
|
||||
Rejects15M float64
|
||||
Rejects30M float64
|
||||
Rejects1h float64
|
||||
Rejects3h float64
|
||||
Rejects6h float64
|
||||
Rejects12h float64
|
||||
Rejects24h float64
|
||||
Rejects48h float64
|
||||
|
||||
Mhs5M float64
|
||||
Mhs15M float64
|
||||
Mhs30M float64
|
||||
Mhs1h float64
|
||||
Mhs3h float64
|
||||
Mhs6h float64
|
||||
Mhs12h float64
|
||||
Mhs24h float64
|
||||
Mhs48h float64
|
||||
|
||||
RejectRatio5M float64
|
||||
RejectRatio15M float64
|
||||
RejectRatio30M float64
|
||||
RejectRatio1h float64
|
||||
RejectRatio3h float64
|
||||
RejectRatio6h float64
|
||||
RejectRatio12h float64
|
||||
RejectRatio24h float64
|
||||
RejectRatio48h float64
|
||||
|
||||
TotalMiners int64
|
||||
Normal int64
|
||||
Abnormal int64
|
||||
Offline int64
|
||||
MhsZero int64
|
||||
MhsLow int64
|
||||
HighRejects int64
|
||||
Unstable int64
|
||||
|
||||
NetTarget string
|
||||
NetHight uint64
|
||||
|
||||
Submits int64
|
||||
Blocks int64
|
||||
Orphans int64
|
||||
|
||||
Reward float64
|
||||
Fee float64
|
||||
|
||||
/*Users sync.Map
|
||||
UsersSLock sync.Mutex*/
|
||||
|
||||
/*PoolSLock sync.Mutex*/
|
||||
|
||||
SubIdx int64
|
||||
|
||||
MinerIndex int64
|
||||
|
||||
//NotifyBlkDetailIdx int32
|
||||
|
||||
CacheUsers sync.Map
|
||||
CacheUsersCnt int32
|
||||
|
||||
CurrentConns int32
|
||||
IpCounts map[string]int
|
||||
IpMutex sync.Mutex
|
||||
}
|
||||
|
||||
type JobListEntry struct {
|
||||
Job_id string
|
||||
Ts time.Time
|
||||
}
|
||||
|
||||
type MhsItem struct {
|
||||
Tt time.Time
|
||||
Diff float64
|
||||
}
|
||||
|
||||
type MhsObj struct {
|
||||
MinerId string
|
||||
Name string
|
||||
Accepts []MhsItem
|
||||
Rejects []MhsItem
|
||||
StartSubmitTime time.Time
|
||||
|
||||
StartDayTime time.Time
|
||||
|
||||
User string
|
||||
Miner string
|
||||
Index string
|
||||
Status string
|
||||
Algo int
|
||||
Release bool
|
||||
|
||||
LockForMhs sync.Mutex
|
||||
}
|
||||
|
||||
type VarDiffOptions struct {
|
||||
VariancePercent float64
|
||||
AdjustTime float64
|
||||
AdjustInterval float64
|
||||
MinDiff float64
|
||||
MaxDiff float64
|
||||
MinShares float64
|
||||
MaxShares float64
|
||||
TargetShares float64
|
||||
SubmitShares float64
|
||||
SilenceCount float64
|
||||
LastCalcTime time.Time
|
||||
Uptimes int
|
||||
Downtimes int
|
||||
Level int
|
||||
LastSubmitTime time.Time
|
||||
}
|
||||
|
||||
type BlockMsg struct {
|
||||
Target string
|
||||
Submit_target string
|
||||
Height int64
|
||||
Success bool
|
||||
Pow string
|
||||
Net_target string
|
||||
Submit string
|
||||
Hash string
|
||||
Header string
|
||||
Accepts float64
|
||||
Total_accepts float64
|
||||
Rejects float64
|
||||
Total_rejects float64
|
||||
Reward float64
|
||||
Fee float64
|
||||
Nonce string
|
||||
SubIdx int64
|
||||
}
|
||||
|
||||
type MinerObj struct {
|
||||
Server *ServerContext
|
||||
Conn net.Conn
|
||||
Authorized bool
|
||||
|
||||
MinerId string
|
||||
JobId uint32
|
||||
Name string
|
||||
|
||||
Jobs sync.Map
|
||||
LockForJobs sync.Mutex
|
||||
JobList *list.List
|
||||
|
||||
Target *big.Int
|
||||
Difficulty float64
|
||||
DifficultyNext float64
|
||||
ServerDifficulty float64
|
||||
ServerTarget *big.Int
|
||||
ServerTargetS string
|
||||
Accepts float64
|
||||
Rejects float64
|
||||
StartSubmitTime time.Time
|
||||
LastSubmitime time.Time
|
||||
SubmitIndex uint32
|
||||
AverageHashrate float64
|
||||
M5Accepts float64
|
||||
M5Hashrate float64
|
||||
M5SubmitTime time.Time
|
||||
LastJobId string
|
||||
LastNonce string
|
||||
CurHeight uint32
|
||||
CurHeight64 uint64
|
||||
Reconnect bool
|
||||
|
||||
LastHeader string
|
||||
|
||||
VarDiffOpt VarDiffOptions
|
||||
|
||||
Version int32
|
||||
Job msg.StratumJob
|
||||
|
||||
User string
|
||||
PassWord string
|
||||
Miner string
|
||||
Session string
|
||||
Duration float64
|
||||
|
||||
Status string
|
||||
ConnSetupTime time.Time
|
||||
TxLock sync.Mutex
|
||||
|
||||
KeepliveCnt float64
|
||||
RecvedLiveAck bool
|
||||
PongFailCnt int
|
||||
PingCnt int
|
||||
|
||||
NexaJob msg.NexaStratumJob
|
||||
Sha3xJob msg.Sha3xStratumJob
|
||||
MoneroJob msg.MoneroStratumJob
|
||||
Tari_Sha3xJob msg.GbtSendMsg
|
||||
|
||||
FromIP string
|
||||
|
||||
OnlineTime time.Time
|
||||
OfflineTime time.Time
|
||||
Retry int64
|
||||
DurationTime float64
|
||||
MinerIndex int64
|
||||
|
||||
Protocol string
|
||||
|
||||
ErrStaleds int64
|
||||
ErrLowDiffs int64
|
||||
ErrDuplicates int64
|
||||
ErrFormats int64
|
||||
ErrOthers int64
|
||||
|
||||
IsDisabled bool
|
||||
|
||||
Submits int64
|
||||
Blocks int64
|
||||
Orphans int64
|
||||
|
||||
Accepts5M float64
|
||||
Accepts15M float64
|
||||
Accepts30M float64
|
||||
Accepts1h float64
|
||||
Accepts3h float64
|
||||
Accepts6h float64
|
||||
Accepts12h float64
|
||||
Accepts24h float64
|
||||
Accepts48h float64
|
||||
|
||||
Rejects5M float64
|
||||
Rejects15M float64
|
||||
Rejects30M float64
|
||||
Rejects1h float64
|
||||
Rejects3h float64
|
||||
Rejects6h float64
|
||||
Rejects12h float64
|
||||
Rejects24h float64
|
||||
Rejects48h float64
|
||||
|
||||
Mhs5M float64
|
||||
Mhs15M float64
|
||||
Mhs30M float64
|
||||
Mhs1h float64
|
||||
Mhs3h float64
|
||||
Mhs6h float64
|
||||
Mhs12h float64
|
||||
Mhs24h float64
|
||||
Mhs48h float64
|
||||
|
||||
RejectRatio5M float64
|
||||
RejectRatio15M float64
|
||||
RejectRatio30M float64
|
||||
RejectRatio1h float64
|
||||
RejectRatio3h float64
|
||||
RejectRatio6h float64
|
||||
RejectRatio12h float64
|
||||
RejectRatio24h float64
|
||||
RejectRatio48h float64
|
||||
|
||||
Reward float64
|
||||
Fee float64
|
||||
|
||||
Zlog zerolog.Logger
|
||||
LogR *lumberjack.Logger
|
||||
ZlogInit bool
|
||||
|
||||
//EndCh chan bool
|
||||
|
||||
DiffHandler diff.KalmanVarDiff
|
||||
|
||||
NeedExit int32
|
||||
|
||||
PingEnabled bool
|
||||
}
|
||||
|
||||
/*type UserBlockMsg struct {
|
||||
User string
|
||||
Miner string
|
||||
Index string
|
||||
Height int64
|
||||
Hash string
|
||||
Pow string
|
||||
Net_target string
|
||||
Submit string
|
||||
Success bool
|
||||
Accepts float64
|
||||
Rejects float64
|
||||
Reward float64
|
||||
Fee float64
|
||||
Nonce string
|
||||
SubIdx int64
|
||||
}*/
|
||||
/*
|
||||
type UserMinerContainer struct {
|
||||
Data map[string]string
|
||||
}*/
|
||||
|
||||
/*
|
||||
type UserObj struct {
|
||||
Server *ServerContext
|
||||
User string
|
||||
Name string
|
||||
|
||||
Normal int64
|
||||
Abnormal int64
|
||||
|
||||
Offline int64
|
||||
MhsZero int64
|
||||
MhsLow int64
|
||||
HighRejects int64
|
||||
Unstable int64
|
||||
|
||||
Submits int64
|
||||
Blocks int64
|
||||
Orphans int64
|
||||
|
||||
Reward float64
|
||||
Fee float64
|
||||
|
||||
Accepts5M float64
|
||||
Accepts15M float64
|
||||
Accepts30M float64
|
||||
Accepts1h float64
|
||||
Accepts3h float64
|
||||
Accepts6h float64
|
||||
Accepts12h float64
|
||||
Accepts24h float64
|
||||
Accepts48h float64
|
||||
|
||||
Rejects5M float64
|
||||
Rejects15M float64
|
||||
Rejects30M float64
|
||||
Rejects1h float64
|
||||
Rejects3h float64
|
||||
Rejects6h float64
|
||||
Rejects12h float64
|
||||
Rejects24h float64
|
||||
Rejects48h float64
|
||||
|
||||
Mhs5M float64
|
||||
Mhs15M float64
|
||||
Mhs30M float64
|
||||
Mhs1h float64
|
||||
Mhs3h float64
|
||||
Mhs6h float64
|
||||
Mhs12h float64
|
||||
Mhs24h float64
|
||||
Mhs48h float64
|
||||
|
||||
RejectRatio5M float64
|
||||
RejectRatio15M float64
|
||||
RejectRatio30M float64
|
||||
RejectRatio1h float64
|
||||
RejectRatio3h float64
|
||||
RejectRatio6h float64
|
||||
RejectRatio12h float64
|
||||
RejectRatio24h float64
|
||||
RejectRatio48h float64
|
||||
}*/
|
||||
|
||||
func md5md5(v string) string {
|
||||
md5Obj := md5.New()
|
||||
md5Obj.Write([]byte(v))
|
||||
char := md5Obj.Sum(nil)
|
||||
return hex.EncodeToString(char)
|
||||
}
|
||||
|
||||
func Guid() string {
|
||||
c := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand.Reader, c); err != nil {
|
||||
return ""
|
||||
}
|
||||
return md5md5(base64.URLEncoding.EncodeToString(c))
|
||||
}
|
||||
|
||||
func VarAdjustDifficulty(miner *MinerObj, adjust int) {
|
||||
if adjust != UP_DIFF && adjust != DOWN_DIFF && adjust != UPDATE_DIFF {
|
||||
miner.Server.Logg.Error("[server]", zap.Int("Not support adjust ", adjust))
|
||||
return
|
||||
}
|
||||
if adjust == UP_DIFF {
|
||||
miner.DifficultyNext = miner.Difficulty
|
||||
if miner.VarDiffOpt.Level == Mid {
|
||||
miner.DifficultyNext *= math.Pow(2, 1)
|
||||
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
|
||||
} else if miner.VarDiffOpt.Level == Hign {
|
||||
miner.DifficultyNext *= math.Pow(2, 2)
|
||||
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
|
||||
}
|
||||
} else if adjust == DOWN_DIFF {
|
||||
miner.DifficultyNext = miner.Difficulty
|
||||
if miner.VarDiffOpt.Level == Mid {
|
||||
miner.DifficultyNext /= math.Pow(2, 1)
|
||||
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
|
||||
} else if miner.VarDiffOpt.Level == Hign {
|
||||
miner.DifficultyNext /= math.Pow(2, 2)
|
||||
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
|
||||
}
|
||||
} else if adjust == UPDATE_DIFF {
|
||||
if miner.VarDiffOpt.SubmitShares > 0 {
|
||||
// re-target if outside bounds
|
||||
if miner.VarDiffOpt.SubmitShares < miner.VarDiffOpt.MinShares || miner.VarDiffOpt.SubmitShares > miner.VarDiffOpt.MaxShares {
|
||||
var change float64 = miner.VarDiffOpt.SubmitShares / miner.VarDiffOpt.TargetShares
|
||||
miner.DifficultyNext = miner.Difficulty
|
||||
miner.DifficultyNext *= change
|
||||
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
|
||||
}
|
||||
miner.VarDiffOpt.SilenceCount = 0
|
||||
} else {
|
||||
// radical measures if there were no shares submitted
|
||||
miner.VarDiffOpt.SilenceCount++
|
||||
miner.DifficultyNext = miner.Difficulty / math.Pow(2, miner.VarDiffOpt.SilenceCount)
|
||||
miner.DifficultyNext = math.Round(miner.DifficultyNext*1000) / 1000
|
||||
}
|
||||
}
|
||||
|
||||
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.TargetShares = miner.VarDiffOpt.AdjustTime / miner.VarDiffOpt.AdjustInterval * miner.DifficultyNext
|
||||
miner.VarDiffOpt.MinShares = miner.VarDiffOpt.AdjustTime / miner.VarDiffOpt.AdjustInterval * miner.DifficultyNext * (1 - miner.VarDiffOpt.VariancePercent)
|
||||
miner.VarDiffOpt.MaxShares = miner.VarDiffOpt.AdjustTime / miner.VarDiffOpt.AdjustInterval * miner.DifficultyNext * (1 + miner.VarDiffOpt.VariancePercent)
|
||||
miner.VarDiffOpt.SubmitShares = 0
|
||||
miner.VarDiffOpt.Uptimes = 0
|
||||
miner.VarDiffOpt.Downtimes = 0
|
||||
miner.Server.Logg.Info("[server]", zap.Float64("DifficultyNext", miner.DifficultyNext))
|
||||
miner.Server.Logg.Info("[server]", zap.Float64("TargetShares", miner.VarDiffOpt.TargetShares), zap.Float64("MinShares", miner.VarDiffOpt.MinShares), zap.Float64("MaxShares", miner.VarDiffOpt.MaxShares))
|
||||
|
||||
now := time.Now()
|
||||
share_interval := now.Sub(miner.LastSubmitime).Seconds()
|
||||
New_diff_into_db(miner.User, miner.Miner, fmt.Sprint(miner.MinerIndex), miner.Difficulty, miner.DifficultyNext, miner.VarDiffOpt.SubmitShares, share_interval, miner.VarDiffOpt.MinShares, miner.VarDiffOpt.MaxShares)
|
||||
}
|
||||
|
||||
var gdiff_db *sql.DB
|
||||
|
||||
func Init_diff_db() {
|
||||
db, err := sql.Open("sqlite3", "./diffs.db")
|
||||
if err != nil {
|
||||
log.Printf("Error opening database: %v", err)
|
||||
return
|
||||
}
|
||||
//defer db.Close()
|
||||
|
||||
gdiff_db = db
|
||||
|
||||
createTableSQL := `
|
||||
CREATE TABLE IF NOT EXISTS diffs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ts TEXT NOT NULL,
|
||||
user TEXT NOT NULL,
|
||||
miner TEXT NOT NULL,
|
||||
minerid TEXT NOT NULL,
|
||||
diff REAL NOT NULL,
|
||||
next REAL NOT NULL,
|
||||
kp REAL NOT NULL,
|
||||
interval REAL NOT NULL,
|
||||
mhs REAL NOT NULL,
|
||||
mhs_est REAL NOT NULL
|
||||
);`
|
||||
_, err = gdiff_db.Exec(createTableSQL)
|
||||
if err != nil {
|
||||
log.Printf("Error creating table: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func New_diff_into_db(user string, miner string, minerid string, diff float64, diff_next float64, kp float64, interval float64, mhs float64, mhs_est float64) {
|
||||
if gdiff_db != nil {
|
||||
insertSQL := `INSERT INTO diffs (ts, user, miner, minerid, diff, next, kp, interval, mhs, mhs_est) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
_, err := gdiff_db.Exec(insertSQL, time.Now().Format("2006-01-02 15:04:05"), user, miner, minerid, diff, diff_next, kp, interval, mhs, mhs_est)
|
||||
if err != nil {
|
||||
log.Printf("Error inserting data from diffs %s: %v", user+"."+miner+"_"+minerid, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func DiffStop() {
|
||||
if gdiff_db != nil {
|
||||
defer gdiff_db.Close()
|
||||
}
|
||||
}
|
||||
1224
internal/server/dbif/dbif.go
Normal file
1224
internal/server/dbif/dbif.go
Normal file
File diff suppressed because it is too large
Load Diff
170
internal/server/diff/diff.go
Normal file
170
internal/server/diff/diff.go
Normal file
@@ -0,0 +1,170 @@
|
||||
// diff.go
|
||||
package diff
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type KalmanVarDiff struct {
|
||||
Kf *KalmanFilter
|
||||
|
||||
StartDiff float64
|
||||
MinDiff float64
|
||||
MaxDiff float64
|
||||
|
||||
TargetInterval float64
|
||||
|
||||
MhsEst float64
|
||||
DiffEst float64
|
||||
}
|
||||
|
||||
type KalmanFilter struct {
|
||||
X float64 // 估计的状态
|
||||
P float64 // 状态协方差
|
||||
F float64 // 状态转移矩阵
|
||||
H float64 // 观测矩阵
|
||||
Q float64 // 过程噪声协方差
|
||||
R float64 // 观测噪声协方差
|
||||
K float64 // 卡尔曼增益
|
||||
}
|
||||
|
||||
func NewKalmanFilter(init_mhs float64, init_state_p float64) *KalmanFilter {
|
||||
x := init_mhs
|
||||
p := init_state_p
|
||||
f := 1.0
|
||||
h := 1.0
|
||||
q := 0.01
|
||||
r := init_mhs * 3
|
||||
//r := 1.0
|
||||
return &KalmanFilter{
|
||||
X: x,
|
||||
P: p,
|
||||
F: f,
|
||||
H: h,
|
||||
Q: q,
|
||||
R: r,
|
||||
}
|
||||
/*
|
||||
return &KalmanFilter{
|
||||
X: 1.0,
|
||||
P: 1.0,
|
||||
F: 1.0,
|
||||
H: 1.0,
|
||||
Q: 0.1,
|
||||
R: 1.0,
|
||||
}*/
|
||||
}
|
||||
|
||||
func (kf *KalmanFilter) Update(measurement float64) (float64, float64) {
|
||||
kf.R = measurement * 2
|
||||
|
||||
// 预测
|
||||
p := kf.X*kf.Q + kf.P
|
||||
|
||||
// 计算卡尔曼增益
|
||||
kf.K = p / (p + kf.R + 1)
|
||||
|
||||
// 更新状态估计
|
||||
if measurement >= kf.X {
|
||||
kf.X = kf.X + kf.K*(measurement-kf.X)
|
||||
} else {
|
||||
kf.X = kf.X - kf.K*(kf.X-measurement)
|
||||
}
|
||||
|
||||
// 更新协方差矩阵
|
||||
kf.P = (1 - kf.K) * p
|
||||
|
||||
// 自适应调整过程噪声和观测噪声
|
||||
//kf.adapt()
|
||||
|
||||
return kf.X, kf.P
|
||||
}
|
||||
|
||||
func (kf *KalmanFilter) adapt() {
|
||||
// 自适应调整参数
|
||||
if kf.P > 10.0 {
|
||||
kf.Q *= 1.1 // 增加过程噪声
|
||||
} else {
|
||||
kf.Q *= 0.9 // 减少过程噪声
|
||||
}
|
||||
if kf.K > 0.5 {
|
||||
kf.R *= 1.1 // 增加观测噪声
|
||||
} else {
|
||||
kf.R *= 0.9 // 减少观测噪声
|
||||
}
|
||||
}
|
||||
|
||||
func (kd *KalmanVarDiff) Init(startDiff float64, minDiff float64, maxDiff float64, targetTime float64) {
|
||||
kd.StartDiff = startDiff
|
||||
kd.MinDiff = minDiff
|
||||
kd.MaxDiff = maxDiff
|
||||
kd.TargetInterval = targetTime
|
||||
kd.DiffEst = startDiff
|
||||
kd.MhsEst = startDiff / targetTime
|
||||
kd.Kf = NewKalmanFilter(startDiff/targetTime, 1.0)
|
||||
}
|
||||
|
||||
func (kd *KalmanVarDiff) DeInit() {
|
||||
|
||||
}
|
||||
|
||||
// 提取科学计数法有效数字(整数部分和一位小数)及指数,并合并为新的浮点数
|
||||
func extractAndCombine(num float64) float64 {
|
||||
// 将浮点数格式化为科学计数法
|
||||
scientificStr := fmt.Sprintf("%.10e", num)
|
||||
|
||||
// 分离小数部分和指数部分
|
||||
parts := strings.Split(scientificStr, "e")
|
||||
if len(parts) != 2 {
|
||||
fmt.Println("Error: unexpected scientific notation format")
|
||||
return 0
|
||||
}
|
||||
|
||||
// 处理小数部分
|
||||
decimalPart := parts[0]
|
||||
exponentPart := parts[1]
|
||||
|
||||
// 去除小数部分前的 "0."
|
||||
decimalPart = strings.TrimPrefix(decimalPart, "0.")
|
||||
|
||||
// 提取整数部分和一位小数
|
||||
decimalParts := strings.Split(decimalPart, ".")
|
||||
if len(decimalParts) < 2 {
|
||||
decimalPart = decimalParts[0] + ".0" // 没有小数部分时,添加 ".0"
|
||||
} else {
|
||||
decimalPart = decimalParts[0] + "." + decimalParts[1][:1] // 只取一位小数
|
||||
//decimalPart = decimalParts[0]
|
||||
}
|
||||
|
||||
// 将指数部分转换为整数
|
||||
exponent, err := strconv.Atoi(exponentPart)
|
||||
if err != nil {
|
||||
fmt.Println("Error parsing exponent:", err)
|
||||
return 0
|
||||
}
|
||||
|
||||
// 计算新的浮点数
|
||||
newNumber := (func() float64 {
|
||||
digit, err := strconv.ParseFloat(decimalPart, 64)
|
||||
if err != nil {
|
||||
fmt.Println("Error parsing decimal part:", err)
|
||||
return 0
|
||||
}
|
||||
return digit * math.Pow(10, float64(exponent))
|
||||
})()
|
||||
|
||||
return newNumber
|
||||
}
|
||||
|
||||
func (kd *KalmanVarDiff) Handler(diff float64, interval float64) (float64, float64) {
|
||||
//newx, newp := kd.Kf.Update(kd.DiffEst / interval)
|
||||
newx, newp := kd.Kf.Update(diff / interval)
|
||||
kd.MhsEst = newx
|
||||
newdiff := newx * kd.TargetInterval
|
||||
kd.DiffEst = newdiff
|
||||
newdiff2 := extractAndCombine(newdiff)
|
||||
return newdiff2, newp
|
||||
}
|
||||
14
internal/server/include/nexaapi.h
Normal file
14
internal/server/include/nexaapi.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef NEXAAPI_H
|
||||
#define NEXAAPI_H
|
||||
#include <stdbool.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool nexa_hash( unsigned char *out, unsigned char *in);
|
||||
bool nexa_hash12( unsigned char *out, unsigned char *in);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
288
internal/server/include/randomx.h
Normal file
288
internal/server/include/randomx.h
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
Copyright (c) 2018-2019, tevador <tevador@gmail.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RANDOMX_H
|
||||
#define RANDOMX_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define RANDOMX_HASH_SIZE 32
|
||||
#define RANDOMX_DATASET_ITEM_SIZE 64
|
||||
|
||||
#ifndef RANDOMX_EXPORT
|
||||
#define RANDOMX_EXPORT
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
RANDOMX_FLAG_DEFAULT = 0,
|
||||
RANDOMX_FLAG_LARGE_PAGES = 1,
|
||||
RANDOMX_FLAG_HARD_AES = 2,
|
||||
RANDOMX_FLAG_FULL_MEM = 4,
|
||||
RANDOMX_FLAG_JIT = 8,
|
||||
RANDOMX_FLAG_SECURE = 16,
|
||||
RANDOMX_FLAG_ARGON2_SSSE3 = 32,
|
||||
RANDOMX_FLAG_ARGON2_AVX2 = 64,
|
||||
RANDOMX_FLAG_ARGON2 = 96
|
||||
} randomx_flags;
|
||||
|
||||
typedef struct randomx_dataset randomx_dataset;
|
||||
typedef struct randomx_cache randomx_cache;
|
||||
typedef struct randomx_vm randomx_vm;
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#ifdef __cpp_constexpr
|
||||
#define CONSTEXPR constexpr
|
||||
#else
|
||||
#define CONSTEXPR
|
||||
#endif
|
||||
|
||||
inline CONSTEXPR randomx_flags operator |(randomx_flags a, randomx_flags b) {
|
||||
return static_cast<randomx_flags>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
inline CONSTEXPR randomx_flags operator &(randomx_flags a, randomx_flags b) {
|
||||
return static_cast<randomx_flags>(static_cast<int>(a) & static_cast<int>(b));
|
||||
}
|
||||
inline randomx_flags& operator |=(randomx_flags& a, randomx_flags b) {
|
||||
return a = a | b;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @return The recommended flags to be used on the current machine.
|
||||
* Does not include:
|
||||
* RANDOMX_FLAG_LARGE_PAGES
|
||||
* RANDOMX_FLAG_FULL_MEM
|
||||
* RANDOMX_FLAG_SECURE
|
||||
* These flags must be added manually if desired.
|
||||
* On OpenBSD RANDOMX_FLAG_SECURE is enabled by default in JIT mode as W^X is enforced by the OS.
|
||||
*/
|
||||
RANDOMX_EXPORT randomx_flags randomx_get_flags(void);
|
||||
|
||||
/**
|
||||
* Creates a randomx_cache structure and allocates memory for RandomX Cache.
|
||||
*
|
||||
* @param flags is any combination of these 2 flags (each flag can be set or not set):
|
||||
* RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages
|
||||
* RANDOMX_FLAG_JIT - create cache structure with JIT compilation support; this makes
|
||||
* subsequent Dataset initialization faster
|
||||
* Optionally, one of these two flags may be selected:
|
||||
* RANDOMX_FLAG_ARGON2_SSSE3 - optimized Argon2 for CPUs with the SSSE3 instruction set
|
||||
* makes subsequent cache initialization faster
|
||||
* RANDOMX_FLAG_ARGON2_AVX2 - optimized Argon2 for CPUs with the AVX2 instruction set
|
||||
* makes subsequent cache initialization faster
|
||||
*
|
||||
* @return Pointer to an allocated randomx_cache structure.
|
||||
* Returns NULL if:
|
||||
* (1) memory allocation fails
|
||||
* (2) the RANDOMX_FLAG_JIT is set and JIT compilation is not supported on the current platform
|
||||
* (3) an invalid or unsupported RANDOMX_FLAG_ARGON2 value is set
|
||||
*/
|
||||
RANDOMX_EXPORT randomx_cache *randomx_alloc_cache(randomx_flags flags);
|
||||
|
||||
/**
|
||||
* Initializes the cache memory and SuperscalarHash using the provided key value.
|
||||
* Does nothing if called again with the same key value.
|
||||
*
|
||||
* @param cache is a pointer to a previously allocated randomx_cache structure. Must not be NULL.
|
||||
* @param key is a pointer to memory which contains the key value. Must not be NULL.
|
||||
* @param keySize is the number of bytes of the key.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_init_cache(randomx_cache *cache, const void *key, size_t keySize);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the internal memory buffer of the cache structure. The size
|
||||
* of the internal memory buffer is RANDOMX_ARGON_MEMORY KiB.
|
||||
*
|
||||
* @param cache is a pointer to a previously allocated randomx_cache structure. Must not be NULL.
|
||||
*
|
||||
* @return Pointer to the internal memory buffer of the cache structure.
|
||||
*/
|
||||
RANDOMX_EXPORT void *randomx_get_cache_memory(randomx_cache *cache);
|
||||
|
||||
/**
|
||||
* Releases all memory occupied by the randomx_cache structure.
|
||||
*
|
||||
* @param cache is a pointer to a previously allocated randomx_cache structure.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_release_cache(randomx_cache* cache);
|
||||
|
||||
/**
|
||||
* Creates a randomx_dataset structure and allocates memory for RandomX Dataset.
|
||||
*
|
||||
* @param flags is the initialization flags. Only one flag is supported (can be set or not set):
|
||||
* RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages
|
||||
*
|
||||
* @return Pointer to an allocated randomx_dataset structure.
|
||||
* NULL is returned if memory allocation fails.
|
||||
*/
|
||||
RANDOMX_EXPORT randomx_dataset *randomx_alloc_dataset(randomx_flags flags);
|
||||
|
||||
/**
|
||||
* Gets the number of items contained in the dataset.
|
||||
*
|
||||
* @return the number of items contained in the dataset.
|
||||
*/
|
||||
RANDOMX_EXPORT unsigned long randomx_dataset_item_count(void);
|
||||
|
||||
/**
|
||||
* Initializes dataset items.
|
||||
*
|
||||
* Note: In order to use the Dataset, all items from 0 to (randomx_dataset_item_count() - 1) must be initialized.
|
||||
* This may be done by several calls to this function using non-overlapping item sequences.
|
||||
*
|
||||
* @param dataset is a pointer to a previously allocated randomx_dataset structure. Must not be NULL.
|
||||
* @param cache is a pointer to a previously allocated and initialized randomx_cache structure. Must not be NULL.
|
||||
* @param startItem is the item number where initialization should start.
|
||||
* @param itemCount is the number of items that should be initialized.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_init_dataset(randomx_dataset *dataset, randomx_cache *cache, unsigned long startItem, unsigned long itemCount);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the internal memory buffer of the dataset structure. The size
|
||||
* of the internal memory buffer is randomx_dataset_item_count() * RANDOMX_DATASET_ITEM_SIZE.
|
||||
*
|
||||
* @param dataset is a pointer to a previously allocated randomx_dataset structure. Must not be NULL.
|
||||
*
|
||||
* @return Pointer to the internal memory buffer of the dataset structure.
|
||||
*/
|
||||
RANDOMX_EXPORT void *randomx_get_dataset_memory(randomx_dataset *dataset);
|
||||
|
||||
/**
|
||||
* Releases all memory occupied by the randomx_dataset structure.
|
||||
*
|
||||
* @param dataset is a pointer to a previously allocated randomx_dataset structure.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_release_dataset(randomx_dataset *dataset);
|
||||
|
||||
/**
|
||||
* Creates and initializes a RandomX virtual machine.
|
||||
*
|
||||
* @param flags is any combination of these 5 flags (each flag can be set or not set):
|
||||
* RANDOMX_FLAG_LARGE_PAGES - allocate scratchpad memory in large pages
|
||||
* RANDOMX_FLAG_HARD_AES - virtual machine will use hardware accelerated AES
|
||||
* RANDOMX_FLAG_FULL_MEM - virtual machine will use the full dataset
|
||||
* RANDOMX_FLAG_JIT - virtual machine will use a JIT compiler
|
||||
* RANDOMX_FLAG_SECURE - when combined with RANDOMX_FLAG_JIT, the JIT pages are never
|
||||
* writable and executable at the same time (W^X policy)
|
||||
* The numeric values of the first 4 flags are ordered so that a higher value will provide
|
||||
* faster hash calculation and a lower numeric value will provide higher portability.
|
||||
* Using RANDOMX_FLAG_DEFAULT (all flags not set) works on all platforms, but is the slowest.
|
||||
* @param cache is a pointer to an initialized randomx_cache structure. Can be
|
||||
* NULL if RANDOMX_FLAG_FULL_MEM is set.
|
||||
* @param dataset is a pointer to a randomx_dataset structure. Can be NULL
|
||||
* if RANDOMX_FLAG_FULL_MEM is not set.
|
||||
*
|
||||
* @return Pointer to an initialized randomx_vm structure.
|
||||
* Returns NULL if:
|
||||
* (1) Scratchpad memory allocation fails.
|
||||
* (2) The requested initialization flags are not supported on the current platform.
|
||||
* (3) cache parameter is NULL and RANDOMX_FLAG_FULL_MEM is not set
|
||||
* (4) dataset parameter is NULL and RANDOMX_FLAG_FULL_MEM is set
|
||||
*/
|
||||
RANDOMX_EXPORT randomx_vm *randomx_create_vm(randomx_flags flags, randomx_cache *cache, randomx_dataset *dataset);
|
||||
|
||||
/**
|
||||
* Reinitializes a virtual machine with a new Cache. This function should be called anytime
|
||||
* the Cache is reinitialized with a new key. Does nothing if called with a Cache containing
|
||||
* the same key value as already set.
|
||||
*
|
||||
* @param machine is a pointer to a randomx_vm structure that was initialized
|
||||
* without RANDOMX_FLAG_FULL_MEM. Must not be NULL.
|
||||
* @param cache is a pointer to an initialized randomx_cache structure. Must not be NULL.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_vm_set_cache(randomx_vm *machine, randomx_cache* cache);
|
||||
|
||||
/**
|
||||
* Reinitializes a virtual machine with a new Dataset.
|
||||
*
|
||||
* @param machine is a pointer to a randomx_vm structure that was initialized
|
||||
* with RANDOMX_FLAG_FULL_MEM. Must not be NULL.
|
||||
* @param dataset is a pointer to an initialized randomx_dataset structure. Must not be NULL.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_vm_set_dataset(randomx_vm *machine, randomx_dataset *dataset);
|
||||
|
||||
/**
|
||||
* Releases all memory occupied by the randomx_vm structure.
|
||||
*
|
||||
* @param machine is a pointer to a previously created randomx_vm structure.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_destroy_vm(randomx_vm *machine);
|
||||
|
||||
/**
|
||||
* Calculates a RandomX hash value.
|
||||
*
|
||||
* @param machine is a pointer to a randomx_vm structure. Must not be NULL.
|
||||
* @param input is a pointer to memory to be hashed. Must not be NULL.
|
||||
* @param inputSize is the number of bytes to be hashed.
|
||||
* @param output is a pointer to memory where the hash will be stored. Must not
|
||||
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *input, size_t inputSize, void *output);
|
||||
|
||||
/**
|
||||
* Set of functions used to calculate multiple RandomX hashes more efficiently.
|
||||
* randomx_calculate_hash_first will begin a hash calculation.
|
||||
* randomx_calculate_hash_next will output the hash value of the previous input
|
||||
* and begin the calculation of the next hash.
|
||||
* randomx_calculate_hash_last will output the hash value of the previous input.
|
||||
*
|
||||
* WARNING: These functions may alter the floating point rounding mode of the calling thread.
|
||||
*
|
||||
* @param machine is a pointer to a randomx_vm structure. Must not be NULL.
|
||||
* @param input is a pointer to memory to be hashed. Must not be NULL.
|
||||
* @param inputSize is the number of bytes to be hashed.
|
||||
* @param nextInput is a pointer to memory to be hashed for the next hash. Must not be NULL.
|
||||
* @param nextInputSize is the number of bytes to be hashed for the next hash.
|
||||
* @param output is a pointer to memory where the hash will be stored. Must not
|
||||
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_first(randomx_vm* machine, const void* input, size_t inputSize);
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize, void* output);
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_last(randomx_vm* machine, void* output);
|
||||
|
||||
/**
|
||||
* Calculate a RandomX commitment from a RandomX hash and its input.
|
||||
*
|
||||
* @param input is a pointer to memory that was hashed. Must not be NULL.
|
||||
* @param inputSize is the number of bytes in the input.
|
||||
* @param hash_in is the output from randomx_calculate_hash* (RANDOMX_HASH_SIZE bytes).
|
||||
* @param com_out is a pointer to memory where the commitment will be stored. Must not
|
||||
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_calculate_commitment(const void* input, size_t inputSize, const void* hash_in, void* com_out);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
4
internal/server/include/sha3xapi.h
Normal file
4
internal/server/include/sha3xapi.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifndef SHA3X_API_H
|
||||
#define SHA3X_API_H
|
||||
void sha3x_hash(unsigned char * out, unsigned char * in);
|
||||
#endif
|
||||
BIN
internal/server/lib/libnexa.so
Normal file
BIN
internal/server/lib/libnexa.so
Normal file
Binary file not shown.
BIN
internal/server/lib/libnexa12B.so
Normal file
BIN
internal/server/lib/libnexa12B.so
Normal file
Binary file not shown.
BIN
internal/server/lib/libnexa16B.so
Normal file
BIN
internal/server/lib/libnexa16B.so
Normal file
Binary file not shown.
BIN
internal/server/lib/librandomx.so
Normal file
BIN
internal/server/lib/librandomx.so
Normal file
Binary file not shown.
BIN
internal/server/lib/libsha3x.a
Normal file
BIN
internal/server/lib/libsha3x.a
Normal file
Binary file not shown.
117
internal/server/monero/hash_randomx.go
Normal file
117
internal/server/monero/hash_randomx.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package monero
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I/home/lizixuan/桌面/tari-server/internal/server/include
|
||||
#cgo LDFLAGS: -L/home/lizixuan/桌面/tari-server/internal/server/lib/randomx -lrandomx
|
||||
#include <randomx.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
type RandomXValidator struct {
|
||||
cache *C.randomx_cache
|
||||
vm *C.randomx_vm
|
||||
flags C.randomx_flags
|
||||
seed []byte
|
||||
}
|
||||
|
||||
// NewRandomXValidator 初始化 cache + vm
|
||||
func NewRandomXValidator(seed []byte) (*RandomXValidator, error) {
|
||||
if len(seed) != 32 {
|
||||
return nil, fmt.Errorf("seed must be 32 bytes")
|
||||
}
|
||||
|
||||
var flags C.randomx_flags = 0
|
||||
|
||||
// 检测 AES-NI 支持
|
||||
if cpu.X86.HasAES {
|
||||
flags |= C.RANDOMX_FLAG_HARD_AES
|
||||
} else {
|
||||
fmt.Println("[RandomX] CPU 不支持 AES-NI,将使用纯软件模式")
|
||||
}
|
||||
|
||||
// ⚠️ 默认启用 JIT(如果系统禁止会报错)
|
||||
flags |= C.RANDOMX_FLAG_JIT
|
||||
|
||||
// 分配 cache
|
||||
cache := C.randomx_alloc_cache(flags)
|
||||
if cache == nil {
|
||||
return nil, fmt.Errorf("failed to alloc cache")
|
||||
}
|
||||
C.randomx_init_cache(cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
|
||||
|
||||
// 创建 vm
|
||||
vm := C.randomx_create_vm(flags, cache, nil)
|
||||
if vm == nil {
|
||||
C.randomx_release_cache(cache)
|
||||
return nil, fmt.Errorf("failed to create randomx vm")
|
||||
}
|
||||
|
||||
return &RandomXValidator{
|
||||
cache: cache,
|
||||
vm: vm,
|
||||
flags: flags,
|
||||
seed: append([]byte{}, seed...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetSeed 更新 seed(替换 cache,并重置 vm)
|
||||
func (v *RandomXValidator) SetSeed(seed []byte) error {
|
||||
if len(seed) != 32 {
|
||||
return fmt.Errorf("seed must be 32 bytes")
|
||||
}
|
||||
|
||||
// 如果相同 seed,不用更新
|
||||
if string(seed) == string(v.seed) {
|
||||
return nil
|
||||
}
|
||||
|
||||
C.randomx_init_cache(v.cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
|
||||
C.randomx_vm_set_cache(v.vm, v.cache)
|
||||
|
||||
v.seed = append(v.seed[:0], seed...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroy 释放 vm + cache
|
||||
func (v *RandomXValidator) Destroy() {
|
||||
if v.vm != nil {
|
||||
C.randomx_destroy_vm(v.vm)
|
||||
v.vm = nil
|
||||
}
|
||||
if v.cache != nil {
|
||||
C.randomx_release_cache(v.cache)
|
||||
v.cache = nil
|
||||
}
|
||||
}
|
||||
|
||||
// BuildPowHash 计算区块哈希
|
||||
func (v *RandomXValidator) BuildPowHash(blockBlob, nonce []byte) ([]byte, []byte, error) {
|
||||
if v.vm == nil {
|
||||
return nil, nil, fmt.Errorf("vm is nil")
|
||||
}
|
||||
|
||||
if len(nonce) != 4 {
|
||||
return nil, nil, fmt.Errorf("nonce must be 4 bytes")
|
||||
}
|
||||
blockHeader := make([]byte, len(blockBlob))
|
||||
copy(blockHeader, blockBlob)
|
||||
copy(blockHeader[39:43], nonce)
|
||||
var hash [32]byte
|
||||
C.randomx_calculate_hash(v.vm,
|
||||
unsafe.Pointer(&blockHeader[0]),
|
||||
C.size_t(len(blockHeader)),
|
||||
unsafe.Pointer(&hash[0]),
|
||||
)
|
||||
|
||||
return hash[:], blockHeader, nil
|
||||
}
|
||||
756
internal/server/monero/monero.go
Normal file
756
internal/server/monero/monero.go
Normal file
@@ -0,0 +1,756 @@
|
||||
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)
|
||||
|
||||
// Index(uint32 → 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
|
||||
}
|
||||
61
internal/server/nexa/hash_nexa.go
Normal file
61
internal/server/nexa/hash_nexa.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// hash_nexa.go
|
||||
package nexa
|
||||
|
||||
/*
|
||||
#cgo CFLAGS : -I../include
|
||||
#cgo LDFLAGS: -L../lib -lnexa
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "nexaapi.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
//"encoding/hex"
|
||||
//"log"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func BuildPowHash(h NexaBlockHeader) []byte {
|
||||
outputs := make([]byte, 32)
|
||||
inb := NexaBlockHeaderToBytes(h)
|
||||
//log.Println("[nexa]in", hex.EncodeToString(inb))
|
||||
in := (*C.uchar)(C.CBytes(inb))
|
||||
output := (*C.uchar)(C.malloc(32))
|
||||
C.nexa_hash(output, in)
|
||||
p := uintptr(unsafe.Pointer(output))
|
||||
for i := 0; i < 32; i++ {
|
||||
j := *(*byte)(unsafe.Pointer(p))
|
||||
outputs[i] = j
|
||||
p += unsafe.Sizeof(j)
|
||||
}
|
||||
C.free(unsafe.Pointer(output))
|
||||
C.free(unsafe.Pointer(in))
|
||||
outputs32 := make([]byte, 32)
|
||||
for i := 0; i < 32; i++ {
|
||||
outputs32[i] = outputs[i]
|
||||
}
|
||||
return outputs32
|
||||
}
|
||||
|
||||
func BuildPowHash12(h NexaBlockHeader12) []byte {
|
||||
outputs := make([]byte, 32)
|
||||
inb := NexaBlockHeaderToBytes12(h)
|
||||
//log.Println("[nexa]in", hex.EncodeToString(inb))
|
||||
in := (*C.uchar)(C.CBytes(inb))
|
||||
output := (*C.uchar)(C.malloc(32))
|
||||
C.nexa_hash12(output, in)
|
||||
p := uintptr(unsafe.Pointer(output))
|
||||
for i := 0; i < 32; i++ {
|
||||
j := *(*byte)(unsafe.Pointer(p))
|
||||
outputs[i] = j
|
||||
p += unsafe.Sizeof(j)
|
||||
}
|
||||
C.free(unsafe.Pointer(output))
|
||||
C.free(unsafe.Pointer(in))
|
||||
outputs32 := make([]byte, 32)
|
||||
for i := 0; i < 32; i++ {
|
||||
outputs32[i] = outputs[i]
|
||||
}
|
||||
return outputs32
|
||||
}
|
||||
943
internal/server/nexa/nexa.go
Normal file
943
internal/server/nexa/nexa.go
Normal file
@@ -0,0 +1,943 @@
|
||||
// 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.0x"
|
||||
|
||||
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))
|
||||
if miner.ZlogInit {
|
||||
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
|
||||
}
|
||||
|
||||
phb, _ := hex.DecodeString(job.Header)
|
||||
nb, _ := hex.DecodeString(nonce)
|
||||
|
||||
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))*/)
|
||||
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(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))
|
||||
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)))
|
||||
}
|
||||
//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)))
|
||||
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())
|
||||
|
||||
/*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_miner_diff = job.JobDifficulty
|
||||
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()))
|
||||
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)
|
||||
}
|
||||
//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))
|
||||
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)))
|
||||
}
|
||||
|
||||
//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) {
|
||||
miner.NexaJob = miner.Server.NexaJob
|
||||
miner.NexaJob.Extranonce1 = miner.Job.Extranonce1
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
params[4] = true
|
||||
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 {
|
||||
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 := 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
|
||||
}
|
||||
117
internal/server/randomxT/hash_randomx.go
Normal file
117
internal/server/randomxT/hash_randomx.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package randomxT
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I/home/lizixuan/桌面/tari-server/internal/server/include
|
||||
#cgo LDFLAGS: -L/home/lizixuan/桌面/tari-server/internal/server/lib/randomx -lrandomx
|
||||
#include <randomx.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
type RandomXValidator struct {
|
||||
cache *C.randomx_cache
|
||||
vm *C.randomx_vm
|
||||
flags C.randomx_flags
|
||||
seed []byte
|
||||
}
|
||||
|
||||
// NewRandomXValidator 初始化 cache + vm
|
||||
func NewRandomXValidator(seed []byte) (*RandomXValidator, error) {
|
||||
if len(seed) != 32 {
|
||||
return nil, fmt.Errorf("seed must be 32 bytes")
|
||||
}
|
||||
|
||||
var flags C.randomx_flags = 0
|
||||
|
||||
// 检测 AES-NI 支持
|
||||
if cpu.X86.HasAES {
|
||||
flags |= C.RANDOMX_FLAG_HARD_AES
|
||||
} else {
|
||||
fmt.Println("[RandomX] CPU 不支持 AES-NI,将使用纯软件模式")
|
||||
}
|
||||
|
||||
// ⚠️ 默认启用 JIT(如果系统禁止会报错)
|
||||
flags |= C.RANDOMX_FLAG_JIT
|
||||
|
||||
// 分配 cache
|
||||
cache := C.randomx_alloc_cache(flags)
|
||||
if cache == nil {
|
||||
return nil, fmt.Errorf("failed to alloc cache")
|
||||
}
|
||||
C.randomx_init_cache(cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
|
||||
|
||||
// 创建 vm
|
||||
vm := C.randomx_create_vm(flags, cache, nil)
|
||||
if vm == nil {
|
||||
C.randomx_release_cache(cache)
|
||||
return nil, fmt.Errorf("failed to create randomx vm")
|
||||
}
|
||||
|
||||
return &RandomXValidator{
|
||||
cache: cache,
|
||||
vm: vm,
|
||||
flags: flags,
|
||||
seed: append([]byte{}, seed...),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetSeed 更新 seed(替换 cache,并重置 vm)
|
||||
func (v *RandomXValidator) SetSeed(seed []byte) error {
|
||||
if len(seed) != 32 {
|
||||
return fmt.Errorf("seed must be 32 bytes")
|
||||
}
|
||||
|
||||
// 如果相同 seed,不用更新
|
||||
if string(seed) == string(v.seed) {
|
||||
return nil
|
||||
}
|
||||
|
||||
C.randomx_init_cache(v.cache, unsafe.Pointer(&seed[0]), C.size_t(len(seed)))
|
||||
C.randomx_vm_set_cache(v.vm, v.cache)
|
||||
|
||||
v.seed = append(v.seed[:0], seed...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroy 释放 vm + cache
|
||||
func (v *RandomXValidator) Destroy() {
|
||||
if v.vm != nil {
|
||||
C.randomx_destroy_vm(v.vm)
|
||||
v.vm = nil
|
||||
}
|
||||
if v.cache != nil {
|
||||
C.randomx_release_cache(v.cache)
|
||||
v.cache = nil
|
||||
}
|
||||
}
|
||||
|
||||
// BuildPowHash 计算区块哈希
|
||||
func (v *RandomXValidator) BuildPowHash(blockBlob, nonce []byte) ([]byte, []byte, error) {
|
||||
if v.vm == nil {
|
||||
return nil, nil, fmt.Errorf("vm is nil")
|
||||
}
|
||||
|
||||
if len(nonce) != 4 {
|
||||
return nil, nil, fmt.Errorf("nonce must be 4 bytes")
|
||||
}
|
||||
blockHeader := make([]byte, len(blockBlob))
|
||||
copy(blockHeader, blockBlob)
|
||||
copy(blockHeader[39:43], nonce)
|
||||
var hash [32]byte
|
||||
C.randomx_calculate_hash(v.vm,
|
||||
unsafe.Pointer(&blockHeader[0]),
|
||||
C.size_t(len(blockHeader)),
|
||||
unsafe.Pointer(&hash[0]),
|
||||
)
|
||||
|
||||
return hash[:], blockHeader, nil
|
||||
}
|
||||
761
internal/server/randomxT/randomxT.go
Normal file
761
internal/server/randomxT/randomxT.go
Normal file
@@ -0,0 +1,761 @@
|
||||
// sha3x.go
|
||||
package randomxT
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
//"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_SHA3X_VERSION string = "sha3x v0.1a"
|
||||
|
||||
type Sha3xBlockHeader struct {
|
||||
Nonce [8]byte
|
||||
Header [32]byte
|
||||
Algo byte
|
||||
}
|
||||
|
||||
func Sha3xBlockHeaderToBytes(h Sha3xBlockHeader) []byte {
|
||||
out := make([]byte, 8+32+1)
|
||||
for i := 0; i < 8; i++ {
|
||||
out[i] = h.Nonce[i]
|
||||
}
|
||||
for i := 0; i < 32; i++ {
|
||||
out[8+i] = h.Header[i]
|
||||
}
|
||||
out[8+32] = h.Algo
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type ServerSha3xContext struct {
|
||||
ServerCtx *coin.ServerContext
|
||||
logg *zap.Logger
|
||||
|
||||
Sha3xJob msg.Sha3xStratumJob
|
||||
}
|
||||
|
||||
var logg *zap.Logger
|
||||
var ServerSha3xCtx ServerSha3xContext
|
||||
|
||||
type Sha3xNotify_params_msg struct {
|
||||
Algo string `json:"algo"`
|
||||
Blob string `json:"blob"`
|
||||
Height uint32 `json:"height"`
|
||||
Job_id string `json:"job_id"`
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
type Sha3xNotify_msg struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Method string `json:"method"`
|
||||
Params Sha3xNotify_params_msg `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.Sha3xStratumJob)
|
||||
|
||||
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))
|
||||
if miner.ZlogInit {
|
||||
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
|
||||
}
|
||||
|
||||
phb, _ := hex.DecodeString(job.Header)
|
||||
|
||||
nb, _ := hex.DecodeString(nonce)
|
||||
|
||||
var calc_hash []byte
|
||||
|
||||
var header Sha3xBlockHeader
|
||||
for i := 0; i < 8; i++ {
|
||||
header.Nonce[i] = nb[i]
|
||||
}
|
||||
for i := 0; i < 32; i++ {
|
||||
header.Header[i] = phb[i]
|
||||
}
|
||||
header.Algo = 1
|
||||
submit_item.Header = hex.EncodeToString(Sha3xBlockHeaderToBytes(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))*/)
|
||||
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(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 := utility.Target2Diff(utility.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))
|
||||
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)))
|
||||
}
|
||||
//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(Sha3xBlockHeaderToBytes(header))
|
||||
calc_hash = BuildPowHash(header)
|
||||
logg.Debug("[server]", zap.String("hash in", hex.EncodeToString(Sha3xBlockHeaderToBytes(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)))
|
||||
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())
|
||||
|
||||
/*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_miner_diff = job.JobDifficulty
|
||||
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) {
|
||||
//if true {
|
||||
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
|
||||
}
|
||||
if new_found && float64(miner.Server.Sha3xJob.U64target) <= 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.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()))
|
||||
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)
|
||||
}
|
||||
//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)
|
||||
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
|
||||
//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))
|
||||
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)))
|
||||
}
|
||||
|
||||
//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 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 Sha3xBlockHeader,*/, job *msg.Sha3xStratumJob, PowHash string, SubIdx int64) {
|
||||
var nm msg.BlockSha3xMsg
|
||||
nm.Id = job.Id
|
||||
nm.Header = job.Header
|
||||
//nm.Nonce = job.Nonce
|
||||
noncer, _ := stratum.ReverseHexStringByByte(job.Nonce)
|
||||
nonce, err := strconv.ParseUint(noncer, 16, 64)
|
||||
nm.Nonce = 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)*/
|
||||
nm.Height = (uint64)(job.Height)
|
||||
logg.Warn("[server]", zap.Uint32("Height", job.Height))
|
||||
|
||||
//Add SubmitIndex
|
||||
/*indexb := utility.Uint32ToByte(miner.SubmitIndex)
|
||||
indexs := hex.EncodeToString(indexb)
|
||||
blk += indexs
|
||||
var SubmitIndex uint32 = utility.ByteToUint32(indexb)*/
|
||||
nm.SubmitIdx = (uint64)(miner.SubmitIndex)
|
||||
logg.Info("[server]", zap.Uint32("SubmitIndex", miner.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("blksha3x"), []byte(blk)}
|
||||
err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blksha3x"), []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 sha3x_parse_miner_notify(miner *coin.MinerObj, msg msg.Sha3xStratumJob) int {
|
||||
if miner.Sha3xJob.Height != msg.Height {
|
||||
miner.Job.IsClean = true
|
||||
}
|
||||
miner.Sha3xJob = msg
|
||||
miner.Sha3xJob.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) {
|
||||
ServerSha3xCtx.ServerCtx = server
|
||||
logg = server.Logg
|
||||
logg.Info("[server]", zap.String("server_sha3x_version", SERVER_SHA3X_VERSION))
|
||||
coin.Init_diff_db()
|
||||
}
|
||||
|
||||
func Start() {
|
||||
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
coin.DiffStop()
|
||||
}
|
||||
|
||||
func InitMiner(miner *coin.MinerObj) {
|
||||
miner.Sha3xJob = miner.Server.Sha3xJob
|
||||
miner.Sha3xJob.Extranonce1 = miner.Job.Extranonce1
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 Sha3xNotify(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 Sha3xNotify_msg
|
||||
|
||||
idb := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(idb, miner.JobId)
|
||||
miner.Job.Job_id = hex.EncodeToString(idb)
|
||||
|
||||
msg.Params.Algo = "sha3x"
|
||||
msg.Params.Job_id = miner.Job.Job_id
|
||||
msg.Params.Blob = miner.Sha3xJob.Header
|
||||
msg.Params.Height = miner.Sha3xJob.Height
|
||||
//target_s, _ := stratum.ReverseHexStringByByte(miner.Sha3xJob.Target)
|
||||
//msg.Params.Target = target_s[48:]
|
||||
target_new, _ := utility.DiffToTarget(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 = miner.Sha3xJob.Height
|
||||
|
||||
miner.Sha3xJob.JobDifficulty = miner.Difficulty
|
||||
|
||||
miner.Jobs.LoadOrStore(miner.Job.Job_id, miner.Sha3xJob)
|
||||
|
||||
/*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
|
||||
|
||||
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.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) {
|
||||
Sha3xNotify(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 HandleJobMsg(server *coin.ServerContext, Msg []byte) {
|
||||
var result msg.Sha3xStratumJob
|
||||
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 = formatUint64ToHexWithPadding(result.U64target)
|
||||
|
||||
//target_new, _ := utility.DiffToTarget((float64)(result.U64target))
|
||||
//target_str := fmt.Sprintf("%064x", target_new.Bytes())
|
||||
//result.Target = target_str
|
||||
|
||||
server.Sha3xJob = msg.Sha3xStratumJob(result)
|
||||
logg.Debug("[gbt]", zap.String("Target", server.Sha3xJob.Target))
|
||||
|
||||
server.Sha3xJob.Extranonce2_size = 8
|
||||
server.SJob.Extranonce2_size = 8
|
||||
logg.Debug("[gbt]", zap.Uint32("Height", server.Sha3xJob.Height), zap.String("Target", server.Sha3xJob.Target), zap.String("Header", server.Sha3xJob.Header) /*, zap.Uint64("Timastamp", server.Sha3xJob.CurTime)*/)
|
||||
targetb, _ := hex.DecodeString(server.Sha3xJob.Target)
|
||||
logg.Debug("[gbt]", zap.Uint64("Id", server.Sha3xJob.Id), zap.Float64("network diff", utility.Target2Diff(utility.Reverse(targetb))))
|
||||
|
||||
server.NetHight = uint64(server.Sha3xJob.Height)
|
||||
server.NetTarget = server.Sha3xJob.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 := sha3x_parse_miner_notify(m, server.Sha3xJob)
|
||||
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
|
||||
Sha3xNotify(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func IsMhsLow(miner *coin.MinerObj) bool {
|
||||
if miner.Mhs5M < 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetBlockInterval() int {
|
||||
return 3600
|
||||
}
|
||||
1865
internal/server/server.go
Normal file
1865
internal/server/server.go
Normal file
File diff suppressed because it is too large
Load Diff
39
internal/server/sha3x/hash_sha3x.go
Normal file
39
internal/server/sha3x/hash_sha3x.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// hash_sha3x.go
|
||||
package sha3x
|
||||
|
||||
/*
|
||||
#cgo CFLAGS : -I../include
|
||||
#cgo LDFLAGS: -L../lib -lsha3x
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sha3xapi.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
//"encoding/hex"
|
||||
//"log"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func BuildPowHash(h Sha3xBlockHeader) []byte {
|
||||
outputs := make([]byte, 32)
|
||||
inb := Sha3xBlockHeaderToBytes(h)
|
||||
//log.Println("[sha3x]in", hex.EncodeToString(inb))
|
||||
in := (*C.uchar)(C.CBytes(inb))
|
||||
output := (*C.uchar)(C.malloc(32))
|
||||
C.sha3x_hash(output, in)
|
||||
p := uintptr(unsafe.Pointer(output))
|
||||
for i := 0; i < 32; i++ {
|
||||
j := *(*byte)(unsafe.Pointer(p))
|
||||
outputs[i] = j
|
||||
p += unsafe.Sizeof(j)
|
||||
}
|
||||
C.free(unsafe.Pointer(output))
|
||||
C.free(unsafe.Pointer(in))
|
||||
outputs32 := make([]byte, 32)
|
||||
for i := 0; i < 32; i++ {
|
||||
outputs32[i] = outputs[i]
|
||||
}
|
||||
return outputs32
|
||||
}
|
||||
761
internal/server/sha3x/sha3x.go
Normal file
761
internal/server/sha3x/sha3x.go
Normal file
@@ -0,0 +1,761 @@
|
||||
// sha3x.go
|
||||
package sha3x
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
//"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_SHA3X_VERSION string = "sha3x v0.1a"
|
||||
|
||||
type Sha3xBlockHeader struct {
|
||||
Nonce [8]byte
|
||||
Header [32]byte
|
||||
Algo byte
|
||||
}
|
||||
|
||||
func Sha3xBlockHeaderToBytes(h Sha3xBlockHeader) []byte {
|
||||
out := make([]byte, 8+32+1)
|
||||
for i := 0; i < 8; i++ {
|
||||
out[i] = h.Nonce[i]
|
||||
}
|
||||
for i := 0; i < 32; i++ {
|
||||
out[8+i] = h.Header[i]
|
||||
}
|
||||
out[8+32] = h.Algo
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type ServerSha3xContext struct {
|
||||
ServerCtx *coin.ServerContext
|
||||
logg *zap.Logger
|
||||
|
||||
Sha3xJob msg.Sha3xStratumJob
|
||||
}
|
||||
|
||||
var logg *zap.Logger
|
||||
var ServerSha3xCtx ServerSha3xContext
|
||||
|
||||
type Sha3xNotify_params_msg struct {
|
||||
Algo string `json:"algo"`
|
||||
Blob string `json:"blob"`
|
||||
Height uint32 `json:"height"`
|
||||
Job_id string `json:"job_id"`
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
type Sha3xNotify_msg struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Method string `json:"method"`
|
||||
Params Sha3xNotify_params_msg `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.Sha3xStratumJob)
|
||||
|
||||
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))
|
||||
if miner.ZlogInit {
|
||||
miner.Zlog.Info().Msg("height " + string(job.Height) + " target " + job.Target + " " + miner.User + "." + miner.Miner)
|
||||
}
|
||||
|
||||
phb, _ := hex.DecodeString(job.Header)
|
||||
|
||||
nb, _ := hex.DecodeString(nonce)
|
||||
|
||||
var calc_hash []byte
|
||||
|
||||
var header Sha3xBlockHeader
|
||||
for i := 0; i < 8; i++ {
|
||||
header.Nonce[i] = nb[i]
|
||||
}
|
||||
for i := 0; i < 32; i++ {
|
||||
header.Header[i] = phb[i]
|
||||
}
|
||||
header.Algo = 1
|
||||
submit_item.Header = hex.EncodeToString(Sha3xBlockHeaderToBytes(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))*/)
|
||||
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(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 := utility.Target2Diff(utility.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))
|
||||
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)))
|
||||
}
|
||||
//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(Sha3xBlockHeaderToBytes(header))
|
||||
calc_hash = BuildPowHash(header)
|
||||
logg.Debug("[server]", zap.String("hash in", hex.EncodeToString(Sha3xBlockHeaderToBytes(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)))
|
||||
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())
|
||||
|
||||
/*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_miner_diff = job.JobDifficulty
|
||||
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) {
|
||||
//if true {
|
||||
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
|
||||
}
|
||||
if new_found && float64(miner.Server.Sha3xJob.U64target) <= 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.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()))
|
||||
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)
|
||||
}
|
||||
//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)
|
||||
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
|
||||
//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))
|
||||
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)))
|
||||
}
|
||||
|
||||
//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 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 Sha3xBlockHeader,*/, job *msg.Sha3xStratumJob, PowHash string, SubIdx int64) {
|
||||
var nm msg.BlockSha3xMsg
|
||||
nm.Id = job.Id
|
||||
nm.Header = job.Header
|
||||
//nm.Nonce = job.Nonce
|
||||
noncer, _ := stratum.ReverseHexStringByByte(job.Nonce)
|
||||
nonce, err := strconv.ParseUint(noncer, 16, 64)
|
||||
nm.Nonce = 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)*/
|
||||
nm.Height = (uint64)(job.Height)
|
||||
logg.Warn("[server]", zap.Uint32("Height", job.Height))
|
||||
|
||||
//Add SubmitIndex
|
||||
/*indexb := utility.Uint32ToByte(miner.SubmitIndex)
|
||||
indexs := hex.EncodeToString(indexb)
|
||||
blk += indexs
|
||||
var SubmitIndex uint32 = utility.ByteToUint32(indexb)*/
|
||||
nm.SubmitIdx = (uint64)(miner.SubmitIndex)
|
||||
logg.Info("[server]", zap.Uint32("SubmitIndex", miner.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("blksha3x"), []byte(blk)}
|
||||
err := miner.Server.PubCh.SendMessage([][]byte{[]byte("blksha3x"), []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 sha3x_parse_miner_notify(miner *coin.MinerObj, msg msg.Sha3xStratumJob) int {
|
||||
if miner.Sha3xJob.Height != msg.Height {
|
||||
miner.Job.IsClean = true
|
||||
}
|
||||
miner.Sha3xJob = msg
|
||||
miner.Sha3xJob.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) {
|
||||
ServerSha3xCtx.ServerCtx = server
|
||||
logg = server.Logg
|
||||
logg.Info("[server]", zap.String("server_sha3x_version", SERVER_SHA3X_VERSION))
|
||||
coin.Init_diff_db()
|
||||
}
|
||||
|
||||
func Start() {
|
||||
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
coin.DiffStop()
|
||||
}
|
||||
|
||||
func InitMiner(miner *coin.MinerObj) {
|
||||
miner.Sha3xJob = miner.Server.Sha3xJob
|
||||
miner.Sha3xJob.Extranonce1 = miner.Job.Extranonce1
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 Sha3xNotify(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 Sha3xNotify_msg
|
||||
|
||||
idb := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(idb, miner.JobId)
|
||||
miner.Job.Job_id = hex.EncodeToString(idb)
|
||||
|
||||
msg.Params.Algo = "sha3x"
|
||||
msg.Params.Job_id = miner.Job.Job_id
|
||||
msg.Params.Blob = miner.Sha3xJob.Header
|
||||
msg.Params.Height = miner.Sha3xJob.Height
|
||||
//target_s, _ := stratum.ReverseHexStringByByte(miner.Sha3xJob.Target)
|
||||
//msg.Params.Target = target_s[48:]
|
||||
target_new, _ := utility.DiffToTarget(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 = miner.Sha3xJob.Height
|
||||
|
||||
miner.Sha3xJob.JobDifficulty = miner.Difficulty
|
||||
|
||||
miner.Jobs.LoadOrStore(miner.Job.Job_id, miner.Sha3xJob)
|
||||
|
||||
/*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
|
||||
|
||||
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.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) {
|
||||
Sha3xNotify(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 HandleJobMsg(server *coin.ServerContext, Msg []byte) {
|
||||
var result msg.Sha3xStratumJob
|
||||
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 = formatUint64ToHexWithPadding(result.U64target)
|
||||
|
||||
//target_new, _ := utility.DiffToTarget((float64)(result.U64target))
|
||||
//target_str := fmt.Sprintf("%064x", target_new.Bytes())
|
||||
//result.Target = target_str
|
||||
|
||||
server.Sha3xJob = msg.Sha3xStratumJob(result)
|
||||
logg.Debug("[gbt]", zap.String("Target", server.Sha3xJob.Target))
|
||||
|
||||
server.Sha3xJob.Extranonce2_size = 8
|
||||
server.SJob.Extranonce2_size = 8
|
||||
logg.Debug("[gbt]", zap.Uint32("Height", server.Sha3xJob.Height), zap.String("Target", server.Sha3xJob.Target), zap.String("Header", server.Sha3xJob.Header) /*, zap.Uint64("Timastamp", server.Sha3xJob.CurTime)*/)
|
||||
targetb, _ := hex.DecodeString(server.Sha3xJob.Target)
|
||||
logg.Debug("[gbt]", zap.Uint64("Id", server.Sha3xJob.Id), zap.Float64("network diff", utility.Target2Diff(utility.Reverse(targetb))))
|
||||
|
||||
server.NetHight = uint64(server.Sha3xJob.Height)
|
||||
server.NetTarget = server.Sha3xJob.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 := sha3x_parse_miner_notify(m, server.Sha3xJob)
|
||||
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
|
||||
Sha3xNotify(m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func IsMhsLow(miner *coin.MinerObj) bool {
|
||||
if miner.Mhs5M < 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetBlockInterval() int {
|
||||
return 3600
|
||||
}
|
||||
Reference in New Issue
Block a user