package container import ( "crypto/ecdsa" "encoding/hex" "fmt" "testing" "time" frostfsidclient "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client" containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container" containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/network/payload" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" ) func TestPutEvent(t *testing.T) { t.Parallel() nst := &testNetworkState{ homHashDisabled: true, epoch: 100, } mc := &testMorphClient{} proc, err := New(&Params{ Log: test.NewLogger(t), PoolSize: 2, AlphabetState: &testAlphabetState{isAlphabet: true}, NetworkState: nst, ContainerClient: &testContainerClient{}, MorphClient: mc, FrostFSIDClient: &testFrostFSIDClient{}, }) require.NoError(t, err, "failed to create processor") p, err := keys.NewPrivateKey() require.NoError(t, err) var usr user.ID user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey())) var pp netmap.PlacementPolicy pp.AddReplicas(netmap.ReplicaDescriptor{}) var cnr containerSDK.Container cnr.Init() cnr.SetOwner(usr) cnr.SetPlacementPolicy(pp) cnr.SetBasicACL(acl.Private) containerSDK.DisableHomomorphicHashing(&cnr) nr := &payload.P2PNotaryRequest{ MainTransaction: &transaction.Transaction{}, } event := &testPutEvent{ cnr: &cnr, pk: p, st: nil, nr: nr, } proc.handlePut(event) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } require.EqualValues(t, []*transaction.Transaction{nr.MainTransaction}, mc.transactions, "invalid notary requests") } func TestDeleteEvent(t *testing.T) { t.Parallel() nst := &testNetworkState{ homHashDisabled: true, epoch: 100, } cc := &testContainerClient{ get: make(map[string]*containercore.Container), } p, err := keys.NewPrivateKey() require.NoError(t, err) mc := &testMorphClient{} proc, err := New(&Params{ Log: test.NewLogger(t), PoolSize: 2, AlphabetState: &testAlphabetState{isAlphabet: true}, NetworkState: nst, ContainerClient: cc, MorphClient: mc, FrostFSIDClient: &testFrostFSIDClient{}, }) require.NoError(t, err, "failed to create processor") var usr user.ID user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey())) var pp netmap.PlacementPolicy pp.AddReplicas(netmap.ReplicaDescriptor{}) var cnr containerSDK.Container cnr.Init() cnr.SetOwner(usr) cnr.SetPlacementPolicy(pp) cnr.SetBasicACL(acl.Private) containerSDK.DisableHomomorphicHashing(&cnr) var cid cid.ID containerSDK.CalculateID(&cid, cnr) cidBin := make([]byte, 32) cid.Encode(cidBin) nr := &payload.P2PNotaryRequest{ MainTransaction: &transaction.Transaction{}, } ev := containerEvent.Delete{ ContainerIDValue: cidBin, SignatureValue: p.Sign(cidBin), NotaryRequestValue: nr, PublicKeyValue: p.PublicKey().Bytes(), } var signature frostfscrypto.Signature signer := frostfsecdsa.Signer(p.PrivateKey) require.NoError(t, signature.Calculate(signer, ev.ContainerID()), "failed to calculate signature") cc.get[hex.EncodeToString(ev.ContainerID())] = &containercore.Container{ Value: cnr, Signature: signature, } proc.handleDelete(ev) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } var expectedDelete cntClient.DeletePrm expectedDelete.SetCID(ev.ContainerID()) expectedDelete.SetSignature(ev.Signature()) require.EqualValues(t, []*transaction.Transaction{nr.MainTransaction}, mc.transactions, "invalid notary requests") } func TestSetEACLEvent(t *testing.T) { t.Parallel() nst := &testNetworkState{ homHashDisabled: true, epoch: 100, } cc := &testContainerClient{ get: make(map[string]*containercore.Container), } mc := &testMorphClient{} proc, err := New(&Params{ Log: test.NewLogger(t), PoolSize: 2, AlphabetState: &testAlphabetState{isAlphabet: true}, NetworkState: nst, ContainerClient: cc, MorphClient: mc, FrostFSIDClient: &testFrostFSIDClient{}, }) require.NoError(t, err, "failed to create processor") p, err := keys.NewPrivateKey() require.NoError(t, err) var usr user.ID user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey())) var pp netmap.PlacementPolicy pp.AddReplicas(netmap.ReplicaDescriptor{}) var cnr containerSDK.Container cnr.Init() cnr.SetOwner(usr) cnr.SetPlacementPolicy(pp) cnr.SetBasicACL(acl.PrivateExtended) containerSDK.DisableHomomorphicHashing(&cnr) var cid cid.ID containerSDK.CalculateID(&cid, cnr) cidBytes := make([]byte, 32) cid.Encode(cidBytes) var signature frostfscrypto.Signature signer := frostfsecdsa.Signer(p.PrivateKey) require.NoError(t, signature.Calculate(signer, cidBytes), "failed to calculate signature") cc.get[hex.EncodeToString(cidBytes)] = &containercore.Container{ Value: cnr, Signature: signature, } table := eacl.NewTable() table.SetCID(cid) table.SetVersion(version.Current()) r := &eacl.Record{} r.AddObjectContainerIDFilter(eacl.MatchStringEqual, cid) table.AddRecord(r) nr := &payload.P2PNotaryRequest{ MainTransaction: &transaction.Transaction{}, } event := containerEvent.SetEACL{ TableValue: table.ToV2().StableMarshal(nil), PublicKeyValue: p.PublicKey().Bytes(), SignatureValue: p.Sign(table.ToV2().StableMarshal(nil)), NotaryRequestValue: nr, } proc.handleSetEACL(event) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } var expectedPutEACL cntClient.PutEACLPrm expectedPutEACL.SetTable(table.ToV2().StableMarshal(nil)) expectedPutEACL.SetKey(p.PublicKey().Bytes()) expectedPutEACL.SetSignature(p.Sign(table.ToV2().StableMarshal(nil))) require.EqualValues(t, []*transaction.Transaction{nr.MainTransaction}, mc.transactions, "invalid notary requests") } type testAlphabetState struct { isAlphabet bool } func (s *testAlphabetState) IsAlphabet() bool { return s.isAlphabet } type testNetworkState struct { homHashDisabled bool epoch uint64 } func (s *testNetworkState) HomomorphicHashDisabled() (bool, error) { return s.homHashDisabled, nil } func (s *testNetworkState) Epoch() (uint64, error) { return s.epoch, nil } type testContainerClient struct { contractAddress util.Uint160 get map[string]*containercore.Container } func (c *testContainerClient) ContractAddress() util.Uint160 { return c.contractAddress } func (c *testContainerClient) Get(cid []byte) (*containercore.Container, error) { key := hex.EncodeToString(cid) if cont, found := c.get[key]; found { return cont, nil } return nil, new(apistatus.ContainerNotFound) } var _ putEvent = &testPutEvent{} type testPutEvent struct { cnr *containerSDK.Container pk *keys.PrivateKey st []byte nr *payload.P2PNotaryRequest } func (e *testPutEvent) MorphEvent() {} func (e *testPutEvent) Container() []byte { return e.cnr.Marshal() } func (e *testPutEvent) PublicKey() []byte { return e.pk.PublicKey().Bytes() } func (e *testPutEvent) Signature() []byte { return e.pk.Sign(e.cnr.Marshal()) } func (e *testPutEvent) SessionToken() []byte { return e.st } func (e *testPutEvent) NotaryRequest() *payload.P2PNotaryRequest { return e.nr } type testMorphClient struct { transactions []*transaction.Transaction } func (c *testMorphClient) NotarySignAndInvokeTX(mainTx *transaction.Transaction) error { c.transactions = append(c.transactions, mainTx) return nil } type testFrostFSIDClient struct{} func (c *testFrostFSIDClient) GetSubject(addr util.Uint160) (*frostfsidclient.Subject, error) { return nil, fmt.Errorf("subject not found") }