Skip to content

Commit

Permalink
all cases for TraverseIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
Hecate2 committed Aug 20, 2024
1 parent eefa8c9 commit b53a686
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/Plugins/RpcServer/RpcServer.SmartContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private void Initialize_SmartContract()
timer = new(OnTimer, null, settings.SessionExpirationTime, settings.SessionExpirationTime);
}

private void Dispose_SmartContract()
internal void Dispose_SmartContract()
{
timer?.Dispose();
Session[] toBeDestroyed;
Expand All @@ -52,7 +52,7 @@ private void Dispose_SmartContract()
session.Dispose();
}

private void OnTimer(object state)
internal void OnTimer(object state)
{
List<(Guid Id, Session Session)> toBeDestroyed = new();
lock (sessions)
Expand Down
98 changes: 87 additions & 11 deletions tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.SmartContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
using Microsoft.AspNetCore.Http;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.Json;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.UnitTests;
Expand All @@ -25,13 +27,12 @@
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

namespace Neo.Plugins.RpcServer.Tests;

public partial class UT_RpcServer
{
static readonly string NeoScriptHash = "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5";
static readonly string GasScriptHash = "0xd2a4cff31913016155e38e474a2c06d08be276cf";
static readonly string NeoTotalSupplyScript = "wh8MC3RvdGFsU3VwcGx5DBT1Y\u002BpAvCg9TQ4FxI6jBbPyoHNA70FifVtS";
static readonly string NeoTransferScript = "CxEMFPlu76Cuc\u002BbgteStE4ozsOWTNUdrDBQtYNweHko3YcnMFOes3ceblcI/lRTAHwwIdHJhbnNmZXIMFPVj6kC8KD1NDgXEjqMFs/Kgc0DvQWJ9W1I=";
static readonly UInt160 ValidatorScriptHash = Contract
Expand Down Expand Up @@ -59,12 +60,12 @@ public void TestInvokeFunction()
{
_rpcServer.wallet = _wallet;

JObject resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash, "totalSupply", new JArray([]), validatorSigner, true));
JObject resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "totalSupply", new JArray([]), validatorSigner, true));
Assert.AreEqual(resp.Count, 8);
Assert.AreEqual(resp["script"], NeoTotalSupplyScript);
Assert.IsTrue(resp.ContainsProperty("gasconsumed"));
Assert.IsTrue(resp.ContainsProperty("diagnostics"));
Assert.AreEqual(resp["diagnostics"]["invokedcontracts"]["call"][0]["hash"], NeoScriptHash);
Assert.AreEqual(resp["diagnostics"]["invokedcontracts"]["call"][0]["hash"], NeoScriptHash.ToString());
Assert.IsTrue(((JArray)resp["diagnostics"]["storagechanges"]).Count == 0);
Assert.AreEqual(resp["state"], "HALT");
Assert.AreEqual(resp["exception"], null);
Expand All @@ -73,7 +74,7 @@ public void TestInvokeFunction()
Assert.AreEqual(resp["stack"][0]["value"], "100000000");
Assert.IsTrue(resp.ContainsProperty("tx"));

resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash, "symbol"));
resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "symbol"));
Assert.AreEqual(resp.Count, 6);
Assert.IsTrue(resp.ContainsProperty("script"));
Assert.IsTrue(resp.ContainsProperty("gasconsumed"));
Expand All @@ -84,7 +85,7 @@ public void TestInvokeFunction()
Assert.AreEqual(resp["stack"][0]["value"], Convert.ToBase64String(Encoding.UTF8.GetBytes("NEO")));

