Skip to content

Commit

Permalink
Add value types and fix namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
shargon committed Feb 21, 2024
1 parent 95118e8 commit 434f451
Show file tree
Hide file tree
Showing 15 changed files with 95 additions and 45 deletions.
56 changes: 47 additions & 9 deletions src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Akka.Util;
using Neo.Cryptography.ECC;
using Neo.SmartContract.Testing.Attributes;
using Neo.VM.Types;
Expand All @@ -11,7 +12,8 @@ namespace Neo.SmartContract.Testing.Extensions
{
public static class TestExtensions
{
private static readonly Dictionary<Type, Dictionary<int, PropertyInfo>> _deserializationCache = new();
private static readonly Dictionary<Type, Dictionary<int, PropertyInfo>> _propertyCache = new();
private static readonly Dictionary<Type, FieldInfo[]> _fieldCache = new();

/// <summary>
/// Convert Array stack item to dotnet array
Expand Down Expand Up @@ -77,14 +79,24 @@ public static class TestExtensions
_ when type == typeof(UInt160) => new UInt160(stackItem.GetSpan().ToArray()),
_ when type == typeof(UInt256) => new UInt256(stackItem.GetSpan().ToArray()),
_ when type == typeof(ECPoint) => ECPoint.FromBytes(stackItem.GetSpan().ToArray(), ECCurve.Secp256r1),
_ when type == typeof(IDictionary<object, object>) && stackItem is Map mp => ToDictionary(mp), // SubItems in StackItem type
_ when type == typeof(Dictionary<object, object>) && stackItem is Map mp => ToDictionary(mp), // SubItems in StackItem type
_ when type == typeof(IList<object>) && stackItem is CompoundType cp => new List<object>(cp.SubItems), // SubItems in StackItem type
_ when type == typeof(List<object>) && stackItem is CompoundType cp => new List<object>(cp.SubItems), // SubItems in StackItem type
_ when typeof(IInteroperable).IsAssignableFrom(type) => CreateInteroperable(stackItem, type),
_ when type.IsArray && stackItem is CompoundType cp => CreateTypeArray(cp.SubItems, type.GetElementType()!),
_ when stackItem is InteropInterface it && it.GetInterface().GetType() == type => it.GetInterface(),
_ when type.IsClass && stackItem is CompoundType cp => CreateObject(cp.SubItems, type),

_ when stackItem is VM.Types.Array ar => type switch
{
_ when type == typeof(IList<object>) => new List<object>(ar.SubItems), // SubItems in StackItem type
_ when type == typeof(List<object>) => new List<object>(ar.SubItems), // SubItems in StackItem type
_ when type.IsArray => CreateTypeArray(ar.SubItems, type.GetElementType()!),
_ when type.IsClass => CreateObject(ar.SubItems, type),
_ when type.IsValueType => CreateValueType(ar.SubItems, type),
_ => throw new FormatException($"Impossible to convert {stackItem} to {type}"),
},
_ when stackItem is Map mp => type switch
{
_ when type == typeof(IDictionary<object, object>) => ToDictionary(mp), // SubItems in StackItem type
_ when type == typeof(Dictionary<object, object>) => ToDictionary(mp), // SubItems in StackItem type
_ => throw new FormatException($"Impossible to convert {stackItem} to {type}"),
},

_ => throw new FormatException($"Impossible to convert {stackItem} to {type}"),
};
Expand All @@ -97,7 +109,7 @@ private static object CreateObject(IEnumerable<StackItem> subItems, Type type)

// Cache the object properties by offset

if (!_deserializationCache.TryGetValue(type, out var cache))
if (!_propertyCache.TryGetValue(type, out var cache))
{
cache = new Dictionary<int, PropertyInfo>();

Expand All @@ -123,7 +135,7 @@ private static object CreateObject(IEnumerable<StackItem> subItems, Type type)
index = 0;
}

_deserializationCache[type] = cache;
_propertyCache[type] = cache;
}

// Fill the object
Expand Down Expand Up @@ -157,6 +169,32 @@ private static IDictionary<object, object> ToDictionary(Map map)
return dictionary;
}

private static object CreateValueType(IEnumerable<StackItem> objects, Type valueType)
{
var arr = objects.ToArray();
var value = Activator.CreateInstance(valueType);

// Cache the object properties by offset

if (!_fieldCache.TryGetValue(valueType, out var cache))
{
cache = valueType.GetFields().ToArray();
_fieldCache[valueType] = cache;
}

if (cache.Length != arr.Length)
{
throw new FormatException($"Error converting {valueType}, field count doesn't match.");
}

for (int x = 0; x < arr.Length; x++)
{
cache[x].SetValue(value, ConvertTo(arr[x], cache[x].FieldType));
}

return value;

Check warning on line 195 in src/Neo.SmartContract.Testing/Extensions/TestExtensions.cs

View workflow job for this annotation

GitHub Actions / Test

Possible null reference return.
}

