package innerring import ( "fmt" "sync/atomic" "testing" "time" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/stretchr/testify/require" ) func TestIndexerReturnsIndexes(t *testing.T) { t.Parallel() commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{ "03ff65b6ae79134a4dce9d0d39d3851e9bab4ee97abf86e81e1c5bbc50cd2826ae", "022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131", }) require.NoError(t, err, "convert string to commitee public keys failed") cf := &testCommiteeFetcher{ keys: commiteeKeys, } irKeys, err := keys.NewPublicKeysFromStrings([]string{ "038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35", "02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3", "022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131", }) require.NoError(t, err, "convert string to IR public keys failed") irf := &testIRFetcher{ keys: irKeys, } t.Run("success", func(t *testing.T) { t.Parallel() key := irKeys[2] indexer := newInnerRingIndexer(cf, irf, key, time.Second) idx, err := indexer.AlphabetIndex() require.NoError(t, err, "failed to get alphabet index") require.Equal(t, int32(1), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.NoError(t, err, "failed to get IR index") require.Equal(t, int32(2), idx, "invalid IR index") size, err := indexer.InnerRingSize() require.NoError(t, err, "failed to get IR size") require.Equal(t, int32(3), size, "invalid IR size") }) t.Run("not found alphabet", func(t *testing.T) { t.Parallel() key := irKeys[0] indexer := newInnerRingIndexer(cf, irf, key, time.Second) idx, err := indexer.AlphabetIndex() require.NoError(t, err, "failed to get alphabet index") require.Equal(t, int32(-1), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.NoError(t, err, "failed to get IR index") require.Equal(t, int32(0), idx, "invalid IR index") }) t.Run("not found IR", func(t *testing.T) { t.Parallel() key := commiteeKeys[0] indexer := newInnerRingIndexer(cf, irf, key, time.Second) idx, err := indexer.AlphabetIndex() require.NoError(t, err, "failed to get alphabet index") require.Equal(t, int32(0), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.NoError(t, err, "failed to get IR index") require.Equal(t, int32(-1), idx, "invalid IR index") }) } func TestIndexerCachesIndexes(t *testing.T) { t.Parallel() commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{}) require.NoError(t, err, "convert string to commitee public keys failed") cf := &testCommiteeFetcher{ keys: commiteeKeys, } irKeys, err := keys.NewPublicKeysFromStrings([]string{}) require.NoError(t, err, "convert string to IR public keys failed") irf := &testIRFetcher{ keys: irKeys, } key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131") require.NoError(t, err, "convert string to public key failed") indexer := newInnerRingIndexer(cf, irf, key, time.Second) idx, err := indexer.AlphabetIndex() require.NoError(t, err, "failed to get alphabet index") require.Equal(t, int32(-1), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.NoError(t, err, "failed to get IR index") require.Equal(t, int32(-1), idx, "invalid IR index") size, err := indexer.InnerRingSize() require.NoError(t, err, "failed to get IR size") require.Equal(t, int32(0), size, "invalid IR size") require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count") require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count") idx, err = indexer.AlphabetIndex() require.NoError(t, err, "failed to get alphabet index") require.Equal(t, int32(-1), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.NoError(t, err, "failed to get IR index") require.Equal(t, int32(-1), idx, "invalid IR index") size, err = indexer.InnerRingSize() require.NoError(t, err, "failed to get IR size") require.Equal(t, int32(0), size, "invalid IR size") require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count") require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count") time.Sleep(2 * time.Second) idx, err = indexer.AlphabetIndex() require.NoError(t, err, "failed to get alphabet index") require.Equal(t, int32(-1), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.NoError(t, err, "failed to get IR index") require.Equal(t, int32(-1), idx, "invalid IR index") size, err = indexer.InnerRingSize() require.NoError(t, err, "failed to get IR size") require.Equal(t, int32(0), size, "invalid IR size") require.Equal(t, int32(2), cf.calls.Load(), "invalid commitee calls count") require.Equal(t, int32(2), irf.calls.Load(), "invalid IR calls count") } func TestIndexerThrowsErrors(t *testing.T) { t.Parallel() cf := &testCommiteeFetcher{ err: fmt.Errorf("test commitee error"), } irKeys, err := keys.NewPublicKeysFromStrings([]string{}) require.NoError(t, err, "convert string to IR public keys failed") irf := &testIRFetcher{ keys: irKeys, } key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131") require.NoError(t, err, "convert string to public key failed") indexer := newInnerRingIndexer(cf, irf, key, time.Second) idx, err := indexer.AlphabetIndex() require.ErrorContains(t, err, "test commitee error", "error from commitee not throwed") require.Equal(t, int32(0), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.ErrorContains(t, err, "test commitee error", "error from IR not throwed") require.Equal(t, int32(0), idx, "invalid IR index") size, err := indexer.InnerRingSize() require.ErrorContains(t, err, "test commitee error", "error from IR not throwed") require.Equal(t, int32(0), size, "invalid IR size") commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{}) require.NoError(t, err, "convert string to commitee public keys failed") cf = &testCommiteeFetcher{ keys: commiteeKeys, } irf = &testIRFetcher{ err: fmt.Errorf("test IR error"), } indexer = newInnerRingIndexer(cf, irf, key, time.Second) idx, err = indexer.AlphabetIndex() require.ErrorContains(t, err, "test IR error", "error from commitee not throwed") require.Equal(t, int32(0), idx, "invalid alphabet index") idx, err = indexer.InnerRingIndex() require.ErrorContains(t, err, "test IR error", "error from IR not throwed") require.Equal(t, int32(0), idx, "invalid IR index") size, err = indexer.InnerRingSize() require.ErrorContains(t, err, "test IR error", "error from IR not throwed") require.Equal(t, int32(0), size, "invalid IR size") } type testCommiteeFetcher struct { keys keys.PublicKeys err error calls atomic.Int32 } func (f *testCommiteeFetcher) Committee() (keys.PublicKeys, error) { f.calls.Add(1) return f.keys, f.err } type testIRFetcher struct { keys keys.PublicKeys err error calls atomic.Int32 } func (f *testIRFetcher) InnerRingKeys() (keys.PublicKeys, error) { f.calls.Add(1) return f.keys, f.err } func BenchmarkKeyPosition(b *testing.B) { list := make(keys.PublicKeys, 7) for i := range list { p, err := keys.NewPrivateKey() require.NoError(b, err) list[i] = p.PublicKey() } key := new(keys.PublicKey) require.NoError(b, key.DecodeBytes(list[5].Bytes())) b.ResetTimer() b.ReportAllocs() for range b.N { if keyPosition(key, list) != 5 { b.FailNow() } } }