Skip to content

Commit

Permalink
Added a web3.js like confirmation method. (#400)
Browse files Browse the repository at this point in the history
* Added a web3.js like confirmation method.

* Version bump.
  • Loading branch information
tiago18c authored Jun 22, 2022
1 parent 9dd423a commit 5221965
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 1 deletion.
2 changes: 1 addition & 1 deletion SharedBuildProperties.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Product>Solnet</Product>
<Version>6.0.12</Version>
<Version>6.0.13</Version>
<Copyright>Copyright 2022 &#169; Solnet</Copyright>
<Authors>blockmountain</Authors>
<PublisherName>blockmountain</PublisherName>
Expand Down
13 changes: 13 additions & 0 deletions src/Solnet.Programs/Abstract/BaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,18 @@ protected async Task<SubscriptionState> SubscribeAccount<T>(string accountAddres

return res;
}


/// <summary>
/// Confirms a transaction - same method as web3.js.
/// </summary>
/// <param name="hash">The hash of the transaction.</param>
/// <param name="validBlockHeight">The last valid block height of the blockhash used in the transaction.</param>
/// <param name="commitment">The state commitment to consider when querying the ledger state.</param>
/// <returns>Returns null if the transaction wasn't confirmed, otherwise returns the confirmation slot and possible transaction error.</returns>
public async Task<ResponseValue<ErrorResult>> ConfirmTransaction(string hash, ulong validBlockHeight, Commitment commitment = Commitment.Finalized)
{
return await TransactionConfirmationUtils.ConfirmTransaction(this.RpcClient, this.StreamingRpcClient, hash, validBlockHeight, commitment);
}
}
}
95 changes: 95 additions & 0 deletions src/Solnet.Rpc/TransactionUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using Solnet.Rpc.Messages;
using Solnet.Rpc.Models;
using Solnet.Rpc.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Solnet.Rpc
{
/// <summary>
/// Utilities to check transaction confirmation status.
/// </summary>
public static class TransactionConfirmationUtils
{
/// <summary>
/// Confirms a transaction - same method as web3.js.
/// </summary>
/// <param name="rpc">The rpc client instance.</param>
/// <param name="streamingRpcClient">The streaming rpc client instance.</param>
/// <param name="hash">The hash of the transaction.</param>
/// <param name="validBlockHeight">The last valid block height of the blockhash used in the transaction.</param>
/// <param name="commitment">The state commitment to consider when querying the ledger state.</param>
/// <returns>Returns null if the transaction wasn't confirmed, otherwise returns the confirmation slot and possible transaction error.</returns>
public static async Task<ResponseValue<ErrorResult>> ConfirmTransaction(IRpcClient rpc, IStreamingRpcClient streamingRpcClient,
string hash, ulong validBlockHeight, Commitment commitment = Commitment.Finalized)
{
TaskCompletionSource t = new();
ResponseValue<ErrorResult> result = null;

var s = await streamingRpcClient.SubscribeSignatureAsync(hash, (s, e) =>
{
result = e;
t.SetResult();
},
commitment);

var checkTask = Task.Run(async () =>
{
var currHeight = await rpc.GetBlockHeightAsync(commitment);
while (currHeight.Result < validBlockHeight)
{
await Task.Delay(1000);
currHeight = await rpc.GetBlockHeightAsync(commitment);
}
});


Task.WaitAny(t.Task, checkTask);

if (!t.Task.IsCompleted)
{
await s.UnsubscribeAsync();
}

return result;
}

/// <summary>
/// Confirms a transaction - old web3.js using constant timeout based on commitment parameter.
/// </summary>
/// <param name="rpc">The rpc client instance.</param>
/// <param name="streamingRpcClient">The streaming rpc client instance.</param>
/// <param name="hash">The hash of the transaction.</param>
/// <param name="commitment">The state commitment to consider when querying the ledger state.</param>
/// <returns>Returns null if the transaction wasn't confirmed, otherwise returns the confirmation slot and possible transaction error.</returns>
public static async Task<ResponseValue<ErrorResult>> ConfirmTransaction(IRpcClient rpc, IStreamingRpcClient streamingRpcClient,
string hash, Commitment commitment = Commitment.Finalized)
{
TaskCompletionSource t = new();
ResponseValue<ErrorResult> result = null;

var s = await streamingRpcClient.SubscribeSignatureAsync(hash, (s, e) =>
{
result = e;
t.SetResult();
},
commitment);

var timeout = commitment == Commitment.Finalized ? TimeSpan.FromSeconds(60) : TimeSpan.FromSeconds(30);
var delay = Task.Delay(timeout);

Task.WaitAny(t.Task, delay);

if (!t.Task.IsCompleted)
{
await s.UnsubscribeAsync();
}

return result;
}

}
}

0 comments on commit 5221965

Please sign in to comment.