Merge pull request #6309 from filecoin-project/feat/better_mining_projection_and_accuracy
Adjust various CLI display ratios to arbitrary precision
This commit is contained in:
commit
35f76f58df
@ -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()
|
||||||
|
|
||||||
@ -311,8 +316,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,54 @@ 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).SetFrac(
|
||||||
color.Blue("%.4f/day (every %s)", winPerDay, winRate.Truncate(time.Second))
|
types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int,
|
||||||
|
pow.TotalPower.QualityAdjPower.Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 {
|
||||||
|
|
||||||
|
// if the corresponding poisson distribution isn't infinitely small then
|
||||||
|
// throw it into the mix as well, accounting for multi-wins
|
||||||
|
winRationWithPoissonFloat := -math.Expm1(-winRatioFloat)
|
||||||
|
winRationWithPoisson := new(corebig.Rat).SetFloat64(winRationWithPoissonFloat)
|
||||||
|
if winRationWithPoisson != nil {
|
||||||
|
winRatio = winRationWithPoisson
|
||||||
|
winRatioFloat = winRationWithPoissonFloat
|
||||||
|
}
|
||||||
|
|
||||||
|
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 of P(Y < k) calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples
|
||||||
|
// https://www.wolframalpha.com/input/?i=t+%3E+0%3B+p+%3E+0%3B+p+%3C+1%3B+c+%3E+0%3B+c+%3C1%3B+1-%281-p%29%5E%28t%29%3Dc%3B+solve+t
|
||||||
|
// t == how many dice-rolls (epochs) before win
|
||||||
|
// p == winRate == ( minerPower / netPower )
|
||||||
|
// c == target probability of win ( 99.9% in this case )
|
||||||
|
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,50 @@ 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).SetFrac(
|
||||||
fmt.Fprintf(w, "%.4f/day (every %s)\n", winPerDay, winRate.Truncate(time.Second))
|
types.BigMul(pow.MinerPower.QualityAdjPower, types.NewInt(build.BlocksPerEpoch)).Int,
|
||||||
|
pow.TotalPower.QualityAdjPower.Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
if winRatioFloat, _ := winRatio.Float64(); winRatioFloat > 0 {
|
||||||
|
|
||||||
|
// if the corresponding poisson distribution isn't infinitely small then
|
||||||
|
// throw it into the mix as well, accounting for multi-wins
|
||||||
|
winRationWithPoissonFloat := -math.Expm1(-winRatioFloat)
|
||||||
|
winRationWithPoisson := new(corebig.Rat).SetFloat64(winRationWithPoissonFloat)
|
||||||
|
if winRationWithPoisson != nil {
|
||||||
|
winRatio = winRationWithPoisson
|
||||||
|
winRatioFloat = winRationWithPoissonFloat
|
||||||
|
}
|
||||||
|
|
||||||
|
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 of P(Y < k) calculated as described in https://en.wikipedia.org/wiki/Geometric_distribution#Probability_Outcomes_Examples
|
||||||
|
// https://www.wolframalpha.com/input/?i=t+%3E+0%3B+p+%3E+0%3B+p+%3C+1%3B+c+%3E+0%3B+c+%3C1%3B+1-%281-p%29%5E%28t%29%3Dc%3B+solve+t
|
||||||
|
// t == how many dice-rolls (epochs) before win
|
||||||
|
// p == winRate == ( minerPower / netPower )
|
||||||
|
// c == target probability of win ( 99.9% in this case )
|
||||||
|
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