Changed how blocks are iterated from sidechain
This commit is contained in:
parent
1b04de234c
commit
9b241e22db
|
@ -539,9 +539,7 @@ func getServerMux(instance *p2pool.P2Pool) *mux.Router {
|
|||
|
||||
var topError error
|
||||
|
||||
for e := range sidechain.IterateBlocksInPPLNSWindow(tip, instance.Consensus(), instance.GetDifficultyByHeight, getByTemplateId, nil, func(err error) {
|
||||
topError = err
|
||||
}) {
|
||||
topError = sidechain.IterateBlocksInPPLNSWindow(tip, instance.Consensus(), instance.GetDifficultyByHeight, getByTemplateId, nil, func(e sidechain.PoolBlockWindowSlot) {
|
||||
if _, err = e.Block.PreProcessBlock(instance.Consensus(), instance.SideChain().DerivationCache(), preAllocatedShares, instance.GetDifficultyByHeight, getByTemplateId); err != nil {
|
||||
topError = err
|
||||
result.Chain = append(result.Chain, p2pooltypes.P2PoolBinaryBlockResult{
|
||||
|
@ -581,7 +579,7 @@ func getServerMux(instance *p2pool.P2Pool) *mux.Router {
|
|||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if topError == nil {
|
||||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
|
|
@ -1278,13 +1278,8 @@ func (i *Index) GetSideBlockFromPoolBlock(b *sidechain.PoolBlock, inclusion Bloc
|
|||
}
|
||||
tip.EffectiveHeight = tip.SideHeight
|
||||
tip.Inclusion = inclusion
|
||||
var bottomHeight uint64
|
||||
for e := range sidechain.IterateBlocksInPPLNSWindow(b, i.consensus, i.GetDifficultyByHeight, i.GetByTemplateId, nil, func(err error) {
|
||||
bottomHeight = 0
|
||||
}) {
|
||||
bottomHeight = e.Block.Side.Height
|
||||
}
|
||||
if bottomHeight == 0 {
|
||||
|
||||
if bottomHeight, err := sidechain.BlocksInPPLNSWindow(b, i.consensus, i.GetDifficultyByHeight, i.GetByTemplateId, nil); err != nil {
|
||||
// unknown
|
||||
tip.WindowDepth = 0
|
||||
} else {
|
||||
|
@ -1316,13 +1311,8 @@ func (i *Index) GetSideBlockFromPoolBlock(b *sidechain.PoolBlock, inclusion Bloc
|
|||
uncleBlock.EffectiveHeight = tip.EffectiveHeight
|
||||
uncleBlock.Inclusion = InclusionInVerifiedChain
|
||||
}
|
||||
var uncleBottomHeight uint64
|
||||
for e := range sidechain.IterateBlocksInPPLNSWindow(uncle, i.consensus, i.GetDifficultyByHeight, i.GetByTemplateId, nil, func(err error) {
|
||||
uncleBottomHeight = 0
|
||||
}) {
|
||||
uncleBottomHeight = e.Block.Side.Height
|
||||
}
|
||||
if uncleBottomHeight == 0 {
|
||||
|
||||
if uncleBottomHeight, err := sidechain.BlocksInPPLNSWindow(uncle, i.consensus, i.GetDifficultyByHeight, i.GetByTemplateId, nil); err != nil {
|
||||
// unknown
|
||||
uncleBlock.WindowDepth = 0
|
||||
} else {
|
||||
|
|
|
@ -78,123 +78,203 @@ type PoolBlockWindowSlot struct {
|
|||
|
||||
type PoolBlockWindowAddWeightFunc func(b *PoolBlock, weight types.Difficulty)
|
||||
|
||||
func IterateBlocksInPPLNSWindow(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, addWeightFunc PoolBlockWindowAddWeightFunc, errorFunc func(err error)) (results chan PoolBlockWindowSlot) {
|
||||
results = make(chan PoolBlockWindowSlot)
|
||||
func IterateBlocksInPPLNSWindow(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, addWeightFunc PoolBlockWindowAddWeightFunc, slotFunc func(slot PoolBlockWindowSlot)) error {
|
||||
|
||||
go func() {
|
||||
defer close(results)
|
||||
cur := tip
|
||||
|
||||
cur := tip
|
||||
var blockDepth uint64
|
||||
|
||||
var blockDepth uint64
|
||||
var mainchainDiff types.Difficulty
|
||||
|
||||
var mainchainDiff types.Difficulty
|
||||
if tip.Side.Parent != types.ZeroHash {
|
||||
seedHeight := randomx.SeedHeight(tip.Main.Coinbase.GenHeight)
|
||||
mainchainDiff = difficultyByHeight(seedHeight)
|
||||
if mainchainDiff == types.ZeroDifficulty {
|
||||
return fmt.Errorf("couldn't get mainchain difficulty for height = %d", seedHeight)
|
||||
}
|
||||
}
|
||||
|
||||
if tip.Side.Parent != types.ZeroHash {
|
||||
seedHeight := randomx.SeedHeight(tip.Main.Coinbase.GenHeight)
|
||||
mainchainDiff = difficultyByHeight(seedHeight)
|
||||
if mainchainDiff == types.ZeroDifficulty {
|
||||
if errorFunc != nil {
|
||||
errorFunc(fmt.Errorf("couldn't get mainchain difficulty for height = %d", seedHeight))
|
||||
// Dynamic PPLNS window starting from v2
|
||||
// Limit PPLNS weight to 2x of the Monero difficulty (max 2 blocks per PPLNS window on average)
|
||||
sidechainVersion := tip.ShareVersion()
|
||||
|
||||
maxPplnsWeight := types.MaxDifficulty
|
||||
|
||||
if sidechainVersion > ShareVersion_V1 {
|
||||
maxPplnsWeight = mainchainDiff.Mul64(2)
|
||||
}
|
||||
|
||||
var pplnsWeight types.Difficulty
|
||||
|
||||
for {
|
||||
curEntry := PoolBlockWindowSlot{
|
||||
Block: cur,
|
||||
}
|
||||
curWeight := cur.Side.Difficulty
|
||||
|
||||
for _, uncleId := range cur.Side.Uncles {
|
||||
if uncle := getByTemplateId(uncleId); uncle == nil {
|
||||
//cannot find uncles
|
||||
return fmt.Errorf("could not find uncle %s", uncleId.String())
|
||||
} else {
|
||||
//Needs to be added regardless - for other consumers
|
||||
curEntry.Uncles = append(curEntry.Uncles, uncle)
|
||||
|
||||
// Skip uncles which are already out of PPLNS window
|
||||
if (tip.Side.Height - uncle.Side.Height) >= consensus.ChainWindowSize {
|
||||
continue
|
||||
}
|
||||
return
|
||||
|
||||
// Take some % of uncle's weight into this share
|
||||
unclePenalty := uncle.Side.Difficulty.Mul64(consensus.UnclePenalty).Div64(100)
|
||||
uncleWeight := uncle.Side.Difficulty.Sub(unclePenalty)
|
||||
newPplnsWeight := pplnsWeight.Add(uncleWeight)
|
||||
|
||||
// Skip uncles that push PPLNS weight above the limit
|
||||
if newPplnsWeight.Cmp(maxPplnsWeight) > 0 {
|
||||
continue
|
||||
}
|
||||
curWeight = curWeight.Add(unclePenalty)
|
||||
|
||||
if addWeightFunc != nil {
|
||||
addWeightFunc(uncle, uncleWeight)
|
||||
}
|
||||
|
||||
pplnsWeight = newPplnsWeight
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic PPLNS window starting from v2
|
||||
// Limit PPLNS weight to 2x of the Monero difficulty (max 2 blocks per PPLNS window on average)
|
||||
sidechainVersion := tip.ShareVersion()
|
||||
// Always add non-uncle shares even if PPLNS weight goes above the limit
|
||||
slotFunc(curEntry)
|
||||
|
||||
maxPplnsWeight := types.MaxDifficulty
|
||||
|
||||
if sidechainVersion > ShareVersion_V1 {
|
||||
maxPplnsWeight = mainchainDiff.Mul64(2)
|
||||
if addWeightFunc != nil {
|
||||
addWeightFunc(cur, curWeight)
|
||||
}
|
||||
|
||||
var pplnsWeight types.Difficulty
|
||||
pplnsWeight = pplnsWeight.Add(curWeight)
|
||||
|
||||
for {
|
||||
curEntry := PoolBlockWindowSlot{
|
||||
Block: cur,
|
||||
}
|
||||
curWeight := cur.Side.Difficulty
|
||||
|
||||
for _, uncleId := range cur.Side.Uncles {
|
||||
if uncle := getByTemplateId(uncleId); uncle == nil {
|
||||
//cannot find uncles
|
||||
if errorFunc != nil {
|
||||
errorFunc(fmt.Errorf("could not find uncle %s", uncleId.String()))
|
||||
}
|
||||
return
|
||||
} else {
|
||||
//Needs to be added regardless - for other consumers
|
||||
curEntry.Uncles = append(curEntry.Uncles, uncle)
|
||||
|
||||
// Skip uncles which are already out of PPLNS window
|
||||
if (tip.Side.Height - uncle.Side.Height) >= consensus.ChainWindowSize {
|
||||
continue
|
||||
}
|
||||
|
||||
// Take some % of uncle's weight into this share
|
||||
unclePenalty := uncle.Side.Difficulty.Mul64(consensus.UnclePenalty).Div64(100)
|
||||
uncleWeight := uncle.Side.Difficulty.Sub(unclePenalty)
|
||||
newPplnsWeight := pplnsWeight.Add(uncleWeight)
|
||||
|
||||
// Skip uncles that push PPLNS weight above the limit
|
||||
if newPplnsWeight.Cmp(maxPplnsWeight) > 0 {
|
||||
continue
|
||||
}
|
||||
curWeight = curWeight.Add(unclePenalty)
|
||||
|
||||
if addWeightFunc != nil {
|
||||
addWeightFunc(uncle, uncleWeight)
|
||||
}
|
||||
|
||||
pplnsWeight = newPplnsWeight
|
||||
}
|
||||
}
|
||||
|
||||
// Always add non-uncle shares even if PPLNS weight goes above the limit
|
||||
results <- curEntry
|
||||
|
||||
if addWeightFunc != nil {
|
||||
addWeightFunc(cur, curWeight)
|
||||
}
|
||||
|
||||
pplnsWeight = pplnsWeight.Add(curWeight)
|
||||
|
||||
// One non-uncle share can go above the limit, but it will also guarantee that "shares" is never empty
|
||||
if pplnsWeight.Cmp(maxPplnsWeight) > 0 {
|
||||
break
|
||||
}
|
||||
|
||||
blockDepth++
|
||||
|
||||
if blockDepth >= consensus.ChainWindowSize {
|
||||
break
|
||||
}
|
||||
|
||||
// Reached the genesis block so we're done
|
||||
if cur.Side.Height == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
parentId := cur.Side.Parent
|
||||
cur = getByTemplateId(parentId)
|
||||
|
||||
if cur == nil {
|
||||
if errorFunc != nil {
|
||||
errorFunc(fmt.Errorf("could not find parent %s", parentId.String()))
|
||||
}
|
||||
return
|
||||
}
|
||||
// One non-uncle share can go above the limit, but it will also guarantee that "shares" is never empty
|
||||
if pplnsWeight.Cmp(maxPplnsWeight) > 0 {
|
||||
break
|
||||
}
|
||||
}()
|
||||
|
||||
return results
|
||||
blockDepth++
|
||||
|
||||
if blockDepth >= consensus.ChainWindowSize {
|
||||
break
|
||||
}
|
||||
|
||||
// Reached the genesis block so we're done
|
||||
if cur.Side.Height == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
parentId := cur.Side.Parent
|
||||
cur = getByTemplateId(parentId)
|
||||
|
||||
if cur == nil {
|
||||
return fmt.Errorf("could not find parent %s", parentId.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetShares(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, preAllocatedShares Shares) (shares Shares, bottomHeight uint64) {
|
||||
func BlocksInPPLNSWindow(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, addWeightFunc PoolBlockWindowAddWeightFunc) (bottomHeight uint64, err error) {
|
||||
|
||||
cur := tip
|
||||
|
||||
var blockDepth uint64
|
||||
|
||||
var mainchainDiff types.Difficulty
|
||||
|
||||
if tip.Side.Parent != types.ZeroHash {
|
||||
seedHeight := randomx.SeedHeight(tip.Main.Coinbase.GenHeight)
|
||||
mainchainDiff = difficultyByHeight(seedHeight)
|
||||
if mainchainDiff == types.ZeroDifficulty {
|
||||
return 0, fmt.Errorf("couldn't get mainchain difficulty for height = %d", seedHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic PPLNS window starting from v2
|
||||
// Limit PPLNS weight to 2x of the Monero difficulty (max 2 blocks per PPLNS window on average)
|
||||
sidechainVersion := tip.ShareVersion()
|
||||
|
||||
maxPplnsWeight := types.MaxDifficulty
|
||||
|
||||
if sidechainVersion > ShareVersion_V1 {
|
||||
maxPplnsWeight = mainchainDiff.Mul64(2)
|
||||
}
|
||||
|
||||
var pplnsWeight types.Difficulty
|
||||
|
||||
for {
|
||||
curWeight := cur.Side.Difficulty
|
||||
|
||||
for _, uncleId := range cur.Side.Uncles {
|
||||
if uncle := getByTemplateId(uncleId); uncle == nil {
|
||||
//cannot find uncles
|
||||
return 0, fmt.Errorf("could not find uncle %s", uncleId.String())
|
||||
} else {
|
||||
// Skip uncles which are already out of PPLNS window
|
||||
if (tip.Side.Height - uncle.Side.Height) >= consensus.ChainWindowSize {
|
||||
continue
|
||||
}
|
||||
|
||||
// Take some % of uncle's weight into this share
|
||||
unclePenalty := uncle.Side.Difficulty.Mul64(consensus.UnclePenalty).Div64(100)
|
||||
uncleWeight := uncle.Side.Difficulty.Sub(unclePenalty)
|
||||
newPplnsWeight := pplnsWeight.Add(uncleWeight)
|
||||
|
||||
// Skip uncles that push PPLNS weight above the limit
|
||||
if newPplnsWeight.Cmp(maxPplnsWeight) > 0 {
|
||||
continue
|
||||
}
|
||||
curWeight = curWeight.Add(unclePenalty)
|
||||
|
||||
if addWeightFunc != nil {
|
||||
addWeightFunc(uncle, uncleWeight)
|
||||
}
|
||||
|
||||
pplnsWeight = newPplnsWeight
|
||||
}
|
||||
}
|
||||
|
||||
// Always add non-uncle shares even if PPLNS weight goes above the limit
|
||||
bottomHeight = cur.Side.Height
|
||||
|
||||
if addWeightFunc != nil {
|
||||
addWeightFunc(cur, curWeight)
|
||||
}
|
||||
|
||||
pplnsWeight = pplnsWeight.Add(curWeight)
|
||||
|
||||
// One non-uncle share can go above the limit, but it will also guarantee that "shares" is never empty
|
||||
if pplnsWeight.Cmp(maxPplnsWeight) > 0 {
|
||||
break
|
||||
}
|
||||
|
||||
blockDepth++
|
||||
|
||||
if blockDepth >= consensus.ChainWindowSize {
|
||||
break
|
||||
}
|
||||
|
||||
// Reached the genesis block so we're done
|
||||
if cur.Side.Height == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
parentId := cur.Side.Parent
|
||||
cur = getByTemplateId(parentId)
|
||||
|
||||
if cur == nil {
|
||||
return 0, fmt.Errorf("could not find parent %s", parentId.String())
|
||||
}
|
||||
}
|
||||
return bottomHeight, nil
|
||||
}
|
||||
|
||||
func GetSharesOrdered(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, preAllocatedShares Shares) (shares Shares, bottomHeight uint64) {
|
||||
index := 0
|
||||
l := len(preAllocatedShares)
|
||||
|
||||
|
@ -211,43 +291,26 @@ func GetShares(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.Ge
|
|||
index++
|
||||
}
|
||||
|
||||
var errorValue error
|
||||
for e := range IterateBlocksInPPLNSWindow(tip, consensus, difficultyByHeight, getByTemplateId, func(b *PoolBlock, weight types.Difficulty) {
|
||||
if bottomHeight, err := BlocksInPPLNSWindow(tip, consensus, difficultyByHeight, getByTemplateId, func(b *PoolBlock, weight types.Difficulty) {
|
||||
insertShare(weight, b.GetAddress())
|
||||
}, func(err error) {
|
||||
errorValue = err
|
||||
}) {
|
||||
bottomHeight = e.Block.Side.Height
|
||||
}
|
||||
|
||||
if errorValue != nil {
|
||||
}); err != nil {
|
||||
return nil, 0
|
||||
} else {
|
||||
shares = preAllocatedShares[:index]
|
||||
|
||||
//remove dupes
|
||||
shares = shares.Compact()
|
||||
|
||||
return shares, bottomHeight
|
||||
}
|
||||
}
|
||||
|
||||
shares = preAllocatedShares[:index]
|
||||
|
||||
// Sort shares based on address
|
||||
slices.SortFunc(shares, func(a *Share, b *Share) bool {
|
||||
return a.Address.ComparePacked(b.Address) < 0
|
||||
})
|
||||
|
||||
//remove dupes
|
||||
index = 0
|
||||
for i, share := range shares {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
if shares[index].Address.Compare(&share.Address) == 0 {
|
||||
shares[index].Weight = shares[index].Weight.Add(share.Weight)
|
||||
} else {
|
||||
index++
|
||||
shares[index].Address = share.Address
|
||||
shares[index].Weight = share.Weight
|
||||
}
|
||||
func GetShares(tip *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, preAllocatedShares Shares) (shares Shares, bottomHeight uint64) {
|
||||
shares, bottomHeight = GetSharesOrdered(tip, consensus, difficultyByHeight, getByTemplateId, preAllocatedShares)
|
||||
if shares == nil {
|
||||
return
|
||||
}
|
||||
|
||||
shares = shares[:index+1]
|
||||
|
||||
//Shuffle shares
|
||||
ShuffleShares(shares, tip.ShareVersion(), tip.Side.CoinbasePrivateKeySeed)
|
||||
|
||||
|
@ -398,7 +461,7 @@ func GetDifficulty(tip *PoolBlock, consensus *Consensus, getByTemplateId GetByTe
|
|||
return curDifficulty, nil, nil
|
||||
}
|
||||
|
||||
func SplitReward(reward uint64, shares Shares) (rewards []uint64) {
|
||||
func SplitRewardNoAllocate(preAllocatedRewards []uint64, reward uint64, shares Shares) (rewards []uint64) {
|
||||
var totalWeight types.Difficulty
|
||||
for i := range shares {
|
||||
totalWeight = totalWeight.Add(shares[i].Weight)
|
||||
|
@ -409,7 +472,7 @@ func SplitReward(reward uint64, shares Shares) (rewards []uint64) {
|
|||
return nil
|
||||
}
|
||||
|
||||
rewards = make([]uint64, len(shares))
|
||||
rewards = preAllocatedRewards
|
||||
|
||||
var w types.Difficulty
|
||||
var rewardGiven uint64
|
||||
|
@ -417,7 +480,7 @@ func SplitReward(reward uint64, shares Shares) (rewards []uint64) {
|
|||
for i := range shares {
|
||||
w = w.Add(shares[i].Weight)
|
||||
nextValue := w.Mul64(reward).Div(totalWeight)
|
||||
rewards[i] = nextValue.Lo - rewardGiven
|
||||
rewards = append(rewards, nextValue.Lo-rewardGiven)
|
||||
rewardGiven = nextValue.Lo
|
||||
}
|
||||
|
||||
|
@ -433,6 +496,10 @@ func SplitReward(reward uint64, shares Shares) (rewards []uint64) {
|
|||
return rewards
|
||||
}
|
||||
|
||||
func SplitReward(reward uint64, shares Shares) (rewards []uint64) {
|
||||
return SplitRewardNoAllocate(make([]uint64, 0, len(shares)), reward, shares)
|
||||
}
|
||||
|
||||
func IsLongerChain(block, candidate *PoolBlock, consensus *Consensus, getByTemplateId GetByTemplateIdFunc, getChainMainByHash GetChainMainByHashFunc) (isLonger, isAlternative bool) {
|
||||
if candidate == nil || !candidate.Verified.Load() || candidate.Invalid.Load() {
|
||||
return false, false
|
||||
|
|
Loading…
Reference in a new issue