2022-06-23 15:16:11 +00:00
|
|
|
package morph
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
2023-05-16 08:22:20 +00:00
|
|
|
"fmt"
|
2022-06-23 15:16:11 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
|
|
|
"testing"
|
2023-04-12 10:52:14 +00:00
|
|
|
"time"
|
2022-06-23 15:16:11 +00:00
|
|
|
|
2024-01-31 14:26:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/util"
|
2023-03-07 13:38:26 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring"
|
2022-06-23 15:16:11 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
2022-10-24 12:49:13 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2022-06-23 15:16:11 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
|
|
"github.com/spf13/viper"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
)
|
|
|
|
|
2022-10-24 12:41:55 +00:00
|
|
|
const (
|
2023-10-24 10:36:03 +00:00
|
|
|
contractsPath = "../../../../../../contract/frostfs-contract-v0.18.0.tar.gz"
|
2022-10-24 12:41:55 +00:00
|
|
|
protoFileName = "proto.yml"
|
|
|
|
)
|
2022-10-24 11:38:55 +00:00
|
|
|
|
2022-06-23 15:16:11 +00:00
|
|
|
func TestInitialize(t *testing.T) {
|
2022-12-23 17:35:35 +00:00
|
|
|
// This test needs frostfs-contract tarball, so it is skipped by default.
|
2022-06-23 15:16:11 +00:00
|
|
|
// It is here for performing local testing after the changes.
|
|
|
|
t.Skip()
|
2022-10-24 12:41:55 +00:00
|
|
|
|
2023-02-15 12:38:50 +00:00
|
|
|
t.Run("1 nodes", func(t *testing.T) {
|
|
|
|
testInitialize(t, 1)
|
|
|
|
})
|
2022-10-24 11:38:55 +00:00
|
|
|
t.Run("4 nodes", func(t *testing.T) {
|
|
|
|
testInitialize(t, 4)
|
|
|
|
})
|
|
|
|
t.Run("7 nodes", func(t *testing.T) {
|
|
|
|
testInitialize(t, 7)
|
|
|
|
})
|
2023-05-15 11:46:17 +00:00
|
|
|
t.Run("16 nodes", func(t *testing.T) {
|
|
|
|
testInitialize(t, 16)
|
|
|
|
})
|
2023-05-16 08:22:20 +00:00
|
|
|
t.Run("max nodes", func(t *testing.T) {
|
2024-01-31 14:26:26 +00:00
|
|
|
testInitialize(t, util.MaxAlphabetNodes)
|
2023-05-16 08:22:20 +00:00
|
|
|
})
|
|
|
|
t.Run("too many nodes", func(t *testing.T) {
|
2024-01-31 14:26:26 +00:00
|
|
|
require.ErrorIs(t, generateTestData(t, t.TempDir(), util.MaxAlphabetNodes+1), util.ErrTooManyAlphabetNodes)
|
2023-05-15 11:46:17 +00:00
|
|
|
})
|
2022-10-24 11:38:55 +00:00
|
|
|
}
|
2022-06-23 15:16:11 +00:00
|
|
|
|
2022-10-24 11:38:55 +00:00
|
|
|
func testInitialize(t *testing.T, committeeSize int) {
|
2022-10-24 12:45:13 +00:00
|
|
|
testdataDir := t.TempDir()
|
2022-06-23 15:16:11 +00:00
|
|
|
v := viper.GetViper()
|
|
|
|
|
2023-05-16 08:22:20 +00:00
|
|
|
require.NoError(t, generateTestData(t, testdataDir, committeeSize))
|
2024-01-31 14:26:26 +00:00
|
|
|
v.Set(util.ProtoConfigPath, filepath.Join(testdataDir, protoFileName))
|
2022-10-24 12:41:55 +00:00
|
|
|
|
|
|
|
// Set to the path or remove the next statement to download from the network.
|
|
|
|
require.NoError(t, initCmd.Flags().Set(contractsInitFlag, contractsPath))
|
2023-10-24 10:36:03 +00:00
|
|
|
|
|
|
|
dumpPath := filepath.Join(testdataDir, "out")
|
|
|
|
require.NoError(t, initCmd.Flags().Set(localDumpFlag, dumpPath))
|
2024-02-01 06:51:24 +00:00
|
|
|
v.Set(util.AlphabetWalletsFlag, testdataDir)
|
2022-10-24 12:41:55 +00:00
|
|
|
v.Set(epochDurationInitFlag, 1)
|
|
|
|
v.Set(maxObjectSizeInitFlag, 1024)
|
|
|
|
|
|
|
|
setTestCredentials(v, committeeSize)
|
|
|
|
require.NoError(t, initializeSideChainCmd(initCmd, nil))
|
|
|
|
|
|
|
|
t.Run("force-new-epoch", func(t *testing.T) {
|
2023-10-24 10:36:03 +00:00
|
|
|
require.NoError(t, forceNewEpoch.Flags().Set(localDumpFlag, dumpPath))
|
2022-10-24 12:41:55 +00:00
|
|
|
require.NoError(t, forceNewEpochCmd(forceNewEpoch, nil))
|
|
|
|
})
|
|
|
|
t.Run("set-config", func(t *testing.T) {
|
2023-10-24 10:36:03 +00:00
|
|
|
require.NoError(t, setConfig.Flags().Set(localDumpFlag, dumpPath))
|
2022-10-24 12:41:55 +00:00
|
|
|
require.NoError(t, setConfigCmd(setConfig, []string{"MaintenanceModeAllowed=true"}))
|
|
|
|
})
|
2022-10-24 12:49:13 +00:00
|
|
|
t.Run("set-policy", func(t *testing.T) {
|
2023-10-24 10:36:03 +00:00
|
|
|
require.NoError(t, setPolicy.Flags().Set(localDumpFlag, dumpPath))
|
2022-10-24 12:49:13 +00:00
|
|
|
require.NoError(t, setPolicyCmd(setPolicy, []string{"ExecFeeFactor=1"}))
|
|
|
|
})
|
|
|
|
t.Run("remove-node", func(t *testing.T) {
|
|
|
|
pk, err := keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
pub := hex.EncodeToString(pk.PublicKey().Bytes())
|
2023-10-24 10:36:03 +00:00
|
|
|
require.NoError(t, removeNodes.Flags().Set(localDumpFlag, dumpPath))
|
2022-10-24 12:49:13 +00:00
|
|
|
require.NoError(t, removeNodesCmd(removeNodes, []string{pub}))
|
|
|
|
})
|
2022-10-24 12:41:55 +00:00
|
|
|
}
|
|
|
|
|
2023-05-16 08:22:20 +00:00
|
|
|
func generateTestData(t *testing.T, dir string, size int) error {
|
2022-10-24 12:41:55 +00:00
|
|
|
v := viper.GetViper()
|
2024-02-01 06:51:24 +00:00
|
|
|
v.Set(util.AlphabetWalletsFlag, dir)
|
2022-10-24 11:38:55 +00:00
|
|
|
|
2022-10-24 12:41:55 +00:00
|
|
|
sizeStr := strconv.FormatUint(uint64(size), 10)
|
2023-05-16 08:22:20 +00:00
|
|
|
if err := generateAlphabetCmd.Flags().Set(alphabetSizeFlag, sizeStr); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-10-24 11:38:55 +00:00
|
|
|
|
2022-10-24 12:41:55 +00:00
|
|
|
setTestCredentials(v, size)
|
2023-05-16 08:22:20 +00:00
|
|
|
if err := generateAlphabetCreds(generateAlphabetCmd, nil); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-06-23 15:16:11 +00:00
|
|
|
|
|
|
|
var pubs []string
|
2022-10-24 12:41:55 +00:00
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
p := filepath.Join(dir, innerring.GlagoliticLetter(i).String()+".json")
|
2022-06-23 15:16:11 +00:00
|
|
|
w, err := wallet.NewWalletFromFile(p)
|
2023-05-16 08:22:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("wallet doesn't exist: %w", err)
|
|
|
|
}
|
2022-06-23 15:16:11 +00:00
|
|
|
for _, acc := range w.Accounts {
|
|
|
|
if acc.Label == singleAccountName {
|
|
|
|
pub, ok := vm.ParseSignatureContract(acc.Contract.Script)
|
2023-05-16 08:22:20 +00:00
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("could not parse signature script for %s", acc.Address)
|
|
|
|
}
|
2022-06-23 15:16:11 +00:00
|
|
|
pubs = append(pubs, hex.EncodeToString(pub))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg := config.Config{}
|
2023-02-15 12:37:35 +00:00
|
|
|
cfg.ProtocolConfiguration.Magic = 12345
|
2023-06-02 11:48:07 +00:00
|
|
|
cfg.ProtocolConfiguration.ValidatorsCount = uint32(size)
|
2023-04-12 10:52:14 +00:00
|
|
|
cfg.ProtocolConfiguration.TimePerBlock = time.Second
|
2022-06-23 15:16:11 +00:00
|
|
|
cfg.ProtocolConfiguration.StandbyCommittee = pubs // sorted by glagolic letters
|
|
|
|
cfg.ProtocolConfiguration.P2PSigExtensions = true
|
2022-10-24 10:56:39 +00:00
|
|
|
cfg.ProtocolConfiguration.VerifyTransactions = true
|
2022-06-23 15:16:11 +00:00
|
|
|
data, err := yaml.Marshal(cfg)
|
2023-05-16 08:22:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-06-23 15:16:11 +00:00
|
|
|
|
2022-10-24 12:41:55 +00:00
|
|
|
protoPath := filepath.Join(dir, protoFileName)
|
2023-05-16 08:22:20 +00:00
|
|
|
return os.WriteFile(protoPath, data, os.ModePerm)
|
2022-10-24 12:41:55 +00:00
|
|
|
}
|
2022-06-23 15:16:11 +00:00
|
|
|
|
2022-10-24 12:41:55 +00:00
|
|
|
func setTestCredentials(v *viper.Viper, size int) {
|
|
|
|
for i := 0; i < size; i++ {
|
|
|
|
v.Set("credentials."+innerring.GlagoliticLetter(i).String(), strconv.FormatUint(uint64(i), 10))
|
|
|
|
}
|
|
|
|
v.Set("credentials.contract", testContractPassword)
|
2022-06-23 15:16:11 +00:00
|
|
|
}
|
2023-11-01 08:07:56 +00:00
|
|
|
|
|
|
|
func TestNextPollInterval(t *testing.T) {
|
|
|
|
var pollInterval time.Duration
|
|
|
|
var iteration int
|
|
|
|
|
2024-01-31 14:26:26 +00:00
|
|
|
pollInterval, hasChanged := util.NextPollInterval(iteration, pollInterval)
|
2023-11-01 08:07:56 +00:00
|
|
|
require.True(t, hasChanged)
|
|
|
|
require.Equal(t, time.Second, pollInterval)
|
|
|
|
|
|
|
|
iteration = 4
|
2024-01-31 14:26:26 +00:00
|
|
|
pollInterval, hasChanged = util.NextPollInterval(iteration, pollInterval)
|
2023-11-01 08:07:56 +00:00
|
|
|
require.False(t, hasChanged)
|
|
|
|
require.Equal(t, time.Second, pollInterval)
|
|
|
|
|
|
|
|
iteration = 5
|
2024-01-31 14:26:26 +00:00
|
|
|
pollInterval, hasChanged = util.NextPollInterval(iteration, pollInterval)
|
2023-11-01 08:07:56 +00:00
|
|
|
require.True(t, hasChanged)
|
|
|
|
require.Equal(t, 2*time.Second, pollInterval)
|
|
|
|
|
|
|
|
iteration = 10
|
2024-01-31 14:26:26 +00:00
|
|
|
pollInterval, hasChanged = util.NextPollInterval(iteration, pollInterval)
|
2023-11-01 08:07:56 +00:00
|
|
|
require.True(t, hasChanged)
|
|
|
|
require.Equal(t, 4*time.Second, pollInterval)
|
|
|
|
|
|
|
|
iteration = 20
|
|
|
|
pollInterval = 32 * time.Second
|
2024-01-31 14:26:26 +00:00
|
|
|
pollInterval, hasChanged = util.NextPollInterval(iteration, pollInterval)
|
2023-11-01 08:07:56 +00:00
|
|
|
require.True(t, hasChanged) // from 32s to 16s
|
|
|
|
require.Equal(t, 16*time.Second, pollInterval)
|
|
|
|
|
|
|
|
pollInterval = 16 * time.Second
|
2024-01-31 14:26:26 +00:00
|
|
|
pollInterval, hasChanged = util.NextPollInterval(iteration, pollInterval)
|
2023-11-01 08:07:56 +00:00
|
|
|
require.False(t, hasChanged)
|
|
|
|
require.Equal(t, 16*time.Second, pollInterval)
|
|
|
|
}
|