From 0e0c513ffe200061fe488ba8b1b710b310c0acb7 Mon Sep 17 00:00:00 2001 From: Dennis Diatlov Date: Thu, 24 Oct 2024 12:24:12 +0100 Subject: [PATCH] chore(net): add some extension methods to Substrate.Gear.Client (#609) --- net/src/Substrate.Gear.Client/GasInfo.cs | 11 +- .../Model/Types/AccountExtensions.cs | 21 ++++ .../SubstrateClientExtExtensions.cs | 105 ++++++++++++++---- 3 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 net/src/Substrate.Gear.Client/Model/Types/AccountExtensions.cs diff --git a/net/src/Substrate.Gear.Client/GasInfo.cs b/net/src/Substrate.Gear.Client/GasInfo.cs index 00e39074..0a73a3d4 100644 --- a/net/src/Substrate.Gear.Client/GasInfo.cs +++ b/net/src/Substrate.Gear.Client/GasInfo.cs @@ -4,18 +4,27 @@ namespace Substrate.Gear.Client; public sealed record GasInfo { + /// /// Represents minimum gas limit required for execution. + /// public required GasUnit MinLimit { get; init; } + /// /// Gas amount that we reserve for some other on-chain interactions. + /// public required GasUnit Reserved { get; init; } + /// /// Contains number of gas burned during message processing. + /// public required GasUnit Burned { get; init; } + /// /// The value may be returned if a program happens to be executed /// the second or next time in a block. + /// public required GasUnit MayBeReturned { get; init; } + /// /// Was the message placed into waitlist at the end of calculating. - /// /// This flag shows, that `min_limit` makes sense and have some guarantees /// only before insertion into waitlist. + /// public bool IsInWaitList { get; init; } } diff --git a/net/src/Substrate.Gear.Client/Model/Types/AccountExtensions.cs b/net/src/Substrate.Gear.Client/Model/Types/AccountExtensions.cs new file mode 100644 index 00000000..3b32327c --- /dev/null +++ b/net/src/Substrate.Gear.Client/Model/Types/AccountExtensions.cs @@ -0,0 +1,21 @@ +using EnsureThat; +using Substrate.NET.Schnorrkel; +using Substrate.NetApi.Model.Types; + +namespace Substrate.Gear.Client.Model.Types; + +public static class AccountExtensions +{ + /// + /// Returns a public key of the account. + /// + /// + /// + public static PublicKey GetPublicKey(this Account account) + { + EnsureArg.IsNotNull(account, nameof(account)); + EnsureArg.HasItems(account.Bytes, nameof(account.Bytes)); + + return new PublicKey(account.Bytes); + } +} diff --git a/net/src/Substrate.Gear.Client/SubstrateClientExtExtensions.cs b/net/src/Substrate.Gear.Client/SubstrateClientExtExtensions.cs index a337f950..eb2421bb 100644 --- a/net/src/Substrate.Gear.Client/SubstrateClientExtExtensions.cs +++ b/net/src/Substrate.Gear.Client/SubstrateClientExtExtensions.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; using Substrate.Gear.Api.Generated; using Substrate.Gear.Api.Generated.Model.gprimitives; -using Substrate.NET.Schnorrkel.Keys; +using Substrate.NET.Schnorrkel; using Substrate.NetApi; using GasUnit = Substrate.NetApi.Model.Types.Primitive.U64; using ValueUnit = Substrate.NetApi.Model.Types.Primitive.U128; @@ -14,20 +14,77 @@ namespace Substrate.Gear.Client; public static class SubstrateClientExtExtensions { - public static async Task CalculateGasForUploadAsync( + /// + /// Calculates amount of gas required for creating a new program from previously uploaded code. + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task CalculateGasForCreateProgramAsync( this SubstrateClientExt nodeClient, - MiniSecret accountSecret, + PublicKey signingAccountKey, + CodeId codeId, + IReadOnlyCollection encodedInitPayload, + ValueUnit value, + CancellationToken cancellationToken) + { + EnsureArg.IsNotNull(nodeClient, nameof(nodeClient)); + EnsureArg.IsNotNull(signingAccountKey, nameof(signingAccountKey)); + EnsureArg.IsNotNull(codeId, nameof(codeId)); + EnsureArg.IsNotNull(encodedInitPayload, nameof(encodedInitPayload)); + + var accountPublicKeyStr = Utils.Bytes2HexString(signingAccountKey.Key); + var encodedInitPayloadStr = Utils.Bytes2HexString( + encodedInitPayload is byte[] encodedInitPayloadBytes + ? encodedInitPayloadBytes + : [.. encodedInitPayload]); + var valueBigInt = value.Value; + var parameters = new object[] + { + accountPublicKeyStr, + codeId, + encodedInitPayloadStr, + valueBigInt, + true + }; + + var gasInfoJson = await nodeClient.InvokeAsync( + "gear_calculateInitCreateGas", + parameters, + cancellationToken) + .ConfigureAwait(false); + + return gasInfoJson.ToGasInfo(); + } + + /// + /// Calculates amount of gas required for uploading code and creating a new program from it. + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task CalculateGasForUploadProgramAsync( + this SubstrateClientExt nodeClient, + PublicKey signingAccountKey, IReadOnlyCollection wasm, IReadOnlyCollection encodedInitPayload, ValueUnit value, CancellationToken cancellationToken) { EnsureArg.IsNotNull(nodeClient, nameof(nodeClient)); - EnsureArg.IsNotNull(accountSecret, nameof(accountSecret)); + EnsureArg.IsNotNull(signingAccountKey, nameof(signingAccountKey)); EnsureArg.HasItems(wasm, nameof(wasm)); EnsureArg.IsNotNull(encodedInitPayload, nameof(encodedInitPayload)); - var accountPublicKeyStr = Utils.Bytes2HexString(accountSecret.GetPair().Public.Key); + var accountPublicKeyStr = Utils.Bytes2HexString(signingAccountKey.Key); var wasmBytesStr = Utils.Bytes2HexString( wasm is byte[] wasmBytes ? wasmBytes @@ -55,25 +112,36 @@ encodedInitPayload is byte[] encodedInitPayloadBytes return gasInfoJson.ToGasInfo(); } - public static async Task CalculateGasGorHandleAsync( + /// + /// Calculates amount of gas required for executing a message by specified program. + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task CalculateGasForHandleAsync( this SubstrateClientExt nodeClient, - MiniSecret accountSecret, + PublicKey signingAccountKey, ActorId programId, IReadOnlyCollection encodedPayload, ValueUnit value, CancellationToken cancellationToken) { EnsureArg.IsNotNull(nodeClient, nameof(nodeClient)); - EnsureArg.IsNotNull(accountSecret, nameof(accountSecret)); + EnsureArg.IsNotNull(signingAccountKey, nameof(signingAccountKey)); EnsureArg.IsNotNull(programId, nameof(programId)); EnsureArg.IsNotNull(encodedPayload, nameof(encodedPayload)); - var accountPublicKeyStr = Utils.Bytes2HexString(accountSecret.GetPair().Public.Key); + var accountPublicKeyStr = Utils.Bytes2HexString(signingAccountKey.Key); var encodedPayloadStr = Utils.Bytes2HexString( encodedPayload is byte[] encodedPayloadBytes ? encodedPayloadBytes : [.. encodedPayload]); - var parameters = new object[] { + var parameters = new object[] + { accountPublicKeyStr, programId, encodedPayloadStr, @@ -92,21 +160,20 @@ encodedPayload is byte[] encodedPayloadBytes private sealed record GasInfoJson { - /// Represents minimum gas limit required for execution. + // Represents minimum gas limit required for execution. [JsonProperty("min_limit")] public ulong MinLimit { get; init; } - /// Gas amount that we reserve for some other on-chain interactions. + // Gas amount that we reserve for some other on-chain interactions. public ulong Reserved { get; init; } - /// Contains number of gas burned during message processing. + // Contains number of gas burned during message processing. public ulong Burned { get; init; } - /// The value may be returned if a program happens to be executed - /// the second or next time in a block. + // The value may be returned if a program happens to be executed + // the second or next time in a block. [JsonProperty("may_be_returned")] public ulong MayBeReturned { get; init; } - /// Was the message placed into waitlist at the end of calculating. - /// - /// This flag shows, that `min_limit` makes sense and have some guarantees - /// only before insertion into waitlist. + // Was the message placed into waitlist at the end of calculating. + // This flag shows, that `min_limit` makes sense and have some guarantees + // only before insertion into waitlist. [JsonProperty("waited")] public bool IsInWaitList { get; init; }