成都兄弟连IT培训学校

176-1289-1020

兄弟连区块链培训open-ethereum-pool以太坊矿池源码分析(2)API分析

编辑:成都兄弟连IT培训学校时间:2019-05-31

兄弟连区块链培训课程体系设计架构包括了区块链的基础语言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

//-inf<=score

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

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,即

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

}

```


上一篇:兄弟连Go语言培训Go编程语言评估报告

下一篇:兄弟连Go语言培训清华尹成带你实战GO案例(4)Go 字符串格式化

联系方式

选择专业时,如果犹豫不定,不知道选择哪个比较好,敬请致电,专业的咨询老师会为你解答。

  • 报名热线:176-1289-1020
  • 咨询老师:何老师
  • 点击咨询:

友情连接:

关于我们|联系我们|网站地图

QQ咨询
在线咨询
在线报名
176-1289-1020
返回顶部