兄弟连区块链培训open-ethereum-pool以太坊矿池源码分析(2)API分析
消息来源:baojiabao.com 作者: 发布时间:2024-04-26
原标题:兄弟连区块链培训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 //-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 } ```
相关文章
- 中兴受美国制裁事件 被罚了20亿美元过程事件始末 中兴被制裁后公司现状
2023-11-02 22:12:46
- B站怎么炸崩了哔哩哔哩服务器今日怎么又炸挂了?技术团队公开早先原因
2023-03-06 19:05:55
- 苹果iPhoneXS/XR手机电池容量续航最强?答案揭晓
2023-02-19 15:09:54
- 华为荣耀两款机型起内讧:荣耀Play官方价格同价同配该如何选?
2023-02-17 23:21:27
- google谷歌原生系统Pixel3 XL/4/5/6 pro手机价格:刘海屏设计顶配版曾卖6900元
2023-02-17 18:58:09
- 科大讯飞同传同声翻译软件造假 浮夸不能只罚酒三杯
2023-02-17 18:46:15
- 华为mate20pro系列手机首发上市日期价格,屏幕和电池参数配置对比
2023-02-17 18:42:49
- 小米MAX4手机上市日期首发价格 骁龙720打造大屏标准
2023-02-17 18:37:22
- 武汉弘芯遣散!结局是总投资1280亿项目烂尾 光刻机抵押换钱
2023-02-16 15:53:18
- 谷歌GoogleDrive网云盘下载改名“GoogleOne” 容量提升价格优惠
2023-02-16 13:34:45
- 巴斯夫将裁员6000人 众化工巨头裁员潮再度引发关注
2023-02-13 16:49:06
- 人手不足 韵达快递客服回应大量包裹派送异常没有收到
2023-02-07 15:25:20
- 资本微念与李子柒销声匿迹谁赢? 微念公司退出子柒文化股东
2023-02-02 09:24:38
- 三星GalaxyS8 S9 S10系统恢复出厂设置一直卡在正在检查更新怎么办
2023-01-24 10:10:02
- 华为Mate50 RS保时捷最新款顶级手机2022多少钱?1.2万元售价外观图片吊打iPhone14
2023-01-06 20:27:09
- 芯片常见的CPU芯片封装方式 QFP和QFN封装的区别?
2022-12-02 17:25:17
- 华为暂缓招聘停止社招了吗?官方回应来了
2022-11-19 11:53:50
- 热血江湖手游:长枪铁甲 刚猛热血 正派枪客全攻略技能介绍大全
2022-11-16 16:59:09
- 东京把玩了尼康微单相机Z7 尼康Z7现在卖多少钱?
2022-10-22 15:21:55
- 苹果iPhone手机灵动岛大热:安卓灵动岛App应用下载安装量超100万次
2022-10-03 22:13:45