[#3] Move to netstandard 2.0
All checks were successful
DCO / DCO (pull_request) Successful in 42s

Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
p.gross 2024-05-29 12:43:00 +03:00
parent ae3fc419a4
commit 0c4723c705
55 changed files with 2508 additions and 1818 deletions

2
.gitignore vendored
View file

@ -4,6 +4,7 @@
*.dll *.dll
*.so *.so
*.dylib *.dylib
*.pdb
# Test binary, built with `go test -c` # Test binary, built with `go test -c`
*.test *.test
@ -31,3 +32,4 @@ antlr-*.jar
# binary # binary
bin/ bin/
release/ release/
obj/

View file

@ -1,12 +1,11 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ClientV2", "src\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj", "{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ProtosV2", "src\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj", "{A087047E-2505-4137-97CC-689A5AD58A0C}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ClientV2", "src\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj", "{F9CE6347-111A-4CE6-8BB2-545469838F47}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{3D804F4A-B0B2-47A5-B006-BE447BE64B50}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{599E2FF8-12C0-414D-B295-4C971A0A1A63}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ModelsV2", "src\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj", "{14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ModelsV2", "src\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj", "{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ProtosV2", "src\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj", "{5012EF96-9C9E-4E77-BC78-B4111EE54107}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -14,25 +13,25 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A087047E-2505-4137-97CC-689A5AD58A0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A087047E-2505-4137-97CC-689A5AD58A0C}.Debug|Any CPU.Build.0 = Debug|Any CPU {50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A087047E-2505-4137-97CC-689A5AD58A0C}.Release|Any CPU.ActiveCfg = Release|Any CPU {50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A087047E-2505-4137-97CC-689A5AD58A0C}.Release|Any CPU.Build.0 = Release|Any CPU {50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}.Release|Any CPU.Build.0 = Release|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9CE6347-111A-4CE6-8BB2-545469838F47}.Release|Any CPU.Build.0 = Release|Any CPU {3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.Build.0 = Release|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Debug|Any CPU.Build.0 = Debug|Any CPU {14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B04EBDF5-A446-49D6-B1D7-7D729D94E8E0}.Release|Any CPU.Build.0 = Release|Any CPU {14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Release|Any CPU.Build.0 = Release|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Debug|Any CPU.Build.0 = Debug|Any CPU {5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.Build.0 = Debug|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Release|Any CPU.ActiveCfg = Release|Any CPU {5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.ActiveCfg = Release|Any CPU
{599E2FF8-12C0-414D-B295-4C971A0A1A63}.Release|Any CPU.Build.0 = Release|Any CPU {5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.Build.0 = Release|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B738F3E1-654D-41A3-B068-58ED122BB688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {B738F3E1-654D-41A3-B068-58ED122BB688}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU {B738F3E1-654D-41A3-B068-58ED122BB688}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.Build.0 = Release|Any CPU {B738F3E1-654D-41A3-B068-58ED122BB688}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -1,3 +1,4 @@
using System;
using System.Security.Cryptography; using System.Security.Cryptography;
using FrostFS.Container; using FrostFS.Container;
using FrostFS.Netmap; using FrostFS.Netmap;
@ -14,15 +15,15 @@ namespace FrostFS.SDK.ClientV2;
public partial class Client: IFrostFSClient public partial class Client: IFrostFSClient
{ {
private GrpcChannel _channel; private GrpcChannel? _channel;
private readonly ECDsa _key; private readonly ECDsa _key;
public readonly OwnerId OwnerId; public readonly OwnerId OwnerId;
public readonly Version Version = new (2, 13); public readonly Version Version = new(2, 13);
private ContainerService.ContainerServiceClient _containerServiceClient; private ContainerService.ContainerServiceClient? _containerServiceClient;
private NetmapService.NetmapServiceClient _netmapServiceClient; private NetmapService.NetmapServiceClient? _netmapServiceClient;
private ObjectService.ObjectServiceClient _objectServiceClient; private ObjectService.ObjectServiceClient? _objectServiceClient;
private SessionService.SessionServiceClient _sessionServiceClient; private SessionService.SessionServiceClient? _sessionServiceClient;
public Client(string key, string host) public Client(string key, string host)
{ {

View file

@ -1,11 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" /> <ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" />
<ProjectReference Include="..\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj" /> <ProjectReference Include="..\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj" />

View file

@ -1,3 +1,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using FrostFS.SDK.ModelsV2; using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Interfaces; namespace FrostFS.SDK.ClientV2.Interfaces;

View file

@ -1,7 +1,10 @@
using System;
using Google.Protobuf;
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using FrostFS.SDK.Cryptography; using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2.Enums; using FrostFS.SDK.ModelsV2.Enums;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC; namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
@ -26,7 +29,7 @@ public static class ContainerMapper
} }
return new ModelsV2.Container( return new ModelsV2.Container(
Enum.Parse<BasicAcl>(basicAclName), (BasicAcl)Enum.Parse(typeof(BasicAcl), basicAclName),
container.PlacementPolicy.ToModel() container.PlacementPolicy.ToModel()
) )
{ {

View file

@ -1,3 +1,5 @@
using System;
using FrostFS.Netmap; using FrostFS.Netmap;
using FrostFS.SDK.ModelsV2.Enums; using FrostFS.SDK.ModelsV2.Enums;
using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo; using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo;
@ -15,7 +17,7 @@ public static class NodeInfoMapper
} }
return new NodeInfo return new NodeInfo
{ {
State = Enum.Parse<NodeState>(nodeStateName), State = (NodeState)Enum.Parse(typeof(NodeState), nodeStateName),
Version = nodeInfo.Version.ToModel() Version = nodeInfo.Version.ToModel()
}; };
} }

View file

@ -1,3 +1,4 @@
using System.Linq;
using FrostFS.Netmap; using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;

View file

@ -1,3 +1,6 @@
using System;
using System.Linq;
using FrostFS.Object; using FrostFS.Object;
using FrostFS.SDK.ModelsV2; using FrostFS.SDK.ModelsV2;
using MatchType = FrostFS.Object.MatchType; using MatchType = FrostFS.Object.MatchType;
@ -26,15 +29,11 @@ public static class ObjectFilterMapper
{ {
public static SearchRequest.Types.Body.Types.Filter ToGrpcMessage(this ObjectFilter filter) public static SearchRequest.Types.Body.Types.Filter ToGrpcMessage(this ObjectFilter filter)
{ {
var objMatchTypeName = Enum.GetName(typeof(MatchType), filter.MatchType); var objMatchTypeName = Enum.GetName(typeof(MatchType), filter.MatchType)
if (objMatchTypeName is null) ?? throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.");
{
throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.");
}
return new SearchRequest.Types.Body.Types.Filter return new SearchRequest.Types.Body.Types.Filter
{ {
MatchType = Enum.Parse<MatchType>(objMatchTypeName), MatchType = (MatchType)Enum.Parse(typeof(MatchType), objMatchTypeName),
Key = filter.Key, Key = filter.Key,
Value = filter.Value Value = filter.Value
}; };
@ -45,18 +44,15 @@ public static class ObjectHeaderMapper
{ {
public static Header ToGrpcMessage(this ObjectHeader header) public static Header ToGrpcMessage(this ObjectHeader header)
{ {
var objTypeName = Enum.GetName(typeof(ObjectType), header.ObjectType); var objTypeName = Enum.GetName(typeof(ObjectType), header.ObjectType)
if (objTypeName is null) ?? throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.");
{
throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.");
}
var head = new Header var head = new Header
{ {
Attributes = { }, Attributes = { },
ContainerId = header.ContainerId.ToGrpcMessage(), ContainerId = header.ContainerId.ToGrpcMessage(),
ObjectType = Enum.Parse<ObjectType>(objTypeName) ObjectType = (ObjectType)Enum.Parse(typeof(ObjectType), objTypeName)
}; };
foreach (var attribute in header.Attributes) foreach (var attribute in header.Attributes)
{ {
head.Attributes.Add(attribute.ToGrpcMessage()); head.Attributes.Add(attribute.ToGrpcMessage());
@ -67,15 +63,11 @@ public static class ObjectHeaderMapper
public static ObjectHeader ToModel(this Header header) public static ObjectHeader ToModel(this Header header)
{ {
var objTypeName = Enum.GetName(typeof(ModelsV2.Enums.ObjectType), header.ObjectType); var objTypeName = Enum.GetName(typeof(ModelsV2.Enums.ObjectType), header.ObjectType)
if (objTypeName is null) ?? throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.");
{
throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.");
}
return new ObjectHeader( return new ObjectHeader(
ContainerId.FromHash(header.ContainerId.Value.ToByteArray()), ContainerId.FromHash(header.ContainerId.Value.ToByteArray()),
Enum.Parse<ModelsV2.Enums.ObjectType>(objTypeName), (ModelsV2.Enums.ObjectType)Enum.Parse(typeof(ModelsV2.Enums.ObjectType), objTypeName),
header.Attributes.Select(attribute => attribute.ToModel()).ToArray() header.Attributes.Select(attribute => attribute.ToModel()).ToArray()
) )
{ {

View file

@ -1,3 +1,4 @@
using System;
using FrostFS.SDK.ModelsV2.Enums; using FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC; namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
@ -8,12 +9,9 @@ public static class StatusMapper
{ {
if (status is null) return new ModelsV2.Status(StatusCode.Success); if (status is null) return new ModelsV2.Status(StatusCode.Success);
var codeName = Enum.GetName(typeof(StatusCode), status.Code); var codeName = Enum.GetName(typeof(StatusCode), status.Code);
if (codeName is null)
{
throw new ArgumentException($"Unknown StatusCode. Value: '{status.Code}'.");
}
return new ModelsV2.Status(Enum.Parse<StatusCode>(codeName), status.Message);
return codeName is null
? throw new ArgumentException($"Unknown StatusCode. Value: '{status.Code}'.")
: new ModelsV2.Status((StatusCode)Enum.Parse(typeof(StatusCode), codeName), status.Message);
} }
} }

View file

@ -0,0 +1,271 @@
using System.Runtime.CompilerServices;
namespace System
{
/// <summary>Represent a type can be used to index a collection either from the start or the end.</summary>
/// <remarks>
/// Index is used by the C# compiler to support the new index syntax
/// <code>
/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
/// int lastElement = someArray[^1]; // lastElement = 5
/// </code>
/// </remarks>
internal readonly struct Index : IEquatable<Index>
{
private readonly int _value;
/// <summary>Construct an Index using a value and indicating if the index is from the start or from the end.</summary>
/// <param name="value">The index value. it has to be zero or positive number.</param>
/// <param name="fromEnd">Indicating if the index is from the start or from the end.</param>
/// <remarks>
/// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Index(int value, bool fromEnd = false)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
if (fromEnd)
_value = ~value;
else
_value = value;
}
// The following private constructors mainly created for perf reason to avoid the checks
private Index(int value)
{
_value = value;
}
/// <summary>Create an Index pointing at first element.</summary>
public static Index Start => new Index(0);
/// <summary>Create an Index pointing at beyond last element.</summary>
public static Index End => new Index(~0);
/// <summary>Create an Index from the start at the position indicated by the value.</summary>
/// <param name="value">The index value from the start.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromStart(int value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
return new Index(value);
}
/// <summary>Create an Index from the end at the position indicated by the value.</summary>
/// <param name="value">The index value from the end.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromEnd(int value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
return new Index(~value);
}
/// <summary>Returns the index value.</summary>
public int Value
{
get
{
if (_value < 0)
{
return ~_value;
}
else
{
return _value;
}
}
}
/// <summary>Indicates whether the index is from the start or the end.</summary>
public bool IsFromEnd => _value < 0;
/// <summary>Calculate the offset from the start using the giving collection length.</summary>
/// <param name="length">The length of the collection that the Index will be used with. length has to be a positive value</param>
/// <remarks>
/// For performance reason, we don't validate the input length parameter and the returned offset value against negative values.
/// we don't validate either the returned offset is greater than the input length.
/// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and
/// then used to index a collection will get out of range exception which will be same affect as the validation.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetOffset(int length)
{
var offset = _value;
if (IsFromEnd)
{
// offset = length - (~value)
// offset = length + (~(~value) + 1)
// offset = length + value + 1
offset += length + 1;
}
return offset;
}
/// <summary>Indicates whether the current Index object is equal to another object of the same type.</summary>
/// <param name="value">An object to compare with this object</param>
public override bool Equals(object? value) => value is Index && _value == ((Index)value)._value;
/// <summary>Indicates whether the current Index object is equal to another Index object.</summary>
/// <param name="other">An object to compare with this object</param>
public bool Equals(Index other) => _value == other._value;
/// <summary>Returns the hash code for this instance.</summary>
public override int GetHashCode() => _value;
/// <summary>Converts integer number to an Index.</summary>
public static implicit operator Index(int value) => FromStart(value);
/// <summary>Converts the value of the current Index object to its equivalent string representation.</summary>
public override string ToString()
{
if (IsFromEnd)
return "^" + ((uint)Value).ToString();
return ((uint)Value).ToString();
}
}
/// <summary>Represent a range has start and end indexes.</summary>
/// <remarks>
/// Range is used by the C# compiler to support the range syntax.
/// <code>
/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 };
/// int[] subArray1 = someArray[0..2]; // { 1, 2 }
/// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 }
/// </code>
/// </remarks>
internal readonly struct Range : IEquatable<Range>
{
/// <summary>Represent the inclusive start index of the Range.</summary>
public Index Start { get; }
/// <summary>Represent the exclusive end index of the Range.</summary>
public Index End { get; }
/// <summary>Construct a Range object using the start and end indexes.</summary>
/// <param name="start">Represent the inclusive start index of the range.</param>
/// <param name="end">Represent the exclusive end index of the range.</param>
public Range(Index start, Index end)
{
Start = start;
End = end;
}
/// <summary>Indicates whether the current Range object is equal to another object of the same type.</summary>
/// <param name="value">An object to compare with this object</param>
public override bool Equals(object? value) =>
value is Range r &&
r.Start.Equals(Start) &&
r.End.Equals(End);
/// <summary>Indicates whether the current Range object is equal to another Range object.</summary>
/// <param name="other">An object to compare with this object</param>
public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End);
/// <summary>Returns the hash code for this instance.</summary>
public override int GetHashCode()
{
return Start.GetHashCode() * 31 + End.GetHashCode();
}
/// <summary>Converts the value of the current Range object to its equivalent string representation.</summary>
public override string ToString()
{
return Start + ".." + End;
}
/// <summary>Create a Range object starting from start index to the end of the collection.</summary>
public static Range StartAt(Index start) => new Range(start, Index.End);
/// <summary>Create a Range object starting from first element in the collection to the end Index.</summary>
public static Range EndAt(Index end) => new Range(Index.Start, end);
/// <summary>Create a Range object starting from first element to the end.</summary>
public static Range All => new Range(Index.Start, Index.End);
/// <summary>Calculate the start offset and length of range object using a collection length.</summary>
/// <param name="length">The length of the collection that the range will be used with. length has to be a positive value.</param>
/// <remarks>
/// For performance reason, we don't validate the input length parameter against negative values.
/// It is expected Range will be used with collections which always have non negative length/count.
/// We validate the range is inside the length scope though.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public (int Offset, int Length) GetOffsetAndLength(int length)
{
int start;
var startIndex = Start;
if (startIndex.IsFromEnd)
start = length - startIndex.Value;
else
start = startIndex.Value;
int end;
var endIndex = End;
if (endIndex.IsFromEnd)
end = length - endIndex.Value;
else
end = endIndex.Value;
if ((uint)end > (uint)length || (uint)start > (uint)end)
{
throw new ArgumentOutOfRangeException(nameof(length));
}
return (start, end - start);
}
}
}
namespace System.Runtime.CompilerServices
{
internal static class RuntimeHelpers
{
/// <summary>
/// Slices the specified array using the specified range.
/// </summary>
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
(int offset, int length) = range.GetOffsetAndLength(array.Length);
if (default(T) != null || typeof(T[]) == array.GetType())
{
// We know the type of the array to be exactly T[].
if (length == 0)
{
return Array.Empty<T>();
}
var dest = new T[length];
Array.Copy(array, offset, dest, 0, length);
return dest;
}
else
{
// The array is actually a U[] where U:T.
var dest = (T[])Array.CreateInstance(array.GetType().GetElementType(), length);
Array.Copy(array, offset, dest, 0, length);
return dest;
}
}
}
}

View file

@ -1,18 +1,22 @@
using System;
using System.Security.Cryptography; using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using Google.Protobuf; using Google.Protobuf;
using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math; using Org.BouncyCastle.Math;
namespace FrostFS.SDK.ClientV2 using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
namespace FrostFS.SDK.ClientV2;
public static class RequestSigner
{ {
public static class RequestSigner
{
public const int RFC6979SignatureSize = 64; public const int RFC6979SignatureSize = 64;
public static byte[] SignRFC6979(this ECDsa key, byte[] data) public static byte[] SignRFC6979(this ECDsa key, byte[] data)
@ -23,17 +27,21 @@ namespace FrostFS.SDK.ClientV2
var privateKey = new ECPrivateKeyParameters(new BigInteger(1, key.PrivateKey()), ecParameters); var privateKey = new ECPrivateKeyParameters(new BigInteger(1, key.PrivateKey()), ecParameters);
var signer = new ECDsaSigner(new HMacDsaKCalculator(digest)); var signer = new ECDsaSigner(new HMacDsaKCalculator(digest));
var hash = new byte[digest.GetDigestSize()]; var hash = new byte[digest.GetDigestSize()];
digest.BlockUpdate(data, 0, data.Length); digest.BlockUpdate(data, 0, data.Length);
digest.DoFinal(hash, 0); digest.DoFinal(hash, 0);
signer.Init(true, privateKey); signer.Init(true, privateKey);
var rs = signer.GenerateSignature(hash); var rs = signer.GenerateSignature(hash);
var signature = new byte[RFC6979SignatureSize]; var signature = new byte[RFC6979SignatureSize];
var rbytes = rs[0].ToByteArrayUnsigned(); var rbytes = rs[0].ToByteArrayUnsigned();
var sbytes = rs[1].ToByteArrayUnsigned(); var sbytes = rs[1].ToByteArrayUnsigned();
var index = RFC6979SignatureSize / 2 - rbytes.Length; var index = RFC6979SignatureSize / 2 - rbytes.Length;
rbytes.CopyTo(signature, index); rbytes.CopyTo(signature, index);
index = RFC6979SignatureSize - sbytes.Length; index = RFC6979SignatureSize - sbytes.Length;
sbytes.CopyTo(signature, index); sbytes.CopyTo(signature, index);
return signature; return signature;
} }
@ -85,13 +93,14 @@ namespace FrostFS.SDK.ClientV2
IResponse => new ResponseVerificationHeader(), IResponse => new ResponseVerificationHeader(),
_ => throw new InvalidOperationException("Unsopported message type") _ => throw new InvalidOperationException("Unsopported message type")
}; };
var verifyOrigin = message.GetVerificationHeader(); var verifyOrigin = message.GetVerificationHeader();
if (verifyOrigin is null) if (verifyOrigin is null)
verify.BodySignature = key.SignMessagePart(message.GetBody()); verify.BodySignature = key.SignMessagePart(message.GetBody());
verify.MetaSignature = key.SignMessagePart(meta); verify.MetaSignature = key.SignMessagePart(meta);
verify.OriginSignature = key.SignMessagePart(verifyOrigin); verify.OriginSignature = key.SignMessagePart(verifyOrigin);
verify.SetOrigin(verifyOrigin); verify.SetOrigin(verifyOrigin);
message.SetVerificationHeader(verify); message.SetVerificationHeader(verify);
} }
}
} }

View file

@ -1,6 +1,8 @@
using FrostFS.Container; using FrostFS.Container;
using FrostFS.SDK.ClientV2.Mappers.GRPC; using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.ModelsV2; using FrostFS.SDK.ModelsV2;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace FrostFS.SDK.ClientV2; namespace FrostFS.SDK.ClientV2;

View file

@ -1,5 +1,8 @@
using FrostFS.Netmap; using System.Threading.Tasks;
using FrostFS.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo; using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo;
namespace FrostFS.SDK.ClientV2; namespace FrostFS.SDK.ClientV2;
@ -10,11 +13,13 @@ public partial class Client
{ {
var request = new LocalNodeInfoRequest var request = new LocalNodeInfoRequest
{ {
Body = new LocalNodeInfoRequest.Types.Body { }, Body = new LocalNodeInfoRequest.Types.Body { }
}; };
request.AddMetaHeader(); request.AddMetaHeader();
request.Sign(_key); request.Sign(_key);
var response = await _netmapServiceClient.LocalNodeInfoAsync(request); var response = await _netmapServiceClient.LocalNodeInfoAsync(request);
return response.Body.ToModel(); return response.Body.ToModel();
} }
@ -22,10 +27,12 @@ public partial class Client
{ {
var request = new NetworkInfoRequest var request = new NetworkInfoRequest
{ {
Body = new NetworkInfoRequest.Types.Body { }, Body = new NetworkInfoRequest.Types.Body { }
}; };
request.AddMetaHeader(); request.AddMetaHeader();
request.Sign(_key); request.Sign(_key);
return await _netmapServiceClient.NetworkInfoAsync(request); return await _netmapServiceClient.NetworkInfoAsync(request);
} }
} }

View file

@ -1,11 +1,16 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Google.Protobuf;
using FrostFS.Object; using FrostFS.Object;
using FrostFS.Refs; using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC; using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography; using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2; using FrostFS.SDK.ModelsV2;
using FrostFS.Session; using FrostFS.Session;
using Google.Protobuf;
using Grpc.Core;
namespace FrostFS.SDK.ClientV2; namespace FrostFS.SDK.ClientV2;
@ -22,12 +27,14 @@ public partial class Client
ContainerId = cid.ToGrpcMessage(), ContainerId = cid.ToGrpcMessage(),
ObjectId = oid.ToGrpcMessage() ObjectId = oid.ToGrpcMessage()
} }
}, }
}; };
request.AddMetaHeader(); request.AddMetaHeader();
request.Sign(_key); request.Sign(_key);
var response = await _objectServiceClient.HeadAsync(request); var response = await _objectServiceClient.HeadAsync(request);
Verifier.CheckResponse(response); Verifier.CheckResponse(response);
return response.Body.Header.Header.ToModel(); return response.Body.Header.Header.ToModel();
} }
@ -43,9 +50,10 @@ public partial class Client
{ {
ContainerId = cid.ToGrpcMessage(), ContainerId = cid.ToGrpcMessage(),
ObjectId = oid.ToGrpcMessage() ObjectId = oid.ToGrpcMessage()
}, }
} }
}; };
request.AddMetaHeader(); request.AddMetaHeader();
request.AddObjectSessionToken( request.AddObjectSessionToken(
sessionToken, sessionToken,
@ -54,43 +62,13 @@ public partial class Client
ObjectSessionContext.Types.Verb.Get, ObjectSessionContext.Types.Verb.Get,
_key _key
); );
request.Sign(_key); request.Sign(_key);
var obj = await GetObject(request); var obj = await GetObject(request);
return obj.ToModel(); return obj.ToModel();
} }
private async Task<Object.Object> GetObject(GetRequest request)
{
using var stream = GetObjectInit(request);
var obj = await stream.ReadHeader();
var payload = new byte[obj.Header.PayloadLength];
var offset = 0;
var chunk = await stream.ReadChunk();
while (chunk is not null)
{
chunk.CopyTo(payload, offset);
offset += chunk.Length;
chunk = await stream.ReadChunk();
}
obj.Payload = ByteString.CopyFrom(payload);
return obj;
}
private ObjectReader GetObjectInit(GetRequest initRequest)
{
if (initRequest is null)
{
throw new ArgumentNullException(nameof(initRequest));
}
return new ObjectReader
{
Call = _objectServiceClient.Get(initRequest)
};
}
public async Task<ObjectId> PutObjectAsync(ObjectHeader header, Stream payload) public async Task<ObjectId> PutObjectAsync(ObjectHeader header, Stream payload)
{ {
return await PutObject(header, payload); return await PutObject(header, payload);
@ -101,68 +79,6 @@ public partial class Client
return await PutObject(header, new MemoryStream(payload)); return await PutObject(header, new MemoryStream(payload));
} }
private async Task<ObjectId> PutObject(ObjectHeader header, Stream payload)
{
var sessionToken = await CreateSessionAsync(uint.MaxValue);
var hdr = header.ToGrpcMessage();
hdr.OwnerId = OwnerId.ToGrpcMessage();
hdr.Version = Version.ToGrpcMessage();
var oid = new ObjectID
{
Value = hdr.Sha256()
};
var request = new PutRequest
{
Body = new PutRequest.Types.Body
{
Init = new PutRequest.Types.Body.Types.Init
{
Header = hdr
},
}
};
request.AddMetaHeader();
request.AddObjectSessionToken(
sessionToken,
hdr.ContainerId,
oid,
ObjectSessionContext.Types.Verb.Put,
_key
);
request.Sign(_key);
using var stream = await PutObjectInit(request);
var buffer = new byte[Constants.ObjectChunkSize];
var bufferLength = await payload.ReadAsync(buffer.AsMemory(0, Constants.ObjectChunkSize));
while (bufferLength > 0)
{
request.Body = new PutRequest.Types.Body
{
Chunk = ByteString.CopyFrom(buffer[..bufferLength]),
};
request.VerifyHeader = null;
request.Sign(_key);
await stream.Write(request);
bufferLength = await payload.ReadAsync(buffer.AsMemory(0, Constants.ObjectChunkSize));
}
var response = await stream.Close();
Verifier.CheckResponse(response);
return ObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray());
}
private async Task<ObjectStreamer> PutObjectInit(PutRequest initRequest)
{
if (initRequest is null)
{
throw new ArgumentNullException(nameof(initRequest));
}
var call = _objectServiceClient.Put();
await call.RequestStream.WriteAsync(initRequest);
return new ObjectStreamer { Call = call };
}
public async Task DeleteObjectAsync(ContainerId cid, ObjectId oid) public async Task DeleteObjectAsync(ContainerId cid, ObjectId oid)
{ {
var request = new DeleteRequest var request = new DeleteRequest
@ -176,6 +92,7 @@ public partial class Client
} }
} }
}; };
request.AddMetaHeader(); request.AddMetaHeader();
request.Sign(_key); request.Sign(_key);
var response = await _objectServiceClient.DeleteAsync(request); var response = await _objectServiceClient.DeleteAsync(request);
@ -193,24 +110,125 @@ public partial class Client
Version = 1 Version = 1
} }
}; };
foreach (var filter in filters) foreach (var filter in filters)
{ {
request.Body.Filters.Add(filter.ToGrpcMessage()); request.Body.Filters.Add(filter.ToGrpcMessage());
} }
;
request.AddMetaHeader(); request.AddMetaHeader();
request.Sign(_key); request.Sign(_key);
var objectsIds = SearchObjects(request); var objectsIds = SearchObjects(request);
await foreach (var oid in objectsIds) await foreach (var oid in objectsIds)
{ {
yield return ObjectId.FromHash(oid.Value.ToByteArray()); yield return ObjectId.FromHash(oid.Value.ToByteArray());
} }
} }
private async Task<Object.Object> GetObject(GetRequest request)
{
using var stream = GetObjectInit(request);
var obj = await stream.ReadHeader();
var payload = new byte[obj.Header.PayloadLength];
var offset = 0;
var chunk = await stream.ReadChunk();
while (chunk is not null)
{
chunk.CopyTo(payload, offset);
offset += chunk.Length;
chunk = await stream.ReadChunk();
}
obj.Payload = ByteString.CopyFrom(payload);
return obj;
}
private ObjectReader GetObjectInit(GetRequest initRequest)
{
if (initRequest is null)
throw new ArgumentNullException(nameof(initRequest));
return new ObjectReader
{
Call = _objectServiceClient.Get(initRequest)
};
}
private async Task<ObjectId> PutObject(ObjectHeader header, Stream payload)
{
var sessionToken = await CreateSessionAsync(uint.MaxValue);
var hdr = header.ToGrpcMessage();
hdr.OwnerId = OwnerId.ToGrpcMessage();
hdr.Version = Version.ToGrpcMessage();
var oid = new ObjectID
{
Value = hdr.Sha256()
};
var request = new PutRequest
{
Body = new PutRequest.Types.Body
{
Init = new PutRequest.Types.Body.Types.Init
{
Header = hdr
},
}
};
request.AddMetaHeader();
request.AddObjectSessionToken(
sessionToken,
hdr.ContainerId,
oid,
ObjectSessionContext.Types.Verb.Put,
_key
);
request.Sign(_key);
using var stream = await PutObjectInit(request);
var buffer = new byte[Constants.ObjectChunkSize];
var bufferLength = await payload.ReadAsync(buffer, 0, Constants.ObjectChunkSize);
while (bufferLength > 0)
{
request.Body = new PutRequest.Types.Body
{
Chunk = ByteString.CopyFrom(buffer[..bufferLength]),
};
request.VerifyHeader = null;
request.Sign(_key);
await stream.Write(request);
bufferLength = await payload.ReadAsync(buffer, 0, Constants.ObjectChunkSize);
}
var response = await stream.Close();
Verifier.CheckResponse(response);
return ObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray());
}
private async Task<ObjectStreamer> PutObjectInit(PutRequest initRequest)
{
if (initRequest is null)
{
throw new ArgumentNullException(nameof(initRequest));
}
var call = _objectServiceClient.Put();
await call.RequestStream.WriteAsync(initRequest);
return new ObjectStreamer(call);
}
private async IAsyncEnumerable<ObjectID> SearchObjects(SearchRequest request) private async IAsyncEnumerable<ObjectID> SearchObjects(SearchRequest request)
{ {
using var stream = SearchObjectsInit(request); using var stream = GetSearchReader(request);
var ids = await stream.Read(); var ids = await stream.Read();
while (ids is not null) while (ids is not null)
{ {
@ -218,110 +236,18 @@ public partial class Client
{ {
yield return oid; yield return oid;
} }
ids = await stream.Read(); ids = await stream.Read();
} }
} }
private SearchReader SearchObjectsInit(SearchRequest initRequest) private SearchReader GetSearchReader(SearchRequest initRequest)
{ {
if (initRequest is null) if (initRequest is null)
{ {
throw new ArgumentNullException(nameof(initRequest)); throw new ArgumentNullException(nameof(initRequest));
} }
return new SearchReader return new SearchReader(_objectServiceClient.Search(initRequest));
{
Call = _objectServiceClient.Search(initRequest)
};
}
}
internal class ObjectReader : IDisposable
{
public AsyncServerStreamingCall<GetResponse> Call { get; init; }
public async Task<Object.Object> ReadHeader()
{
if (!await Call.ResponseStream.MoveNext())
{
throw new InvalidOperationException("unexpect end of stream");
}
var response = Call.ResponseStream.Current;
Verifier.CheckResponse(response);
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Init)
throw new InvalidOperationException("unexpect message type");
return new Object.Object
{
ObjectId = response.Body.Init.ObjectId,
Header = response.Body.Init.Header,
};
}
public async Task<byte[]?> ReadChunk()
{
if (!await Call.ResponseStream.MoveNext())
{
return null;
}
var response = Call.ResponseStream.Current;
Verifier.CheckResponse(response);
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Chunk)
throw new InvalidOperationException("unexpect message type");
return response.Body.Chunk.ToByteArray();
}
public void Dispose()
{
Call.Dispose();
}
}
internal class ObjectStreamer : IDisposable
{
public AsyncClientStreamingCall<PutRequest, PutResponse> Call { get; init; }
public async Task Write(PutRequest request)
{
if (request is null)
{
throw new ArgumentNullException(nameof(request));
}
await Call.RequestStream.WriteAsync(request);
}
public async Task<PutResponse> Close()
{
await Call.RequestStream.CompleteAsync();
return await Call.ResponseAsync;
}
public void Dispose()
{
Call.Dispose();
}
}
internal class SearchReader : IDisposable
{
public AsyncServerStreamingCall<SearchResponse> Call { get; init; }
public async Task<List<ObjectID>?> Read()
{
if (!await Call.ResponseStream.MoveNext())
{
return null;
}
var response = Call.ResponseStream.Current;
Verifier.CheckResponse(response);
return response.Body?.IdList.ToList();
}
public void Dispose()
{
Call.Dispose();
} }
} }

