788 lines
19 KiB
Go
788 lines
19 KiB
Go
// coin.go
|
|
package coin
|
|
|
|
import (
|
|
"bytes"
|
|
"container/list"
|
|
"crypto/md5"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
|
|
"database/sql"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"strconv"
|
|
|
|
"io"
|
|
"log"
|
|
"math"
|
|
"math/big"
|
|
"net"
|
|
|
|
"fmt"
|
|
"pool/internal/db"
|
|
"pool/internal/msg"
|
|
"pool/internal/server/diff"
|
|
"pool/internal/utility"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/btcsuite/btcd/wire"
|
|
|
|
"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 = 60 //job expired time (second)
|
|
const LOCAL_JOBS_EXPIRED_TIME uint32 = 300 //300 //local jobs expired time (second)
|
|
const LOCAL_JOBS_TOTAL_SIZE uint32 = 300 //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
|
|
AlphJob msg.AlphStratumJob
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
|
|
Duration float64
|
|
|
|
Status string
|
|
ConnSetupTime time.Time
|
|
TxLock sync.Mutex
|
|
|
|
KeepliveCnt float64
|
|
RecvedLiveAck bool
|
|
PongFailCnt int
|
|
PingCnt int
|
|
|
|
NexaJob msg.NexaStratumJob
|
|
AlphJob msg.AlphStratumJob
|
|
|
|
//EndCh chan bool
|
|
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
|
|
}
|
|
|
|
/*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()
|
|
}
|
|
}
|
|
|
|
func Build_coinbase(coinbase1 string, extranonce1 string, extranonce2, coinbase2 string, doublehash bool) ([]byte, error) {
|
|
var coinbase_string string = coinbase1 + extranonce1 + extranonce2 + coinbase2
|
|
coinbase_bytes, err := hex.DecodeString(coinbase_string)
|
|
if err != nil {
|
|
//log.Println("[dash]failed to Build_coinbase", err)
|
|
return nil, err
|
|
}
|
|
//fmt.Println("coinbase", coinbase_string, hex.EncodeToString(coinbase_bytes))
|
|
var coinbase []byte
|
|
if doublehash {
|
|
coinbase = chainhash.DoubleHashB(coinbase_bytes)
|
|
} else {
|
|
coinbase = chainhash.HashB(coinbase_bytes)
|
|
}
|
|
//fmt.Println("coinbase_hash", hex.EncodeToString(coinbase))
|
|
//fmt.Println("coinbase_hash", coinbase)
|
|
return coinbase, nil
|
|
}
|
|
|
|
// build merkel root hash value
|
|
func Build_merkle_root(coinbase []byte, transaction_list *[]string) ([]byte, error) {
|
|
var merkle_root []byte
|
|
merkle_root = coinbase
|
|
count := len(*transaction_list)
|
|
var i int
|
|
for i = 0; i < count; i++ {
|
|
//fmt.Println("merkle_hash start", i, hex.EncodeToString(merkle_root))
|
|
t_bytes, err := hex.DecodeString((*transaction_list)[i])
|
|
if err != nil {
|
|
//log.Println("[dash]failed to Build_merkle_root", err)
|
|
return nil, err
|
|
}
|
|
for j := 0; j < len(t_bytes); j++ {
|
|
merkle_root = append(merkle_root, t_bytes[j])
|
|
}
|
|
//fmt.Println("merkle_hash append", i, hex.EncodeToString(merkle_root))
|
|
merkle := chainhash.DoubleHashB(merkle_root)
|
|
//fmt.Println("merkle_hash", i, hex.EncodeToString(merkle))
|
|
merkle_root = merkle
|
|
}
|
|
return merkle_root, nil
|
|
}
|
|
|
|
func BuildBlockHash(job *msg.StratumJob, doublehash bool, pow func(h wire.BlockHeader) chainhash.Hash) ([]byte, wire.BlockHeader) {
|
|
var bh wire.BlockHeader
|
|
//log.Printf("[dash]c1 %s,e1 %s,e2 %s,c2 %s\n", job.Coinbase1, job.Extranonce1, job.Extranonce2, job.Coinbase2)
|
|
coinbase, err := Build_coinbase(job.Coinbase1, job.Extranonce1, job.Extranonce2, job.Coinbase2, doublehash)
|
|
if err != nil {
|
|
return nil, bh
|
|
}
|
|
//log.Println("[dash]trans", job.Transactions)
|
|
merkle_root, err := Build_merkle_root(coinbase, job.Transactions)
|
|
if err != nil {
|
|
return nil, bh
|
|
}
|
|
vb := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(vb, uint32(job.Version))
|
|
tb := make([]byte, 4)
|
|
binary.LittleEndian.PutUint32(tb, uint32(job.Timestamp.Unix()))
|
|
bh, err = Build_block_hash(hex.EncodeToString(vb), job.PrevblockBig, merkle_root, hex.EncodeToString(tb), job.BitsS, job.Nonce)
|
|
if err != nil {
|
|
return nil, bh
|
|
}
|
|
powhash := pow(bh)
|
|
//log.Printf("POW hash:%s", powhash.String())
|
|
return powhash.CloneBytes(), bh
|
|
}
|
|
|
|
func Build_block_hash(block_version string, prev_hash string, merkle_root []byte, ntime string, nbits string, nonce string) (wire.BlockHeader, error) {
|
|
var header wire.BlockHeader
|
|
b, err := strconv.ParseUint(nbits, 16, 32)
|
|
if err != nil {
|
|
//log.Println("[dash]failed to Build_block_hash", err)
|
|
return header, err
|
|
}
|
|
header.Bits = uint32(b)
|
|
//log.Printf("Bits:%x", header.Bits)
|
|
p_bytes, err := hex.DecodeString(prev_hash)
|
|
if err != nil {
|
|
log.Println("[dash]failed to Build_block_hash", err)
|
|
return header, err
|
|
}
|
|
p, err := chainhash.NewHash(utility.Convert_big_endian(p_bytes))
|
|
header.PrevBlock = *p
|
|
//log.Printf("Prev Block:%s", hex.EncodeToString(header.PrevBlock.CloneBytes()))
|
|
m, err := chainhash.NewHash(merkle_root)
|
|
header.MerkleRoot = *m
|
|
//log.Printf("MerkleRoot:%s", hex.EncodeToString(header.MerkleRoot.CloneBytes()))
|
|
n, err := strconv.ParseUint(nonce, 16, 32)
|
|
if err != nil {
|
|
//log.Println("[dash]failed to Build_block_hash", err)
|
|
return header, err
|
|
}
|
|
header.Nonce = uint32(n)
|
|
//log.Printf("Nonce:%x", header.Nonce)
|
|
v, err := hex.DecodeString(block_version)
|
|
if err != nil {
|
|
//log.Println("[dash]failed to Build_block_hash", err)
|
|
return header, err
|
|
}
|
|
vBuffer := bytes.NewBuffer(v)
|
|
binary.Read(vBuffer, binary.BigEndian, &(header.Version))
|
|
//log.Printf("Version:%x", header.Version)
|
|
t, err := strconv.ParseInt(ntime, 16, 64)
|
|
if err != nil {
|
|
//log.Println("[dash]failed to Build_block_hash", err)
|
|
return header, err
|
|
}
|
|
header.Timestamp = time.Unix(t, 0)
|
|
//log.Printf("nTime %v", header.Timestamp)
|
|
|
|
return header, nil
|
|
}
|