diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json
index 772a221714..ccce32d36c 100644
--- a/src/Neo.CLI/config.json
+++ b/src/Neo.CLI/config.json
@@ -6,7 +6,7 @@
"Active": false
},
"Storage": {
- "Engine": "LevelDBStore",
+ "Engine": "MemoryStore",
"Path": "Data_LevelDB_{0}"
},
"P2P": {
diff --git a/src/Plugins/RestServer/Controllers/v1/ContractsController.cs b/src/Plugins/RestServer/Controllers/v1/ContractsController.cs
index ede2fc4f3b..4d61840d16 100644
--- a/src/Plugins/RestServer/Controllers/v1/ContractsController.cs
+++ b/src/Plugins/RestServer/Controllers/v1/ContractsController.cs
@@ -15,6 +15,7 @@
using Neo.Plugins.RestServer.Extensions;
using Neo.Plugins.RestServer.Helpers;
using Neo.Plugins.RestServer.Models;
+using Neo.Plugins.RestServer.Models.Contract;
using Neo.Plugins.RestServer.Models.Error;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;
@@ -187,7 +188,7 @@ public IActionResult GetContractNef(
///
/// ScriptHash
/// method name
- /// JArray of the contract parameters.
+ /// JArray of the contract parameters.
/// Execution Engine object.
/// Successful
/// An error occurred. See Response for details.
@@ -199,7 +200,7 @@ public IActionResult InvokeContract(
[FromQuery(Name = "method")]
string method,
[FromBody]
- ContractParameter[] contractParameters)
+ InvokeParams invokeParameters)
{
var contracts = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, scriptHash);
if (contracts == null)
@@ -208,7 +209,7 @@ public IActionResult InvokeContract(
throw new QueryParameterNotFoundException(nameof(method));
try
{
- var engine = ScriptHelper.InvokeMethod(_neoSystem.Settings, _neoSystem.StoreView, contracts.Hash, method, contractParameters, out var script);
+ var engine = ScriptHelper.InvokeMethod(_neoSystem.Settings, _neoSystem.StoreView, contracts.Hash, method, invokeParameters.ContractParameters, invokeParameters.Signers, out var script);
return Ok(engine.ToModel());
}
catch (Exception ex)
diff --git a/src/Plugins/RestServer/Controllers/v1/NodeController.cs b/src/Plugins/RestServer/Controllers/v1/NodeController.cs
index 447173e6b2..7d51c5a87b 100644
--- a/src/Plugins/RestServer/Controllers/v1/NodeController.cs
+++ b/src/Plugins/RestServer/Controllers/v1/NodeController.cs
@@ -30,13 +30,13 @@ namespace Neo.Plugins.RestServer.Controllers.v1
[ApiController]
public class NodeController : ControllerBase
{
- private readonly LocalNode _neolocalnode;
- private readonly NeoSystem _neosystem;
+ private readonly LocalNode _neoLocalNode;
+ private readonly NeoSystem _neoSystem;
public NodeController()
{
- _neolocalnode = RestServerPlugin.LocalNode ?? throw new InvalidOperationException();
- _neosystem = RestServerPlugin.NeoSystem ?? throw new InvalidOperationException();
+ _neoLocalNode = RestServerPlugin.LocalNode ?? throw new InvalidOperationException();
+ _neoSystem = RestServerPlugin.NeoSystem ?? throw new InvalidOperationException();
}
///
@@ -49,7 +49,7 @@ public NodeController()
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(RemoteNodeModel[]))]
public IActionResult GetPeers()
{
- var rNodes = _neolocalnode
+ var rNodes = _neoLocalNode
.GetRemoteNodes()
.OrderByDescending(o => o.LastBlockIndex)
.ToArray();
@@ -83,6 +83,6 @@ public IActionResult GetPlugins() =>
[HttpGet("settings", Name = "GetNodeProtocolSettings")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ProtocolSettingsModel))]
public IActionResult GetSettings() =>
- Ok(_neosystem.Settings.ToModel());
+ Ok(_neoSystem.Settings.ToModel());
}
}
diff --git a/src/Plugins/RestServer/Controllers/v1/TokensController.cs b/src/Plugins/RestServer/Controllers/v1/TokensController.cs
index cbdebc4a20..78078b7cd3 100644
--- a/src/Plugins/RestServer/Controllers/v1/TokensController.cs
+++ b/src/Plugins/RestServer/Controllers/v1/TokensController.cs
@@ -34,11 +34,11 @@ namespace Neo.Plugins.RestServer.Controllers.v1
[ApiController]
public class TokensController : ControllerBase
{
- private readonly NeoSystem _neosystem;
+ private readonly NeoSystem _neoSystem;
public TokensController()
{
- _neosystem = RestServerPlugin.NeoSystem ?? throw new NodeNetworkException();
+ _neoSystem = RestServerPlugin.NeoSystem ?? throw new NodeNetworkException();
}
#region NEP-17
@@ -63,7 +63,7 @@ public IActionResult GetNEP17(
{
if (skip < 1 || take < 1 || take > RestServerSettings.Current.MaxPageSize)
throw new InvalidParameterRangeException();
- var tokenList = NativeContract.ContractManagement.ListContracts(_neosystem.StoreView);
+ var tokenList = NativeContract.ContractManagement.ListContracts(_neoSystem.StoreView);
var vaildContracts = tokenList
.Where(ContractHelper.IsNep17Supported)
.OrderBy(o => o.Manifest.Name)
@@ -76,7 +76,7 @@ public IActionResult GetNEP17(
{
try
{
- var token = new NEP17Token(_neosystem, contract.Hash);
+ var token = new NEP17Token(_neoSystem, contract.Hash);
listResults.Add(token.ToModel());
}
catch
@@ -100,7 +100,7 @@ public IActionResult GetNEP17Count()
{
return Ok(new CountModel()
{
- Count = NativeContract.ContractManagement.ListContracts(_neosystem.StoreView).Count(ContractHelper.IsNep17Supported)
+ Count = NativeContract.ContractManagement.ListContracts(_neoSystem.StoreView).Count(ContractHelper.IsNep17Supported)
});
}
@@ -120,13 +120,13 @@ public IActionResult GetNEP17(
[FromRoute(Name = "address")]
UInt160 lookupAddressOrScripthash)
{
- var contract = NativeContract.ContractManagement.GetContract(_neosystem.StoreView, tokenAddessOrScripthash) ??
+ var contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, tokenAddessOrScripthash) ??
throw new ContractNotFoundException(tokenAddessOrScripthash);
if (ContractHelper.IsNep17Supported(contract) == false)
throw new Nep17NotSupportedException(tokenAddessOrScripthash);
try
{
- var token = new NEP17Token(_neosystem, tokenAddessOrScripthash);
+ var token = new NEP17Token(_neoSystem, tokenAddessOrScripthash);
return Ok(new TokenBalanceModel()
{
Name = token.Name,
@@ -167,7 +167,7 @@ public IActionResult GetNEP11(
{
if (skip < 1 || take < 1 || take > RestServerSettings.Current.MaxPageSize)
throw new InvalidParameterRangeException();
- var tokenList = NativeContract.ContractManagement.ListContracts(_neosystem.StoreView);
+ var tokenList = NativeContract.ContractManagement.ListContracts(_neoSystem.StoreView);
var vaildContracts = tokenList
.Where(ContractHelper.IsNep11Supported)
.OrderBy(o => o.Manifest.Name)
@@ -180,7 +180,7 @@ public IActionResult GetNEP11(
{
try
{
- var token = new NEP11Token(_neosystem, contract.Hash);
+ var token = new NEP11Token(_neoSystem, contract.Hash);
listResults.Add(token.ToModel());
}
catch
@@ -202,7 +202,7 @@ public IActionResult GetNEP11(
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CountModel))]
public IActionResult GetNEP11Count()
{
- return Ok(new CountModel() { Count = NativeContract.ContractManagement.ListContracts(_neosystem.StoreView).Count(ContractHelper.IsNep11Supported) });
+ return Ok(new CountModel() { Count = NativeContract.ContractManagement.ListContracts(_neoSystem.StoreView).Count(ContractHelper.IsNep11Supported) });
}
///
@@ -221,13 +221,13 @@ public IActionResult GetNEP11(
[FromRoute(Name = "address")]
UInt160 addressHash)
{
- var contract = NativeContract.ContractManagement.GetContract(_neosystem.StoreView, sAddressHash) ??
+ var contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, sAddressHash) ??
throw new ContractNotFoundException(sAddressHash);
if (ContractHelper.IsNep11Supported(contract) == false)
throw new Nep11NotSupportedException(sAddressHash);
try
{
- var token = new NEP11Token(_neosystem, sAddressHash);
+ var token = new NEP11Token(_neoSystem, sAddressHash);
return Ok(new TokenBalanceModel()
{
Name = token.Name,
@@ -259,7 +259,7 @@ public IActionResult GetBalances(
[FromRoute(Name = "address")]
UInt160 addressOrScripthash)
{
- var tokenList = NativeContract.ContractManagement.ListContracts(_neosystem.StoreView);
+ var tokenList = NativeContract.ContractManagement.ListContracts(_neoSystem.StoreView);
var validContracts = tokenList
.Where(w => ContractHelper.IsNep17Supported(w) || ContractHelper.IsNep11Supported(w))
.OrderBy(o => o.Manifest.Name);
@@ -268,7 +268,7 @@ public IActionResult GetBalances(
{
try
{
- var token = new NEP17Token(_neosystem, contract.Hash);
+ var token = new NEP17Token(_neoSystem, contract.Hash);
var balance = token.BalanceOf(addressOrScripthash).Value;
if (balance == 0)
continue;
@@ -282,7 +282,7 @@ public IActionResult GetBalances(
TotalSupply = token.TotalSupply().Value,
});
- var nft = new NEP11Token(_neosystem, contract.Hash);
+ var nft = new NEP11Token(_neoSystem, contract.Hash);
balance = nft.BalanceOf(addressOrScripthash).Value;
if (balance == 0)
continue;
diff --git a/src/Plugins/RestServer/Controllers/v1/UtilsController.cs b/src/Plugins/RestServer/Controllers/v1/UtilsController.cs
index afd5df92c0..88d03d0fca 100644
--- a/src/Plugins/RestServer/Controllers/v1/UtilsController.cs
+++ b/src/Plugins/RestServer/Controllers/v1/UtilsController.cs
@@ -28,11 +28,11 @@ namespace Neo.Plugins.RestServer.Controllers.v1
[ApiController]
public class UtilsController : ControllerBase
{
- private readonly NeoSystem _neosystem;
+ private readonly NeoSystem _neoSystem;
public UtilsController()
{
- _neosystem = RestServerPlugin.NeoSystem ?? throw new NodeNetworkException();
+ _neoSystem = RestServerPlugin.NeoSystem ?? throw new NodeNetworkException();
}
#region Validation
@@ -52,7 +52,7 @@ public IActionResult ScriptHashToWalletAddress(
{
try
{
- return Ok(new UtilsAddressModel() { Address = ScriptHash.ToAddress(_neosystem.Settings.AddressVersion) });
+ return Ok(new UtilsAddressModel() { Address = ScriptHash.ToAddress(_neoSystem.Settings.AddressVersion) });
}
catch (FormatException)
{
@@ -75,7 +75,7 @@ public IActionResult WalletAddressToScriptHash(
{
try
{
- return Ok(new UtilsScriptHashModel() { ScriptHash = address.ToScriptHash(_neosystem.Settings.AddressVersion) });
+ return Ok(new UtilsScriptHashModel() { ScriptHash = address.ToScriptHash(_neoSystem.Settings.AddressVersion) });
}
catch (FormatException)
{
@@ -99,7 +99,7 @@ public IActionResult ValidateAddress(
return Ok(new UtilsAddressIsValidModel()
{
Address = AddressOrScriptHash,
- IsValid = RestServerUtility.TryConvertToScriptHash(AddressOrScriptHash, _neosystem.Settings, out _),
+ IsValid = RestServerUtility.TryConvertToScriptHash(AddressOrScriptHash, _neoSystem.Settings, out _),
});
}
diff --git a/src/Plugins/RestServer/Helpers/ScriptHelper.cs b/src/Plugins/RestServer/Helpers/ScriptHelper.cs
index 955993d277..d592ef8708 100644
--- a/src/Plugins/RestServer/Helpers/ScriptHelper.cs
+++ b/src/Plugins/RestServer/Helpers/ScriptHelper.cs
@@ -16,6 +16,7 @@
using Neo.VM;
using Neo.VM.Types;
using System;
+using System.Linq;
namespace Neo.Plugins.RestServer.Helpers
{
@@ -31,11 +32,21 @@ public static bool InvokeMethod(ProtocolSettings protocolSettings, DataCache sna
return engine.State == VMState.HALT;
}
- public static ApplicationEngine InvokeMethod(ProtocolSettings protocolSettings, DataCache snapshot, UInt160 scriptHash, string method, ContractParameter[] args, out byte[] script)
+ public static ApplicationEngine InvokeMethod(ProtocolSettings protocolSettings, DataCache snapshot, UInt160 scriptHash, string method, ContractParameter[] args, Signer[]? signers, out byte[] script)
{
using var scriptBuilder = new ScriptBuilder();
scriptBuilder.EmitDynamicCall(scriptHash, method, CallFlags.ReadOnly, args);
script = scriptBuilder.ToArray();
+ var tx = signers == null ? null : new Transaction
+ {
+ Version = 0,
+ Nonce = (uint)Random.Shared.Next(),
+ ValidUntilBlock = NativeContract.Ledger.CurrentIndex(snapshot) + protocolSettings.MaxValidUntilBlockIncrement,
+ Signers = signers,
+ Attributes = [],
+ Script = script,
+ Witnesses = [.. signers.Select(s => new Witness())],
+ };
using var engine = ApplicationEngine.Run(script, snapshot, settings: protocolSettings, gas: RestServerSettings.Current.MaxGasInvoke);
return engine;
}
@@ -45,7 +56,7 @@ public static ApplicationEngine InvokeScript(ReadOnlyMemory script, Signer
var neoSystem = RestServerPlugin.NeoSystem ?? throw new InvalidOperationException();
var snapshot = neoSystem.GetSnapshotCache();
- Transaction? tx = signers == null ? null : new Transaction
+ var tx = signers == null ? null : new Transaction
{
Version = 0,
Nonce = (uint)Random.Shared.Next(),
diff --git a/src/Plugins/RestServer/Models/Contract/InvokeParams.cs b/src/Plugins/RestServer/Models/Contract/InvokeParams.cs
new file mode 100644
index 0000000000..f455e19d7e
--- /dev/null
+++ b/src/Plugins/RestServer/Models/Contract/InvokeParams.cs
@@ -0,0 +1,22 @@
+// Copyright (C) 2015-2024 The Neo Project.
+//
+// InvokeParams.cs file belongs to the neo project and is free
+// software distributed under the MIT software license, see the
+// accompanying file LICENSE in the main directory of the
+// repository or http://www.opensource.org/licenses/mit-license.php
+// for more details.
+//
+// Redistribution and use in source and binary forms with or without
+// modifications are permitted.
+
+using Neo.Network.P2P.Payloads;
+using Neo.SmartContract;
+
+namespace Neo.Plugins.RestServer.Models.Contract
+{
+ public class InvokeParams
+ {
+ public ContractParameter[] ContractParameters { get; set; } = [];
+ public Signer[] Signers { get; set; } = [];
+ }
+}
diff --git a/src/Plugins/RestServer/Newtonsoft/Json/ContractInvokeParametersJsonConverter.cs b/src/Plugins/RestServer/Newtonsoft/Json/ContractInvokeParametersJsonConverter.cs
new file mode 100644
index 0000000000..e455cef718
--- /dev/null
+++ b/src/Plugins/RestServer/Newtonsoft/Json/ContractInvokeParametersJsonConverter.cs
@@ -0,0 +1,35 @@
+// Copyright (C) 2015-2024 The Neo Project.
+//
+// ContractInvokeParametersJsonConverter.cs file belongs to the neo project and is free
+// software distributed under the MIT software license, see the
+// accompanying file LICENSE in the main directory of the
+// repository or http://www.opensource.org/licenses/mit-license.php
+// for more details.
+//
+// Redistribution and use in source and binary forms with or without
+// modifications are permitted.
+
+using Neo.Plugins.RestServer.Models.Contract;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+
+namespace Neo.Plugins.RestServer.Newtonsoft.Json
+{
+ public class ContractInvokeParametersJsonConverter : JsonConverter
+ {
+ public override bool CanRead => true;
+ public override bool CanWrite => false;
+
+ public override InvokeParams ReadJson(JsonReader reader, Type objectType, InvokeParams? existingValue, bool hasExistingValue, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var token = JToken.ReadFrom(reader);
+ return RestServerUtility.ContractInvokeParametersFromJToken(token);
+ }
+
+ public override void WriteJson(JsonWriter writer, InvokeParams? value, global::Newtonsoft.Json.JsonSerializer serializer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/Plugins/RestServer/RestServerSettings.cs b/src/Plugins/RestServer/RestServerSettings.cs
index de95f68eda..38c886941b 100644
--- a/src/Plugins/RestServer/RestServerSettings.cs
+++ b/src/Plugins/RestServer/RestServerSettings.cs
@@ -78,8 +78,8 @@ public class RestServerSettings
MissingMemberHandling = MissingMemberHandling.Error,
NullValueHandling = NullValueHandling.Include,
Formatting = Formatting.None,
- Converters = new JsonConverter[]
- {
+ Converters =
+ [
new StringEnumConverter(),
new BigDecimalJsonConverter(),
new BlockHeaderJsonConverter(),
@@ -87,6 +87,7 @@ public class RestServerSettings
new ContractAbiJsonConverter(),
new ContractEventDescriptorJsonConverter(),
new ContractGroupJsonConverter(),
+ new ContractInvokeParametersJsonConverter(),
new ContractJsonConverter(),
new ContractManifestJsonConverter(),
new ContractMethodJsonConverter(),
@@ -119,7 +120,7 @@ public class RestServerSettings
new WitnessConditionJsonConverter(),
new WitnessJsonConverter(),
new WitnessRuleJsonConverter(),
- },
+ ],
},
};
diff --git a/src/Plugins/RestServer/RestServerUtility.cs b/src/Plugins/RestServer/RestServerUtility.cs
index 3b5172a503..53bf798c17 100644
--- a/src/Plugins/RestServer/RestServerUtility.cs
+++ b/src/Plugins/RestServer/RestServerUtility.cs
@@ -10,6 +10,8 @@
// modifications are permitted.
using Neo.Cryptography.ECC;
+using Neo.Network.P2P.Payloads;
+using Neo.Plugins.RestServer.Models.Contract;
using Neo.SmartContract;
using Neo.VM;
using Neo.VM.Types;
@@ -246,6 +248,53 @@ public static JToken StackItemToJToken(StackItem item, IList<(StackItem, JToken?
return o;
}
+ public static InvokeParams ContractInvokeParametersFromJToken(JToken token)
+ {
+ if (token is null)
+ throw new ArgumentNullException();
+ if (token.Type != JTokenType.Object)
+ throw new FormatException();
+
+ var obj = (JObject)token;
+ var contractParametersProp = obj
+ .Properties()
+ .SingleOrDefault(a => a.Name.Equals("contractParameters", StringComparison.InvariantCultureIgnoreCase));
+ var signersProp = obj
+ .Properties()
+ .SingleOrDefault(a => a.Name.Equals("signers", StringComparison.InvariantCultureIgnoreCase));
+
+ return new()
+ {
+ ContractParameters = [.. contractParametersProp!.Value.Select(ContractParameterFromJToken)],
+ Signers = [.. signersProp!.Value.Select(SignerFromJToken)],
+ };
+ }
+
+ public static Signer SignerFromJToken(JToken? token)
+ {
+ if (token is null)
+ throw new ArgumentNullException();
+ if (token.Type != JTokenType.Object)
+ throw new FormatException();
+
+ var obj = (JObject)token;
+ var accountProp = obj
+ .Properties()
+ .SingleOrDefault(a => a.Name.Equals("account", StringComparison.InvariantCultureIgnoreCase));
+ var scopesProp = obj
+ .Properties()
+ .SingleOrDefault(a => a.Name.Equals("scopes", StringComparison.InvariantCultureIgnoreCase));
+
+ if (accountProp == null || scopesProp == null)
+ throw new FormatException();
+
+ return new()
+ {
+ Account = UInt160.Parse(accountProp.ToObject()),
+ Scopes = Enum.Parse(scopesProp.ToObject()!),
+ };
+ }
+
public static ContractParameter ContractParameterFromJToken(JToken? token)
{
if (token is null)