View file

@ -0,0 +1,50 @@
using System;
using System.Threading.Tasks;
using Grpc.Core;
using FrostFS.Object;
namespace FrostFS.SDK.ClientV2;
internal class ObjectReader : IDisposable
{
public AsyncServerStreamingCall<GetResponse> Call { get; set; }
public async Task<Object.Object> ReadHeader()
{
if (!await Call.ResponseStream.MoveNext())
throw new InvalidOperationException("unexpect end of stream");
var response = Call.ResponseStream.Current;
Verifier.CheckResponse(response);
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Init)
throw new InvalidOperationException("unexpect message type");
return new Object.Object
{
ObjectId = response.Body.Init.ObjectId,
Header = response.Body.Init.Header,
};
}
public async Task<byte[]?> ReadChunk()
{
if (!await Call.ResponseStream.MoveNext())
return null;
var response = Call.ResponseStream.Current;
Verifier.CheckResponse(response);
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Chunk)
throw new InvalidOperationException("unexpect message type");
return response.Body.Chunk.ToByteArray();
}
public void Dispose()
{
Call.Dispose();
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Threading.Tasks;
using Grpc.Core;
using FrostFS.Object;
namespace FrostFS.SDK.ClientV2;
internal class ObjectStreamer(AsyncClientStreamingCall<PutRequest, PutResponse> call) : IDisposable
{
public AsyncClientStreamingCall<PutRequest, PutResponse> Call { get; private set; } = call;
public async Task Write(PutRequest request)
{
if (request is null)
{
throw new ArgumentNullException(nameof(request));
}
await Call.RequestStream.WriteAsync(request);
}
public async Task<PutResponse> Close()
{
await Call.RequestStream.CompleteAsync();
return await Call.ResponseAsync;
}
public void Dispose()
{
Call.Dispose();
}
}

View file

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Grpc.Core;
using FrostFS.Object;
using FrostFS.Refs;
namespace FrostFS.SDK.ClientV2;
internal class SearchReader(AsyncServerStreamingCall<SearchResponse> call) : IDisposable
{
public AsyncServerStreamingCall<SearchResponse> Call { get; private set; } = call;
public async Task<List<ObjectID>?> Read()
{
if (!await Call.ResponseStream.MoveNext())
{
return null;
}
var response = Call.ResponseStream.Current;
Verifier.CheckResponse(response);
return response.Body?.IdList.ToList();
}
public void Dispose()
{
Call.Dispose();
}
}

View file

@ -1,3 +1,5 @@
using System.Threading.Tasks;
using FrostFS.SDK.ClientV2.Mappers.GRPC; using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.Session; using FrostFS.Session;
@ -15,14 +17,17 @@ public partial class Client
Expiration = expiration, Expiration = expiration,
} }
}; };
request.AddMetaHeader(); request.AddMetaHeader();
request.Sign(_key); request.Sign(_key);
return await CreateSession(request); return await CreateSession(request);
} }
private async Task<SessionToken> CreateSession(CreateRequest request) private async Task<SessionToken> CreateSession(CreateRequest request)
{ {
var resp = await _sessionServiceClient.CreateAsync(request); var resp = await _sessionServiceClient.CreateAsync(request);
return new SessionToken return new SessionToken
{ {
Body = new SessionToken.Types.Body Body = new SessionToken.Types.Body

View file

@ -1,34 +1,42 @@
using System;
using System.Security.Cryptography; using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using Google.Protobuf; using Google.Protobuf;
using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math; using Org.BouncyCastle.Math;
namespace FrostFS.SDK.ClientV2 using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
namespace FrostFS.SDK.ClientV2;
public static class Verifier
{ {
public static class Verifier
{
public const int RFC6979SignatureSize = 64; public const int RFC6979SignatureSize = 64;
private static BigInteger[] DecodeSignature(byte[] sig) private static BigInteger[] DecodeSignature(byte[] sig)
{ {
if (sig.Length != RFC6979SignatureSize) if (sig.Length != RFC6979SignatureSize)
throw new FormatException($"Wrong signature size, expect={RFC6979SignatureSize}, actual={sig.Length}"); throw new FormatException($"Wrong signature size, expect={RFC6979SignatureSize}, actual={sig.Length}");
var rs = new BigInteger[2]; var rs = new BigInteger[2];
rs[0] = new BigInteger(1, sig[..32]); rs[0] = new BigInteger(1, sig[..32]);
rs[1] = new BigInteger(1, sig[32..]); rs[1] = new BigInteger(1, sig[32..]);
return rs; return rs;
} }
public static bool VerifyRFC6979(this byte[] publicKey, byte[] data, byte[] sig) public static bool VerifyRFC6979(this byte[] publicKey, byte[] data, byte[] sig)
{ {
if (publicKey is null || data is null || sig is null) return false; if (publicKey is null || data is null || sig is null)
return false;
var rs = DecodeSignature(sig); var rs = DecodeSignature(sig);
var digest = new Sha256Digest(); var digest = new Sha256Digest();
var signer = new ECDsaSigner(new HMacDsaKCalculator(digest)); var signer = new ECDsaSigner(new HMacDsaKCalculator(digest));
@ -36,9 +44,11 @@ namespace FrostFS.SDK.ClientV2
var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N); var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N);
var bcPublicKey = new ECPublicKeyParameters(secp256R1.Curve.DecodePoint(publicKey), ecParameters); var bcPublicKey = new ECPublicKeyParameters(secp256R1.Curve.DecodePoint(publicKey), ecParameters);
var hash = new byte[digest.GetDigestSize()]; var hash = new byte[digest.GetDigestSize()];
digest.BlockUpdate(data, 0, data.Length); digest.BlockUpdate(data, 0, data.Length);
digest.DoFinal(hash, 0); digest.DoFinal(hash, 0);
signer.Init(false, bcPublicKey); signer.Init(false, bcPublicKey);
return signer.VerifySignature(hash, rs[0], rs[1]); return signer.VerifySignature(hash, rs[0], rs[1]);
} }
@ -54,19 +64,28 @@ namespace FrostFS.SDK.ClientV2
public static bool VerifyMessagePart(this Signature sig, IMessage data) public static bool VerifyMessagePart(this Signature sig, IMessage data)
{ {
if (sig is null || sig.Key is null || sig.Sign is null) return false; if (sig is null || sig.Key is null || sig.Sign is null)
return false;
using var key = sig.Key.ToByteArray().LoadPublicKey(); using var key = sig.Key.ToByteArray().LoadPublicKey();
var data2Verify = data is null ? Array.Empty<byte>() : data.ToByteArray(); var data2Verify = data is null ? Array.Empty<byte>() : data.ToByteArray();
return key.VerifyData(data2Verify, sig.Sign.ToByteArray()); return key.VerifyData(data2Verify, sig.Sign.ToByteArray());
} }
public static bool VerifyMatryoskaLevel(IMessage body, IMetaHeader meta, IVerificationHeader verification) public static bool VerifyMatryoskaLevel(IMessage body, IMetaHeader meta, IVerificationHeader verification)
{ {
if (!verification.MetaSignature.VerifyMessagePart(meta)) return false; if (!verification.MetaSignature.VerifyMessagePart(meta))
return false;
var origin = verification.GetOrigin(); var origin = verification.GetOrigin();
if (!verification.OriginSignature.VerifyMessagePart(origin)) return false;
if (!verification.OriginSignature.VerifyMessagePart(origin))
return false;
if (origin is null) if (origin is null)
return verification.BodySignature.VerifyMessagePart(body); return verification.BodySignature.VerifyMessagePart(body);
return verification.BodySignature is null && VerifyMatryoskaLevel(body, meta.GetOrigin(), origin); return verification.BodySignature is null && VerifyMatryoskaLevel(body, meta.GetOrigin(), origin);
} }
@ -79,11 +98,9 @@ namespace FrostFS.SDK.ClientV2
{ {
if (!resp.Verify()) if (!resp.Verify())
throw new FormatException($"invalid response, type={resp.GetType()}"); throw new FormatException($"invalid response, type={resp.GetType()}");
var status = resp.MetaHeader.Status.ToModel(); var status = resp.MetaHeader.Status.ToModel();
if (!status.IsSuccess()) if (!status.IsSuccess())
{
throw new ApplicationException(status.ToString()); throw new ApplicationException(status.ToString());
} }
}
}
} }

View file

@ -1,9 +1,11 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace FrostFS.SDK.Cryptography namespace FrostFS.SDK.Cryptography;
internal static class ArrayHelper
{ {
internal static class ArrayHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte[] Concat(params byte[][] buffers) public static byte[] Concat(params byte[][] buffers)
{ {
@ -19,5 +21,4 @@ namespace FrostFS.SDK.Cryptography
return dst; return dst;
} }
}
} }

View file

@ -0,0 +1,20 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// In SDK-style projects such as this one, several assembly attributes that were historically
// defined in this file are now automatically added during build and populated with
// values defined in project properties. For details of which attributes are included
// and how to customise this process see: https://aka.ms/assembly-info-properties
// Setting ComVisible to false makes the types in this assembly not visible to COM
// components. If you need to access a type in this assembly from COM, set the ComVisible
// attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM.
[assembly: Guid("08a8487e-39ce-41fb-9c24-13f73ff2bde0")]
[assembly: InternalsVisibleToAttribute("FrostFS.SDK.Cryptography.Test")]

View file

@ -1,20 +1,31 @@
using System;
using System.Linq;
using System.Numerics; using System.Numerics;
using System.Text; using System.Text;
namespace FrostFS.SDK.Cryptography using Org.BouncyCastle.Security.Certificates;
namespace FrostFS.SDK.Cryptography;
public static class Base58
{ {
public static class Base58
{
public const string Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; public const string Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
public static byte[] Base58CheckDecode(this string input) public static byte[] Base58CheckDecode(this string input)
{ {
if (input is null) throw new ArgumentNullException(nameof(input)); if (input is null)
throw new ArgumentNullException(nameof(input));
byte[] buffer = Decode(input); byte[] buffer = Decode(input);
if (buffer.Length < 4) throw new FormatException();
byte[] checksum = buffer[0..(buffer.Length - 4)].Sha256().Sha256(); if (buffer.Length < 4)
if (!buffer.AsSpan(^4).SequenceEqual(checksum.AsSpan(..4)))
throw new FormatException(); throw new FormatException();
byte[] checksum = buffer[0..(buffer.Length - 4)].Sha256().Sha256();
if (!buffer.AsSpan(buffer.Length - 4).SequenceEqual(checksum[..4].AsSpan()))
throw new FormatException();
var ret = buffer[..^4]; var ret = buffer[..^4];
Array.Clear(buffer, 0, buffer.Length); Array.Clear(buffer, 0, buffer.Length);
return ret; return ret;
@ -25,7 +36,7 @@ namespace FrostFS.SDK.Cryptography
byte[] checksum = data.ToArray().Sha256().Sha256(); byte[] checksum = data.ToArray().Sha256().Sha256();
Span<byte> buffer = stackalloc byte[data.Length + 4]; Span<byte> buffer = stackalloc byte[data.Length + 4];
data.CopyTo(buffer); data.CopyTo(buffer);
checksum.AsSpan(..4).CopyTo(buffer[data.Length..]); checksum[..4].AsSpan().CopyTo(buffer[data.Length..]);
var ret = Encode(buffer); var ret = Encode(buffer);
buffer.Clear(); buffer.Clear();
return ret; return ret;
@ -40,22 +51,32 @@ namespace FrostFS.SDK.Cryptography
int digit = Alphabet.IndexOf(input[i]); int digit = Alphabet.IndexOf(input[i]);
if (digit < 0) if (digit < 0)
throw new FormatException($"Invalid Base58 character '{input[i]}' at position {i}"); throw new FormatException($"Invalid Base58 character '{input[i]}' at position {i}");
bi = bi * Alphabet.Length + digit; bi = bi * Alphabet.Length + digit;
} }
// Encode BigInteger to byte[]
// Leading zero bytes get encoded as leading `1` characters
int leadingZeroCount = input.TakeWhile(c => c == Alphabet[0]).Count(); int leadingZeroCount = input.TakeWhile(c => c == Alphabet[0]).Count();
var leadingZeros = new byte[leadingZeroCount]; var leadingZeros = new byte[leadingZeroCount];
if (bi.IsZero) return leadingZeros;
var bytesWithoutLeadingZeros = bi.ToByteArray(isUnsigned: true, isBigEndian: true); if (bi.IsZero)
return leadingZeros;
var bytesBigEndian = bi.ToByteArray().Reverse();
var firstNonZeroIndex = 0;
while(bytesBigEndian.ElementAt(firstNonZeroIndex) == 0x0)
firstNonZeroIndex++;
var bytesWithoutLeadingZeros = bytesBigEndian.Skip(firstNonZeroIndex).ToArray();
return ArrayHelper.Concat(leadingZeros, bytesWithoutLeadingZeros); return ArrayHelper.Concat(leadingZeros, bytesWithoutLeadingZeros);
} }
public static string Encode(ReadOnlySpan<byte> input) public static string Encode(ReadOnlySpan<byte> input)
{ {
// Decode byte[] to BigInteger var data = input.ToArray().Reverse().Concat(new byte[] { 0 }).ToArray();
BigInteger value = new(input, isUnsigned: true, isBigEndian: true); BigInteger value = new(data);
// Encode BigInteger to Base58 string // Encode BigInteger to Base58 string
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -73,5 +94,4 @@ namespace FrostFS.SDK.Cryptography
} }
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,13 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BouncyCastle.NetCore" Version="2.2.1" /> <PackageReference Include="Google.Protobuf" Version="3.27.0" />
<PackageReference Include="Google.Protobuf" Version="3.26.1" /> <PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="System.Memory" Version="4.5.5" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,8 +1,8 @@
using System.Buffers.Binary;
using System.Security.Cryptography;
using FrostFS.SDK.Cryptography.Tz;
using Google.Protobuf; using Google.Protobuf;
using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Digests;
using System;
using System.Buffers.Binary;
using System.Security.Cryptography;
namespace FrostFS.SDK.Cryptography; namespace FrostFS.SDK.Cryptography;
@ -31,10 +31,8 @@ public static class Helper
internal static byte[] Sha256(this ReadOnlySpan<byte> value) internal static byte[] Sha256(this ReadOnlySpan<byte> value)
{ {
var buffer = new byte[32];
using var sha256 = SHA256.Create(); using var sha256 = SHA256.Create();
sha256.TryComputeHash(value, buffer, out _); return sha256.ComputeHash(value.ToArray());
return buffer;
} }
public static ByteString Sha256(this IMessage data) public static ByteString Sha256(this IMessage data)
@ -47,17 +45,6 @@ public static class Helper
return ByteString.CopyFrom(data.ToByteArray().Sha256()); return ByteString.CopyFrom(data.ToByteArray().Sha256());
} }
public static ByteString TzHash(this IMessage data)
{
return ByteString.CopyFrom(new TzHash().ComputeHash(data.ToByteArray()));
}
public static ByteString TzHash(this ByteString data)
{
return ByteString.CopyFrom(new TzHash().ComputeHash(data.ToByteArray()));
}
public static ulong Murmur64(this byte[] value, uint seed) public static ulong Murmur64(this byte[] value, uint seed)
{ {

View file

@ -1,7 +1,10 @@
using System.Buffers.Binary; using System;
using System.Buffers.Binary;
using System.Linq;
using System.Numerics; using System.Numerics;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.Sec;
namespace FrostFS.SDK.Cryptography; namespace FrostFS.SDK.Cryptography;
@ -22,8 +25,10 @@ public static class KeyExtension
$"{nameof(Compress)} argument isn't uncompressed public key. " + $"{nameof(Compress)} argument isn't uncompressed public key. " +
$"expected length={UncompressedPublicKeyLength}, actual={publicKey.Length}" $"expected length={UncompressedPublicKeyLength}, actual={publicKey.Length}"
); );
var secp256R1 = SecNamedCurves.GetByName("secp256r1"); var secp256R1 = SecNamedCurves.GetByName("secp256r1");
var point = secp256R1.Curve.DecodePoint(publicKey); var point = secp256R1.Curve.DecodePoint(publicKey);
return point.GetEncoded(true); return point.GetEncoded(true);
} }
@ -34,8 +39,10 @@ public static class KeyExtension
$"{nameof(Decompress)} argument isn't compressed public key. " + $"{nameof(Decompress)} argument isn't compressed public key. " +
$"expected length={CompressedPublicKeyLength}, actual={publicKey.Length}" $"expected length={CompressedPublicKeyLength}, actual={publicKey.Length}"
); );
var secp256R1 = SecNamedCurves.GetByName("secp256r1"); var secp256R1 = SecNamedCurves.GetByName("secp256r1");
var point = secp256R1.Curve.DecodePoint(publicKey); var point = secp256R1.Curve.DecodePoint(publicKey);
return point.GetEncoded(false); return point.GetEncoded(false);
} }
@ -46,10 +53,12 @@ public static class KeyExtension
$"{nameof(CreateSignatureRedeemScript)} argument isn't compressed public key. " + $"{nameof(CreateSignatureRedeemScript)} argument isn't compressed public key. " +
$"expected length={CompressedPublicKeyLength}, actual={publicKey.Length}" $"expected length={CompressedPublicKeyLength}, actual={publicKey.Length}"
); );
var script = new byte[] { 0x0c, CompressedPublicKeyLength }; //PUSHDATA1 33 var script = new byte[] { 0x0c, CompressedPublicKeyLength }; //PUSHDATA1 33
script = ArrayHelper.Concat(script, publicKey); script = ArrayHelper.Concat(script, publicKey);
script = ArrayHelper.Concat(script, new byte[] { 0x41 }); //SYSCALL script = ArrayHelper.Concat(script, new byte[] { 0x41 }); //SYSCALL
script = ArrayHelper.Concat(script, BitConverter.GetBytes(CheckSigDescriptor)); //Neo_Crypto_CheckSig script = ArrayHelper.Concat(script, BitConverter.GetBytes(CheckSigDescriptor)); //Neo_Crypto_CheckSig
return script; return script;
} }
@ -64,15 +73,20 @@ public static class KeyExtension
Span<byte> data = stackalloc byte[21]; Span<byte> data = stackalloc byte[21];
data[0] = version; data[0] = version;
scriptHash.CopyTo(data[1..]); scriptHash.CopyTo(data[1..]);
return Base58.Base58CheckEncode(data); return Base58.Base58CheckEncode(data);
} }
private static byte[] GetPrivateKeyFromWIF(string wif) private static byte[] GetPrivateKeyFromWIF(string wif)
{ {
if (wif == null) throw new ArgumentNullException(); if (wif == null)
throw new ArgumentNullException();
var data = wif.Base58CheckDecode(); var data = wif.Base58CheckDecode();
if (data.Length != 34 || data[0] != 0x80 || data[33] != 0x01) if (data.Length != 34 || data[0] != 0x80 || data[33] != 0x01)
throw new FormatException(); throw new FormatException();
var privateKey = new byte[32]; var privateKey = new byte[32];
Buffer.BlockCopy(data, 1, privateKey, 0, privateKey.Length); Buffer.BlockCopy(data, 1, privateKey, 0, privateKey.Length);
Array.Clear(data, 0, data.Length); Array.Clear(data, 0, data.Length);
@ -92,6 +106,7 @@ public static class KeyExtension
$" isn't encoded compressed public key. " + $" isn't encoded compressed public key. " +
$"expected length={CompressedPublicKeyLength}, actual={publicKey.Length}" $"expected length={CompressedPublicKeyLength}, actual={publicKey.Length}"
); );
return publicKey.GetScriptHash().ToAddress(NeoAddressVersion); return publicKey.GetScriptHash().ToAddress(NeoAddressVersion);
} }
@ -130,12 +145,14 @@ public static class KeyExtension
Y = publicKey[32..] Y = publicKey[32..]
} }
}); });
return key; return key;
} }
public static ECDsa LoadWif(this string wif) public static ECDsa LoadWif(this string wif)
{ {
var privateKey = GetPrivateKeyFromWIF(wif); var privateKey = GetPrivateKeyFromWIF(wif);
return LoadPrivateKey(privateKey); return LoadPrivateKey(privateKey);
} }
@ -151,6 +168,7 @@ public static class KeyExtension
Y = publicKeyFull[32..] Y = publicKeyFull[32..]
} }
}); });
return key; return key;
} }
} }

