package governance import ( "encoding/binary" "sort" "testing" "time" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" frostfscontract "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs" nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/rolemanagement" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test" "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" ) func TestHandleAlphabetSyncEvent(t *testing.T) { t.Parallel() testKeys := generateTestKeys(t) es := &testEpochState{ epoch: 100, } as := &testAlphabetState{ isAlphabet: true, } v := &testVoter{} irf := &testIRFetcher{ publicKeys: testKeys.sidechainKeys, } m := &testMorphClient{ commiteeKeys: testKeys.sidechainKeys, } mn := &testMainnetClient{ alphabetKeys: testKeys.mainnetKeys, } f := &testFrostFSClient{} nm := &testNetmapClient{} proc, err := New( &Params{ Log: test.NewLogger(t), EpochState: es, AlphabetState: as, Voter: v, IRFetcher: irf, MorphClient: m, MainnetClient: mn, FrostFSClient: f, NetmapClient: nm, }, ) require.NoError(t, err, "failed to create processor") ev := Sync{ txHash: util.Uint256{100}, } proc.HandleAlphabetSync(ev) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } require.EqualValues(t, []VoteValidatorPrm{ { Validators: testKeys.newAlphabetExp, Hash: &ev.txHash, }, }, v.votes, "invalid vote calls") var irUpdateExp []nmClient.UpdateIRPrm require.EqualValues(t, irUpdateExp, nm.updates, "invalid IR updates") var expAlphabetUpdate client.UpdateAlphabetListPrm expAlphabetUpdate.SetHash(ev.txHash) expAlphabetUpdate.SetList(testKeys.newInnerRingExp) require.EqualValues(t, []client.UpdateAlphabetListPrm{expAlphabetUpdate}, m.alphabetUpdates, "invalid alphabet updates") var expNotaryUpdate client.UpdateNotaryListPrm expNotaryUpdate.SetHash(ev.txHash) expNotaryUpdate.SetList(testKeys.newAlphabetExp) require.EqualValues(t, []client.UpdateNotaryListPrm{expNotaryUpdate}, m.notaryUpdates, "invalid notary list updates") buf := make([]byte, 8) binary.LittleEndian.PutUint64(buf, es.epoch) id := append([]byte(alphabetUpdateIDPrefix), buf...) var expFrostFSAlphabetUpd frostfscontract.AlphabetUpdatePrm expFrostFSAlphabetUpd.SetID(id) expFrostFSAlphabetUpd.SetPubs(testKeys.newAlphabetExp) require.EqualValues(t, []frostfscontract.AlphabetUpdatePrm{expFrostFSAlphabetUpd}, f.updates, "invalid FrostFS alphabet updates") } func TestHandleAlphabetDesignateEvent(t *testing.T) { t.Parallel() testKeys := generateTestKeys(t) es := &testEpochState{ epoch: 100, } as := &testAlphabetState{ isAlphabet: true, } v := &testVoter{} irf := &testIRFetcher{ publicKeys: testKeys.sidechainKeys, } m := &testMorphClient{ commiteeKeys: testKeys.sidechainKeys, } mn := &testMainnetClient{ alphabetKeys: testKeys.mainnetKeys, } f := &testFrostFSClient{} nm := &testNetmapClient{} proc, err := New( &Params{ Log: test.NewLogger(t), EpochState: es, AlphabetState: as, Voter: v, IRFetcher: irf, MorphClient: m, MainnetClient: mn, FrostFSClient: f, NetmapClient: nm, }, ) require.NoError(t, err, "failed to create processor") ev := rolemanagement.Designate{ TxHash: util.Uint256{100}, Role: noderoles.NeoFSAlphabet, } proc.HandleAlphabetSync(ev) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } require.EqualValues(t, []VoteValidatorPrm{ { Validators: testKeys.newAlphabetExp, Hash: &ev.TxHash, }, }, v.votes, "invalid vote calls") var irUpdatesExp []nmClient.UpdateIRPrm require.EqualValues(t, irUpdatesExp, nm.updates, "invalid IR updates") var alpabetUpdExp client.UpdateAlphabetListPrm alpabetUpdExp.SetList(testKeys.newInnerRingExp) alpabetUpdExp.SetHash(ev.TxHash) require.EqualValues(t, []client.UpdateAlphabetListPrm{alpabetUpdExp}, m.alphabetUpdates, "invalid alphabet updates") var expNotaryUpdate client.UpdateNotaryListPrm expNotaryUpdate.SetList(testKeys.newAlphabetExp) expNotaryUpdate.SetHash(ev.TxHash) require.EqualValues(t, []client.UpdateNotaryListPrm{expNotaryUpdate}, m.notaryUpdates, "invalid notary list updates") buf := make([]byte, 8) binary.LittleEndian.PutUint64(buf, es.epoch) id := append([]byte(alphabetUpdateIDPrefix), buf...) var expFrostFSAlphabetUpd frostfscontract.AlphabetUpdatePrm expFrostFSAlphabetUpd.SetID(id) expFrostFSAlphabetUpd.SetPubs(testKeys.newAlphabetExp) require.EqualValues(t, []frostfscontract.AlphabetUpdatePrm{expFrostFSAlphabetUpd}, f.updates, "invalid FrostFS alphabet updates") } type testKeys struct { sidechainKeys keys.PublicKeys mainnetKeys keys.PublicKeys newAlphabetExp keys.PublicKeys newInnerRingExp keys.PublicKeys } func generateTestKeys(t *testing.T) testKeys { for { var result testKeys for range 4 { pk, err := keys.NewPrivateKey() require.NoError(t, err, "failed to create private key") result.sidechainKeys = append(result.sidechainKeys, pk.PublicKey()) } result.mainnetKeys = append(result.mainnetKeys, result.sidechainKeys...) pk, err := keys.NewPrivateKey() require.NoError(t, err, "failed to create private key") result.mainnetKeys = append(result.mainnetKeys, pk.PublicKey()) result.newAlphabetExp, err = newAlphabetList(result.sidechainKeys, result.mainnetKeys) require.NoError(t, err, "failed to create expected new alphabet") if len(result.newAlphabetExp) == 0 { continue // can be happen because of random and sort } var irKeys keys.PublicKeys irKeys = append(irKeys, result.sidechainKeys...) result.newInnerRingExp, err = updateInnerRing(irKeys, result.sidechainKeys, result.newAlphabetExp) require.NoError(t, err, "failed to create expected new IR") sort.Sort(result.newInnerRingExp) return result } } type testEpochState struct { epoch uint64 } func (s *testEpochState) EpochCounter() uint64 { return s.epoch } type testAlphabetState struct { isAlphabet bool } func (s *testAlphabetState) IsAlphabet() bool { return s.isAlphabet } type testVoter struct { votes []VoteValidatorPrm } func (v *testVoter) VoteForSidechainValidator(prm VoteValidatorPrm) error { v.votes = append(v.votes, prm) return nil } type testIRFetcher struct { publicKeys keys.PublicKeys } func (f *testIRFetcher) InnerRingKeys() (keys.PublicKeys, error) { return f.publicKeys, nil } type testMorphClient struct { commiteeKeys keys.PublicKeys alphabetUpdates []client.UpdateAlphabetListPrm notaryUpdates []client.UpdateNotaryListPrm } func (c *testMorphClient) Committee() (res keys.PublicKeys, err error) { return c.commiteeKeys, nil } func (c *testMorphClient) UpdateNeoFSAlphabetList(prm client.UpdateAlphabetListPrm) error { c.alphabetUpdates = append(c.alphabetUpdates, prm) return nil } func (c *testMorphClient) UpdateNotaryList(prm client.UpdateNotaryListPrm) error { c.notaryUpdates = append(c.notaryUpdates, prm) return nil } type testMainnetClient struct { alphabetKeys keys.PublicKeys designateHash util.Uint160 } func (c *testMainnetClient) NeoFSAlphabetList() (res keys.PublicKeys, err error) { return c.alphabetKeys, nil } func (c *testMainnetClient) GetDesignateHash() util.Uint160 { return c.designateHash } type testFrostFSClient struct { updates []frostfscontract.AlphabetUpdatePrm } func (c *testFrostFSClient) AlphabetUpdate(p frostfscontract.AlphabetUpdatePrm) error { c.updates = append(c.updates, p) return nil } type testNetmapClient struct { updates []nmClient.UpdateIRPrm } func (c *testNetmapClient) UpdateInnerRing(p nmClient.UpdateIRPrm) error { c.updates = append(c.updates, p) return nil }