Skip to content

Commit

Permalink
Merge pull request #1021 from Portkey-Wallet/release/3.1.2
Browse files Browse the repository at this point in the history
Asynchronous message processing
  • Loading branch information
chaoxkang authored Dec 18, 2024
2 parents ccd6dc3 + 16b6130 commit 3567e3b
Show file tree
Hide file tree
Showing 35 changed files with 1,923 additions and 1,135 deletions.
8 changes: 8 additions & 0 deletions src/CAServer.Application.Contracts/Commons/AddressHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,12 @@ public static string GetAelfChainId(string network)
? network
: null;
}

public static bool IsFullAelfAddress(string address)
{
return address.StartsWith($"{CommonConstant.ELF}{CommonConstant.Underline}") &&
(address.EndsWith($"{CommonConstant.Underline}{CommonConstant.MainChainId}") ||
address.EndsWith($"{CommonConstant.Underline}{CommonConstant.TDVVChainId}") ||
address.EndsWith($"{CommonConstant.Underline}{CommonConstant.TDVWChainId}"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace CAServer.Commons;

public static class AelfClientConstant
{
public const string MainChainClient = "MainChainClient";
public const string SideChainClient = "SideChainClient";
}
31 changes: 19 additions & 12 deletions src/CAServer.Application.Contracts/Commons/ShiftChainHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,17 @@ public static bool MatchForAddress(string chain, string fromChain, string addres

public static AddressFormat GetAddressFormat(string fromChain, string address)
{
if (address.Split("_").Length == 3 && address.Split("_")[1].Length == 50)
if (address.Contains(CommonConstant.Underline) && address.StartsWith(CommonConstant.ELF))
{
if (!IsAelfAddress(AddressHelper.ToShortAddress(address)))
{
return AddressFormat.NoSupport;
}
if (address.EndsWith(CommonConstant.MainChainId))
{
return AddressFormat.Main;
}else if (address.EndsWith(CommonConstant.TDVWChainId) || address.EndsWith(CommonConstant.TDVVChainId))
}
if (address.EndsWith(CommonConstant.TDVWChainId) || address.EndsWith(CommonConstant.TDVVChainId))
{
return AddressFormat.Dapp;
}
Expand All @@ -178,30 +183,25 @@ public static AddressFormat GetAddressFormat(string fromChain, string address)

if (IsAelfAddress(address))
{
if (fromChain == CommonConstant.MainChainId)
{
return AddressFormat.Main;
}

return AddressFormat.Dapp;
return fromChain == CommonConstant.MainChainId ? AddressFormat.Main : AddressFormat.Dapp;
}

if (address.Length == 42)
if (IsEthAddress(address))
{
return AddressFormat.ETH;
}

if (address.Length == 34)
if (IsTrxAddress(address))
{
return AddressFormat.TRX;
}

if (address.Length == 43 || address.Length == 44)
if (IsSolanaAddress(address))
{
return AddressFormat.Solana;
}

if (address.Length == 48 && (address.StartsWith("EQ") || address.StartsWith("UQ")))
if (IsTonAddress(address))
{
return AddressFormat.TON;
}
Expand All @@ -227,6 +227,11 @@ private static bool IsAelfAddress(string address)
return false;
}
}

private static bool IsEthAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["ETH"]);
private static bool IsTrxAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["TRX"]);
private static bool IsSolanaAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["Solana"]);
private static bool IsTonAddress(string address) => Regex.IsMatch(address, NetworkPatternMap["TON"]);

public static bool VerifyAddress(string chain, string address)
{
Expand All @@ -242,6 +247,8 @@ public static bool VerifyAddress(string chain, string address)

return !NetworkPatternMap.ContainsKey(chain) || Regex.IsMatch(address, NetworkPatternMap[chain]);
}


}