View file

@ -1,10 +1,11 @@
using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Security.Cryptography; using System.Security.Cryptography;
namespace FrostFS.SDK.Cryptography namespace FrostFS.SDK.Cryptography;
internal class Murmur3_128 : HashAlgorithm
{ {
internal class Murmur3_128 : HashAlgorithm
{
private const ulong c1 = 0x87c37b91114253d5; private const ulong c1 = 0x87c37b91114253d5;
private const ulong c2 = 0x4cf5ad432745937f; private const ulong c2 = 0x4cf5ad432745937f;
private const uint m = 5; private const uint m = 5;
@ -27,6 +28,7 @@ namespace FrostFS.SDK.Cryptography
length += cbSize; length += cbSize;
int remainder = cbSize & 15; int remainder = cbSize & 15;
int alignedLength = ibStart + (cbSize - remainder); int alignedLength = ibStart + (cbSize - remainder);
for (int i = ibStart; i < alignedLength; i += 16) for (int i = ibStart; i < alignedLength; i += 16)
{ {
ulong k1 = BinaryPrimitives.ReadUInt64LittleEndian(array.AsSpan(i)); ulong k1 = BinaryPrimitives.ReadUInt64LittleEndian(array.AsSpan(i));
@ -48,6 +50,7 @@ namespace FrostFS.SDK.Cryptography
h2 += h1; h2 += h1;
h2 = h2 * m + n2; h2 = h2 * m + n2;
} }
if (remainder > 0) if (remainder > 0)
{ {
ulong k1 = 0, k2 = 0; ulong k1 = 0, k2 = 0;
@ -98,6 +101,7 @@ namespace FrostFS.SDK.Cryptography
h2 = Fimix64(h2); h2 = Fimix64(h2);
h1 += h2; h1 += h2;
h2 += h1; h2 += h1;
return BitConverter.GetBytes(h1); return BitConverter.GetBytes(h1);
} }
@ -115,7 +119,7 @@ namespace FrostFS.SDK.Cryptography
k ^= k >> 33; k ^= k >> 33;
k *= 0xc4ceb9fe1a85ec53; k *= 0xc4ceb9fe1a85ec53;
k ^= k >> 33; k ^= k >> 33;
return k; return k;
} }
}
} }