// This call triggers not only NEO but also unclaimed GAS
resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash, "transfer", new JArray([
resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "transfer", new JArray([
new JObject() { ["type"] = "Hash160", ["value"] = MultisigScriptHash.ToString() },
new JObject() { ["type"] = "Hash160", ["value"] = ValidatorScriptHash.ToString() },
new JObject() { ["type"] = "Integer", ["value"] = "1" },
Expand All @@ -94,17 +95,17 @@ public void TestInvokeFunction()
Assert.AreEqual(resp["script"], NeoTransferScript);
Assert.IsTrue(resp.ContainsProperty("gasconsumed"));
Assert.IsTrue(resp.ContainsProperty("diagnostics"));
Assert.AreEqual(resp["diagnostics"]["invokedcontracts"]["call"][0]["hash"], NeoScriptHash);
Assert.AreEqual(resp["diagnostics"]["invokedcontracts"]["call"][0]["hash"], NeoScriptHash.ToString());
Assert.IsTrue(((JArray)resp["diagnostics"]["storagechanges"]).Count == 4);
Assert.AreEqual(resp["state"], "HALT");
Assert.AreEqual(resp["exception"], $"The smart contract or address {MultisigScriptHash.ToString()} is not found");
JArray notifications = (JArray)resp["notifications"];
Assert.AreEqual(notifications.Count, 2);
Assert.AreEqual(notifications[0]["eventname"].AsString(), "Transfer");
Assert.AreEqual(notifications[0]["contract"].AsString(), NeoScriptHash);
Assert.AreEqual(notifications[0]["contract"].AsString(), NeoScriptHash.ToString());
Assert.AreEqual(notifications[0]["state"]["value"][2]["value"], "1");
Assert.AreEqual(notifications[1]["eventname"].AsString(), "Transfer");
Assert.AreEqual(notifications[1]["contract"].AsString(), GasScriptHash);
Assert.AreEqual(notifications[1]["contract"].AsString(), GasScriptHash.ToString());
Assert.AreEqual(notifications[1]["state"]["value"][2]["value"], "50000000");

_rpcServer.wallet = null;
Expand All @@ -117,7 +118,7 @@ public void TestInvokeScript()
Assert.AreEqual(resp.Count, 7);
Assert.IsTrue(resp.ContainsProperty("gasconsumed"));
Assert.IsTrue(resp.ContainsProperty("diagnostics"));
Assert.AreEqual(resp["diagnostics"]["invokedcontracts"]["call"][0]["hash"], NeoScriptHash);
Assert.AreEqual(resp["diagnostics"]["invokedcontracts"]["call"][0]["hash"], NeoScriptHash.ToString());
Assert.AreEqual(resp["state"], "HALT");
Assert.AreEqual(resp["exception"], null);
Assert.AreEqual(((JArray)resp["notifications"]).Count, 0);
Expand All @@ -133,7 +134,8 @@ public void TestInvokeScript()
[TestMethod]
public void TestTraverseIterator()
{
JObject resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash, "getAllCandidates", new JArray([]), validatorSigner, true));
// GetAllCandidates that should return 0 candidates
JObject resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "getAllCandidates", new JArray([]), validatorSigner, true));
string sessionId = resp["session"].AsString();
string iteratorId = resp["stack"][0]["id"].AsString();
JArray respArray = (JArray)_rpcServer.TraverseIterator([sessionId, iteratorId, 100]);
Expand All @@ -147,6 +149,80 @@ public void TestTraverseIterator()
{
Assert.AreEqual(e.Message, "Unknown session");
}

// register candidate in snapshot
resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "registerCandidate",
new JArray([new JObject()
{
["type"] = "PublicKey",
["value"] = TestProtocolSettings.SoleNode.StandbyCommittee[0].ToString(),
}]), validatorSigner, true));
Assert.AreEqual(resp["state"], "HALT");
SnapshotCache snapshot = _neoSystem.GetSnapshotCache();
Transaction? tx = new Transaction
{
Nonce = 233,
ValidUntilBlock = NativeContract.Ledger.CurrentIndex(snapshot) + _neoSystem.Settings.MaxValidUntilBlockIncrement,
Signers = [new Signer() { Account = ValidatorScriptHash, Scopes = WitnessScope.CalledByEntry }],
Attributes = Array.Empty<TransactionAttribute>(),
Script = Convert.FromBase64String(resp["script"].AsString()),
Witnesses = null,
};
ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: _neoSystem.Settings, gas: 1200_0000_0000);
engine.SnapshotCache.Commit();

// GetAllCandidates that should return 1 candidate
resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "getAllCandidates", new JArray([]), validatorSigner, true));
sessionId = resp["session"].AsString();
iteratorId = resp["stack"][0]["id"].AsString();
respArray = (JArray)_rpcServer.TraverseIterator([sessionId, iteratorId, 100]);
Assert.AreEqual(respArray.Count, 1);
Assert.AreEqual(respArray[0]["type"], "Struct");
JArray value = (JArray)respArray[0]["value"];
Assert.AreEqual(value.Count, 2);
Assert.AreEqual(value[0]["type"], "ByteString");
Assert.AreEqual(value[0]["value"], Convert.ToBase64String(TestProtocolSettings.SoleNode.StandbyCommittee[0].ToArray()));
Assert.AreEqual(value[1]["type"], "Integer");
Assert.AreEqual(value[1]["value"], "0");