public class ChainInfo
Expand Down
3 changes: 3 additions & 0 deletions src/CAServer.Application/CAServerApplicationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using CAServer.CAAccount.Provider;
using CAServer.Cache;
using CAServer.Common;
using CAServer.Common.AelfClient;
using CAServer.Commons;
using CAServer.CryptoGift;
using CAServer.DataReporting;
Expand Down Expand Up @@ -173,6 +174,8 @@ public override void ConfigureServices(ServiceConfigurationContext context)
context.Services.AddScoped<IIpInfoClient, IpInfoClient>();
context.Services.AddScoped<IHttpClientService, HttpClientService>();
context.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
context.Services.AddSingleton<IContractClient, MainChainContractClient>();
context.Services.AddSingleton<IContractClient, SideChainContractClient>();

Configure<VariablesOptions>(configuration.GetSection("Variables"));
context.Services.AddScoped<IImRequestProvider, ImRequestProvider>();
Expand Down
28 changes: 28 additions & 0 deletions src/CAServer.Application/Common/AelfClient/IContractClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using AElf.Client.Dto;
using AElf.Types;
using Google.Protobuf;

namespace CAServer.Common.AelfClient;

public interface IContractClient
{
Task<Transaction> GenerateTransactionAsync(
string from,
string to,
string methodName,
IMessage input);

Task<BlockDto> GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false);

Task<SendTransactionOutput> SendTransactionAsync(SendTransactionInput input);

Task<TransactionResultDto> GetTransactionResultAsync(string transactionId);
Task<string> ExecuteTransactionAsync(ExecuteTransactionDto input);

Transaction SignTransaction(string privateKeyHex, Transaction transaction);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Linq;
using CAServer.Commons;
using Volo.Abp.DependencyInjection;

namespace CAServer.Common.AelfClient;

public interface IContractClientSelector
{
IContractClient GetContractClient(string chainId);
}

public class ContractClientSelector : IContractClientSelector, ISingletonDependency
{
private readonly IEnumerable<IContractClient> _contractClients;

public ContractClientSelector(IEnumerable<IContractClient> contractClients)
{
_contractClients = contractClients;
}

public IContractClient GetContractClient(string chainId)
{
return chainId == CommonConstant.MainChainId
? _contractClients.FirstOrDefault(t => t.GetType().Name == nameof(MainChainContractClient))
: _contractClients.FirstOrDefault(t => t.GetType().Name == nameof(SideChainContractClient));
}
}
185 changes: 185 additions & 0 deletions src/CAServer.Application/Common/AelfClient/MainChainContractClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using AElf;
using AElf.Client.Dto;
using AElf.Cryptography;
using AElf.Types;
using CAServer.Commons;
using Google.Protobuf;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Volo.Abp;

namespace CAServer.Common.AelfClient;

public class MainChainContractClient : IContractClient
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<MainChainContractClient> _logger;

public MainChainContractClient(IHttpClientFactory httpClientFactory, ILogger<MainChainContractClient> logger)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
}

public async Task<Transaction> GenerateTransactionAsync(
string from,
string to,
string methodName,
IMessage input)
{
try
{
var chainStatusAsync = await GetChainStatusAsync();
return new Transaction()
{
From = Address.FromBase58(from),
To = Address.FromBase58(to),
MethodName = methodName,
Params = input.ToByteString(),
RefBlockNumber = chainStatusAsync.BestChainHeight,
RefBlockPrefix = ByteString.CopyFrom(Hash.LoadFromHex(chainStatusAsync.BestChainHash).Value
.Take<byte>(4).ToArray<byte>())
};
}
catch (Exception ex)
{
_logger.LogError(ex, "[ContractClient.GenerateTransactionAsync] error, msg:{0},trace:{1}", ex.Message,
ex.StackTrace ?? "-");
return (Transaction)null;
}
}

public async Task<BlockDto> GetBlockByHeightAsync(long blockHeight, bool includeTransactions = false)
{
var uri = string.Format("api/blockChain/blockByHeight?blockHeight={0}&includeTransactions={1}",
blockHeight, includeTransactions);
return await GetAsync<BlockDto>(uri);
}