View file

@ -0,0 +1,271 @@
using System.Runtime.CompilerServices;
namespace System
{
/// <summary>Represent a type can be used to index a collection either from the start or the end.</summary>
/// <remarks>
/// Index is used by the C# compiler to support the new index syntax
/// <code>
/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ;
/// int lastElement = someArray[^1]; // lastElement = 5
/// </code>
/// </remarks>
internal readonly struct Index : IEquatable<Index>
{
private readonly int _value;
/// <summary>Construct an Index using a value and indicating if the index is from the start or from the end.</summary>
/// <param name="value">The index value. it has to be zero or positive number.</param>
/// <param name="fromEnd">Indicating if the index is from the start or from the end.</param>
/// <remarks>
/// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Index(int value, bool fromEnd = false)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
if (fromEnd)
_value = ~value;
else
_value = value;
}
// The following private constructors mainly created for perf reason to avoid the checks
private Index(int value)
{
_value = value;
}
/// <summary>Create an Index pointing at first element.</summary>
public static Index Start => new Index(0);
/// <summary>Create an Index pointing at beyond last element.</summary>
public static Index End => new Index(~0);
/// <summary>Create an Index from the start at the position indicated by the value.</summary>
/// <param name="value">The index value from the start.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromStart(int value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
return new Index(value);
}
/// <summary>Create an Index from the end at the position indicated by the value.</summary>
/// <param name="value">The index value from the end.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Index FromEnd(int value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
return new Index(~value);
}
/// <summary>Returns the index value.</summary>
public int Value
{
get
{
if (_value < 0)
{
return ~_value;
}
else
{
return _value;
}
}
}
/// <summary>Indicates whether the index is from the start or the end.</summary>
public bool IsFromEnd => _value < 0;
/// <summary>Calculate the offset from the start using the giving collection length.</summary>
/// <param name="length">The length of the collection that the Index will be used with. length has to be a positive value</param>
/// <remarks>
/// For performance reason, we don't validate the input length parameter and the returned offset value against negative values.
/// we don't validate either the returned offset is greater than the input length.
/// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and
/// then used to index a collection will get out of range exception which will be same affect as the validation.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetOffset(int length)
{
var offset = _value;
if (IsFromEnd)
{
// offset = length - (~value)
// offset = length + (~(~value) + 1)
// offset = length + value + 1
offset += length + 1;
}
return offset;
}
/// <summary>Indicates whether the current Index object is equal to another object of the same type.</summary>
/// <param name="value">An object to compare with this object</param>
public override bool Equals(object? value) => value is Index && _value == ((Index)value)._value;
/// <summary>Indicates whether the current Index object is equal to another Index object.</summary>
/// <param name="other">An object to compare with this object</param>
public bool Equals(Index other) => _value == other._value;
/// <summary>Returns the hash code for this instance.</summary>
public override int GetHashCode() => _value;
/// <summary>Converts integer number to an Index.</summary>
public static implicit operator Index(int value) => FromStart(value);
/// <summary>Converts the value of the current Index object to its equivalent string representation.</summary>
public override string ToString()
{
if (IsFromEnd)
return "^" + ((uint)Value).ToString();
return ((uint)Value).ToString();
}
}
/// <summary>Represent a range has start and end indexes.</summary>
/// <remarks>
/// Range is used by the C# compiler to support the range syntax.
/// <code>
/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 };
/// int[] subArray1 = someArray[0..2]; // { 1, 2 }
/// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 }
/// </code>
/// </remarks>
internal readonly struct Range : IEquatable<Range>
{
/// <summary>Represent the inclusive start index of the Range.</summary>
public Index Start { get; }
/// <summary>Represent the exclusive end index of the Range.</summary>
public Index End { get; }
/// <summary>Construct a Range object using the start and end indexes.</summary>
/// <param name="start">Represent the inclusive start index of the range.</param>
/// <param name="end">Represent the exclusive end index of the range.</param>
public Range(Index start, Index end)
{
Start = start;
End = end;
}
/// <summary>Indicates whether the current Range object is equal to another object of the same type.</summary>
/// <param name="value">An object to compare with this object</param>
public override bool Equals(object? value) =>
value is Range r &&
r.Start.Equals(Start) &&
r.End.Equals(End);
/// <summary>Indicates whether the current Range object is equal to another Range object.</summary>
/// <param name="other">An object to compare with this object</param>
public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End);
/// <summary>Returns the hash code for this instance.</summary>
public override int GetHashCode()
{
return Start.GetHashCode() * 31 + End.GetHashCode();
}
/// <summary>Converts the value of the current Range object to its equivalent string representation.</summary>
public override string ToString()
{
return Start + ".." + End;
}
/// <summary>Create a Range object starting from start index to the end of the collection.</summary>
public static Range StartAt(Index start) => new Range(start, Index.End);
/// <summary>Create a Range object starting from first element in the collection to the end Index.</summary>
public static Range EndAt(Index end) => new Range(Index.Start, end);
/// <summary>Create a Range object starting from first element to the end.</summary>
public static Range All => new Range(Index.Start, Index.End);
/// <summary>Calculate the start offset and length of range object using a collection length.</summary>
/// <param name="length">The length of the collection that the range will be used with. length has to be a positive value.</param>
/// <remarks>
/// For performance reason, we don't validate the input length parameter against negative values.
/// It is expected Range will be used with collections which always have non negative length/count.
/// We validate the range is inside the length scope though.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public (int Offset, int Length) GetOffsetAndLength(int length)
{
int start;
var startIndex = Start;
if (startIndex.IsFromEnd)
start = length - startIndex.Value;
else
start = startIndex.Value;
int end;
var endIndex = End;
if (endIndex.IsFromEnd)
end = length - endIndex.Value;
else
end = endIndex.Value;
if ((uint)end > (uint)length || (uint)start > (uint)end)
{
throw new ArgumentOutOfRangeException(nameof(length));
}
return (start, end - start);
}
}
}
namespace System.Runtime.CompilerServices
{
internal static class RuntimeHelpers
{
/// <summary>
/// Slices the specified array using the specified range.
/// </summary>
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
(int offset, int length) = range.GetOffsetAndLength(array.Length);
if (default(T) != null || typeof(T[]) == array.GetType())
{
// We know the type of the array to be exactly T[].
if (length == 0)
{
return Array.Empty<T>();
}
var dest = new T[length];
Array.Copy(array, offset, dest, 0, length);
return dest;
}
else
{
// The array is actually a U[] where U:T.
var dest = (T[])Array.CreateInstance(array.GetType().GetElementType(), length);
Array.Copy(array, offset, dest, 0, length);
return dest;
}
}
}
}

