100 lines
2.8 KiB
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)
|
|
}
|
|
}
|