Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion neo
Submodule neo updated 53 files
+13 −3 .github/workflows/main.yml
+1 −2 benchmarks/Neo.Benchmarks/Benchmarks.cs
+34 −1,442 src/Neo.VM/ExecutionEngine.cs
+65 −0 src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs
+390 −0 src/Neo.VM/JumpTable/JumpTable.Compound.cs
+396 −0 src/Neo.VM/JumpTable/JumpTable.Control.cs
+265 −0 src/Neo.VM/JumpTable/JumpTable.Numeric.cs
+213 −0 src/Neo.VM/JumpTable/JumpTable.Push.cs
+363 −0 src/Neo.VM/JumpTable/JumpTable.Slot.cs
+106 −0 src/Neo.VM/JumpTable/JumpTable.Splice.cs
+124 −0 src/Neo.VM/JumpTable/JumpTable.Stack.cs
+60 −0 src/Neo.VM/JumpTable/JumpTable.Types.cs
+71 −0 src/Neo.VM/JumpTable/JumpTable.cs
+1 −0 src/Neo.VM/Neo.VM.csproj
+2 −1 src/Neo/Hardfork.cs
+1 −0 src/Neo/Neo.csproj
+12 −7 src/Neo/NeoSystem.cs
+1 −1 src/Neo/Persistence/DataCache.cs
+19 −0 src/Neo/Persistence/MemoryStoreProvider.cs
+19 −10 src/Neo/Persistence/StoreFactory.cs
+47 −5 src/Neo/ProtocolSettings.cs
+1 −1 src/Neo/SmartContract/ApplicationEngine.Contract.cs
+92 −50 src/Neo/SmartContract/ApplicationEngine.cs
+3 −1 src/Neo/SmartContract/IApplicationEngineProvider.cs
+165 −0 src/Neo/SmartContract/Native/ContractEventAttribute.cs
+33 −56 src/Neo/SmartContract/Native/ContractManagement.cs
+10 −0 src/Neo/SmartContract/Native/ContractMethodAttribute.cs
+4 −0 src/Neo/SmartContract/Native/ContractMethodMetadata.cs
+17 −1 src/Neo/SmartContract/Native/CryptoLib.cs
+9 −31 src/Neo/SmartContract/Native/FungibleToken.cs
+7 −3 src/Neo/SmartContract/Native/GasToken.cs
+1 −3 src/Neo/SmartContract/Native/LedgerContract.cs
+139 −32 src/Neo/SmartContract/Native/NativeContract.cs
+21 −64 src/Neo/SmartContract/Native/NeoToken.cs
+15 −56 src/Neo/SmartContract/Native/OracleContract.cs
+8 −7 src/Neo/SmartContract/Native/PolicyContract.cs
+4 −27 src/Neo/SmartContract/Native/RoleManagement.cs
+1 −1 src/Neo/SmartContract/Native/StdLib.cs
+10 −0 src/Neo/SmartContract/StorageItem.cs
+90 −0 src/Neo/Wallets/Helper.cs
+1 −88 src/Neo/Wallets/Wallet.cs
+2 −2 tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs
+6 −0 tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs
+151 −0 tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs
+32 −0 tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs
+93 −0 tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs
+21 −0 tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs
+5 −4 tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs
+3 −3 tests/Neo.UnitTests/SmartContract/UT_InteropService.cs
+3 −3 tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs
+8 −1 tests/Neo.UnitTests/TestBlockchain.cs
+127 −0 tests/Neo.UnitTests/UT_ProtocolSettings.cs
+15 −4 tests/Neo.VM.Tests/Types/TestEngine.cs
14 changes: 12 additions & 2 deletions src/Neo.SmartContract.Testing/InvalidTypes/InvalidUInt160.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@ namespace Neo.SmartContract.Testing.InvalidTypes
{
public class InvalidUInt160
{
/// <summary>
/// Zero
/// </summary>
public static readonly UInt160 Zero = UInt160.Zero;

/// <summary>
/// Null UInt160
/// </summary>
public static readonly UInt160? Null = null;

/// <summary>
/// This will be an invalid UInt160
/// This will be an invalid UInt160 (ByteString)
/// </summary>
public static readonly UInt160 InvalidLength = new();

/// <summary>
/// This will be an invalid UInt160 (Integer)
/// </summary>
public static readonly UInt160 Invalid = new();
public static readonly UInt160 InvalidType = new();
}
}
14 changes: 12 additions & 2 deletions src/Neo.SmartContract.Testing/InvalidTypes/InvalidUInt256.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@ namespace Neo.SmartContract.Testing.InvalidTypes
{
public class InvalidUInt256
{
/// <summary>
/// Zero
/// </summary>
public static readonly UInt160 Zero = UInt160.Zero;

/// <summary>
/// Null UInt256
/// </summary>
public static readonly UInt256? Null = null;

/// <summary>
/// This will be an invalid UInt256
/// This will be an invalid UInt256 (ByteString)
/// </summary>
public static readonly UInt256 InvalidLength = new();

/// <summary>
/// This will be an invalid UInt256 (Integer)
/// </summary>
public static readonly UInt256 Invalid = new();
public static readonly UInt256 InvalidType = new();
}
}
1 change: 0 additions & 1 deletion src/Neo.SmartContract.Testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,4 +473,3 @@ The currently known limitations are:

- Receive events during the deploy, because the object is returned after performing the deploy, it is not possible to intercept notifications for the deploy unless the contract is previously created with `FromHash` knowing the hash of the contract to be created.
- It is possible that if the contract is updated, the coverage calculation may be incorrect. The update method of a contract can be tested, but if the same script and abi as the original are not used, it can result in a coverage calculation error.
- Some native contracts use the values of `CallingScriptHash` and `EntryScriptHash` for certain actions, such as `CheckWitness`, so overriding the syscalls with `OnGetEntryScriptHash` and `OnGetCallingScriptHash` could fail.
11 changes: 9 additions & 2 deletions src/Neo.SmartContract.Testing/SmartContract.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using Neo.SmartContract.Testing.Extensions;
using Neo.SmartContract.Testing.Storage;
using Neo.VM;
using Neo.VM.Types;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;

Expand Down Expand Up @@ -61,11 +63,16 @@ internal StackItem Invoke(string methodName, params object[] args)
{
var arg = args[i];

if (ReferenceEquals(arg, InvalidTypes.InvalidUInt160.Invalid) ||
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.Invalid))
if (ReferenceEquals(arg, InvalidTypes.InvalidUInt160.InvalidLength) ||
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidLength))
{
arg = System.Array.Empty<byte>();
}
else if (ReferenceEquals(arg, InvalidTypes.InvalidUInt160.InvalidType) ||
ReferenceEquals(arg, InvalidTypes.InvalidUInt256.InvalidType))
{
arg = BigInteger.Zero;
}

script.EmitPush(arg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Buffers.Binary;
using System.Numerics;

namespace Neo.SmartContract.Testing
namespace Neo.SmartContract.Testing.Storage
{
public class SmartContractStorage
{
Expand Down Expand Up @@ -34,6 +34,18 @@ private int GetContractId()
return _contractId.Value;
}

/// <summary>
/// Check if the entry exist
/// </summary>
/// <param name="key">Key</param>
public bool Contains(byte key) => Contains(new byte[] { key });

/// <summary>
/// Check if the entry exist
/// </summary>
/// <param name="key">Key</param>
public bool Contains(string key) => Contains(Utility.StrictUTF8.GetBytes(key));

/// <summary>
/// Check if the entry exist
/// </summary>
Expand All @@ -45,6 +57,18 @@ public bool Contains(ReadOnlyMemory<byte> key)
return entry != null;
}

/// <summary>
/// Read an entry from the smart contract storage
/// </summary>
/// <param name="key">Key</param>
public ReadOnlyMemory<byte> Get(byte key) => Get(new byte[] { key });

/// <summary>
/// Read an entry from the smart contract storage
/// </summary>
/// <param name="key">Key</param>
public ReadOnlyMemory<byte> Get(string key) => Get(Utility.StrictUTF8.GetBytes(key));

/// <summary>
/// Read an entry from the smart contract storage
/// </summary>
Expand All @@ -62,6 +86,20 @@ public ReadOnlyMemory<byte> Get(ReadOnlyMemory<byte> key)
return null;
}

/// <summary>
/// Put an entry in the smart contract storage
/// </summary>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
public void Put(byte key, ReadOnlyMemory<byte> value) => Put(new byte[] { key }, value);

/// <summary>
/// Put an entry in the smart contract storage
/// </summary>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
public void Put(string key, ReadOnlyMemory<byte> value) => Put(Utility.StrictUTF8.GetBytes(key), value);

/// <summary>
/// Put an entry in the smart contract storage
/// </summary>
Expand All @@ -75,6 +113,20 @@ public void Put(ReadOnlyMemory<byte> key, ReadOnlyMemory<byte> value)
entry.Value = value;
}

/// <summary>
/// Put an entry in the smart contract storage
/// </summary>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
public void Put(byte key, BigInteger value) => Put(new byte[] { key }, value);

/// <summary>
/// Put an entry in the smart contract storage
/// </summary>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
public void Put(string key, BigInteger value) => Put(Utility.StrictUTF8.GetBytes(key), value);

/// <summary>
/// Put an entry in the smart contract storage
/// </summary>
Expand All @@ -88,6 +140,18 @@ public void Put(ReadOnlyMemory<byte> key, BigInteger value)
entry.Set(value);
}