View file

@ -1,10 +1,11 @@
using System.Security.Cryptography; using System;
using System.Security.Cryptography;
namespace FrostFS.SDK.Cryptography.Tz namespace FrostFS.SDK.Cryptography.Tz;
// GF127 represents element of GF(2^127)
public class GF127 : IEquatable<GF127>
{ {
// GF127 represents element of GF(2^127)
public class GF127 : IEquatable<GF127>
{
public const int ByteSize = 16; public const int ByteSize = 16;
public const ulong MSB64 = (ulong)1 << 63; // 2^63 public const ulong MSB64 = (ulong)1 << 63; // 2^63
public static readonly GF127 Zero = new(0, 0); public static readonly GF127 Zero = new(0, 0);
@ -220,8 +221,8 @@ namespace FrostFS.SDK.Cryptography.Tz
Array.Reverse(t1); Array.Reverse(t1);
} }
_data[0] = BitConverter.ToUInt64(t0); _data[0] = BitConverter.ToUInt64(t0, 0);
_data[1] = BitConverter.ToUInt64(t1); _data[1] = BitConverter.ToUInt64(t1, 0);
if ((_data[1] & MSB64) != 0) if ((_data[1] & MSB64) != 0)
throw new ArgumentException(nameof(data) + " invalid data"); throw new ArgumentException(nameof(data) + " invalid data");
return this; return this;
@ -247,7 +248,6 @@ namespace FrostFS.SDK.Cryptography.Tz
// ToString() returns hex-encoded representation, starting with MSB. // ToString() returns hex-encoded representation, starting with MSB.
public override string ToString() public override string ToString()
{ {
return Convert.ToHexString(ToByteArray()); return BitConverter.ToString(ToByteArray()).Replace("-", "");
}
} }
} }

