Added .payout command, cleanup link generation

This commit is contained in:
DataHoarder 2023-04-28 20:54:19 +02:00
parent 25e5c06246
commit ab823b04ad
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
3 changed files with 94 additions and 25 deletions

31
bot.go
View file

@ -14,7 +14,6 @@ import (
"gopkg.in/sorcix/irc.v2"
"io"
"log"
"math"
"net/http"
"net/url"
"nhooyr.io/websocket"
@ -277,26 +276,20 @@ func main() {
// see about irc.ERR_NICKNAMEINUSE or irc.ERR_NICKCOLLISION to recover nick
payoutFound := func(e *channelEntry, b *index.FoundBlock, o *index.MainCoinbaseOutput, sub *Subscription) {
uHeight := (b.SideHeight << 16) | (uint64(b.MainBlock.Id[0]) << 8) | uint64(b.MainBlock.Id[1])
payoutIndex := (b.SideHeight << uint64(math.Ceil(math.Log2(float64(e.Consensus.ChainWindowSize*4))))) | uint64(o.Index)
bot.Msg(sub.Nick, fmt.Sprintf(
"%sPAYOUT%s on %s: %s%s%s XMR%s to %s%s%s :: Main height %s%d%s, Side height %d :: %s/s/%s :: Verify payout %s/p/%s",
"%sPAYOUT%s on %s: %s%s%s XMR%s to %s%s%s :: Main height %s%d%s, Side height %d :: %s :: Verify payout %s",
FormatColorLightGreen+FormatBold, FormatReset, e.Name,
FormatColorOrange, FormatBold, utils.XMRUnits(o.Value), FormatReset,
FormatItalic, utils.Shorten(o.MinerAddress.ToBase58(), 10), FormatReset,
FormatColorRed, b.MainBlock.Height, FormatReset,
b.SideHeight,
e.ApiEndpoint, utils.EncodeBinaryNumber(uHeight),
e.ApiEndpoint, utils.EncodeBinaryNumber(payoutIndex),
GetShareLink(e.ApiEndpoint, b.SideHeight, b.MainBlock.Id),
GetPayoutLink(e.ApiEndpoint, b.SideHeight, o.Index, e.Consensus),
))
}
shareFound := func(e *channelEntry, tip *index.SideBlock, sub *Subscription) {
uHeight := (tip.SideHeight << 16) | (uint64(tip.MainId[0]) << 8) | uint64(tip.MainId[1])
shareCount := 0
uncleCount := 0
@ -322,11 +315,11 @@ func main() {
if tip.UncleOf != types.ZeroHash {
bot.Msg(sub.Nick, fmt.Sprintf(
"%sUNCLE SHARE FOUND%s on %s: Side height %s%d%s, Parent Side height %s%d%s :: %s/s/%s :: Accounted for %d%% of value :: Template Id %s%s%s :: Window shares %d (+%d uncles) ~%.03f%% :: Miner Address %s%s",
"%sUNCLE SHARE FOUND%s on %s: Side height %s%d%s, Parent Side height %s%d%s :: %s :: Accounted for %d%% of value :: Template Id %s%s%s :: Window shares %d (+%d uncles) ~%.03f%% :: Miner Address %s%s",
FormatColorLightGreen+FormatBold, FormatReset, e.Name,
FormatColorRed, tip.SideHeight, FormatReset,
FormatColorRed, tip.EffectiveHeight, FormatReset,
e.ApiEndpoint, utils.EncodeBinaryNumber(uHeight),
GetShareLink(e.ApiEndpoint, tip.SideHeight, tip.MainId),
100-e.Consensus.UnclePenalty,
FormatItalic, utils.Shorten(tip.TemplateId.String(), 8), FormatReset,
shareCount, uncleCount, shareRatio*100,
@ -338,10 +331,10 @@ func main() {
uncleText = fmt.Sprintf(":: Includes %d uncle(s) for extra %d%% of their value ", len(tip.Uncles), e.Consensus.UnclePenalty)
}
bot.Msg(sub.Nick, fmt.Sprintf(
"%sSHARE FOUND%s on %s: Side height %s%d%s :: %s/s/%s %s:: Template Id %s%s%s :: Window shares %d (+%d uncles) ~%.03f%% :: Miner Address %s%s",
"%sSHARE FOUND%s on %s: Side height %s%d%s :: %s %s:: Template Id %s%s%s :: Window shares %d (+%d uncles) ~%.03f%% :: Miner Address %s%s",
FormatColorLightGreen+FormatBold, FormatReset, e.Name,
FormatColorRed, tip.SideHeight, FormatReset,
e.ApiEndpoint, utils.EncodeBinaryNumber(uHeight),
GetShareLink(e.ApiEndpoint, tip.SideHeight, tip.MainId),
uncleText,
FormatItalic, utils.Shorten(tip.TemplateId.String(), 8), FormatReset,
shareCount, uncleCount, shareRatio*100,
@ -351,18 +344,17 @@ func main() {
}
blockFound := func(e *channelEntry, b *index.FoundBlock, previous *index.FoundBlock) {
uHeight := (b.SideHeight << 16) | (uint64(b.MainBlock.Id[0]) << 8) | uint64(b.MainBlock.Id[1])
effort := float64(0)
if previous != nil {
effort = float64(b.CumulativeDifficulty.SubWrap(previous.CumulativeDifficulty).Mul64(100).Lo) / float64(b.MainBlock.Difficulty)
}
bot.Msg(e.Channel, fmt.Sprintf(
"%sBLOCK FOUND%s on %s: Main height %s%d%s, Side height %d :: %s/s/%s :: Effort %s%.02f%%%s :: %s%d miners paid%s, total %s%s%s XMR%s :: Id %s%s",
"%sBLOCK FOUND%s on %s: Main height %s%d%s, Side height %d :: %s :: Effort %s%.02f%%%s :: %s%d miners paid%s, total %s%s%s XMR%s :: Id %s%s",
FormatColorLightGreen+FormatBold, FormatReset, e.Name,
FormatColorRed, b.MainBlock.Height, FormatReset,
b.SideHeight,
e.ApiEndpoint, utils.EncodeBinaryNumber(uHeight),
GetShareLink(e.ApiEndpoint, b.SideHeight, b.MainBlock.Id),
EffortColor(effort), effort, FormatReset,
FormatColorOrange, b.WindowOutputs, FormatReset,
FormatColorOrange, FormatBold, utils.XMRUnits(b.MainBlock.Reward), FormatReset,
@ -370,12 +362,11 @@ func main() {
))
doPleromaPost(e, fmt.Sprintf(
"BLOCK FOUND on %s, Main height %d, Side height %d :: %s/s/%s :: Effort %.02f%% :: %d miners paid, total %s XMR :: Id %s",
"BLOCK FOUND on %s, Main height %d, Side height %d :: %s :: Effort %.02f%% :: %d miners paid, total %s XMR :: Id %s",
e.Name,
b.MainBlock.Height,
b.SideHeight,
e.ApiEndpoint,
utils.EncodeBinaryNumber(uHeight),
GetShareLink(e.ApiEndpoint, b.SideHeight, b.MainBlock.Id),
effort,
b.WindowOutputs,
utils.XMRUnits(b.MainBlock.Reward),

View file

@ -69,8 +69,6 @@ var commands = []command{
}
poolInfo := getPoolInfo(e.ApiEndpoint)
uHeight := (lastFound.SideHeight << 16) | (uint64(lastFound.MainBlock.Id[0]) << 8) | uint64(lastFound.MainBlock.Id[1])
effort := float64(0)
if previous != nil {
effort = float64(lastFound.CumulativeDifficulty.SubWrap(previous.CumulativeDifficulty).Mul64(100).Lo) / float64(lastFound.MainBlock.Difficulty)
@ -81,12 +79,12 @@ var commands = []command{
currentDifficulty, _ := types.DifficultyFromString(poolInfo["mainchain"].(map[string]any)["difficulty"].(string))
bot.Msg(replyTo, fmt.Sprintf(
"Pool %s, last block found at height %s%d%s %s, %s UTC :: %s/s/%s :: Effort %s%.02f%%%s :: %s%d miner outputs%s paid for %s%s%s XMR%s :: Current Effort %s%.02f%%%s :: Pool height %d :: Pool Hashrate %sH/s :: Global hashrate %sH/s",
"Pool %s, last block found at height %s%d%s %s, %s UTC :: %s :: Effort %s%.02f%%%s :: %s%d miner outputs%s paid for %s%s%s XMR%s :: Current Effort %s%.02f%%%s :: Pool height %d :: Pool Hashrate %sH/s :: Global hashrate %sH/s",
e.Name,
FormatColorRed, lastFound.MainBlock.Height, FormatReset,
TimeElapsed(lastFound.MainBlock.Timestamp),
time.Unix(int64(lastFound.MainBlock.Timestamp), 0).UTC().Format(time.DateTime),
e.ApiEndpoint, utils.EncodeBinaryNumber(uHeight),
GetShareLink(e.ApiEndpoint, lastFound.SideHeight, lastFound.MainBlock.Id),
EffortColor(effort), effort, FormatReset,
FormatColorOrange, lastFound.WindowOutputs, FormatReset,
FormatColorOrange, FormatBold, utils.XMRUnits(lastFound.MainBlock.Reward), FormatReset,
@ -111,6 +109,7 @@ var commands = []command{
return true
}
type result struct {
Name string
Endpoint string
ShareCount int
UncleCount int
@ -135,6 +134,7 @@ var commands = []command{
var tr []*result
for _, sub := range subs {
var r result
r.Name = e.Name
r.Tip = e.Tip
r.Endpoint = e.ApiEndpoint
r.Address = sub.Address
@ -178,11 +178,13 @@ var commands = []command{
for _, r := range results {
ratio := float64(r.YourWeight.Lo) / float64(r.TotalWeight.Lo)
bot.Msg(replyTo, fmt.Sprintf(
"Your shares %d (+%d uncles) ~%.03f%% %sH/s :: Miner Statistics %s/m/%s :: Shares/Uncles position %s %s",
"Pool %s, your shares %d (+%d uncles) ~%.03f%% %sH/s :: Miner Address %s%s%s :: Miner Statistics %s/m/%s :: Shares/Uncles position %s %s",
r.Name,
r.ShareCount,
r.UncleCount,
ratio*100,
utils.SiUnits(ratio*float64(types.DifficultyFrom64(r.Tip.Difficulty).Div64(r.Consensus.TargetBlockTime).Lo), 2),
FormatItalic, utils.Shorten(r.Address.ToBase58(), 10), FormatReset,
r.Endpoint,
utils.EncodeBinaryNumber(r.MinerId),
r.SharesPosition.String(),
@ -194,6 +196,66 @@ var commands = []command{
},
},
{
Help: ".payout",
Description: "Displays your last payout details across all pools",
Match: regexp.MustCompile("(?i)^\\.(payouts?|payments?|last-payments?)[ \t]*"),
Handle: func(db *DB, entries []*channelEntry, bot *hbot.Bot, message *hbot.Message, replyTo string, matches ...string) bool {
subs := db.GetByNick(message.Name)
if len(subs) == 0 {
bot.Msg(replyTo, "No known subscriptions to your nick.")
return true
}
type result struct {
Name string
Endpoint string
Payouts []*index.Payout
Address *address.Address
Consensus *sidechain.Consensus
}
var results []*result
for _, e := range filterEntriesForChannel(bot, message, entries) {
func(e *channelEntry) {
for _, sub := range subs {
payouts := getSliceFromAPI[*index.Payout](e.ApiEndpoint, fmt.Sprintf("/api/payouts/%s", sub.Address.ToBase58()))
if len(payouts) > 0 {
results = append(results, &result{
Name: e.Name,
Endpoint: e.ApiEndpoint,
Payouts: payouts,
Address: sub.Address,
Consensus: e.Consensus,
})
}
}
}(e)
}
if len(results) == 0 {
bot.Msg(replyTo, "You do not currently have any previous payouts across the tracked pools.")
} else {
for _, r := range results {
bot.Msg(replyTo, fmt.Sprintf(
"Pool %s, last payout for address %s%s%s was %s%s%s XMR%s on block %s%d%s %s, %s UTC :: %s :: Verify payout %s",
r.Name,
FormatItalic, utils.Shorten(r.Address.ToBase58(), 10), FormatReset,
FormatColorOrange, FormatBold, utils.XMRUnits(r.Payouts[0].Reward), FormatReset,
FormatColorRed, r.Payouts[0].MainHeight, FormatReset,
TimeElapsed(r.Payouts[0].Timestamp),
time.Unix(int64(r.Payouts[0].Timestamp), 0).UTC().Format(time.DateTime),
GetShareLink(r.Endpoint, r.Payouts[0].SideHeight, r.Payouts[0].MainId),
GetPayoutLink(r.Endpoint, r.Payouts[0].SideHeight, r.Payouts[0].Index, r.Consensus),
))
}
}
return true
},
},
{
Help: ".subscribe MONERO_ADDRESS",

View file

@ -1,6 +1,12 @@
package main
import (
"fmt"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"git.gammaspectra.live/P2Pool/p2pool-observer/utils"
"golang.org/x/exp/constraints"
"math"
"strconv"
"strings"
"time"
@ -47,3 +53,13 @@ func TimeElapsed(timestamp uint64) string {
return strings.Join(result, " ") + " ago"
}
}
func GetShareLink(host string, sideHeight uint64, mainId types.Hash) string {
uHeight := (sideHeight << 16) | (uint64(mainId[0]) << 8) | uint64(mainId[1])
return fmt.Sprintf("%s/s/%s", host, utils.EncodeBinaryNumber(uHeight))
}
func GetPayoutLink[T constraints.Integer](host string, sideHeight uint64, index T, consensus *sidechain.Consensus) string {
payoutIndex := (sideHeight << uint64(math.Ceil(math.Log2(float64(consensus.ChainWindowSize*4))))) | uint64(index)
return fmt.Sprintf("%s/p/%s", host, utils.EncodeBinaryNumber(payoutIndex))
}