-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate NeoFS into oracle module #518
Changes from 33 commits
6d9cc91
96edad1
7103dd0
6918692
29ad815
564a274
216e4a5
6055b23
69a9b96
168772e
4fab776
f2c4f1a
4271fef
889063e
1e4ba46
45b27f0
c9d553a
1737d7f
600510d
c969a80
7858eba
6fcd803
3f14021
b382515
f9e8d18
eb5b3e2
12ce5e3
320a00c
80292e3
9362337
5a81e73
081ba3e
283ad69
a73077d
e42ad1a
d64199f
5a38300
b7c757d
38d3348
d459ce8
53ca335
7f54e78
46cef90
5402997
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,128 @@ | ||||||
using Google.Protobuf; | ||||||
using Neo.Cryptography.ECC; | ||||||
using Neo.Network.P2P.Payloads; | ||||||
using Neo.Wallets; | ||||||
using NeoFS.API.v2.Client; | ||||||
using NeoFS.API.v2.Client.ObjectParams; | ||||||
using NeoFS.API.v2.Cryptography; | ||||||
using NeoFS.API.v2.Refs; | ||||||
using System; | ||||||
using System.Collections.Generic; | ||||||
using System.Linq; | ||||||
using System.Net; | ||||||
using System.Threading; | ||||||
using System.Threading.Tasks; | ||||||
using Object = NeoFS.API.v2.Object.Object; | ||||||
using Range = NeoFS.API.v2.Object.Range; | ||||||
|
||||||
namespace Neo.Plugins | ||||||
{ | ||||||
class OracleNeoFSProtocol : IOracleProtocol | ||||||
{ | ||||||
private readonly System.Security.Cryptography.ECDsa privateKey; | ||||||
|
||||||
public OracleNeoFSProtocol(Wallet wallet, ECPoint[] oracles) | ||||||
{ | ||||||
byte[] key = oracles.Select(p => wallet.GetAccount(p)).Where(p => p is not null && p.HasKey && !p.Lock).FirstOrDefault().GetKey().PrivateKey; | ||||||
privateKey = key.LoadPrivateKey(); | ||||||
} | ||||||
|
||||||
public void Configure() | ||||||
{ | ||||||
} | ||||||
|
||||||
public void Dispose() | ||||||
{ | ||||||
privateKey.Dispose(); | ||||||
} | ||||||
|
||||||
public async Task<(OracleResponseCode, string)> ProcessAsync(Uri uri, CancellationToken cancellation) | ||||||
{ | ||||||
Utility.Log(nameof(OracleNeoFSProtocol), LogLevel.Debug, $"Request: {uri.AbsoluteUri}"); | ||||||
|
||||||
if (!Settings.Default.AllowPrivateHost) | ||||||
{ | ||||||
IPHostEntry entry = await Dns.GetHostEntryAsync(uri.Host); | ||||||
if (entry.IsInternal()) | ||||||
return (OracleResponseCode.Forbidden, null); | ||||||
} | ||||||
try | ||||||
{ | ||||||
byte[] res = await GetAsync(uri, Settings.Default.NeoFS.EndPoint, cancellation); | ||||||
Utility.Log(nameof(OracleNeoFSProtocol), LogLevel.Debug, $"NeoFS result: {res.ToHexString()}"); | ||||||
return (OracleResponseCode.Success, Convert.ToBase64String(res)); | ||||||
} | ||||||
catch (Exception e) | ||||||
{ | ||||||
Utility.Log(nameof(OracleNeoFSProtocol), LogLevel.Debug, $"NeoFS result: error,{e.Message}"); | ||||||
return (OracleResponseCode.Error, null); | ||||||
} | ||||||
} | ||||||
|
||||||
private async Task<byte[]> GetAsync(Uri uri, string host, CancellationToken cancellation) | ||||||
{ | ||||||
string[] ps = uri.AbsolutePath.Split("/"); | ||||||
if (ps.Length < 2) throw new FormatException("Invalid neofs url"); | ||||||
ContainerID containerID = ContainerID.FromBase58String(ps[0]); | ||||||
ObjectID objectID = ObjectID.FromBase58String(ps[1]); | ||||||
Address objectAddr = new() | ||||||
{ | ||||||
ContainerId = containerID, | ||||||
ObjectId = objectID | ||||||
}; | ||||||
Client client = new(privateKey, host, 120000); | ||||||
var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellation); | ||||||
tokenSource.CancelAfter(Settings.Default.NeoFS.Timeout); | ||||||
if (ps.Length == 2) | ||||||
return await GetPayloadAsync(client, objectAddr, tokenSource.Token); | ||||||
return ps[2] switch | ||||||
{ | ||||||
"range" => await GetRangeAsync(client, objectAddr, ps.Skip(3).ToArray(), tokenSource.Token), | ||||||
"header" => GetHeader(client, objectAddr, tokenSource.Token), | ||||||
"hash" => GetHash(client, objectAddr, ps.Skip(3).ToArray(), tokenSource.Token), | ||||||
_ => throw new Exception("invalid command") | ||||||
}; | ||||||
} | ||||||
|
||||||
private static async Task<byte[]> GetPayloadAsync(Client client, Address addr, CancellationToken cancellation) | ||||||
{ | ||||||
Object obj = await client.GetObject(cancellation, new GetObjectParams() { Address = addr }, new CallOptions { Ttl = 2 }); | ||||||
return obj.Payload.ToByteArray(); | ||||||
} | ||||||
|
||||||
private static Task<byte[]> GetRangeAsync(Client client, Address addr, string[] ps, CancellationToken cancellation) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need it be async here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the difference? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regardless of whether it is an |
||||||
{ | ||||||
if (ps.Length == 0) throw new Exception("object range is invalid (expected 'Offset|Length'"); | ||||||
Range range = ParseRange(ps[0]); | ||||||
return client.GetObjectPayloadRangeData(cancellation, new RangeDataParams() { Address = addr, Range = range }, new CallOptions { Ttl = 2 }); | ||||||
} | ||||||
|
||||||
private static byte[] GetHeader(Client client, Address addr, CancellationToken cancellation) | ||||||
{ | ||||||
var obj = client.GetObjectHeader(cancellation, new ObjectHeaderParams() { Address = addr }, new CallOptions { Ttl = 2 }); | ||||||
return obj.ToByteArray(); | ||||||
} | ||||||
|
||||||
private static byte[] GetHash(Client client, Address addr, string[] ps, CancellationToken cancellation) | ||||||
{ | ||||||
if (ps.Length == 0 || ps[0] == "") | ||||||
{ | ||||||
Object obj = client.GetObjectHeader(cancellation, new ObjectHeaderParams() { Address = addr }, new CallOptions { Ttl = 2 }); | ||||||
return obj.Header.PayloadHash.Sum.ToByteArray(); | ||||||
} | ||||||
Range range = ParseRange(ps[0]); | ||||||
List<byte[]> hashes = client.GetObjectPayloadRangeHash(cancellation, new RangeChecksumParams() { Address = addr, Ranges = new List<Range>() { range } }, new CallOptions { Ttl = 2 }); | ||||||
if (hashes.Count == 0) throw new Exception(string.Format("{0}: empty response", "object range is invalid (expected 'Offset|Length'")); | ||||||
return hashes[0]; | ||||||
} | ||||||
|
||||||
private static Range ParseRange(string s) | ||||||
{ | ||||||
int sepIndex = s.IndexOf("|"); | ||||||
if (sepIndex < 0) throw new Exception("object range is invalid (expected 'Offset|Length'"); | ||||||
ulong offset = ulong.Parse(s[..sepIndex]); | ||||||
ulong length = ulong.Parse(s[sepIndex..]); | ||||||
return new Range() { Offset = offset, Length = length }; | ||||||
} | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the package should be renamed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have any suggestion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neo.FileSystem.API
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will rename.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Namespace renamed. PackageId will rename in the future.