private static object CreateTypeArray(IEnumerable<StackItem> objects, Type elementType)
{
var obj = objects.ToArray();
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/ContractManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class ContractManagement : SmartContract
{
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/CryptoLib.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class CryptoLib : SmartContract
{
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/GasToken.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class GasToken : SmartContract
{
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/LedgerContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class LedgerContract : SmartContract
{
Expand Down
4 changes: 2 additions & 2 deletions src/Neo.SmartContract.Testing/Native/NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class NeoToken : SmartContract
{
Expand Down Expand Up @@ -100,7 +100,7 @@ public class Candidate
/// Safe method
/// </summary>
[DisplayName("getAccountState")]
public abstract Native.NeoToken.NeoAccountState GetAccountState(UInt160? account);
public abstract Neo.SmartContract.Native.NeoToken.NeoAccountState GetAccountState(UInt160? account);

/// <summary>
/// Safe method
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/OracleContract.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class OracleContract : SmartContract
{
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class PolicyContract : SmartContract
{
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/RoleManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class RoleManagement : SmartContract
{
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Native/StdLib.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Numerics;

namespace Neo.SmartContract.Testing;
namespace Neo.SmartContract.Testing.Native;

public abstract class StdLib : SmartContract
{
Expand Down
29 changes: 15 additions & 14 deletions src/Neo.SmartContract.Testing/NativeArtifacts.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Neo.Persistence;
using Neo.SmartContract.Testing.Native;
using System;
using System.Reflection;

Expand Down Expand Up @@ -64,15 +65,15 @@ public NativeArtifacts(TestEngine engine)
{
_engine = engine;

ContractManagement = _engine.FromHash<ContractManagement>(Native.NativeContract.ContractManagement.Hash, Native.NativeContract.ContractManagement.Id);
CryptoLib = _engine.FromHash<CryptoLib>(Native.NativeContract.CryptoLib.Hash, Native.NativeContract.CryptoLib.Id);
GAS = _engine.FromHash<GasToken>(Native.NativeContract.GAS.Hash, Native.NativeContract.GAS.Id);
NEO = _engine.FromHash<NeoToken>(Native.NativeContract.NEO.Hash, Native.NativeContract.NEO.Id);
Ledger = _engine.FromHash<LedgerContract>(Native.NativeContract.Ledger.Hash, Native.NativeContract.Ledger.Id);
Oracle = _engine.FromHash<OracleContract>(Native.NativeContract.Oracle.Hash, Native.NativeContract.Oracle.Id);
Policy = _engine.FromHash<PolicyContract>(Native.NativeContract.Policy.Hash, Native.NativeContract.Policy.Id);
RoleManagement = _engine.FromHash<RoleManagement>(Native.NativeContract.RoleManagement.Hash, Native.NativeContract.RoleManagement.Id);
StdLib = _engine.FromHash<StdLib>(Native.NativeContract.StdLib.Hash, Native.NativeContract.StdLib.Id);
ContractManagement = _engine.FromHash<ContractManagement>(Neo.SmartContract.Native.NativeContract.ContractManagement.Hash, Neo.SmartContract.Native.NativeContract.ContractManagement.Id);
CryptoLib = _engine.FromHash<CryptoLib>(Neo.SmartContract.Native.NativeContract.CryptoLib.Hash, Neo.SmartContract.Native.NativeContract.CryptoLib.Id);
GAS = _engine.FromHash<GasToken>(Neo.SmartContract.Native.NativeContract.GAS.Hash, Neo.SmartContract.Native.NativeContract.GAS.Id);
NEO = _engine.FromHash<NeoToken>(Neo.SmartContract.Native.NativeContract.NEO.Hash, Neo.SmartContract.Native.NativeContract.NEO.Id);
Ledger = _engine.FromHash<LedgerContract>(Neo.SmartContract.Native.NativeContract.Ledger.Hash, Neo.SmartContract.Native.NativeContract.Ledger.Id);
Oracle = _engine.FromHash<OracleContract>(Neo.SmartContract.Native.NativeContract.Oracle.Hash, Neo.SmartContract.Native.NativeContract.Oracle.Id);
Policy = _engine.FromHash<PolicyContract>(Neo.SmartContract.Native.NativeContract.Policy.Hash, Neo.SmartContract.Native.NativeContract.Policy.Id);
RoleManagement = _engine.FromHash<RoleManagement>(Neo.SmartContract.Native.NativeContract.RoleManagement.Hash, Neo.SmartContract.Native.NativeContract.RoleManagement.Id);
StdLib = _engine.FromHash<StdLib>(Neo.SmartContract.Native.NativeContract.StdLib.Hash, Neo.SmartContract.Native.NativeContract.StdLib.Id);
}

/// <summary>
Expand All @@ -92,12 +93,12 @@ public void Initialize(bool commit = false)

// Process native contracts

foreach (var native in new Native.NativeContract[]
foreach (var native in new Neo.SmartContract.Native.NativeContract[]
{
Native.NativeContract.ContractManagement,
Native.NativeContract.Ledger,
Native.NativeContract.NEO,
Native.NativeContract.GAS
Neo.SmartContract.Native.NativeContract.ContractManagement,
Neo.SmartContract.Native.NativeContract.Ledger,
Neo.SmartContract.Native.NativeContract.NEO,
Neo.SmartContract.Native.NativeContract.GAS
}
)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Neo.SmartContract.Testing/Storage/EngineStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Neo.SmartContract.Testing.Storage
public class EngineStorage
{
// Key to check if native contracts are initialized, by default: Neo.votersCountPrefix
private static readonly StorageKey _initKey = new() { Id = Native.NativeContract.NEO.Id, Key = new byte[] { 1 } };
private static readonly StorageKey _initKey = new() { Id = Neo.SmartContract.Native.NativeContract.NEO.Id, Key = new byte[] { 1 } };

/// <summary>
/// Store
Expand Down
3 changes: 2 additions & 1 deletion src/Neo.SmartContract.Testing/TestingApplicationEngine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
using Neo.SmartContract.Native;
using Neo.SmartContract.Testing.Extensions;
using Neo.VM;
using Neo.VM.Types;
Expand Down Expand Up @@ -76,7 +77,7 @@ private void RecoverCoverage(Instruction instruction)
{
// We need the contract state without pay gas

var state = Native.NativeContract.ContractManagement.GetContract(Engine.Storage.Snapshot, contractHash);
var state = NativeContract.ContractManagement.GetContract(Engine.Storage.Snapshot, contractHash);

coveredContract = new(Engine.MethodDetection, contractHash, state);
Engine.Coverage[contractHash] = coveredContract;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Cryptography.ECC;
using Neo.IO;
using Neo.SmartContract.Testing;
using Neo.SmartContract.Testing.Extensions;
using Neo.SmartContract.Testing.Native;
using Neo.VM;
using Neo.VM.Types;
using System.Numerics;
Expand Down Expand Up @@ -31,5 +31,14 @@ public void TestClass()
Assert.AreEqual(point, ret.PublicKey);
Assert.AreEqual(1, ret.Votes);
}

[TestMethod]
public void TestValueType()
{
StackItem stackItem = new Array(new StackItem[] { 1, 2 });
var ret = stackItem.ConvertTo(typeof((int, int)));

Assert.IsTrue(ret.GetType().IsValueType);
}
}
}
19 changes: 10 additions & 9 deletions tests/Neo.SmartContract.Testing.UnitTests/TestEngineTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Neo.SmartContract.Testing.Extensions;
using Neo.SmartContract.Testing.Native;
using Neo.VM;
using System.Collections.Generic;
using System.IO;
Expand All @@ -19,7 +20,7 @@ protected MyUndeployedContract(SmartContractInitialize initialize) : base(initia
//[TestMethod]
public void GenerateNativeArtifacts()
{
foreach (var n in Native.NativeContract.Contracts)
foreach (var n in Neo.SmartContract.Native.NativeContract.Contracts)
{
var manifest = n.Manifest;
var source = manifest.GetArtifactsSource(manifest.Name, generateProperties: true);
Expand Down Expand Up @@ -86,14 +87,14 @@ public void TestNativeContracts()
{
TestEngine engine = new(false);

Assert.AreEqual(engine.Native.ContractManagement.Hash, Native.NativeContract.ContractManagement.Hash);
Assert.AreEqual(engine.Native.StdLib.Hash, Native.NativeContract.StdLib.Hash);
Assert.AreEqual(engine.Native.CryptoLib.Hash, Native.NativeContract.CryptoLib.Hash);
Assert.AreEqual(engine.Native.GAS.Hash, Native.NativeContract.GAS.Hash);
Assert.AreEqual(engine.Native.NEO.Hash, Native.NativeContract.NEO.Hash);
Assert.AreEqual(engine.Native.Oracle.Hash, Native.NativeContract.Oracle.Hash);
Assert.AreEqual(engine.Native.Policy.Hash, Native.NativeContract.Policy.Hash);
Assert.AreEqual(engine.Native.RoleManagement.Hash, Native.NativeContract.RoleManagement.Hash);
Assert.AreEqual(engine.Native.ContractManagement.Hash, Neo.SmartContract.Native.NativeContract.ContractManagement.Hash);
Assert.AreEqual(engine.Native.StdLib.Hash, Neo.SmartContract.Native.NativeContract.StdLib.Hash);
Assert.AreEqual(engine.Native.CryptoLib.Hash, Neo.SmartContract.Native.NativeContract.CryptoLib.Hash);
Assert.AreEqual(engine.Native.GAS.Hash, Neo.SmartContract.Native.NativeContract.GAS.Hash);
Assert.AreEqual(engine.Native.NEO.Hash, Neo.SmartContract.Native.NativeContract.NEO.Hash);
Assert.AreEqual(engine.Native.Oracle.Hash, Neo.SmartContract.Native.NativeContract.Oracle.Hash);
Assert.AreEqual(engine.Native.Policy.Hash, Neo.SmartContract.Native.NativeContract.Policy.Hash);
Assert.AreEqual(engine.Native.RoleManagement.Hash, Neo.SmartContract.Native.NativeContract.RoleManagement.Hash);
}

[TestMethod]
Expand Down

0 comments on commit 434f451

Please sign in to comment.