View file

@ -1,9 +1,10 @@
using System.Security.Cryptography; using System;
using System.Security.Cryptography;
namespace FrostFS.SDK.Cryptography.Tz namespace FrostFS.SDK.Cryptography.Tz;
public static class Helper
{ {
public static class Helper
{
public static ulong NextUlong(this RandomNumberGenerator rng) public static ulong NextUlong(this RandomNumberGenerator rng)
{ {
var buff = new byte[8]; var buff = new byte[8];
@ -26,5 +27,4 @@ namespace FrostFS.SDK.Cryptography.Tz
{ {
return 64 - GetLeadingZeros(value); return 64 - GetLeadingZeros(value);
} }
}
} }

View file

@ -1,16 +1,21 @@
namespace FrostFS.SDK.Cryptography.Tz using System;
using System.Linq;
namespace FrostFS.SDK.Cryptography.Tz;
public class SL2 : IEquatable<SL2>
{ {
public class SL2 : IEquatable<SL2>
{
// 2x2 matrix // 2x2 matrix
private readonly GF127[][] data; private readonly GF127[][] data;
public static readonly SL2 ID = new(new GF127(1, 0), new GF127(0, 0), public static readonly SL2 ID = new(
new GF127(0, 0), new GF127(1, 0)); new GF127(1, 0), new GF127(0, 0), new GF127(0, 0), new GF127(1, 0));
public static readonly SL2 A = new(new GF127(2, 0), new GF127(1, 0),
new GF127(1, 0), new GF127(0, 0)); public static readonly SL2 A = new(
public static readonly SL2 B = new(new GF127(2, 0), new GF127(3, 0), new GF127(2, 0), new GF127(1, 0), new GF127(1, 0), new GF127(0, 0));
new GF127(1, 0), new GF127(1, 0));
public static readonly SL2 B = new(
new GF127(2, 0), new GF127(3, 0), new GF127(1, 0), new GF127(1, 0));
// Indexer // Indexer
public GF127[] this[int i] public GF127[] this[int i]
@ -27,7 +32,7 @@
} }
public SL2(GF127 g00, GF127 g01, GF127 g10, GF127 g11) public SL2(GF127 g00, GF127 g01, GF127 g10, GF127 g11)
: this(new GF127[][] { new[] { g00, g01 }, new[] { g10, g11 } }) : this([[g00, g01], [g10, g11]])
{ {
} }
@ -66,31 +71,29 @@
this[1][1].Equals(other[1][1]); this[1][1].Equals(other[1][1]);
} }
// 2X2 matrix multiplication // 2X2 matrix multiplication
public static SL2 operator *(SL2 a, SL2 b) public static SL2 operator *(SL2 a, SL2 b)
{ {
return new SL2(a[0][0] * b[0][0] + a[0][1] * b[1][0], a[0][0] * b[0][1] + a[0][1] * b[1][1], return new SL2(
a[1][0] * b[0][0] + a[1][1] * b[1][0], a[1][0] * b[0][1] + a[1][1] * b[1][1]); a[0][0] * b[0][0] + a[0][1] * b[1][0],
a[0][0] * b[0][1] + a[0][1] * b[1][1],
a[1][0] * b[0][0] + a[1][1] * b[1][0],
a[1][0] * b[0][1] + a[1][1] * b[1][1]);
} }
// Multiplication using strassen algorithm // Multiplication using strassen algorithm
public static SL2 MulStrassen(SL2 a, SL2 b) public static SL2 MulStrassen(SL2 a, SL2 b)
{ {
GF127[] t = new GF127[7]; GF127[] t =
t[0] = (a[0][0] + a[1][1]) * (b[0][0] + b[1][1]); // t[0] == (a11 + a22) * (b11 + b22) [
(a[0][0] + a[1][1]) * (b[0][0] + b[1][1]), // t[0] == (a11 + a22) * (b11 + b22)
t[1] = (a[1][0] + a[1][1]) * b[0][0]; // t[1] == (a21 + a22) * b11 (a[1][0] + a[1][1]) * b[0][0], // t[1] == (a21 + a22) * b11
(b[0][1] + b[1][1]) * a[0][0], // t[2] == (b12 + b22) * a11
t[2] = (b[0][1] + b[1][1]) * a[0][0]; // t[2] == (b12 + b22) * a11 (b[1][0] + b[0][0]) * a[1][1], // t[3] == (b21 + b11) * a22
(a[0][0] + a[0][1]) * b[1][1], // t[4] == (a11 + a12) * b22
t[3] = (b[1][0] + b[0][0]) * a[1][1]; // t[3] == (b21 + b11) * a22 (a[1][0] + a[0][0]) * (b[0][0] + b[0][1]), // t[5] == (a21 + a11) * (b11 + b12)
(a[0][1] + a[1][1]) * (b[1][0] + b[1][1]), // t[6] == (a12 + a22) * (b21 + b22)
t[4] = (a[0][0] + a[0][1]) * b[1][1]; // t[4] == (a11 + a12) * b22 ];
t[5] = (a[1][0] + a[0][0]) * (b[0][0] + b[0][1]); // t[5] == (a21 + a11) * (b11 + b12)
t[6] = (a[0][1] + a[1][1]) * (b[1][0] + b[1][1]); // t[6] == (a12 + a22) * (b21 + b22)
SL2 r = new(); SL2 r = new();
r[0][1] = t[2] + t[4]; // r12 == a11*b12 + a11*b22 + a11*b22 + a12*b22 == a11*b12 + a12*b22 r[0][1] = t[2] + t[4]; // r12 == a11*b12 + a11*b22 + a11*b22 + a12*b22 == a11*b12 + a12*b22
@ -109,7 +112,7 @@
public static SL2 Inv(SL2 a) public static SL2 Inv(SL2 a)
{ {
GF127[] t = new GF127[2]; GF127[] t = new GF127[2];
t[0] = a[0][0] * a[1][1] + a[0][1] * a[1][0]; // t[0] = a[0][0] * a[1][1] + a[0][1] * a[1][0];
t[1] = GF127.Inv(t[0]); t[1] = GF127.Inv(t[0]);
SL2 r = new(); SL2 r = new();
@ -173,5 +176,4 @@
return this[0][0].ToString() + this[0][1].ToString() + return this[0][0].ToString() + this[0][1].ToString() +
this[1][0].ToString() + this[1][1].ToString(); this[1][0].ToString() + this[1][1].ToString();
} }
}
} }

