generated from CareBoo/UPMTemplate-2020
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(atomic-txn): add APIs for building, signing, and serializing Ato…
…mic Txns Start the process for creating an Atomic Txn with `Transaction.Atomic` API. TransactionGroup APIs are now obsolete. fix #131
- Loading branch information
1 parent
c1a2cfb
commit 858ff9e
Showing
33 changed files
with
1,431 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
using System; | ||
using System.Threading; | ||
using AlgoSdk.Kmd; | ||
using Cysharp.Threading.Tasks; | ||
using Unity.Collections; | ||
using UnityEngine; | ||
|
||
namespace AlgoSdk | ||
{ | ||
public struct KmdAccount | ||
: IAccount | ||
, IAsyncSigner | ||
{ | ||
readonly KmdClient client; | ||
readonly FixedString128Bytes walletId; | ||
readonly FixedString128Bytes walletPassword; | ||
readonly Address address; | ||
|
||
FixedString128Bytes walletHandleToken; | ||
|
||
public KmdAccount( | ||
KmdClient client, | ||
FixedString128Bytes walletId, | ||
FixedString128Bytes walletPassword, | ||
Address address, | ||
FixedString128Bytes walletHandleToken = default | ||
) | ||
{ | ||
this.client = client; | ||
this.walletId = walletId; | ||
this.walletPassword = walletPassword; | ||
this.address = address; | ||
|
||
this.walletHandleToken = walletHandleToken; | ||
} | ||
|
||
public Address Address => address; | ||
|
||
public async UniTask<FixedString128Bytes> RefreshWalletHandleToken(CancellationToken cancellationToken = default) | ||
{ | ||
if (walletHandleToken.Length > 0) | ||
{ | ||
var (renewErr, renewResponse) = await client.RenewWalletHandleToken(walletHandleToken).WithCancellation(cancellationToken); | ||
if (renewErr) | ||
{ | ||
Debug.LogError(renewErr); | ||
} | ||
} | ||
else | ||
{ | ||
var (initErr, initResponse) = await client.InitWalletHandleToken(walletId, walletPassword).WithCancellation(cancellationToken); | ||
if (initErr) | ||
{ | ||
Debug.LogError(initErr); | ||
} | ||
walletHandleToken = initResponse.WalletHandleToken; | ||
} | ||
return walletHandleToken; | ||
} | ||
|
||
public async UniTask<SignedTxn<T>[]> SignTxnsAsync<T>(T[] txns, TxnIndices txnsToSign, CancellationToken cancellationToken = default) | ||
where T : ITransaction, IEquatable<T> | ||
{ | ||
var result = new SignedTxn<T>[txns.Length]; | ||
var indexEnum = txnsToSign.GetEnumerator(); | ||
ErrorResponse signErr; | ||
SignTransactionResponse signResp; | ||
while (indexEnum.MoveNext()) | ||
{ | ||
var i = indexEnum.Current; | ||
(signErr, signResp) = await client.SignTransaction(Address, AlgoApiSerializer.SerializeMessagePack(txns[i]), walletHandleToken, walletPassword); | ||
if (signErr) | ||
{ | ||
Debug.LogError(signErr); | ||
} | ||
else | ||
{ | ||
result[i] = AlgoApiSerializer.DeserializeMessagePack<SignedTxn<T>>(signResp.SignedTransaction); | ||
} | ||
} | ||
return result; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
123 changes: 123 additions & 0 deletions
123
Runtime/CareBoo.AlgoSdk/Transaction/Atomic/AtomicTxn.AsyncSigning.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
using AlgoSdk.MessagePack; | ||
using Cysharp.Threading.Tasks; | ||
using Unity.Collections; | ||
|
||
namespace AlgoSdk | ||
{ | ||
public static partial class AtomicTxn | ||
{ | ||
/// <summary> | ||
/// Represents an Atomic Txn that is being signed with asynchronous signers. | ||
/// </summary> | ||
/// <remarks> | ||
/// Once all signatures have been added, serialize this transaction | ||
/// group to msgpack with <see cref="FinishSigningAsync"/>. | ||
/// </remarks> | ||
public partial struct AsyncSigning : ISigning<AsyncSigning> | ||
{ | ||
readonly Transaction[] txns; | ||
readonly TransactionSignature[] sigs; | ||
readonly List<UniTask> asyncSignings; | ||
|
||
/// <summary> | ||
/// Create a new Atomic Txn group that contains some asynchronous signers. | ||
/// </summary> | ||
/// <param name="txns">Transactions that are part of this group.</param> | ||
/// <param name="sigs">Existing signatures.</param> | ||
/// <param name="signedIndices">Indices of transactions with existing signatures.</param> | ||
public AsyncSigning(Transaction[] txns, TransactionSignature[] sigs, TxnIndices signedIndices) | ||
{ | ||
this.txns = txns; | ||
this.sigs = sigs; | ||
this.SignedTxnIndices = signedIndices; | ||
this.asyncSignings = new List<UniTask>(); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public Transaction[] Txns => txns; | ||
|
||
/// <inheritdoc /> | ||
public TransactionSignature[] Sigs => sigs; | ||
|
||
/// <inheritdoc /> | ||
public TxnIndices SignedTxnIndices { get; set; } | ||
|
||
/// <inheritdoc /> | ||
public AsyncSigning AsAsync() => this; | ||
|
||
/// <inheritdoc cref="AtomicTxn.SignWithAsync{AsyncSigning,TSigner}(AsyncSigning,TSigner,TxnIndices,CancellationToken)" /> | ||
public AsyncSigning SignWithAsync<T>(T signer, TxnIndices txnsToSign, CancellationToken cancellationToken = default) | ||
where T : IAsyncSigner | ||
{ | ||
this.CheckTxnIndicesToSign(txnsToSign); | ||
|
||
SignedTxnIndices |= txnsToSign; | ||
var signing = signer.SignTxnsAsync(txns, txnsToSign, cancellationToken); | ||
var settingSignatures = SetSignaturesAsync(signing, txnsToSign); | ||
asyncSignings.Add(settingSignatures); | ||
|
||
return this; | ||
} | ||
|
||
/// <inheritdoc cref="AtomicTxn.SignWithAsync{AsyncSigning,TSigner,TProgress}(AsyncSigning,TSigner,TxnIndices,TProgress,CancellationToken)" /> | ||
public AsyncSigning SignWithAsync<T, TProgress>( | ||
T signer, | ||
TxnIndices txnsToSign, | ||
TProgress progress, | ||
CancellationToken cancellationToken = default | ||
) | ||
where T : IAsyncSignerWithProgress | ||
where TProgress : IProgress<float> | ||
{ | ||
this.CheckTxnIndicesToSign(txnsToSign); | ||
|
||
SignedTxnIndices |= txnsToSign; | ||
var signing = signer.SignTxnsAsync(txns, txnsToSign, progress, cancellationToken); | ||
var settingSignatures = SetSignaturesAsync(signing, txnsToSign); | ||
asyncSignings.Add(settingSignatures); | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Finish signing this group and return the raw msgpack, ready to submit. | ||
/// </summary> | ||
/// <returns>Msgpack encoding of the transaction group.</returns> | ||
public async UniTask<byte[]> FinishSigningAsync() | ||
{ | ||
using var nativeBytes = await FinishSigningAsync(Allocator.Persistent); | ||
return nativeBytes.ToArray(); | ||
} | ||
|
||
/// <summary> | ||
/// Finish signing this group and return the msgpack of the group, ready to send to the network. | ||
/// </summary> | ||
/// <param name="allocator">Allocator to use in the returned NativeList (which must be disposed).</param> | ||
/// <returns>A natively-allocated, msgpack-encoded transaction group, ready to send to the network.</returns> | ||
public async UniTask<NativeList<byte>> FinishSigningAsync(Allocator allocator) | ||
{ | ||
var sigCount = SignedTxnIndices.Count(); | ||
if (sigCount != txns.Length) | ||
throw new InvalidOperationException($"There are still {txns.Length - sigCount} transactions that need to be signed."); | ||
|
||
await UniTask.WhenAll(asyncSignings); | ||
var writer = new MessagePackWriter(allocator); | ||
for (var i = 0; i < txns.Length; i++) | ||
{ | ||
var signedTxn = new SignedTxn { Txn = txns[i], Signature = sigs[i] }; | ||
AlgoApiFormatterCache<SignedTxn>.Formatter.Serialize(ref writer, signedTxn); | ||
} | ||
return writer.Data; | ||
} | ||
|
||
async UniTask SetSignaturesAsync(UniTask<SignedTxn<Transaction>[]> signing, TxnIndices indices) | ||
{ | ||
var signedTxns = await signing; | ||
this.SetSignatures(signedTxns, indices); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.