forked from TrueCloudLab/frostfs-node
96da7ceb4f
We should go through every key in main chain list to merget lists as fast as possible. Previously we drop main chain traversing as soon as we have no more new keys to add. Instead we should try to go for old keys in the list and add it as more as we can. Signed-off-by: Alex Vanin <alexey@nspcc.ru>
110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package governance
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
)
|
|
|
|
var (
|
|
errNotEnoughKeys = errors.New("alphabet list in mainnet is too short")
|
|
errNotEqualLen = errors.New("old and new alphabet lists have different length")
|
|
errEmptySidechain = errors.New("sidechain list is empty")
|
|
)
|
|
|
|
// newAlphabetList returns updated list of sidechain keys with no more than 1\3
|
|
// of new keys from mainnet list. Function returns `errEmptySidechain` if
|
|
// sidechain list is empty. Function returns `errNotEnoughKeys` if mainnet
|
|
// list contains less keys than sidechain list. Function returns (nil, nil) if
|
|
// mainnet list contains all keys from sidechain list.
|
|
//
|
|
// Sorts passed slices.
|
|
func newAlphabetList(sidechain, mainnet keys.PublicKeys) (keys.PublicKeys, error) {
|
|
sort.Sort(sidechain)
|
|
sort.Sort(mainnet)
|
|
|
|
ln := len(sidechain)
|
|
if ln == 0 {
|
|
return nil, errEmptySidechain
|
|
}
|
|
|
|
if len(mainnet) < ln {
|
|
return nil, fmt.Errorf("%w: expecting %d keys", errNotEnoughKeys, ln)
|
|
}
|
|
|
|
hmap := make(map[string]bool, ln)
|
|
result := make(keys.PublicKeys, 0, ln)
|
|
|
|
for _, node := range sidechain {
|
|
hmap[node.Address()] = false
|
|
}
|
|
|
|
newNodes := 0
|
|
newNodeLimit := (ln - 1) / 3
|
|
|
|
for _, node := range mainnet {
|
|
if len(result) == ln {
|
|
break
|
|
}
|
|
|
|
limitReached := newNodes == newNodeLimit
|
|
|
|
mainnetAddr := node.Address()
|
|
if _, ok := hmap[mainnetAddr]; !ok {
|
|
if limitReached {
|
|
continue
|
|
}
|
|
newNodes++
|
|
} else {
|
|
hmap[mainnetAddr] = true
|
|
}
|
|
|
|
result = append(result, node)
|
|
}
|
|
|
|
if newNodes == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
for _, node := range sidechain {
|
|
if len(result) == ln {
|
|
break
|
|
}
|
|
|
|
if !hmap[node.Address()] {
|
|
result = append(result, node)
|
|
}
|
|
}
|
|
|
|
sort.Sort(result)
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// updateInnerRing function removes `before` keys from `innerRing` and adds
|
|
// `after` keys in the list. If length of `before` and `after` is not the same
|
|
// then function returns errNotEqualLen
|
|
func updateInnerRing(innerRing, before, after keys.PublicKeys) (keys.PublicKeys, error) {
|
|
lnBefore := len(before)
|
|
if lnBefore != len(after) {
|
|
return nil, errNotEqualLen
|
|
}
|
|
|
|
result := make(keys.PublicKeys, 0, len(innerRing))
|
|
|
|
// O(n^2) for 7 nodes is not THAT bad.
|
|
loop:
|
|
for i := range innerRing {
|
|
for j := range before {
|
|
if innerRing[i].Equal(before[j]) {
|
|
result = append(result, after[j])
|
|
continue loop
|
|
}
|
|
}
|
|
result = append(result, innerRing[i])
|
|
}
|
|
|
|
return result, nil
|
|
}
|