Fixed miner output calculations

This commit is contained in:
DataHoarder 2023-03-20 11:47:09 +01:00
parent f818b06cd6
commit 84b8b99040
Signed by: DataHoarder
SSH key fingerprint: SHA256:EnPQOqPpbCa7nzalCEJY2sd9iPluFIBuJu2rDFalACI
4 changed files with 79 additions and 164 deletions

View file

@ -47,13 +47,13 @@ func main() {
log.Panic(err) log.Panic(err)
} }
defer db.Close() defer db.Close()
api, err := p2poolapi.New(db, os.Getenv("API_FOLDER"))
p2api := p2poolapi.NewP2PoolApi(*p2poolApiHost)
api, err := p2poolapi.New(db, p2api)
if err != nil { if err != nil {
log.Panic(err) log.Panic(err)
} }
p2api := p2poolapi.NewP2PoolApi(*p2poolApiHost)
for status := p2api.Status(); !p2api.Status().Synchronized; status = p2api.Status() { for status := p2api.Status(); !p2api.Status().Synchronized; status = p2api.Status() {
log.Printf("[API] Not synchronized (height %d, id %s), waiting five seconds", status.Height, status.Id) log.Printf("[API] Not synchronized (height %d, id %s), waiting five seconds", status.Height, status.Id)
time.Sleep(time.Second * 5) time.Sleep(time.Second * 5)

View file

@ -29,24 +29,17 @@ func main() {
log.Panic(err) log.Panic(err)
} }
defer db.Close() defer db.Close()
api, err := p2poolapi.New(db, os.Getenv("API_FOLDER"))
p2api := p2poolapi.NewP2PoolApi(*p2poolApiHost)
api, err := p2poolapi.New(db, p2api)
if err != nil { if err != nil {
log.Panic(err) log.Panic(err)
} }
p2api := p2poolapi.NewP2PoolApi(*p2poolApiHost)
//TODO: force-insert section //TODO: force-insert section
tip := db.GetChainTip() tip := db.GetChainTip()
/*bId, _ := types.HashFromString("f36ae9e2ed3e1e2ab7b79c9ac2767692f02c41b2aaf78e16fcc123730354ce86")
b := db.GetBlockById(bId)
if tx, _ := client.GetDefaultClient().GetCoinbaseTransaction(b.Coinbase.Id); tx != nil {
_ = db.SetBlockFound(b.Id, true)
processFoundBlockWithTransaction(api, b, tx)
}*/
isFresh := tip == nil isFresh := tip == nil
var tipHeight uint64 var tipHeight uint64

View file

@ -52,8 +52,8 @@ func MatchOutputs(c *transaction.CoinbaseTransaction, miners []*Miner, privateKe
addresses := make(map[address.PackedAddress]*Miner, len(miners)) addresses := make(map[address.PackedAddress]*Miner, len(miners))
outputs := make([]*transaction.Output, len(c.Outputs)) outputs := make([]*transaction.Output, len(c.Outputs))
for i, o := range c.Outputs { for i := range c.Outputs {
outputs[i] = &o outputs[i] = &c.Outputs[i]
} }
//TODO: this sorting will be inefficient come the hard fork //TODO: this sorting will be inefficient come the hard fork
@ -89,7 +89,7 @@ func MatchOutputs(c *transaction.CoinbaseTransaction, miners []*Miner, privateKe
Output: o, Output: o,
}) })
outputs[i] = nil outputs[i] = nil
//outputs = slices.Compact(outputs) outputs = slices.Compact(outputs)
break break
} }
} }

View file