View file

@ -1,139 +1,140 @@
using System.Security; //using System;
using System.Security.Cryptography; //using System.Collections.Generic;
//using System.Security;
//using System.Security.Cryptography;
namespace FrostFS.SDK.Cryptography.Tz //namespace FrostFS.SDK.Cryptography.Tz;
{
public class TzHash : HashAlgorithm
{
private const int TzHashLength = 64;
private GF127[] x;
public override int HashSize => TzHashLength;
public TzHash() //public class TzHash : HashAlgorithm
{ //{
Initialize(); // private const int TzHashLength = 64;
} // private GF127[] x;
// public override int HashSize => TzHashLength;
public override void Initialize() // public TzHash()
{ // {
x = new GF127[4]; // Initialize();
Reset(); // }
HashValue = null;
}
public void Reset() // public override void Initialize()
{ // {
x[0] = new GF127(1, 0); // x = new GF127[4];
x[1] = new GF127(0, 0); // Reset();
x[2] = new GF127(0, 0); // HashValue = null;
x[3] = new GF127(1, 0); // }
}
public byte[] ToByteArray() // public void Reset()
{ // {
var buff = new byte[HashSize]; // x[0] = new GF127(1, 0);
for (int i = 0; i < 4; i++) // x[1] = new GF127(0, 0);
{ // x[2] = new GF127(0, 0);
Array.Copy(x[i].ToByteArray(), 0, buff, i * 16, 16); // x[3] = new GF127(1, 0);
} // }
return buff;
}
[SecurityCritical] // public byte[] ToByteArray()
protected override void HashCore(byte[] array, int ibStart, int cbSize) // {
{ // var buff = new byte[HashSize];
_ = HashData(array[ibStart..(ibStart + cbSize)]); // for (int i = 0; i < 4; i++)
} // {
// Array.Copy(x[i].ToByteArray(), 0, buff, i * 16, 16);
// }
// return buff;
// }
[SecurityCritical] // [SecurityCritical]
protected override byte[] HashFinal() // protected override void HashCore(byte[] array, int ibStart, int cbSize)
{ // {
return HashValue = ToByteArray(); // _ = HashData(array[ibStart..(ibStart + cbSize)]);
} // }
[SecurityCritical] // [SecurityCritical]
private int HashData(byte[] data) // protected override byte[] HashFinal()
{ // {
var n = data.Length; // return HashValue = ToByteArray();
for (int i = 0; i < n; i++) // }
{
for (int j = 7; j >= 0; j--)
{
MulBitRight(ref x[0], ref x[1], ref x[2], ref x[3], (data[i] & (1 << j)) != 0);
}
}
return n;
}
// MulBitRight() multiply A (if the bit is 0) or B (if the bit is 1) on the right side // [SecurityCritical]
private void MulBitRight(ref GF127 c00, ref GF127 c01, ref GF127 c10, ref GF127 c11, bool bit) // private int HashData(byte[] data)
{ // {
// plan 1 // var n = data.Length;
GF127 t; // for (int i = 0; i < n; i++)
if (bit) // {
{ // MulB // for (int j = 7; j >= 0; j--)
t = c00; // {
c00 = GF127.Mul10(c00) + c01; // c00 = c00 * x + c01 // MulBitRight(ref x[0], ref x[1], ref x[2], ref x[3], (data[i] & (1 << j)) != 0);
c01 = GF127.Mul11(t) + c01; // c01 = c00 * (x+1) + c01 // }
// }
// return n;
// }
t = c10; // // MulBitRight() multiply A (if the bit is 0) or B (if the bit is 1) on the right side
c10 = GF127.Mul10(c10) + c11; // c10 = c10 * x + c11 // private void MulBitRight(ref GF127 c00, ref GF127 c01, ref GF127 c10, ref GF127 c11, bool bit)
c11 = GF127.Mul11(t) + c11; // c11 = c10 * (x+1) + c11 // {
} // // plan 1
else // GF127 t;
{ // MulA // if (bit)
t = c00; // { // MulB
c00 = GF127.Mul10(c00) + c01; // c00 = c00 * x + c01 // t = c00;
c01 = t; // c01 = c00 // c00 = GF127.Mul10(c00) + c01; // c00 = c00 * x + c01
// c01 = GF127.Mul11(t) + c01; // c01 = c00 * (x+1) + c01
t = c10; // t = c10;
c10 = GF127.Mul10(c10) + c11; // c10 = c10 * x + c11 // c10 = GF127.Mul10(c10) + c11; // c10 = c10 * x + c11
c11 = t; // c11 = c10; // c11 = GF127.Mul11(t) + c11; // c11 = c10 * (x+1) + c11
} // }
// else
// { // MulA
// t = c00;
// c00 = GF127.Mul10(c00) + c01; // c00 = c00 * x + c01
// c01 = t; // c01 = c00
//// plan 2 // t = c10;
//var r = new SL2(c00, c01, c10, c11); // c10 = GF127.Mul10(c10) + c11; // c10 = c10 * x + c11
//if (bit) // c11 = t; // c11 = c10;
// r.MulB(); // }
//else
// r.MulA();
}
// Concat() performs combining of hashes based on homomorphic characteristic. // //// plan 2
public static byte[] Concat(List<byte[]> hs) // //var r = new SL2(c00, c01, c10, c11);
{ // //if (bit)
var r = SL2.ID; // // r.MulB();
foreach (var h in hs) // //else
{ // // r.MulA();
r *= new SL2().FromByteArray(h); // }
}
return r.ToByteArray();
}
// Validate() checks if hashes in hs combined are equal to h. // // Concat() performs combining of hashes based on homomorphic characteristic.
public static bool Validate(byte[] h, List<byte[]> hs) // public static byte[] Concat(List<byte[]> hs)
{ // {
var expected = new SL2().FromByteArray(h); // var r = SL2.ID;
var actual = new SL2().FromByteArray(Concat(hs)); // foreach (var h in hs)
return expected.Equals(actual); // {
} // r *= new SL2().FromByteArray(h);
// }
// return r.ToByteArray();
// }
// SubtractR() returns hash a, such that Concat(a, b) == c // // Validate() checks if hashes in hs combined are equal to h.
public static byte[] SubstractR(byte[] b, byte[] c) // public static bool Validate(byte[] h, List<byte[]> hs)
{ // {
var t1 = new SL2().FromByteArray(b); // var expected = new SL2().FromByteArray(h);
var t2 = new SL2().FromByteArray(c); // var actual = new SL2().FromByteArray(Concat(hs));
var r = t2 * SL2.Inv(t1); // return expected.Equals(actual);
return r.ToByteArray(); // }
}
// SubtractL() returns hash b, such that Concat(a, b) == c // // SubtractR() returns hash a, such that Concat(a, b) == c
public static byte[] SubstractL(byte[] a, byte[] c) // public static byte[] SubstractR(byte[] b, byte[] c)
{ // {
var t1 = new SL2().FromByteArray(a); // var t1 = new SL2().FromByteArray(b);
var t2 = new SL2().FromByteArray(c); // var t2 = new SL2().FromByteArray(c);
var r = SL2.Inv(t1) * t2; // var r = t2 * SL2.Inv(t1);
return r.ToByteArray(); // return r.ToByteArray();
} // }
}
} // // SubtractL() returns hash b, such that Concat(a, b) == c
// public static byte[] SubstractL(byte[] a, byte[] c)
// {
// var t1 = new SL2().FromByteArray(a);
// var t2 = new SL2().FromByteArray(c);
// var r = SL2.Inv(t1) * t2;
// return r.ToByteArray();
// }
//}

View file

@ -1,17 +1,24 @@
using Google.Protobuf; using Google.Protobuf;
using System;
namespace FrostFS.SDK.Cryptography namespace FrostFS.SDK.Cryptography;
public static class UUIDExtension
{ {
public static class UUIDExtension
{
public static Guid ToUuid(this ByteString id) public static Guid ToUuid(this ByteString id)
{ {
return Guid.Parse(Convert.ToHexString(id.ToByteArray())); return Guid.Parse(BitConverter.ToString(id.ToByteArray()).Replace("-", ""));
} }
public static byte[] ToBytes(this Guid id) public static byte[] ToBytes(this Guid id)
{ {
return Convert.FromHexString(id.ToString("N")); var str = id.ToString("N");
} var len = str.Length;
var bytes = new byte[len/2];
for (int i = 0; i < len; i += 2)
bytes[i/2] = Convert.ToByte(str.Substring(i, 2), 16);
return bytes;
} }
} }

View file

@ -1,3 +1,5 @@
using System;
using FrostFS.SDK.ModelsV2.Enums; using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap; using FrostFS.SDK.ModelsV2.Netmap;

View file

@ -1,4 +1,6 @@
using FrostFS.SDK.Cryptography; using System;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK.ModelsV2; namespace FrostFS.SDK.ModelsV2;
@ -14,9 +16,8 @@ public class ContainerId
public static ContainerId FromHash(byte[] hash) public static ContainerId FromHash(byte[] hash)
{ {
if (hash.Length != Constants.Sha256HashLength) if (hash.Length != Constants.Sha256HashLength)
{
throw new FormatException("ContainerID must be a sha256 hash."); throw new FormatException("ContainerID must be a sha256 hash.");
}
return new ContainerId(Base58.Encode(hash)); return new ContainerId(Base58.Encode(hash));
} }

