From 9229fac02ae1d120675cc6db72b5e8053a12d041 Mon Sep 17 00:00:00 2001 From: yuriy0803 <68668177+yuriy0803@users.noreply.github.com> Date: Tue, 2 Mar 2021 23:48:27 +0100 Subject: [PATCH] block charts --- api/server.go | 2 + storage/redis.go | 48 +++++++++ www/app/controllers/blocks.js | 177 ++++++++++++++++++++++++++++++++++ www/app/templates/blocks.hbs | 1 + 4 files changed, 228 insertions(+) create mode 100644 www/app/controllers/blocks.js diff --git a/api/server.go b/api/server.go index 06ec0f8..280725b 100644 --- a/api/server.go +++ b/api/server.go @@ -204,6 +204,7 @@ func (s *ApiServer) collectStats() { } if len(s.config.LuckWindow) > 0 { stats["luck"], err = s.backend.CollectLuckStats(s.config.LuckWindow) + stats["luckCharts"], err = s.backend.CollectLuckCharts(s.config.LuckWindow[0]) if err != nil { log.Printf("Failed to fetch luck stats from backend: %v", err) return @@ -301,6 +302,7 @@ func (s *ApiServer) BlocksIndex(w http.ResponseWriter, r *http.Request) { reply["candidates"] = stats["candidates"] reply["candidatesTotal"] = stats["candidatesTotal"] reply["luck"] = stats["luck"] + reply["luckCharts"] = stats["luckCharts"] } err := json.NewEncoder(w).Encode(reply) diff --git a/storage/redis.go b/storage/redis.go index 7186bb3..a218d84 100644 --- a/storage/redis.go +++ b/storage/redis.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "math/big" + "sort" "strconv" "strings" "time" @@ -46,6 +47,15 @@ type PaymentCharts struct { Amount int64 `json:"amount"` } +type LuckCharts struct { + Timestamp int64 `json:"x"` + Height int64 `json:"height"` + Difficulty int64 `json:"difficulty"` + Shares int64 `json:"shares"` + SharesDiff float64 `json:"sharesDiff"` + Reward string `json:"reward"` +} + type SumRewardData struct { Interval int64 `json:"inverval"` Reward int64 `json:"reward"` @@ -1102,6 +1112,44 @@ func (r *RedisClient) CollectLuckStats(windows []int) (map[string]interface{}, e return stats, nil } +func (r *RedisClient) CollectLuckCharts(max int) (stats []*LuckCharts, err error) { + var result []*LuckCharts + tx := r.client.Multi() + defer tx.Close() + + cmds, err := tx.Exec(func() error { + tx.ZRevRangeWithScores(r.formatKey("blocks", "matured"), 0, int64(max-1)) + return nil + }) + if err != nil { + return result, err + } + blocks := convertBlockResults(cmds[0].(*redis.ZSliceCmd)) + + for i, block := range blocks { + if i > (max - 1) { + break + } + lc := LuckCharts{} + var sharesDiff = float64(block.TotalShares) / float64(block.Difficulty) + lc.Timestamp = block.Timestamp + lc.Height = block.RoundHeight + lc.Difficulty = block.Difficulty + lc.Shares = block.TotalShares + lc.SharesDiff = sharesDiff + lc.Reward = block.RewardString + result = append(result, &lc) + } + sort.Sort(TimestampSorter(result)) + return result, nil +} + +type TimestampSorter []*LuckCharts + +func (a TimestampSorter) Len() int { return len(a) } +func (a TimestampSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a TimestampSorter) Less(i, j int) bool { return a[i].Timestamp < a[j].Timestamp } + func convertCandidateResults(raw *redis.ZSliceCmd) []*BlockData { var result []*BlockData for _, v := range raw.Val() { diff --git a/www/app/controllers/blocks.js b/www/app/controllers/blocks.js new file mode 100644 index 0000000..4fc69a8 --- /dev/null +++ b/www/app/controllers/blocks.js @@ -0,0 +1,177 @@ +import Ember from 'ember'; + +export default Ember.Controller.extend({ + applicationController: Ember.inject.controller('application'), + config: Ember.computed.reads('applicationController.config'), + settings: Ember.computed.reads('applicationController.model.settings'), + + BlockUnlockDepth: Ember.computed('settings', { + get() { + var depth = this.get('settings.BlockUnlockDepth'); + if (depth) { + return depth; + } + return this.get('config').BlockUnlockDepth; + } + }), + + chartOptions: Ember.computed("model.luckCharts", { + get() { + var e = this, + t = e.getWithDefault("model.luckCharts"), + a = { + colors: ['#f45b5b', '#8085e9', '#8d4654', '#7798BF', '#aaeeee', + '#ff0066', '#eeaaee', '#55BF3B', '#DF5353', '#7798BF', '#aaeeee'], + chart: { + backgroundColor: "rgba(255, 255, 255, 0.1)", + marginRight: 10, + height: 200, + events: { + load: function() { + var series = this.series[0]; + setInterval(function() { + var x = (new Date()).getTime(), + y = e.getWithDefault("model.luckCharts.difficulty"); + series.addPoint([x, y], true, true); + }, 1090000000); + } + } + }, + title: { + text: "" + }, + xAxis: { + labels: { + style: { + color: '#6e6e70' + } + }, + ordinal: false, + type: "datetime", + dateTimeLabelFormats: { + millisecond: "%H:%M:%S", + second: "%H:%M:%S", + minute: "%H:%M", + hour: "%H:%M", + day: "%e. %b", + week: "%e. %b", + month: "%b '%y", + year: "%Y" + } + }, + yAxis: { + labels: { + style: { + color: '#6e6e70' + } + }, + title: { + text: "shares and difficulty", + style: { + color: 'black', + fontSize: '16px', + fontWeight: 'bold' + } + }, + softMax: 100, + }, + plotLines: [{ + value: 0, + width: 1, + color: "#808080" + }], + plotOptions: { + series: { + shadow: true + }, + candlestick: { + lineColor: '#404048' + }, + map: { + shadow: false + } + }, + legend: { + enabled: true + }, + tooltip: { + formatter: function() { + var ss = this.y > 1000000000000 ? "" + (this.y / 1000000000000).toFixed(2) + " TH" : this.y > 1000000000 ? "" + (this.y / 1000000000).toFixed(2) + " GH" : this.y > 1000000 ? "" + (this.y / 1000000).toFixed(2) + " MH" : this.y > 1000 ? "" + (this.y / 1000).toFixed(2) + " KH" : "" + this.y.toFixed(2) + " H"; + return ss + "
Number: " + this.point.h + "
" + this.point.d + "
Reward: " + (this.point.w/1000000000000000000).toFixed(8) + e.get('config.Unit') + "
Variance: " + (this.point.s*100).toFixed(2)+ "%"; + }, + + useHTML: true + }, + exporting: { + enabled: false + }, + series: [{ + step: 'center', + color: "#E99002", + name: "difficulty", + data: function() { + var e, a = []; + if (null != t) { + for (e = 0; e <= t.length - 1; e += 1) { + var n = 0, + r = 0, + l = 0; + r = new Date(1e3 * t[e].x); + l = r.toLocaleString(); + n = t[e].difficulty; + a.push({ + x: r, + d: l, + h: t[e].height, + w: t[e].reward, + s: t[e].sharesDiff, + y: n + }); + } + } else { + a.push({ + x: 0, + d: 0, + y: 0 + }); + } + return a; + }() + }, { + step: 'center', + name: "shares", + data: function() { + var e, a = []; + if (null != t) { + for (e = 0; e <= t.length - 1; e += 1) { + var n = 0, + r = 0, + l = 0; + r = new Date(1e3 * t[e].x); + l = r.toLocaleString(); + n = t[e].shares; + a.push({ + x: r, + d: l, + h: t[e].height, + w: t[e].reward, + s: t[e].sharesDiff, + y: n + }); + } + } else { + a.push({ + x: 0, + d: 0, + y: 0 + }); + } + return a; + }() + }] + }; + return a; + } + }) + +}); \ No newline at end of file diff --git a/www/app/templates/blocks.hbs b/www/app/templates/blocks.hbs index b951828..2d36a2d 100644 --- a/www/app/templates/blocks.hbs +++ b/www/app/templates/blocks.hbs @@ -9,6 +9,7 @@
+ {{high-charts mode=stockChart chartOptions=chartOptions content=chartData}} {{#if model.luck}} {{partial "luck"}} {{/if}}