兄弟連區塊鏈培訓open-ethereum-pool以太坊礦池源碼分析(2)API分析
原標題:兄弟連區塊鏈培訓open-ethereum-pool以太坊礦池源碼分析(2)API分析
兄弟連區塊鏈培訓課程體系設計架構包括了區塊鏈的基礎語言Go語言、區塊鏈後端技術體系、區塊鏈公鏈、區塊鏈分散式應用開發等內容講解,以及到最後的面試指導和項目實戰。課程由清華微軟谷歌名師團隊精心打造,歷時半年時間共同研發而出。
#open-ethereum-pool以太坊礦池-api模塊
##ApiServer相關定義
```go
typeApiConfigstruct{
Enabledbool`json:"enabled"`
Listenstring`json:"listen"`
StatsCollectIntervalstring`json:"statsCollectInterval"`
HashrateWindowstring`json:"hashrateWindow"`
HashrateLargeWindowstring`json:"hashrateLargeWindow"`
LuckWindow[]int`json:"luckWindow"`
Paymentsint64`json:"payments"`
Blocksint64`json:"blocks"`
PurgeOnlybool`json:"purgeOnly"`
PurgeIntervalstring`json:"purgeInterval"`
}
typeApiServerstruct{
config*ApiConfig
backend*storage.RedisClient
hashrateWindowtime.Duration
hashrateLargeWindowtime.Duration
statsatomic.Value
minersmap[string]*Entry
minersMusync.RWMutex
statsIntvtime.Duration
}
typeEntrystruct{
statsmap[string]interface{}
updatedAtint64
}
//代碼位置api/server.go
```
##startApi流程圖
##CollectStats原理
```go
//config.StatsCollectInterval為CollectStats定時器,時間為5秒
//調取:stats,err:=s.backend.CollectStats(s.hashrateWindow,s.config.Blocks,s.config.Payments)
//s.hashrateWindow即cfg.HashrateWindow,即:為每個礦工估計算力的快速時間間隔,30分鐘
//s.config.Blocks即:前端顯示的最大塊數,50個
//s.config.Payments即:前端顯示的最大付款數量,50個
func(r*RedisClient)CollectStats(smallWindowtime.Duration,maxBlocks,maxPaymentsint64)(map[string]interface{},error){
//換算成秒
window:=int64(smallWindow/time.Second)
//創建map
stats:=make(map[string]interface{})
//Redis事務塊
tx:=r.client.Multi()
defertx.Close()
//換算成秒
now:=util.MakeTimestamp()/1000
cmds,err:=tx.Exec(func()error{
//針對min和max參數需要額外說明的是,-inf和+inf分別表示Sorted-Sets中分數的最高值和最低值
//預設情況下,min和max表示的範圍是閉區間範圍,即min<=score<=max內的成員將被返回
//然而我們可以通過在min和max的前面添加"("字元來表示開區間,如(minmax表示min<score<=max,而(min(max表示min<score<max
//-inf<=score<now-window
//Zremrangebyscore命令用於移除有序集中,指定分數(score)區間內的所有成員
//ZREMRANGEBYSCOREeth:hashrate-inf(now-window
//慎重使用
tx.ZRemRangeByScore(r.formatKey("hashrate"),"-inf",fmt.Sprint("(",now-window))
//顯示整個有序集成員
//ZRANGEeth:hashrate0-1WITHSCORES
tx.ZRangeWithScores(r.formatKey("hashrate"),0,-1)
//Hgetall命令用於返回哈希表中,所有的欄位和值
//HGETALLeth:stats
tx.HGetAllMap(r.formatKey("stats"))
//Zrevrange命令返回有序集中,指定區間內的成員
//ZREVRANGEeth:blocks:candidates0-1WITHSCORES
//candidates為候選者
tx.ZRevRangeWithScores(r.formatKey("blocks","candidates"),0,-1)
//同上
//ZREVRANGEeth:blocks:immature0-1WITHSCORES
//immature為未成年
tx.ZRevRangeWithScores(r.formatKey("blocks","immature"),0,-1)
//同上
//ZREVRANGEeth:blocks:matured049WITHSCORES
//matured為成熟
tx.ZRevRangeWithScores(r.formatKey("blocks","matured"),0,maxBlocks-1)
//Zcard命令用於計算集合中元素的數量
//ZCARDeth:blocks:candidates
tx.ZCard(r.formatKey("blocks","candidates"))
//同上
//ZCARDeth:blocks:immature
tx.ZCard(r.formatKey("blocks","immature"))
//同上
//ZCARDeth:blocks:matured
tx.ZCard(r.formatKey("blocks","matured"))
//同上
//ZCARDeth:payments:all
tx.ZCard(r.formatKey("payments","all"))
//同上
//ZREVRANGEeth:payments:all049WITHSCORES
tx.ZRevRangeWithScores(r.formatKey("payments","all"),0,maxPayments-1)
returnnil
})
iferr!=nil{
returnnil,err
}
//Hgetall命令用於返回哈希表中,所有的欄位和值
//HGETALLeth:stats
result,_:=cmds[2].(*redis.StringStringMapCmd).Result()
stats["stats"]=convertStringMap(result)
//Zrevrange命令返回有序集中,指定區間內的成員
//ZREVRANGEeth:blocks:candidates0-1WITHSCORES
//Zcard命令用於計算集合中元素的數量
//ZCARDeth:blocks:candidates
candidates:=convertCandidateResults(cmds[3].(*redis.ZSliceCmd))
stats["candidates"]=candidates
stats["candidatesTotal"]=cmds[6].(*redis.IntCmd).Val()
//ZREVRANGEeth:blocks:immature0-1WITHSCORES
//ZCARDeth:blocks:immature
immature:=convertBlockResults(cmds[4].(*redis.ZSliceCmd))
stats["immature"]=immature
stats["immatureTotal"]=cmds[7].(*redis.IntCmd).Val()
//ZREVRANGEeth:blocks:matured049WITHSCORES
//ZCARDeth:blocks:matured
matured:=convertBlockResults(cmds[5].(*redis.ZSliceCmd))
stats["matured"]=matured
stats["maturedTotal"]=cmds[8].(*redis.IntCmd).Val()
//ZREVRANGEeth:payments:all049WITHSCORES
//ZCARDeth:payments:all
payments:=convertPaymentsResults(cmds[10].(*redis.ZSliceCmd))
stats["payments"]=payments
stats["paymentsTotal"]=cmds[9].(*redis.IntCmd).Val()
//顯示整個有序集成員
//ZRANGEeth:hashrate0-1WITHSCORES
totalHashrate,miners:=convertMinersStats(window,cmds[1].(*redis.ZSliceCmd))
stats["miners"]=miners
stats["minersTotal"]=len(miners)
stats["hashrate"]=totalHashrate
returnstats,nil
}
```
##CollectLuckStats原理
```go
//調取:stats["luck"],err=s.backend.CollectLuckStats(s.config.LuckWindow)
//"luckWindow":[64,128,256],
//Collectstatsforshares/diffratioforthisnumberofblocks
func(r*RedisClient)CollectLuckStats(windows[]int)(map[string]interface{},error){
//創建statsmap
stats:=make(map[string]interface{})
tx:=r.client.Multi()
defertx.Close()
//max即256
max:=int64(windows[len(windows)-1])
cmds,err:=tx.Exec(func()error{
//Zrevrange命令返回有序集中,指定區間內的成員
//ZREVRANGEeth:blocks:immature0-1WITHSCORES
tx.ZRevRangeWithScores(r.formatKey("blocks","immature"),0,-1)
//ZREVRANGEeth:blocks:matured0max-1WITHSCORES
tx.ZRevRangeWithScores(r.formatKey("blocks","matured"),0,max-1)
returnnil
})
iferr!=nil{
returnstats,err
}
//獲取blocks
blocks:=convertBlockResults(cmds[0].(*redis.ZSliceCmd),cmds[1].(*redis.ZSliceCmd))
calcLuck:=func(maxint)(int,float64,float64,float64){
vartotalint
varsharesDiff,uncles,orphansfloat64
fori,block:=rangeblocks{
ifi>(max-1){
break
}
//叔塊
ifblock.Uncle{
uncles++
}
//孤塊
ifblock.Orphan{
orphans++
}
//shares/Diff
sharesDiff+=float64(block.TotalShares)/float64(block.Difficulty)
//total計數
total++
}
iftotal>0{
//單塊平均shares/Diff
sharesDiff/=float64(total)
//uncles率
uncles/=float64(total)
//孤塊率
orphans/=float64(total)
}
//返回total計數,平均shares/Diff,uncles率,孤塊率
returntotal,sharesDiff,uncles,orphans
}
//遍歷windows,逐一計算calcLuck,即最近64塊、128塊、256塊的數據統計
for_,max:=rangewindows{
total,sharesDiff,uncleRate,orphanRate:=calcLuck(max)
row:=map[string]float64{
"luck":sharesDiff,"uncleRate":uncleRate,"orphanRate":orphanRate,
}
//寫入statsmap
stats[strconv.Itoa(total)]=row
//計數不對
iftotal<max{
break
}
}
returnstats,nil
}
funcconvertBlockResults(rows...*redis.ZSliceCmd)[]*BlockData{
varresult[]*BlockData
//遍歷rows
for_,row:=rangerows{
//遍歷blocks
for_,v:=rangerow.Val(){
//"uncleHeight:orphan:nonce:blockHash:timestamp:diff:totalShares:rewardInWei"
block:=BlockData{}
block.Height=int64(v.Score)
block.RoundHeight=block.Height
fields:=strings.Split(v.Member.(string),":")
block.UncleHeight,_=strconv.ParseInt(fields[0],10,64)
block.Uncle=block.UncleHeight>0
block.Orphan,_=strconv.ParseBool(fields[1])
block.Nonce=fields[2]
block.Hash=fields[3]
block.Timestamp,_=strconv.ParseInt(fields[4],10,64)
block.Difficulty,_=strconv.ParseInt(fields[5],10,64)
block.TotalShares,_=strconv.ParseInt(fields[6],10,64)
block.RewardString=fields[7]
block.ImmatureReward=fields[7]
block.immatureKey=v.Member.(string)
result=append(result,&block)
}
}
returnresult
}
```
##purgeStale原理
```go
//config.PurgeInterval為FlushStaleStats定時器,時間為10分鐘
//調取:total,err:=s.backend.FlushStaleStats(s.hashrateWindow,s.hashrateLargeWindow)
//s.hashrateWindow即cfg.HashrateWindow,即:為每個礦工估計算力的快速時間間隔,30分鐘
//s.hashrateLargeWindow即cfg.HashrateLargeWindow,即:長期和精確的hashrate時間間隔,3小時
func(r*RedisClient)FlushStaleStats(window,largeWindowtime.Duration)(int64,error){
//換算成秒
now:=util.MakeTimestamp()/1000
//max即(now-window,即<(now-window
max:=fmt.Sprint("(",now-int64(window/time.Second))
//Zremrangebyscore命令用於移除有序集中,指定分數(score)區間內的所有成員
//ZREMRANGEBYSCOREeth:hashrate-inf(now-window
//慎重使用
total,err:=r.client.ZRemRangeByScore(r.formatKey("hashrate"),"-inf",max).Result()
iferr!=nil{
returntotal,err
}
varcint64
//創建map
miners:=make(map[string]struct{})
//即(now-largeWindow,即<now-largeWindow
max=fmt.Sprint("(",now-int64(largeWindow/time.Second))
for{
varkeys[]string
varerrerror
//SCAN命令用於迭代當前資料庫中的資料庫鍵
//SCAN0MATCHeth:hashrate:*COUNT100
//SCANcMATCHeth:hashrate:*COUNT100
c,keys,err=r.client.Scan(c,r.formatKey("hashrate","*"),100).Result()
iferr!=nil{
returntotal,err
}
for_,row:=rangekeys{
//eth:hashrate:login中截取login
login:=strings.Split(row,":")[2]
//沒有處理過miners[login]
if_,ok:=miners[login];!ok{
//Zremrangebyscore命令用於移除有序集中,指定分數(score)區間內的所有成員
//ZREMRANGEBYSCOREeth:hashrate:login-inf(now-window
n,err:=r.client.ZRemRangeByScore(r.formatKey("hashrate",login),"-inf",max).Result()
iferr!=nil{
returntotal,err
}
//已處理的計入miners[login]
miners[login]=struct{}{}
//已處理的數量
total+=n
}
}
ifc==0{
break
}
}
returntotal,nil
}
```
TAG:兄弟連IT教育 |