Adjust various CLI display ratios to arbitrary precision
Originally the deviations from using float64 were insignificant, but at exabyte scale they start to show up. Cleanup all displays, and clarify the expectation text, adding an extra 99.9% probability calculator to `lotus-miner info`
This commit is contained in:
parent
216fa5c965
commit
c2e5a837e6
@ -47,6 +47,11 @@ func BigDiv(a, b BigInt) BigInt {
|
|||||||
return BigInt{Int: big.NewInt(0).Div(a.Int, b.Int)}
|
return BigInt{Int: big.NewInt(0).Div(a.Int, b.Int)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BigDivFloat(num, den BigInt) float64 {
|
||||||
|
res, _ := new(big.Rat).SetFrac(num.Int, den.Int).Float64()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
func BigMod(a, b BigInt) BigInt {
|
func BigMod(a, b BigInt) BigInt {
|
||||||
return BigInt{Int: big.NewInt(0).Mod(a.Int, b.Int)}
|
return BigInt{Int: big.NewInt(0).Mod(a.Int, b.Int)}
|
||||||
}
|
}
|
||||||
|
26
cli/state.go
26
cli/state.go
@ -183,18 +183,23 @@ var StateMinerInfo = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rpercI := types.BigDiv(types.BigMul(pow.MinerPower.RawBytePower, types.NewInt(1000000)), pow.TotalPower.RawBytePower)
|
|
||||||
qpercI := types.BigDiv(types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(1000000)), pow.TotalPower.QualityAdjPower)
|
|
||||||
|
|
||||||
fmt.Printf("Byte Power: %s / %s (%0.4f%%)\n",
|
fmt.Printf("Byte Power: %s / %s (%0.4f%%)\n",
|
||||||
color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)),
|
color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)),
|
||||||
types.SizeStr(pow.TotalPower.RawBytePower),
|
types.SizeStr(pow.TotalPower.RawBytePower),
|
||||||
float64(rpercI.Int64())/10000)
|
types.BigDivFloat(
|
||||||
|
types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)),
|
||||||
|
pow.TotalPower.RawBytePower,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
fmt.Printf("Actual Power: %s / %s (%0.4f%%)\n",
|
fmt.Printf("Actual Power: %s / %s (%0.4f%%)\n",
|
||||||
color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)),
|
color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)),
|
||||||
types.DeciStr(pow.TotalPower.QualityAdjPower),
|
types.DeciStr(pow.TotalPower.QualityAdjPower),
|
||||||
float64(qpercI.Int64())/10000)
|
types.BigDivFloat(
|
||||||
|
types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)),
|
||||||
|
pow.TotalPower.QualityAdjPower,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
@ -302,8 +307,15 @@ var StatePowerCmd = &cli.Command{
|
|||||||
tp := power.TotalPower
|
tp := power.TotalPower
|
||||||
if cctx.Args().Present() {
|
if cctx.Args().Present() {
|
||||||
mp := power.MinerPower
|
mp := power.MinerPower
|
||||||
percI := types.BigDiv(types.BigMul(mp.QualityAdjPower, types.NewInt(1000000)), tp.QualityAdjPower)
|
fmt.Printf(
|
||||||
fmt.Printf("%s(%s) / %s(%s) ~= %0.4f%%\n", mp.QualityAdjPower.String(), types.SizeStr(mp.QualityAdjPower), tp.QualityAdjPower.String(), types.SizeStr(tp.QualityAdjPower), float64(percI.Int64())/10000)
|
"%s(%s) / %s(%s) ~= %0.4f%%\n",
|
||||||
|
mp.QualityAdjPower.String(), types.SizeStr(mp.QualityAdjPower),
|
||||||
|
tp.QualityAdjPower.String(), types.SizeStr(tp.QualityAdjPower),
|
||||||
|
types.BigDivFloat(
|
||||||
|
types.BigMul(mp.QualityAdjPower, big.NewInt(100)),
|
||||||
|
tp.QualityAdjPower,
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%s(%s)\n", tp.QualityAdjPower.String(), types.SizeStr(tp.QualityAdjPower))
|
fmt.Printf("%s(%s)\n", tp.QualityAdjPower.String(), types.SizeStr(tp.QualityAdjPower))
|
||||||
}
|
}
|
||||||
|
@ -172,12 +172,13 @@ var syncScrapePowerCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
qpercI := types.BigDiv(types.BigMul(totalWonPower.QualityAdjPower, types.NewInt(1000000)), totalPower.TotalPower.QualityAdjPower)
|
|
||||||
|
|
||||||
fmt.Println("Number of winning miners: ", len(miners))
|
fmt.Println("Number of winning miners: ", len(miners))
|
||||||
fmt.Println("QAdjPower of winning miners: ", totalWonPower.QualityAdjPower)
|
fmt.Println("QAdjPower of winning miners: ", totalWonPower.QualityAdjPower)
|
||||||
fmt.Println("QAdjPower of all miners: ", totalPower.TotalPower.QualityAdjPower)
|
fmt.Println("QAdjPower of all miners: ", totalPower.TotalPower.QualityAdjPower)
|
||||||
fmt.Println("Percentage of winning QAdjPower: ", float64(qpercI.Int64())/10000)
|
fmt.Println("Percentage of winning QAdjPower: ", types.BigDivFloat(
|
||||||
|
types.BigMul(totalWonPower.QualityAdjPower, big.NewInt(100)),
|
||||||
|
totalPower.TotalPower.QualityAdjPower,
|
||||||
|
))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -3,6 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
corebig "math/big"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -21,6 +23,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/blockstore"
|
"github.com/filecoin-project/lotus/blockstore"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
@ -120,19 +123,23 @@ func infoCmdAct(cctx *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rpercI := types.BigDiv(types.BigMul(pow.MinerPower.RawBytePower, types.NewInt(1000000)), pow.TotalPower.RawBytePower)
|
|
||||||
qpercI := types.BigDiv(types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(1000000)), pow.TotalPower.QualityAdjPower)
|
|
||||||
|
|
||||||
fmt.Printf("Power: %s / %s (%0.4f%%)\n",
|
fmt.Printf("Power: %s / %s (%0.4f%%)\n",
|
||||||
color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)),
|
color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)),
|
||||||
types.DeciStr(pow.TotalPower.QualityAdjPower),
|
types.DeciStr(pow.TotalPower.QualityAdjPower),
|
||||||
float64(qpercI.Int64())/10000)
|
types.BigDivFloat(
|
||||||
|
types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)),
|
||||||
|
pow.TotalPower.QualityAdjPower,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
fmt.Printf("\tRaw: %s / %s (%0.4f%%)\n",
|
fmt.Printf("\tRaw: %s / %s (%0.4f%%)\n",
|
||||||
color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)),
|
color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)),
|
||||||
types.SizeStr(pow.TotalPower.RawBytePower),
|
types.SizeStr(pow.TotalPower.RawBytePower),
|
||||||
float64(rpercI.Int64())/10000)
|
types.BigDivFloat(
|
||||||
|
types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)),
|
||||||
|
pow.TotalPower.RawBytePower,
|
||||||
|
),
|
||||||
|
)
|
||||||
secCounts, err := api.StateMinerSectorCount(ctx, maddr, types.EmptyTSK)
|
secCounts, err := api.StateMinerSectorCount(ctx, maddr, types.EmptyTSK)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -146,7 +153,7 @@ func infoCmdAct(cctx *cli.Context) error {
|
|||||||
} else {
|
} else {
|
||||||
var faultyPercentage float64
|
var faultyPercentage float64
|
||||||
if secCounts.Live != 0 {
|
if secCounts.Live != 0 {
|
||||||
faultyPercentage = float64(10000*nfaults/secCounts.Live) / 100.
|
faultyPercentage = float64(100*nfaults) / float64(secCounts.Live)
|
||||||
}
|
}
|
||||||
fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n",
|
fmt.Printf("\tProving: %s (%s Faulty, %.2f%%)\n",
|
||||||
types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize)))),
|
types.SizeStr(types.BigMul(types.NewInt(proving), types.NewInt(uint64(mi.SectorSize)))),
|
||||||
@ -157,16 +164,47 @@ func infoCmdAct(cctx *cli.Context) error {
|
|||||||
if !pow.HasMinPower {
|
if !pow.HasMinPower {
|
||||||
fmt.Print("Below minimum power threshold, no blocks will be won")
|
fmt.Print("Below minimum power threshold, no blocks will be won")
|
||||||
} else {
|
} else {
|
||||||
expWinChance := float64(types.BigMul(qpercI, types.NewInt(build.BlocksPerEpoch)).Int64()) / 1000000
|
|
||||||
if expWinChance > 0 {
|
|
||||||
if expWinChance > 1 {
|
|
||||||
expWinChance = 1
|
|
||||||
}
|
|
||||||
winRate := time.Duration(float64(time.Second*time.Duration(build.BlockDelaySecs)) / expWinChance)
|
|
||||||
winPerDay := float64(time.Hour*24) / float64(winRate)
|
|
||||||
|
|
||||||
fmt.Print("Expected block win rate: ")
|
winRatio := new(corebig.Rat).Mul(
|
||||||
color.Blue("%.4f/day (every %s)", winPerDay, winRate.Truncate(time.Second))
|
new(corebig.Rat).SetFrac(
|
||||||
|
types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int,
|
||||||
|
pow.TotalPower.QualityAdjPower.Int,
|
||||||
|
),
|
||||||
|
// decrease the rate ever-so-slightly to very roughly account for the multi-win poisson distribution
|
||||||
|
// FIXME - this is not a scientifically derived number... like at all
|
||||||
|
corebig.NewRat(99997, 100000),
|
||||||
|
)
|
||||||
|
|
||||||
|
if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 {
|
||||||
|
|
||||||
|
weekly, _ := new(corebig.Rat).Mul(
|
||||||
|
winRatio,
|
||||||
|
new(corebig.Rat).SetInt64(7*builtin.EpochsInDay),
|
||||||
|
).Float64()
|
||||||
|
|
||||||
|
avgDuration, _ := new(corebig.Rat).Mul(
|
||||||
|
new(corebig.Rat).SetInt64(builtin.EpochDurationSeconds),
|
||||||
|
new(corebig.Rat).Inv(winRatio),
|
||||||
|
).Float64()
|
||||||
|
|
||||||
|
fmt.Print("Projected average block win rate: ")
|
||||||
|
color.Blue(
|
||||||
|
"%.02f/week (every %s)",
|
||||||
|
weekly,
|
||||||
|
(time.Second * time.Duration(avgDuration)).Truncate(time.Second).String(),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Geometric distribution calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples
|
||||||
|
// https://www.wolframalpha.com/input/?i=c%3D99%3B+p%3D188809111007232%3B+n%3D5740343177447735296%3B+%281-%284.99*p%2Fn%29%29%5E%28t*2880%29%3D%281-%28c%2F100%29%29
|
||||||
|
fmt.Print("Projected block win with ")
|
||||||
|
color.Green(
|
||||||
|
"99.9%% probability every %s",
|
||||||
|
(time.Second * time.Duration(
|
||||||
|
builtin.EpochDurationSeconds*math.Log(1-0.999)/
|
||||||
|
math.Log(1-winRatioFloat),
|
||||||
|
)).Truncate(time.Second).String(),
|
||||||
|
)
|
||||||
|
fmt.Println("(projections DO NOT account for future network and miner growth)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ var provingInfoCmd = &cli.Command{
|
|||||||
|
|
||||||
var faultPerc float64
|
var faultPerc float64
|
||||||
if proving > 0 {
|
if proving > 0 {
|
||||||
faultPerc = float64(faults*10000/proving) / 100
|
faultPerc = float64(faults * 100 / proving)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch)
|
fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch)
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
|
corebig "math/big"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
@ -27,6 +29,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
tstats "github.com/filecoin-project/lotus/tools/stats"
|
tstats "github.com/filecoin-project/lotus/tools/stats"
|
||||||
)
|
)
|
||||||
@ -581,18 +584,24 @@ func (i *MinerInfo) MarshalPlainText() ([]byte, error) {
|
|||||||
fmt.Fprintf(w, "Sector Size: %s\n", i.SectorSize)
|
fmt.Fprintf(w, "Sector Size: %s\n", i.SectorSize)
|
||||||
|
|
||||||
pow := i.MinerPower
|
pow := i.MinerPower
|
||||||
rpercI := types.BigDiv(types.BigMul(pow.MinerPower.RawBytePower, types.NewInt(1000000)), pow.TotalPower.RawBytePower)
|
|
||||||
qpercI := types.BigDiv(types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(1000000)), pow.TotalPower.QualityAdjPower)
|
|
||||||
|
|
||||||
fmt.Fprintf(w, "Byte Power: %s / %s (%0.4f%%)\n",
|
fmt.Fprintf(w, "Byte Power: %s / %s (%0.4f%%)\n",
|
||||||
types.SizeStr(pow.MinerPower.RawBytePower),
|
types.SizeStr(pow.MinerPower.RawBytePower),
|
||||||
types.SizeStr(pow.TotalPower.RawBytePower),
|
types.SizeStr(pow.TotalPower.RawBytePower),
|
||||||
float64(rpercI.Int64())/10000)
|
types.BigDivFloat(
|
||||||
|
types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)),
|
||||||
|
pow.TotalPower.RawBytePower,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
fmt.Fprintf(w, "Actual Power: %s / %s (%0.4f%%)\n",
|
fmt.Fprintf(w, "Actual Power: %s / %s (%0.4f%%)\n",
|
||||||
types.DeciStr(pow.MinerPower.QualityAdjPower),
|
types.DeciStr(pow.MinerPower.QualityAdjPower),
|
||||||
types.DeciStr(pow.TotalPower.QualityAdjPower),
|
types.DeciStr(pow.TotalPower.QualityAdjPower),
|
||||||
float64(qpercI.Int64())/10000)
|
types.BigDivFloat(
|
||||||
|
types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)),
|
||||||
|
pow.TotalPower.QualityAdjPower,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
fmt.Fprintf(w, "\tCommitted: %s\n", types.SizeStr(i.CommittedBytes))
|
fmt.Fprintf(w, "\tCommitted: %s\n", types.SizeStr(i.CommittedBytes))
|
||||||
|
|
||||||
@ -608,16 +617,43 @@ func (i *MinerInfo) MarshalPlainText() ([]byte, error) {
|
|||||||
if !i.MinerPower.HasMinPower {
|
if !i.MinerPower.HasMinPower {
|
||||||
fmt.Fprintf(w, "Below minimum power threshold, no blocks will be won\n")
|
fmt.Fprintf(w, "Below minimum power threshold, no blocks will be won\n")
|
||||||
} else {
|
} else {
|
||||||
expWinChance := float64(types.BigMul(qpercI, types.NewInt(build.BlocksPerEpoch)).Int64()) / 1000000
|
|
||||||
if expWinChance > 0 {
|
|
||||||
if expWinChance > 1 {
|
|
||||||
expWinChance = 1
|
|
||||||
}
|
|
||||||
winRate := time.Duration(float64(time.Second*time.Duration(build.BlockDelaySecs)) / expWinChance)
|
|
||||||
winPerDay := float64(time.Hour*24) / float64(winRate)
|
|
||||||
|
|
||||||
fmt.Fprintln(w, "Expected block win rate: ")
|
winRatio := new(corebig.Rat).Mul(
|
||||||
fmt.Fprintf(w, "%.4f/day (every %s)\n", winPerDay, winRate.Truncate(time.Second))
|
new(corebig.Rat).SetFrac(
|
||||||
|
types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int,
|
||||||
|
pow.TotalPower.QualityAdjPower.Int,
|
||||||
|
),
|
||||||
|
// decrease the rate ever-so-slightly to very roughly account for the multi-win poisson distribution
|
||||||
|
// FIXME - this is not a scientifically derived number... like at all
|
||||||
|
corebig.NewRat(99997, 100000),
|
||||||
|
)
|
||||||
|
|
||||||
|
if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 {
|
||||||
|
|
||||||
|
weekly, _ := new(corebig.Rat).Mul(
|
||||||
|
winRatio,
|
||||||
|
new(corebig.Rat).SetInt64(7*builtin.EpochsInDay),
|
||||||
|
).Float64()
|
||||||
|
|
||||||
|
avgDuration, _ := new(corebig.Rat).Mul(
|
||||||
|
new(corebig.Rat).SetInt64(builtin.EpochDurationSeconds),
|
||||||
|
new(corebig.Rat).Inv(winRatio),
|
||||||
|
).Float64()
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "Projected average block win rate: %.02f/week (every %s)\n",
|
||||||
|
weekly,
|
||||||
|
(time.Second * time.Duration(avgDuration)).Truncate(time.Second).String(),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Geometric distribution calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples
|
||||||
|
// https://www.wolframalpha.com/input/?i=c%3D99%3B+p%3D188809111007232%3B+n%3D5740343177447735296%3B+%281-%284.99*p%2Fn%29%29%5E%28t*2880%29%3D%281-%28c%2F100%29%29
|
||||||
|
fmt.Fprintf(w, "Projected block win with 99.9%% probability every %s\n",
|
||||||
|
(time.Second * time.Duration(
|
||||||
|
builtin.EpochDurationSeconds*math.Log(1-0.999)/
|
||||||
|
math.Log(1-winRatioFloat),
|
||||||
|
)).Truncate(time.Second).String(),
|
||||||
|
)
|
||||||
|
fmt.Fprintln(w, "(projections DO NOT account for future network and miner growth)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user