// No result when traversed again
respArray = (JArray)_rpcServer.TraverseIterator([sessionId, iteratorId, 100]);
Assert.AreEqual(respArray.Count, 0);

// GetAllCandidates again
resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "getAllCandidates", new JArray([]), validatorSigner, true));
sessionId = resp["session"].AsString();
iteratorId = resp["stack"][0]["id"].AsString();

// Insufficient result count limit
respArray = (JArray)_rpcServer.TraverseIterator([sessionId, iteratorId, 0]);
Assert.AreEqual(respArray.Count, 0);

// Mocking session timeout
Thread.Sleep(_rpcServerSettings.SessionExpirationTime.Milliseconds + 1);
_rpcServer.OnTimer(new object());
try
{
respArray = (JArray)_rpcServer.TraverseIterator([sessionId, iteratorId, 100]);
}
catch (RpcException e)
{
Assert.AreEqual(e.Message, "Unknown session");
}

// Mocking disposal
resp = (JObject)_rpcServer.InvokeFunction(new JArray(NeoScriptHash.ToString(), "getAllCandidates", new JArray([]), validatorSigner, true));
sessionId = resp["session"].AsString();
iteratorId = resp["stack"][0]["id"].AsString();
_rpcServer.Dispose_SmartContract();
try
{
respArray = (JArray)_rpcServer.TraverseIterator([sessionId, iteratorId, 100]);
}
catch (RpcException e)
{
Assert.AreEqual(e.Message, "Unknown session");
}
}

[TestMethod]
Expand Down
18 changes: 17 additions & 1 deletion tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

using Microsoft.AspNetCore.Http;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.IO;
using Neo.Ledger;
using Neo.Persistence;
using Neo.SmartContract;
Expand All @@ -19,7 +20,9 @@
using Neo.Wallets;
using Neo.Wallets.NEP6;
using System;
using System.Linq;
using System.Net;
using System.Numerics;
using System.Text;

namespace Neo.Plugins.RpcServer.Tests
Expand All @@ -28,19 +31,32 @@ namespace Neo.Plugins.RpcServer.Tests
public partial class UT_RpcServer
{
private NeoSystem _neoSystem;
private RpcServerSettings _rpcServerSettings;
private RpcServer _rpcServer;
private TestMemoryStoreProvider _memoryStoreProvider;
private MemoryStore _memoryStore;
private readonly NEP6Wallet _wallet = TestUtils.GenerateTestWallet("123");
private WalletAccount _walletAccount;

static readonly UInt160 NeoScriptHash = UInt160.Parse("0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5");
static readonly UInt160 GasScriptHash = UInt160.Parse("0xd2a4cff31913016155e38e474a2c06d08be276cf");
const byte NativePrefixAccount = 20;
const byte NativePrefixTotalSupply = 11;

[TestInitialize]
public void TestSetup()
{
_memoryStore = new MemoryStore();
_memoryStoreProvider = new TestMemoryStoreProvider(_memoryStore);
_neoSystem = new NeoSystem(TestProtocolSettings.SoleNode, _memoryStoreProvider);
_rpcServer = new RpcServer(_neoSystem, RpcServerSettings.Default with { SessionEnabled = true, Network = TestProtocolSettings.SoleNode.Network });
_rpcServerSettings = RpcServerSettings.Default with
{
SessionEnabled = true,
SessionExpirationTime = TimeSpan.FromSeconds(1),
MaxGasInvoke = 1500_0000_0000,
Network = TestProtocolSettings.SoleNode.Network,
};
_rpcServer = new RpcServer(_neoSystem, _rpcServerSettings);
_walletAccount = _wallet.Import("KxuRSsHgJMb3AMSN6B9P3JHNGMFtxmuimqgR9MmXPcv3CLLfusTd");
var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash);
var snapshot = _neoSystem.GetSnapshotCache();
Expand Down

0 comments on commit b53a686

Please sign in to comment.