public async Task<SendTransactionOutput> SendTransactionAsync(SendTransactionInput input)
{
var uri = "api/blockChain/sendTransaction";
var param = new Dictionary<string, string>()
{
{
"RawTransaction",
input.RawTransaction
}
};
return await PostAsync<SendTransactionOutput>(uri, param);
}

public async Task<TransactionResultDto> GetTransactionResultAsync(string transactionId)
{
var url = "api/blockChain/transactionResult?transactionId=" + transactionId;
return await GetAsync<TransactionResultDto>(url);
}

public async Task<string> ExecuteTransactionAsync(ExecuteTransactionDto input)
{
var url = "api/blockChain/executeTransaction";
var param = new Dictionary<string, string>()
{
{
"RawTransaction",
input.RawTransaction
}
};
return await PostAsync(url, param);
}

public Transaction SignTransaction(string privateKeyHex, Transaction transaction)
{
byte[] byteArray = transaction.GetHash().ToByteArray();
byte[] numArray =
CryptoHelper.SignWithPrivateKey(ByteArrayHelper.HexStringToByteArray(privateKeyHex), byteArray);
transaction.Signature = ByteString.CopyFrom(numArray);
return transaction;
}

public async Task<ChainStatusDto> GetChainStatusAsync()
{
var uri = "api/blockChain/chainStatus";
return await GetAsync<ChainStatusDto>(uri);
}

public async Task<T> GetAsync<T>(string url)
{
var client = _httpClientFactory.CreateClient(AelfClientConstant.MainChainClient);
var response = await client.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
if (!ResponseSuccess(response.StatusCode))
{
_logger.LogError(
"[ContractClientError] MainChainContractClient GetError Response not success, url:{url}, code:{code}, message: {message}",
url, response.StatusCode, content);

throw new UserFriendlyException(content, ((int)response.StatusCode).ToString());
}

return JsonConvert.DeserializeObject<T>(content);
}

public async Task<T> PostAsync<T>(string url, object paramObj)
{
var requestInput = paramObj == null ? string.Empty : JsonConvert.SerializeObject(paramObj, Formatting.None);

var requestContent = new StringContent(
requestInput,
Encoding.UTF8,
MediaTypeNames.Application.Json);

var client = _httpClientFactory.CreateClient(AelfClientConstant.MainChainClient);

var response = await client.PostAsync(url, requestContent);
var content = await response.Content.ReadAsStringAsync();

if (!ResponseSuccess(response.StatusCode))
{
_logger.LogError(
"[ContractClientError] MainChainContractClient PostError Response not success, url:{url}, code:{code}, message: {message}, params:{param}",
url, response.StatusCode, content, JsonConvert.SerializeObject(paramObj));

throw new UserFriendlyException(content, ((int)response.StatusCode).ToString());
}

return JsonConvert.DeserializeObject<T>(content);
}

public async Task<string> PostAsync(string url, object paramObj)
{
var requestInput = paramObj == null ? string.Empty : JsonConvert.SerializeObject(paramObj, Formatting.None);

var requestContent = new StringContent(
requestInput,
Encoding.UTF8,
MediaTypeNames.Application.Json);

var client = _httpClientFactory.CreateClient(AelfClientConstant.MainChainClient);

var response = await client.PostAsync(url, requestContent);
var content = await response.Content.ReadAsStringAsync();

if (!ResponseSuccess(response.StatusCode))
{
_logger.LogError(
"[ContractClientError] MainChainContractClient PostError Response not success, url:{url}, code:{code}, message: {message}, params:{param}",
url, response.StatusCode, content, JsonConvert.SerializeObject(paramObj));

throw new UserFriendlyException(content, ((int)response.StatusCode).ToString());
}

return content;
}

private bool ResponseSuccess(HttpStatusCode statusCode) =>
statusCode is HttpStatusCode.OK or HttpStatusCode.NoContent;
}
Loading

0 comments on commit 3567e3b

Please sign in to comment.