consensus/p2pool/api/api.go

145 lines
3.5 KiB
Go

package api
import (
"git.gammaspectra.live/P2Pool/p2pool-observer/database"
"git.gammaspectra.live/P2Pool/p2pool-observer/monero/randomx"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
)
type Api struct {
db *database.Database
p2api *P2PoolApi
}
func New(db *database.Database, p2api *P2PoolApi) (*Api, error) {
api := &Api{
db: db,
p2api: p2api,
}
return api, nil
}
func (a *Api) GetDatabase() *database.Database {
return a.db
}
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)
var blockDepth uint64
block := tip
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
}
mainchainDiff := a.p2api.MainDifficultyByHeight(randomx.SeedHeight(tip.Main.Height))
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) >= 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)
}
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
}
if b, ok := blockCache[block.Height-1]; ok && b.Id == block.PreviousId {
block = b
} else {
block = a.db.GetBlockById(block.PreviousId)
}
if block == nil {
break
}
}
totalReward := tip.Coinbase.Reward
if 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 (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
}