consensus/p2pool/stratum/mapping.go

100 lines
2.8 KiB
Go

package stratum
import (
"git.gammaspectra.live/P2Pool/consensus/v3/p2pool/sidechain"
"git.gammaspectra.live/P2Pool/consensus/v3/types"
"slices"
)
const ShuffleMappingZeroKeyIndex = 0
type ShuffleMapping struct {
// Including the index mapping contains a new miner in the list
Including []int
// Excluding the index mapping doesn't contain a new miner.
// len(Excluding) = len(Including) - 1 (unless len(Including) == 1, where it's also 1)
Excluding []int
}
// BuildShuffleMapping Creates a mapping of source to destination miner output post shuffle
// This uses two mappings, one where a new miner is added to the list, and one where the count stays the same
// Usual usage will place Zero key in index 0
func BuildShuffleMapping(n int, shareVersion sidechain.ShareVersion, transactionPrivateKeySeed types.Hash, oldMappings ShuffleMapping) (mappings ShuffleMapping) {
if n <= 1 {
return ShuffleMapping{
Including: []int{0},
Excluding: []int{0},
}
}
shuffleSequence1 := make([]int, n)
for i := range shuffleSequence1 {
shuffleSequence1[i] = i
}
shuffleSequence2 := make([]int, n-1)
for i := range shuffleSequence2 {
shuffleSequence2[i] = i
}
sidechain.ShuffleSequence(shareVersion, transactionPrivateKeySeed, n, func(i, j int) {
shuffleSequence1[i], shuffleSequence1[j] = shuffleSequence1[j], shuffleSequence1[i]
})
sidechain.ShuffleSequence(shareVersion, transactionPrivateKeySeed, n-1, func(i, j int) {
shuffleSequence2[i], shuffleSequence2[j] = shuffleSequence2[j], shuffleSequence2[i]
})
mappings.Including = slices.Grow(oldMappings.Including, n)[:n]
mappings.Excluding = slices.Grow(oldMappings.Excluding, n-1)[:n-1]
for i := range shuffleSequence1 {
mappings.Including[shuffleSequence1[i]] = i
}
//Flip
for i := range shuffleSequence2 {
mappings.Excluding[shuffleSequence2[i]] = i
}
return mappings
}
// ApplyShuffleMapping Applies a shuffle mapping depending on source length
// Returns nil in case no source length matches shuffle mapping
func ApplyShuffleMapping[T any](v []T, mappings ShuffleMapping) []T {
n := len(v)
result := make([]T, n)
if n == len(mappings.Including) {
for i := range v {
result[mappings.Including[i]] = v[i]
}
} else if n == len(mappings.Excluding) {
for i := range v {
result[mappings.Excluding[i]] = v[i]
}
} else {
return nil
}
return result
}
type ShuffleMappingIndices [][3]int
func (m ShuffleMapping) RangePossibleIndices(f func(i, ix0, ix1, ix2 int)) {
n := len(m.Including)
var ix0, ix1, ix2 int
for i := 0; i < n; i++ {
// Count with all + miner
ix0 = m.Including[i]
if i > ShuffleMappingZeroKeyIndex {
// Count with all + miner shifted to a slot before
ix1 = m.Including[i-1]
// Count with all miners minus one
ix2 = m.Including[i-1]
} else {
ix1 = -1
ix2 = -1
}
f(i, ix0, ix1, ix2)
}
}