@ -1,31 +1,21 @@
package api package api
import ( import (
"encoding/json"
"fmt"
"git.gammaspectra.live/P2Pool/p2pool-observer/database" "git.gammaspectra.live/P2Pool/p2pool-observer/database"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool" "git.gammaspectra.live/P2Pool/p2pool-observer/monero/randomx"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
"git.gammaspectra.live/P2Pool/p2pool-observer/types" "git.gammaspectra.live/P2Pool/p2pool-observer/types"
"io"
"os"
"path"
) )
type Api struct { type Api struct {
db *database.Database db *database.Database
path string p2api *P2PoolApi
} }
func New(db *database.Database, p string) (*Api, error) { func New(db *database.Database, p2api *P2PoolApi) (*Api, error) {
api := &Api{ api := &Api{
db: db, db: db,
path: path.Clean(p), p2api: p2api,
}
if info, err := os.Stat(api.path); err != nil {
return nil, err
} else if !info.IsDir() {
return nil, fmt.Errorf("directory path does not exist %s %s", p, api.path)
} }
return api, nil return api, nil
@ -36,48 +26,91 @@ func (a *Api) GetDatabase() *database.Database {
} }
func (a *Api) GetBlockWindowPayouts(tip *database.Block) (shares map[uint64]types.Difficulty) { func (a *Api) GetBlockWindowPayouts(tip *database.Block) (shares map[uint64]types.Difficulty) {
if tip == nil {
return nil
}
//TODO: adjust for fork //TODO: adjust for fork
shares = make(map[uint64]types.Difficulty) shares = make(map[uint64]types.Difficulty)
blockCount := 0 var blockDepth uint64
block := tip block := tip
blockCache := make(map[uint64]*database.Block, p2pool.PPLNSWindow) blockCache := make(map[uint64]*database.Block, a.p2api.Consensus().ChainWindowSize)
for b := range a.db.GetBlocksInWindow(&tip.Height, p2pool.PPLNSWindow) { for b := range a.db.GetBlocksInWindow(&tip.Height, a.p2api.Consensus().ChainWindowSize) {
blockCache[b.Height] = b blockCache[b.Height] = b
} }
for { mainchainDiff := a.p2api.MainDifficultyByHeight(randomx.SeedHeight(tip.Main.Height))
if _, ok := shares[block.MinerId]; !ok {
shares[block.MinerId] = types.DifficultyFrom64(0)
}
shares[block.MinerId] = shares[block.MinerId].Add(block.Difficulty) if mainchainDiff == types.ZeroDifficulty {
return nil
}
//TODO: remove this hack
sidechainVersion := sidechain.ShareVersion_V1
if tip.Timestamp >= sidechain.ShareVersion_V2MainNetTimestamp {
sidechainVersion = sidechain.ShareVersion_V2
}
maxPplnsWeight := types.MaxDifficulty
if sidechainVersion > sidechain.ShareVersion_V1 {
maxPplnsWeight = mainchainDiff.Mul64(2)
}
var pplnsWeight types.Difficulty
for {
curWeight := block.Difficulty
for uncle := range a.db.GetUnclesByParentId(block.Id) { for uncle := range a.db.GetUnclesByParentId(block.Id) {
if (tip.Height - uncle.Block.Height) >= p2pool.PPLNSWindow { if (tip.Height - uncle.Block.Height) >= a.p2api.Consensus().ChainWindowSize {
continue continue
} }
unclePenalty := uncle.Block.Difficulty.Mul64(a.p2api.Consensus().UnclePenalty).Div64(100)
uncleWeight := uncle.Block.Difficulty.Sub(unclePenalty)
newPplnsWeight := pplnsWeight.Add(uncleWeight)
if newPplnsWeight.Cmp(maxPplnsWeight) > 0 {
continue
}
curWeight = curWeight.Add(uncleWeight)
if _, ok := shares[uncle.Block.MinerId]; !ok { if _, ok := shares[uncle.Block.MinerId]; !ok {
shares[uncle.Block.MinerId] = types.DifficultyFrom64(0) shares[uncle.Block.MinerId] = types.DifficultyFrom64(0)
} }
shares[uncle.Block.MinerId] = shares[uncle.Block.MinerId].Add(uncleWeight)
product := uncle.Block.Difficulty.Mul64(p2pool.UnclePenalty) }
unclePenalty := product.Div64(100)
if _, ok := shares[block.MinerId]; !ok {
shares[block.MinerId] = shares[block.MinerId].Add(unclePenalty) shares[block.MinerId] = types.DifficultyFrom64(0)
shares[uncle.Block.MinerId] = shares[uncle.Block.MinerId].Add(uncle.Block.Difficulty.Sub(unclePenalty)) }
shares[block.MinerId] = shares[block.MinerId].Add(curWeight)
pplnsWeight = pplnsWeight.Add(curWeight)
if pplnsWeight.Cmp(maxPplnsWeight) > 0 {
break
}
blockDepth++
if blockDepth >= a.p2api.Consensus().ChainWindowSize {
break
}
if block.Height == 0 {
break
} }
blockCount++
if b, ok := blockCache[block.Height-1]; ok && b.Id == block.PreviousId { if b, ok := blockCache[block.Height-1]; ok && b.Id == block.PreviousId {
block = b block = b
} else { } else {
block = a.db.GetBlockById(block.PreviousId) block = a.db.GetBlockById(block.PreviousId)
} }
if block == nil || blockCount >= p2pool.PPLNSWindow { if block == nil {
break break
} }
} }
@ -101,122 +134,11 @@ func (a *Api) GetBlockWindowPayouts(tip *database.Block) (shares map[uint64]type
} }
} }
if blockCount != p2pool.PPLNSWindow { if (block == nil || block.Height != 0) &&
((sidechainVersion == sidechain.ShareVersion_V1 && blockDepth != a.p2api.Consensus().ChainWindowSize) ||
(sidechainVersion > sidechain.ShareVersion_V1 && (blockDepth != a.p2api.Consensus().ChainWindowSize) && pplnsWeight.Cmp(maxPplnsWeight) <= 0)) {
return nil return nil
} }
return shares return shares
} }
func (a *Api) GetWindowPayouts(height, totalReward *uint64) (shares map[uint64]types.Difficulty) {
shares = make(map[uint64]types.Difficulty)
var tip uint64
if height != nil {
tip = *height
} else {
tip = a.db.GetChainTip().Height
}
blockCount := 0
for block := range a.db.GetBlocksInWindow(&tip, p2pool.PPLNSWindow) {
if _, ok := shares[block.MinerId]; !ok {
shares[block.MinerId] = types.DifficultyFrom64(0)
}
shares[block.MinerId] = shares[block.MinerId].Add(block.Difficulty)
for uncle := range a.db.GetUnclesByParentId(block.Id) {
if (tip - uncle.Block.Height) >= p2pool.PPLNSWindow {
continue
}
if _, ok := shares[uncle.Block.MinerId]; !ok {
shares[uncle.Block.MinerId] = types.DifficultyFrom64(0)
}
product := uncle.Block.Difficulty.Mul64(p2pool.UnclePenalty)
unclePenalty := product.Div64(100)
shares[block.MinerId] = shares[block.MinerId].Add(unclePenalty)
shares[uncle.Block.MinerId] = shares[uncle.Block.MinerId].Add(uncle.Block.Difficulty.Sub(unclePenalty))
}
blockCount++
}
if totalReward != nil && *totalReward > 0 {
totalWeight := types.DifficultyFrom64(0)
for _, w := range shares {
totalWeight = totalWeight.Add(w)
}
w := types.DifficultyFrom64(0)
rewardGiven := types.DifficultyFrom64(0)
for miner, weight := range shares {
w = w.Add(weight)
nextValue := w.Mul64(*totalReward).Div(totalWeight)
shares[miner] = nextValue.Sub(rewardGiven)
rewardGiven = nextValue
}
}
if blockCount != p2pool.PPLNSWindow {
return nil
}
return shares
}
// GetPoolBlocks
// Deprecated
func (a *Api) GetPoolBlocks() (result []struct {
Height uint64 `json:"height"`
Hash types.Hash `json:"hash"`
Difficulty uint64 `json:"difficulty"`
TotalHashes uint64 `json:"totalHashes"`
Ts uint64 `json:"ts"`
}, err error) {
f, err := os.Open(fmt.Sprintf("%s/pool/blocks", a.path))
if err != nil {
return result, err
}
defer f.Close()
if buf, err := io.ReadAll(f); err != nil {
return result, err
} else {
err = json.Unmarshal(buf, &result)
return result, err
}
}
// GetPoolStats
// Deprecated
func (a *Api) GetPoolStats() (result struct {
PoolList []string `json:"pool_list"`
PoolStatistics struct {
HashRate uint64 `json:"hashRate"`
Difficulty uint64 `json:"difficulty"`
Hash types.Hash `json:"hash"`
Height uint64 `json:"height"`
Miners uint64 `json:"miners"`
TotalHashes uint64 `json:"totalHashes"`
LastBlockFoundTime uint64 `json:"lastBlockFoundTime"`
LastBlockFound uint64 `json:"lastBlockFound"`
TotalBlocksFound uint64 `json:"totalBlocksFound"`
} `json:"pool_statistics"`
}, err error) {
f, err := os.Open(fmt.Sprintf("%s/pool/stats", a.path))
if err != nil {
return result, err
}
defer f.Close()
if buf, err := io.ReadAll(f); err != nil {
return result, err
} else {
err = json.Unmarshal(buf, &result)
return result, err
}
}