package alphabet_test import ( "context" "testing" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/alphabet" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/timers" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" ) func TestProcessorEmitsGasToNetmapAndAlphabet(t *testing.T) { t.Parallel() var emission uint64 = 100_000 var index int = 5 var parsedWallets []util.Uint160 = []util.Uint160{{20}, {25}} alphabetContracts := innerring.NewAlphabetContracts() for i := range index + 1 { alphabetContracts[innerring.GlagoliticLetter(i)] = util.Uint160{uint8(i)} } morphClient := &testMorphClient{} var node1 netmap.NodeInfo key1, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35") require.NoError(t, err, "failed to parse key1") node1.SetPublicKey(key1.Bytes()) var node2 netmap.NodeInfo key2, err := keys.NewPublicKeyFromString("02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3") require.NoError(t, err, "failed to parse key2") node2.SetPublicKey(key2.Bytes()) nodes := []netmap.NodeInfo{node1, node2} network := &netmap.NetMap{} network.SetNodes(nodes) netmapClient := &testNetmapClient{ netmap: network, } params := &alphabet.Params{ ParsedWallets: parsedWallets, Log: test.NewLogger(t), PoolSize: 2, StorageEmission: emission, IRList: &testIndexer{index: index}, AlphabetContracts: alphabetContracts, MorphClient: morphClient, NetmapClient: netmapClient, } processor, err := alphabet.New(params) require.NoError(t, err, "failed to create processor instance") processor.HandleGasEmission(context.Background(), timers.NewAlphabetEmitTick{}) processor.WaitPoolRunning() require.EqualValues(t, []invokedMethod{ { contract: alphabetContracts[innerring.GlagoliticLetter(index)], fee: 0, method: "emit", }, }, morphClient.invokedMethods, "invalid invoked morph methods") require.EqualValues(t, []transferGas{ { receiver: key1.GetScriptHash(), amount: fixedn.Fixed8(25_000), }, { receiver: key2.GetScriptHash(), amount: fixedn.Fixed8(25_000), }, }, morphClient.transferedGas, "invalid transfered Gas") require.EqualValues(t, []batchTransferGas{ { receivers: parsedWallets, amount: fixedn.Fixed8(25_000), }, }, morphClient.batchTransferedGas, "invalid batch transfered Gas") } func TestProcessorEmitsGasToNetmapIfNoParsedWallets(t *testing.T) { t.Parallel() var emission uint64 = 100_000 var index int = 5 var parsedWallets []util.Uint160 alphabetContracts := innerring.NewAlphabetContracts() for i := range index + 1 { alphabetContracts[innerring.GlagoliticLetter(i)] = util.Uint160{uint8(i)} } morphClient := &testMorphClient{} var node1 netmap.NodeInfo key1, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35") require.NoError(t, err, "failed to parse key1") node1.SetPublicKey(key1.Bytes()) var node2 netmap.NodeInfo key2, err := keys.NewPublicKeyFromString("02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3") require.NoError(t, err, "failed to parse key2") node2.SetPublicKey(key2.Bytes()) nodes := []netmap.NodeInfo{node1, node2} network := &netmap.NetMap{} network.SetNodes(nodes) netmapClient := &testNetmapClient{ netmap: network, } params := &alphabet.Params{ ParsedWallets: parsedWallets, Log: test.NewLogger(t), PoolSize: 2, StorageEmission: emission, IRList: &testIndexer{index: index}, AlphabetContracts: alphabetContracts, MorphClient: morphClient, NetmapClient: netmapClient, } processor, err := alphabet.New(params) require.NoError(t, err, "failed to create processor instance") processor.HandleGasEmission(context.Background(), timers.NewAlphabetEmitTick{}) processor.WaitPoolRunning() require.EqualValues(t, []invokedMethod{ { contract: alphabetContracts[innerring.GlagoliticLetter(index)], fee: 0, method: "emit", }, }, morphClient.invokedMethods, "invalid invoked morph methods") require.EqualValues(t, []transferGas{ { receiver: key1.GetScriptHash(), amount: fixedn.Fixed8(50_000), }, { receiver: key2.GetScriptHash(), amount: fixedn.Fixed8(50_000), }, }, morphClient.transferedGas, "invalid transfered Gas") require.Equal(t, 0, len(morphClient.batchTransferedGas), "invalid batch transfered Gas") } func TestProcessorDoesntEmitGasIfNoNetmapOrParsedWallets(t *testing.T) { t.Parallel() var emission uint64 = 100_000 var index int = 5 var parsedWallets []util.Uint160 alphabetContracts := innerring.NewAlphabetContracts() for i := range index + 1 { alphabetContracts[innerring.GlagoliticLetter(i)] = util.Uint160{uint8(i)} } morphClient := &testMorphClient{} var nodes []netmap.NodeInfo network := &netmap.NetMap{} network.SetNodes(nodes) netmapClient := &testNetmapClient{ netmap: network, } params := &alphabet.Params{ ParsedWallets: parsedWallets, Log: test.NewLogger(t), PoolSize: 2, StorageEmission: emission, IRList: &testIndexer{index: index}, AlphabetContracts: alphabetContracts, MorphClient: morphClient, NetmapClient: netmapClient, } processor, err := alphabet.New(params) require.NoError(t, err, "failed to create processor instance") processor.HandleGasEmission(context.Background(), timers.NewAlphabetEmitTick{}) processor.WaitPoolRunning() require.EqualValues(t, []invokedMethod{ { contract: alphabetContracts[innerring.GlagoliticLetter(index)], fee: 0, method: "emit", }, }, morphClient.invokedMethods, "invalid invoked morph methods") require.Equal(t, 0, len(morphClient.transferedGas), "invalid transfered Gas") require.Equal(t, 0, len(morphClient.batchTransferedGas), "invalid batch transfered Gas") } type testIndexer struct { index int } func (i *testIndexer) AlphabetIndex(context.Context) int { return i.index } type invokedMethod struct { contract util.Uint160 fee fixedn.Fixed8 method string args []any } type transferGas struct { receiver util.Uint160 amount fixedn.Fixed8 } type batchTransferGas struct { receivers []util.Uint160 amount fixedn.Fixed8 } type testMorphClient struct { invokedMethods []invokedMethod transferedGas []transferGas batchTransferedGas []batchTransferGas } func (c *testMorphClient) Invoke(_ context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (uint32, error) { c.invokedMethods = append(c.invokedMethods, invokedMethod{ contract: contract, fee: fee, method: method, args: args, }) return 0, nil } func (c *testMorphClient) TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error { c.transferedGas = append(c.transferedGas, transferGas{ receiver: receiver, amount: amount, }) return nil } func (c *testMorphClient) BatchTransferGas(receivers []util.Uint160, amount fixedn.Fixed8) error { c.batchTransferedGas = append(c.batchTransferedGas, batchTransferGas{ receivers: receivers, amount: amount, }) return nil } type testNetmapClient struct { netmap *netmap.NetMap } func (c *testNetmapClient) NetMap() (*netmap.NetMap, error) { return c.netmap, nil }