View file

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

View file

@ -2,8 +2,8 @@ namespace FrostFS.SDK.ModelsV2.Netmap;
public class PlacementPolicy public class PlacementPolicy
{ {
public Replica[] Replicas { get; init; } public Replica[] Replicas { get; private set; }
public bool Unique { get; init; } public bool Unique { get; private set; }
public PlacementPolicy(bool unique, params Replica[] replicas) public PlacementPolicy(bool unique, params Replica[] replicas)
{ {

View file

@ -1,4 +1,6 @@
using FrostFS.SDK.Cryptography; using System;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK.ModelsV2; namespace FrostFS.SDK.ModelsV2;

View file

@ -1,4 +1,5 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using FrostFS.SDK.Cryptography; using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK.ModelsV2; namespace FrostFS.SDK.ModelsV2;

View file

@ -1,19 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.26.1" /> <PackageReference Include="Google.Protobuf" Version="3.26.1" />
<PackageReference Include="Grpc.Core" Version="2.46.6" /> <PackageReference Include="Grpc.Net.Client" Version="2.62.0" />
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.62.0" /> <PackageReference Include="Grpc.Tools" Version="2.64.0">
<PackageReference Include="Grpc.Tools" Version="2.63.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -29,5 +29,4 @@
<Protobuf Include="status\*.proto" GrpcServices="Client" /> <Protobuf Include="status\*.proto" GrpcServices="Client" />
<Protobuf Include="tombstone\*.proto" GrpcServices="Client" /> <Protobuf Include="tombstone\*.proto" GrpcServices="Client" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,9 +1,8 @@
using Google.Protobuf; using Google.Protobuf;
namespace FrostFS.Session namespace FrostFS.Session;
public interface IMetaHeader : IMessage
{ {
public interface IMetaHeader : IMessage
{
IMetaHeader GetOrigin(); IMetaHeader GetOrigin();
}
} }

View file

@ -1,8 +1,7 @@
namespace FrostFS.Session namespace FrostFS.Session;
public interface IRequest : IVerificableMessage
{ {
public interface IRequest : IVerificableMessage
{
RequestMetaHeader MetaHeader { get; set; } RequestMetaHeader MetaHeader { get; set; }
RequestVerificationHeader VerifyHeader { get; set; } RequestVerificationHeader VerifyHeader { get; set; }
}
} }

View file

@ -1,8 +1,7 @@
namespace FrostFS.Session namespace FrostFS.Session;
public interface IResponse : IVerificableMessage
{ {
public interface IResponse : IVerificableMessage
{
ResponseMetaHeader MetaHeader { get; set; } ResponseMetaHeader MetaHeader { get; set; }
ResponseVerificationHeader VerifyHeader { get; set; } ResponseVerificationHeader VerifyHeader { get; set; }
}
} }

View file

@ -1,13 +1,12 @@
using Google.Protobuf; using Google.Protobuf;
namespace FrostFS.Session namespace FrostFS.Session;
public interface IVerificableMessage : IMessage
{ {
public interface IVerificableMessage : IMessage
{
IMetaHeader GetMetaHeader(); IMetaHeader GetMetaHeader();
void SetMetaHeader(IMetaHeader metaHeader); void SetMetaHeader(IMetaHeader metaHeader);
IVerificationHeader GetVerificationHeader(); IVerificationHeader GetVerificationHeader();
void SetVerificationHeader(IVerificationHeader verificationHeader); void SetVerificationHeader(IVerificationHeader verificationHeader);
IMessage GetBody(); IMessage GetBody();
}
} }

View file

@ -1,14 +1,13 @@
using FrostFS.Refs; using FrostFS.Refs;
using Google.Protobuf; using Google.Protobuf;
namespace FrostFS.Session namespace FrostFS.Session;
public interface IVerificationHeader : IMessage
{ {
public interface IVerificationHeader : IMessage
{
Signature BodySignature { get; set; } Signature BodySignature { get; set; }
Signature MetaSignature { get; set; } Signature MetaSignature { get; set; }
Signature OriginSignature { get; set; } Signature OriginSignature { get; set; }
IVerificationHeader GetOrigin(); IVerificationHeader GetOrigin();
void SetOrigin(IVerificationHeader verificationHeader); void SetOrigin(IVerificationHeader verificationHeader);
}
} }

View file

@ -1,10 +1,11 @@
using FrostFS.Session;
using Google.Protobuf; using Google.Protobuf;
namespace FrostFS.Container using FrostFS.Session;
namespace FrostFS.Container;
public partial class AnnounceUsedSpaceRequest : IRequest
{ {
public partial class AnnounceUsedSpaceRequest : IRequest
{
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
@ -29,369 +30,368 @@ namespace FrostFS.Container
{ {
return Body; return Body;
} }
} }
public partial class AnnounceUsedSpaceResponse : IResponse public partial class AnnounceUsedSpaceResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class GetRequest : IRequest public partial class GetRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (RequestMetaHeader)metaHeader; MetaHeader = (RequestMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (RequestVerificationHeader)verificationHeader; VerifyHeader = (RequestVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class GetResponse : IResponse public partial class GetResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class PutRequest : IRequest public partial class PutRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (RequestMetaHeader)metaHeader; MetaHeader = (RequestMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (RequestVerificationHeader)verificationHeader; VerifyHeader = (RequestVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class PutResponse : IResponse public partial class PutResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class DeleteRequest : IRequest public partial class DeleteRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (RequestMetaHeader)metaHeader; MetaHeader = (RequestMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (RequestVerificationHeader)verificationHeader; VerifyHeader = (RequestVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class DeleteResponse : IResponse public partial class DeleteResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class ListRequest : IRequest public partial class ListRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (RequestMetaHeader)metaHeader; MetaHeader = (RequestMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (RequestVerificationHeader)verificationHeader; VerifyHeader = (RequestVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class ListResponse : IResponse public partial class ListResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class SetExtendedACLRequest : IRequest public partial class SetExtendedACLRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (RequestMetaHeader)metaHeader; MetaHeader = (RequestMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (RequestVerificationHeader)verificationHeader; VerifyHeader = (RequestVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class SetExtendedACLResponse : IResponse public partial class SetExtendedACLResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class GetExtendedACLRequest : IRequest public partial class GetExtendedACLRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (RequestMetaHeader)metaHeader; MetaHeader = (RequestMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (RequestVerificationHeader)verificationHeader; VerifyHeader = (RequestVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class GetExtendedACLResponse : IResponse public partial class GetExtendedACLResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
}
} }

View file

@ -1,10 +1,10 @@
using FrostFS.Session; using FrostFS.Session;
using Google.Protobuf; using Google.Protobuf;
namespace FrostFS.Netmap namespace FrostFS.Netmap;
public partial class LocalNodeInfoRequest : IRequest
{ {
public partial class LocalNodeInfoRequest : IRequest
{
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
@ -29,89 +29,88 @@ namespace FrostFS.Netmap
{ {
return Body; return Body;
} }
} }
public partial class LocalNodeInfoResponse : IResponse public partial class LocalNodeInfoResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class NetworkInfoRequest : IRequest public partial class NetworkInfoRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (RequestMetaHeader)metaHeader; MetaHeader = (RequestMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (RequestVerificationHeader)verificationHeader; VerifyHeader = (RequestVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
} }
public partial class NetworkInfoResponse : IResponse public partial class NetworkInfoResponse : IResponse
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
} }
IVerificationHeader IVerificableMessage.GetVerificationHeader() IVerificationHeader IVerificableMessage.GetVerificationHeader()
{ {
return VerifyHeader; return VerifyHeader;
} }
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
{ {
MetaHeader = (ResponseMetaHeader)metaHeader; MetaHeader = (ResponseMetaHeader)metaHeader;
} }
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
{ {
VerifyHeader = (ResponseVerificationHeader)verificationHeader; VerifyHeader = (ResponseVerificationHeader)verificationHeader;
} }
public IMessage GetBody() public IMessage GetBody()
{ {
return Body; return Body;
} }
}
} }

View file

@ -1,9 +1,9 @@
using Google.Protobuf; using Google.Protobuf;
namespace FrostFS.Session namespace FrostFS.Session;
public partial class CreateResponse : IResponse
{ {
public partial class CreateResponse : IResponse
{
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
@ -28,10 +28,10 @@ namespace FrostFS.Session
{ {
return Body; return Body;
} }
} }
public partial class CreateRequest : IRequest public partial class CreateRequest : IRequest
{ {
IMetaHeader IVerificableMessage.GetMetaHeader() IMetaHeader IVerificableMessage.GetMetaHeader()
{ {
return MetaHeader; return MetaHeader;
@ -56,5 +56,4 @@ namespace FrostFS.Session
{ {
return Body; return Body;
} }
}
} }

View file

@ -1,18 +1,17 @@
namespace FrostFS.Session namespace FrostFS.Session;
{
public partial class RequestMetaHeader : IMetaHeader
{
public IMetaHeader GetOrigin()
{
return Origin;
}
}
public partial class ResponseMetaHeader : IMetaHeader public partial class RequestMetaHeader : IMetaHeader
{ {
public IMetaHeader GetOrigin()
{
return Origin;
}
}
public partial class ResponseMetaHeader : IMetaHeader
{
public IMetaHeader GetOrigin() public IMetaHeader GetOrigin()
{ {
return Origin; return Origin;
} }
}
} }

View file

@ -1,7 +1,7 @@
namespace FrostFS.Session namespace FrostFS.Session;
public partial class RequestVerificationHeader : IVerificationHeader
{ {
public partial class RequestVerificationHeader : IVerificationHeader
{
IVerificationHeader IVerificationHeader.GetOrigin() IVerificationHeader IVerificationHeader.GetOrigin()
{ {
return Origin; return Origin;
@ -11,10 +11,10 @@ namespace FrostFS.Session
{ {
Origin = (RequestVerificationHeader)verificationHeader; Origin = (RequestVerificationHeader)verificationHeader;
} }
} }
public partial class ResponseVerificationHeader : IVerificationHeader public partial class ResponseVerificationHeader : IVerificationHeader
{ {
IVerificationHeader IVerificationHeader.GetOrigin() IVerificationHeader IVerificationHeader.GetOrigin()
{ {
return Origin; return Origin;
@ -24,5 +24,4 @@ namespace FrostFS.Session
{ {
Origin = (ResponseVerificationHeader)verificationHeader; Origin = (ResponseVerificationHeader)verificationHeader;
} }
}
} }

View file

@ -1,9 +1,8 @@
namespace FrostFS.Session namespace FrostFS.Session;
public partial class XHeader
{ {
public partial class XHeader
{
public const string ReservedXHeaderPrefix = "__NEOFS__"; public const string ReservedXHeaderPrefix = "__NEOFS__";
public const string XHeaderNetmapEpoch = ReservedXHeaderPrefix + "NETMAP_EPOCH"; public const string XHeaderNetmapEpoch = ReservedXHeaderPrefix + "NETMAP_EPOCH";
public const string XHeaderNetmapLookupDepth = ReservedXHeaderPrefix + "NETMAP_LOOKUP_DEPTH"; public const string XHeaderNetmapLookupDepth = ReservedXHeaderPrefix + "NETMAP_LOOKUP_DEPTH";
}
} }