/// <summary>
/// Remove an entry from the smart contract storage
/// </summary>
/// <param name="key">Key</param>
public void Remove(byte key) => Remove(new byte[] { key });

/// <summary>
/// Remove an entry from the smart contract storage
/// </summary>
/// <param name="key">Key</param>
public void Remove(string key) => Remove(Utility.StrictUTF8.GetBytes(key));

/// <summary>
/// Remove an entry from the smart contract storage
/// </summary>
Expand Down
10 changes: 6 additions & 4 deletions src/Neo.SmartContract.Testing/TestEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ namespace Neo.SmartContract.Testing
{
public class TestEngine
{
public delegate UInt160? OnGetScriptHash(UInt160 current, UInt160 expected);

internal readonly Dictionary<UInt160, CoveredContract> Coverage = new();
private readonly Dictionary<UInt160, List<SmartContract>> _contracts = new();
private readonly Dictionary<UInt160, Dictionary<string, CustomMock>> _customMocks = new();
Expand Down Expand Up @@ -146,15 +148,15 @@ public UInt160 CommitteeAddress

/// <summary>
/// On GetEntryScriptHash
/// The argument is the ExecutingScriptHash, and it must return the new EntryScriptHash, or null if we don't want to make any change
/// The argument is the ExecutingScriptHash and the expected return, and it must return the new EntryScriptHash, or null if we don't want to make any change
/// </summary>
public Func<UInt160, UInt160?>? OnGetEntryScriptHash { get; set; } = null;
public OnGetScriptHash? OnGetEntryScriptHash { get; set; } = null;

/// <summary>
/// On GetCallingScriptHash
/// The argument is the ExecutingScriptHash, and it must return the new CallingScriptHash, or null if we don't want to make any change
/// The argument is the ExecutingScriptHash and the expected return, and it must return the new CallingScriptHash, or null if we don't want to make any change
/// </summary>
public Func<UInt160, UInt160?>? OnGetCallingScriptHash { get; set; } = null;
public OnGetScriptHash? OnGetCallingScriptHash { get; set; } = null;

/// <summary>
/// Gas
Expand Down
48 changes: 25 additions & 23 deletions src/Neo.SmartContract.Testing/TestingApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,30 @@ internal class TestingApplicationEngine : ApplicationEngine
/// </summary>
public TestEngine Engine { get; }

/// <summary>
/// Override CallingScriptHash
/// </summary>
public override UInt160 CallingScriptHash
{
get
{
var expected = base.CallingScriptHash;
return Engine.OnGetCallingScriptHash?.Invoke(CurrentScriptHash, expected) ?? expected;
}
}

/// <summary>
/// Override EntryScriptHash
/// </summary>
public override UInt160 EntryScriptHash
{
get
{
var expected = base.EntryScriptHash;
return Engine.OnGetEntryScriptHash?.Invoke(CurrentScriptHash, expected) ?? expected;
}
}

public TestingApplicationEngine(TestEngine engine, TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock)
: base(trigger, container, snapshot, persistingBlock, engine.ProtocolSettings, engine.Gas, null)
{
Expand Down Expand Up @@ -165,30 +189,8 @@ private void RecoverCoverage(Instruction instruction)

protected override void OnSysCall(InteropDescriptor descriptor)
{
if (descriptor == System_Runtime_GetEntryScriptHash)
{
var currentHash = InstructionContext.GetScriptHash();
var hash = Engine.OnGetEntryScriptHash?.Invoke(currentHash);

if (hash is not null)
{
Push(Convert(hash));
return;
}
}
else if (descriptor == System_Runtime_GetCallingScriptHash)
{
var currentHash = InstructionContext.GetScriptHash();
var hash = Engine.OnGetCallingScriptHash?.Invoke(currentHash);

if (hash is not null)
{
Push(Convert(hash));
return;
}
}
// descriptor.Hash == 1381727586 && descriptor.Name == "System.Contract.Call" && descriptor.Parameters.Count == 4)
else if (descriptor == System_Contract_Call)
if (descriptor == System_Contract_Call)
{
// Check if the syscall is a contract call and we need to mock it because it was defined by the user

Expand Down
9 changes: 6 additions & 3 deletions src/Neo.SmartContract.Testing/TestingStandards/Nep17Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public virtual void TestBalanceOf()
{
Assert.AreEqual(0, Contract.BalanceOf(Bob.Account));
Assert.ThrowsException<VMUnhandledException>(() => Contract.BalanceOf(InvalidUInt160.Null));
Assert.ThrowsException<VMUnhandledException>(() => Contract.BalanceOf(InvalidUInt160.Invalid));
Assert.ThrowsException<VMUnhandledException>(() => Contract.BalanceOf(InvalidUInt160.InvalidLength));
Assert.ThrowsException<VMUnhandledException>(() => Contract.BalanceOf(InvalidUInt160.InvalidType));
}

[TestMethod]
Expand Down Expand Up @@ -156,8 +157,10 @@ public virtual void TestTransfer()
Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(Alice.Account, InvalidUInt160.Null, 0)));

Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(Alice.Account, Bob.Account, -1)));
Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(InvalidUInt160.Invalid, Bob.Account, -1)));
Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(Alice.Account, InvalidUInt160.Invalid, 0)));
Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(InvalidUInt160.InvalidLength, Bob.Account, -1)));
Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(InvalidUInt160.InvalidType, Bob.Account, -1)));
Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(Alice.Account, InvalidUInt160.InvalidLength, 0)));
Assert.ThrowsException<VMUnhandledException>(() => Assert.IsTrue(Contract.Transfer(Alice.Account, InvalidUInt160.InvalidType, 0)));

