From cf81c015da8fd17c282dd7a74ebb97a2e7c70ac9 Mon Sep 17 00:00:00 2001
From: Hecate2 <2474101468@qq.com>
Date: Thu, 24 Nov 2022 15:30:11 +0800
Subject: [PATCH] AwaitConfirmedTransaction
---
Fairy.Utils.cs | 106 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 101 insertions(+), 5 deletions(-)
diff --git a/Fairy.Utils.cs b/Fairy.Utils.cs
index 40f5534..f71cd75 100644
--- a/Fairy.Utils.cs
+++ b/Fairy.Utils.cs
@@ -1,6 +1,7 @@
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Json;
+using Neo.Ledger;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
@@ -64,6 +65,46 @@ protected virtual JObject VirtualDeploy(JArray _params)
return json;
}
+ ///
+ /// Wait until the transaction is included in blocks
+ ///
+ /// UInt256String; bool(verbose); waitBlockCount
+ ///
+ ///
+ [RpcMethod]
+ protected virtual JToken AwaitConfirmedTransaction(JArray _params)
+ {
+ UInt256 hash = UInt256.Parse(_params[0].AsString());
+ bool verbose = _params.Count >= 2 && _params[1].AsBoolean();
+ uint waitBlockCount = _params.Count >= 2 ? uint.Parse(_params[2].AsString()) : 2;
+ JToken json = GetConfirmedTransaction(hash, verbose);
+ if (json != null)
+ {
+ return json;
+ }
+ uint count = 1;
+ bool expectBlockIn15Secs = false;
+ CommittedHandler getConfirmedTransactionAfterCommitted = delegate(NeoSystem @system, Block @block){ count += 1; expectBlockIn15Secs = true; json = GetConfirmedTransaction(hash, verbose); };
+ Blockchain.Committed += getConfirmedTransactionAfterCommitted;
+ while (count <= waitBlockCount)
+ {
+ if (expectBlockIn15Secs == false)
+ Thread.Sleep(500);
+ else
+ {
+ expectBlockIn15Secs = false;
+ Thread.Sleep(14500);
+ }
+ if (json != null)
+ {
+ Blockchain.Committed -= getConfirmedTransactionAfterCommitted;
+ return json;
+ }
+ }
+ Blockchain.Committed -= getConfirmedTransactionAfterCommitted;
+ throw new RpcException(-100, $"Transaction not found in {waitBlockCount} blocks");
+ }
+
[RpcMethod]
protected virtual JObject PutStorageWithSession(JArray _params)
{
@@ -158,7 +199,7 @@ protected virtual JObject SetNep17Balance(JArray _params)
return SetTokenBalance(session, contract, account, balance, prefix);
}
- private JObject SetTokenBalance(string session, UInt160 contract, UInt160 account, ulong balance, byte prefixAccount)
+ protected JObject SetTokenBalance(string session, UInt160 contract, UInt160 account, ulong balance, byte prefixAccount)
{
byte[] balanceBytes = BitConverter.GetBytes(balance);
FairyEngine oldEngine = sessionStringToFairySession[session].engine;
@@ -197,7 +238,62 @@ private JObject SetTokenBalance(string session, UInt160 contract, UInt160 accoun
}
}
- private static JObject ToJson(StackItem item, int max)
+ protected JToken GetConfirmedTransaction(UInt256 hash, bool verbose)
+ {
+ // Do not consider anything in MemPool, because they have not been confirmed
+ //if (system.MemPool.TryGetValue(hash, out Transaction tx) && !verbose)
+ // return Convert.ToBase64String(tx.ToArray());
+ Transaction? tx = null;
+ DataCache snapshot = system.StoreView;
+ TransactionState state = NativeContract.Ledger.GetTransactionState(snapshot, hash);
+ tx ??= state?.Transaction;
+ if (tx is null)
+ {
+ return null;
+ }
+ else
+ {
+ if (!verbose) return Convert.ToBase64String(tx.ToArray());
+ JObject json = TransactionToJson(tx, system.Settings);
+ if (state is not null)
+ {
+ TrimmedBlock block = NativeContract.Ledger.GetTrimmedBlock(snapshot, NativeContract.Ledger.GetBlockHash(snapshot, state.BlockIndex));
+ json["blockhash"] = block.Hash.ToString();
+ json["confirmations"] = NativeContract.Ledger.CurrentIndex(snapshot) - block.Index + 1;
+ json["blocktime"] = block.Header.Timestamp;
+ }
+ return json;
+ }
+ }
+
+ protected static JObject BlockToJson(Block block, ProtocolSettings settings)
+ {
+ JObject json = block.ToJson(settings);
+ json["tx"] = block.Transactions.Select(p => TransactionToJson(p, settings)).ToArray();
+ return json;
+ }
+
+ protected static JObject TransactionToJson(Transaction tx, ProtocolSettings settings)
+ {
+ JObject json = tx.ToJson(settings);
+ json["sysfee"] = tx.SystemFee.ToString();
+ json["netfee"] = tx.NetworkFee.ToString();
+ return json;
+ }
+
+ protected static JObject NativeContractToJson(NativeContract contract, ProtocolSettings settings)
+ {
+ return new JObject
+ {
+ ["id"] = contract.Id,
+ ["hash"] = contract.Hash.ToString(),
+ ["nef"] = contract.Nef.ToJson(),
+ ["manifest"] = contract.Manifest.ToJson(),
+ ["updatehistory"] = settings.NativeUpdateHistory[contract.Name].Select(p => (JToken)p).ToArray()
+ };
+ }
+
+ protected static JObject ToJson(StackItem item, int max)
{
JObject json = item.ToJson();
if (item is InteropInterface interopInterface && interopInterface.GetInterface