consensus/cmd/web/views/tpl_position_graph.go
DataHoarder 55661a12da
All checks were successful
continuous-integration/drone/push Build is passing
WIP: Bootstrap-based responsive interface, CSS only
2024-03-20 13:37:26 +01:00

176 lines
4.9 KiB
Go

package views
import (
"fmt"
"git.gammaspectra.live/P2Pool/p2pool-observer/cmd/index"
cmdutils "git.gammaspectra.live/P2Pool/p2pool-observer/cmd/utils"
"math"
"slices"
"strconv"
"time"
)
type PositionGraphDivider struct {
StartValue float64
EndValue float64
Label string
Color string
}
type PositionGraphPoint struct {
X, Y float64
Link, Color, Label string
Square bool
}
const DefaultBlocksPositionChartDuration = time.Hour * 24
func NewBlocksPositionChart(ctx *GlobalRequestContext, foundBlocks []*index.FoundBlock, x time.Duration) (dividersX, dividersY []PositionGraphDivider, points []PositionGraphPoint) {
current := time.Unix(int64(ctx.Pool.SideChain.LastBlock.Timestamp), 0).UTC()
secondsPerBlock := time.Second * time.Duration(ctx.Consensus.TargetBlockTime)
xSeconds := x.Seconds()
var highestEffort float64
for i, b := range foundBlocks {
var p PositionGraphPoint
var effortNumber float64
if len(foundBlocks) > (i + 1) {
effortNumber = found_block_effort(b, foundBlocks[i+1])
} else if effortIndex := slices.IndexFunc(ctx.Pool.SideChain.Effort.Last, func(e cmdutils.PoolInfoResultSideChainEffortLastEntry) bool { return e.Id == b.MainBlock.Id }); effortIndex != -1 {
effortNumber = ctx.Pool.SideChain.Effort.Last[effortIndex].Effort
}
p.Label = fmt.Sprintf("Block %d %s", b.MainBlock.Height, time_elapsed_short(b.MainBlock.Timestamp))
p.X = (xSeconds - current.Sub(time.Unix(int64(b.MainBlock.Timestamp), 0).UTC()).Seconds()) / xSeconds
if p.X < 0 {
//do not include if it is over chart
continue
}
p.Y = effortNumber
if effortNumber > highestEffort {
highestEffort = effortNumber
}
if effortNumber > 0.0 {
p.Label += fmt.Sprintf(" / %.2f%%", effortNumber)
p.Color = effort_color(effortNumber)
}
p.Link = "/share/" + hex(ctx, b.MainBlock.SideTemplateId)
points = append(points, p)
}
highestEffortInt := int(math.Ceil(highestEffort / 100))
highestEffort = float64(highestEffortInt * 100)
//adjust y
for i := range points {
points[i].Y = (highestEffort - points[i].Y) / highestEffort
}
for i := highestEffortInt; i > 0; i-- {
dividersY = append(dividersY, PositionGraphDivider{
StartValue: float64(i*100) / highestEffort,
EndValue: float64((i-1)*100) / highestEffort,
Label: strconv.FormatUint(uint64(i*100), 10) + "%",
})
}
dividersX = append(dividersX, PositionGraphDivider{
StartValue: (time.Duration(ctx.Pool.SideChain.Window.Blocks) * secondsPerBlock).Seconds() / xSeconds,
EndValue: 0,
Label: "PPLNS",
Color: "rgba(255, 102, 0, 0.5)",
})
return dividersX, dividersY, points
}
func NewSharesPositionChart(ctx *GlobalRequestContext, shares []*index.SideBlock, payouts *[]*index.Payout, efforts *[]float64, x time.Duration) (dividersX, dividersY []PositionGraphDivider, points []PositionGraphPoint) {
current := time.Unix(int64(ctx.Pool.SideChain.LastBlock.Timestamp), 0).UTC()
secondsPerBlock := time.Second * time.Duration(ctx.Consensus.TargetBlockTime)
xSeconds := x.Seconds()
var highestEffort float64
for i, s := range shares {
var p PositionGraphPoint
var effortNumber float64
if efforts != nil {
if effort := (*efforts)[i]; effort >= 0 {
effortNumber = effort
}
}
p.Label = fmt.Sprintf("Share %d %s", s.SideHeight, time_elapsed_short(s.Timestamp))
p.X = (xSeconds - current.Sub(time.Unix(int64(s.Timestamp), 0).UTC()).Seconds()) / xSeconds
if p.X < 0 {
//do not include if it is over chart
continue
}
p.Y = effortNumber
if effortNumber > highestEffort {
highestEffort = effortNumber
}
if effortNumber > 0.0 {
p.Label += fmt.Sprintf(" / %.2f%%", effortNumber)
p.Color = effort_color(effortNumber)
}
p.Link = "/share/" + hex(ctx, s.TemplateId)
if s.IsUncle() {
p.Label += " (uncle)"
p.Square = true
}
points = append(points, p)
}
highestEffortInt := max(3, int(math.Ceil(highestEffort/100)))
highestEffort = float64(highestEffortInt * 100)
//adjust y
for i := range points {
points[i].Y = (highestEffort - points[i].Y) / highestEffort
}
for i := highestEffortInt; i > 0; i-- {
dividersY = append(dividersY, PositionGraphDivider{
StartValue: float64(i*100) / highestEffort,
EndValue: float64((i-1)*100) / highestEffort,
Label: strconv.FormatUint(uint64(i*100), 10) + "%",
})
}
dividersX = append(dividersX, PositionGraphDivider{
StartValue: (time.Duration(ctx.Pool.SideChain.Window.Blocks) * secondsPerBlock).Seconds() / xSeconds,
EndValue: 0,
Label: "PPLNS",
Color: "rgba(255, 102, 0, 0.5)",
})
if payouts != nil {
for _, p := range *payouts {
x := (xSeconds - current.Sub(time.Unix(int64(p.Timestamp), 0).UTC()).Seconds()) / xSeconds
if x < 0 {
//do not include if it is over chart
continue
}
dividersX = append(dividersX, PositionGraphDivider{
StartValue: 1 - x,
EndValue: 1 - x,
})
}
}
return dividersX, dividersY, points
}