// Invoke transfer without signature

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ public virtual void TestSetGetOwner()
Engine.SetTransactionSigners(Alice);
Assert.ThrowsException<Exception>(() => Contract.Owner = UInt160.Zero);
Assert.ThrowsException<InvalidOperationException>(() => Contract.Owner = InvalidUInt160.Null);
Assert.ThrowsException<Exception>(() => Contract.Owner = InvalidUInt160.Invalid);
Assert.ThrowsException<Exception>(() => Contract.Owner = InvalidUInt160.InvalidLength);
Assert.ThrowsException<Exception>(() => Contract.Owner = InvalidUInt160.InvalidType);

Contract.Owner = Bob.Account;
Assert.AreEqual(Bob.Account, Contract.Owner);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class Contract_NativeContracts
public void Test_Init()
{
snapshot = new TestDataCache();
genesisBlock = new NeoSystem(TestProtocolSettings.Default, new MemoryStore()).GenesisBlock;
genesisBlock = new NeoSystem(TestProtocolSettings.Default, new MemoryStoreProvider()).GenesisBlock;
}

[TestMethod]
Expand Down
2 changes: 1 addition & 1 deletion tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ public void tuple2_Test()
[TestMethod]
public void event_Test()
{
var system = new NeoSystem(TestProtocolSettings.Default, new MemoryStore());
var system = new NeoSystem(TestProtocolSettings.Default, new MemoryStoreProvider());
using var testengine = new TestEngine(verificable: new Transaction()
{
Signers = new Signer[] { new Signer() { Account = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01") } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class ContractTest
[TestInitialize]
public void Init()
{
var system = new NeoSystem(TestProtocolSettings.Default, new MemoryStore());
var system = new NeoSystem(TestProtocolSettings.Default, new MemoryStoreProvider());
_engine = new TestEngine.TestEngine(verificable: new Transaction()
{
Signers = new Signer[] { new Signer() { Account = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01") } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static class TestBlockchain

static TestBlockchain()
{
TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, new MemoryStore());
TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, new MemoryStoreProvider());
}

public static StorageKey CreateStorageKey(this NativeContract contract, byte prefix, ISerializable key = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ public void TestDeployWithOwner()
// Try with invalid owners

Assert.ThrowsException<Exception>(() => Engine.Deploy<Nep17Contract>(NefFile, Manifest, UInt160.Zero));
Assert.ThrowsException<Exception>(() => Engine.Deploy<Nep17Contract>(NefFile, Manifest, InvalidUInt160.Invalid));
Assert.ThrowsException<Exception>(() => Engine.Deploy<Nep17Contract>(NefFile, Manifest, InvalidUInt160.InvalidLength));
Assert.ThrowsException<Exception>(() => Engine.Deploy<Nep17Contract>(NefFile, Manifest, InvalidUInt160.InvalidType));

// Test SetOwner notification

Expand Down
2 changes: 1 addition & 1 deletion tests/Neo.SmartContract.TestEngine/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static void ContractAdd(this DataCache snapshot, ContractState contract)

public static void DeployNativeContracts(this DataCache snapshot, Block? persistingBlock = null)
{
persistingBlock ??= new NeoSystem(TestProtocolSettings.Default, new MemoryStore()).GenesisBlock;
persistingBlock ??= new NeoSystem(TestProtocolSettings.Default, new MemoryStoreProvider()).GenesisBlock;

var method = typeof(SmartContract.Native.ContractManagement).GetMethod("OnPersist", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var engine = new TestEngine(TriggerType.OnPersist, null, snapshot, persistingBlock);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public void TestCheckpoint()

// Check that all it works

Assert.IsTrue(engine.Native.NEO.Storage.Contains(1)); // Prefix_VotersCount
Assert.AreEqual(100_000_000, engine.Native.NEO.TotalSupply);

// Create checkpoint
Expand Down
Loading