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)
}
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 {
log.Panic(err)
}
p2api := p2poolapi.NewP2PoolApi(*p2poolApiHost)
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)
time.Sleep(time.Second * 5)

View File

@ -29,24 +29,17 @@ func main() {
log.Panic(err)
}
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 {
log.Panic(err)
}
p2api := p2poolapi.NewP2PoolApi(*p2poolApiHost)
//TODO: force-insert section
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
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))
outputs := make([]*transaction.Output, len(c.Outputs))
for i, o := range c.Outputs {
outputs[i] = &o
for i := range c.Outputs {
outputs[i] = &c.Outputs[i]
}
//TODO: this sorting will be inefficient come the hard fork
@ -89,7 +89,7 @@ func MatchOutputs(c *transaction.CoinbaseTransaction, miners []*Miner, privateKe
Output: o,
})
outputs[i] = nil
//outputs = slices.Compact(outputs)
outputs = slices.Compact(outputs)
break
}
}

View File

@ -1,31 +1,21 @@
package api
import (
"encoding/json"
"fmt"
"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"
"io"
"os"
"path"
)
type Api struct {
db *database.Database
path string
db *database.Database
p2api *P2PoolApi
}
func New(db *database.Database, p string) (*Api, error) {
func New(db *database.Database, p2api *P2PoolApi) (*Api, error) {
api := &Api{
db: db,
path: path.Clean(p),
}
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)
db: db,
p2api: p2api,
}
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) {
if tip == nil {
return nil
}
//TODO: adjust for fork
shares = make(map[uint64]types.Difficulty)
blockCount := 0
var blockDepth uint64
block := tip
blockCache := make(map[uint64]*database.Block, p2pool.PPLNSWindow)
for b := range a.db.GetBlocksInWindow(&tip.Height, p2pool.PPLNSWindow) {
blockCache := make(map[uint64]*database.Block, a.p2api.Consensus().ChainWindowSize)
for b := range a.db.GetBlocksInWindow(&tip.Height, a.p2api.Consensus().ChainWindowSize) {
blockCache[b.Height] = b
}
for {
if _, ok := shares[block.MinerId]; !ok {
shares[block.MinerId] = types.DifficultyFrom64(0)
}
mainchainDiff := a.p2api.MainDifficultyByHeight(randomx.SeedHeight(tip.Main.Height))
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) {
if (tip.Height - uncle.Block.Height) >= p2pool.PPLNSWindow {
if (tip.Height - uncle.Block.Height) >= a.p2api.Consensus().ChainWindowSize {
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 {
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))
shares[uncle.Block.MinerId] = shares[uncle.Block.MinerId].Add(uncleWeight)
}
if _, ok := shares[block.MinerId]; !ok {
shares[block.MinerId] = types.DifficultyFrom64(0)
}
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 {
block = b
} else {
block = a.db.GetBlockById(block.PreviousId)
}
if block == nil || blockCount >= p2pool.PPLNSWindow {
if block == nil {
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 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
}
}