using System.Linq; using System.Text; using System.Threading.Tasks; using FrostFS.Netmap; using static FrostFS.Netmap.NetworkConfig.Types; namespace FrostFS.SDK.ClientV2; internal sealed class NetmapServiceProvider : ContextAccessor { private readonly NetmapService.NetmapServiceClient netmapServiceClient; internal NetmapServiceProvider(NetmapService.NetmapServiceClient netmapServiceClient, EnvironmentContext context) : base(context) { this.netmapServiceClient = netmapServiceClient; } internal async Task GetNetworkSettingsAsync(CallContext ctx) { if (EnvironmentContext.NetworkSettings != null) return EnvironmentContext.NetworkSettings; var response = await GetNetworkInfoAsync(ctx).ConfigureAwait(false); var settings = new NetworkSettings(); var info = response.Body.NetworkInfo; settings.Epoch = info.CurrentEpoch; settings.MagicNumber = info.MagicNumber; settings.MsPerBlock = info.MsPerBlock; foreach (var param in info.NetworkConfig.Parameters) { SetNetworksParam(param, settings); } EnvironmentContext.NetworkSettings = settings; return settings; } internal async Task GetLocalNodeInfoAsync(PrmNodeInfo args) { var ctx = args.Context!; ctx.Key ??= EnvironmentContext.Key?.ECDsaKey; if (ctx.Key == null) throw new InvalidObjectException(nameof(ctx.Key)); var request = new LocalNodeInfoRequest { Body = new LocalNodeInfoRequest.Types.Body { } }; request.AddMetaHeader(args.XHeaders); request.Sign(ctx.Key); var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken); Verifier.CheckResponse(response); return response.Body.ToModel(); } internal async Task GetNetworkInfoAsync(CallContext ctx) { ctx.Key ??= EnvironmentContext.Key?.ECDsaKey; if (ctx.Key == null) throw new InvalidObjectException(nameof(ctx.Key)); var request = new NetworkInfoRequest(); request.AddMetaHeader(null); request.Sign(ctx.Key); var response = await netmapServiceClient.NetworkInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken) .ConfigureAwait(false); Verifier.CheckResponse(response); return response; } internal async Task GetNetmapSnapshotAsync(PrmNetmapSnapshot args) { var ctx = args.Context!; ctx.Key ??= EnvironmentContext.Key?.ECDsaKey; if (ctx.Key == null) throw new InvalidObjectException(nameof(ctx.Key)); var request = new NetmapSnapshotRequest(); request.AddMetaHeader(args.XHeaders); request.Sign(ctx.Key); var response = await netmapServiceClient.NetmapSnapshotAsync(request, null, ctx.Deadline, ctx.CancellationToken); Verifier.CheckResponse(response); return response.ToModel(); } private static bool GetBoolValue(byte[] bytes) { return bytes.Any(b => b != 0); } private static ulong GetLongValue(byte[] bytes) { ulong val = 0; for (var i = bytes.Length - 1; i >= 0; i--) val = (val << 8) + bytes[i]; return val; } private static void SetNetworksParam(Parameter param, NetworkSettings settings) { var key = Encoding.UTF8.GetString(param.Key.ToByteArray()); var valueBytes = param.Value.ToByteArray(); switch (key) { case "AuditFee": settings.AuditFee = GetLongValue(valueBytes); break; case "BasicIncomeRate": settings.BasicIncomeRate = GetLongValue(valueBytes); break; case "ContainerFee": settings.ContainerFee = GetLongValue(valueBytes); break; case "ContainerAliasFee": settings.ContainerAliasFee = GetLongValue(valueBytes); break; case "EpochDuration": settings.EpochDuration = GetLongValue(valueBytes); break; case "InnerRingCandidateFee": settings.InnerRingCandidateFee = GetLongValue(valueBytes); break; case "MaxECDataCount": settings.MaxECDataCount = GetLongValue(valueBytes); break; case "MaxECParityCount": settings.MaxECParityCount = GetLongValue(valueBytes); break; case "MaxObjectSize": settings.MaxObjectSize = GetLongValue(valueBytes); break; case "WithdrawFee": settings.WithdrawFee = GetLongValue(valueBytes); break; case "HomomorphicHashingDisabled": settings.HomomorphicHashingDisabled = GetBoolValue(valueBytes); break; case "MaintenanceModeAllowed": settings.MaintenanceModeAllowed = GetBoolValue(valueBytes); break; default: settings.UnnamedSettings.Add(key, valueBytes); break; } } }