diff --git a/src/Plugins/RpcServer/ParameterConverter.cs b/src/Plugins/RpcServer/ParameterConverter.cs
index a6d1cdab59..e8fdb39252 100644
--- a/src/Plugins/RpcServer/ParameterConverter.cs
+++ b/src/Plugins/RpcServer/ParameterConverter.cs
@@ -299,6 +299,15 @@ internal static Address ToAddress(this JToken token, byte version)
return new Address(scriptHash, version);
}
+ internal static Address[] ToAddresses(this JToken token, byte version)
+ {
+ if (token is null) return null;
+ if (token is not JArray array)
+ throw new RpcException(RpcError.InvalidParams.WithData($"Invalid Addresses: {token}"));
+
+ return array.Select(p => ToAddress(p, version)).ToArray();
+ }
+
private static ContractParameter[] ToContractParameters(this JToken token)
{
if (token is null) return null;
diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs
index 57b073c0e0..194c02ea3c 100644
--- a/src/Plugins/RpcServer/RpcServer.Wallet.cs
+++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs
@@ -14,6 +14,7 @@
using Neo.Json;
using Neo.Network.P2P.Payloads;
using Neo.Persistence;
+using Neo.Plugins.RpcServer.Model;
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.VM;
@@ -24,6 +25,7 @@
using System.IO;
using System.Linq;
using System.Numerics;
+using Address = Neo.Plugins.RpcServer.Model.Address;
using Helper = Neo.Wallets.Helper;
namespace Neo.Plugins.RpcServer
@@ -83,16 +85,16 @@ protected internal virtual JToken CloseWallet()
/// Response format:
/// {"jsonrpc": "2.0", "id": 1, "result": "A WIF-encoded private key as a string"}
///
- /// An 1-element array containing the address(UInt160 or Base58Check address) as a string.
+ /// The address(UInt160 or Base58Check address) to export the private key for.
/// The exported private key as a string.
/// Thrown when no wallet is open or the address is invalid.
[RpcMethod]
- protected internal virtual JToken DumpPrivKey(JArray _params)
+ protected internal virtual JToken DumpPrivKey(Address address)
{
CheckWallet();
- var scriptHash = _params[0].AsString().AddressToScriptHash(system.Settings.AddressVersion);
- var account = wallet.GetAccount(scriptHash);
- if (account is null) throw new RpcException(RpcError.UnknownAccount.WithData($"{scriptHash}"));
+
+ var account = wallet.GetAccount(address.ScriptHash);
+ if (account is null) throw new RpcException(RpcError.UnknownAccount.WithData($"{address.ScriptHash}"));
return account.GetKey().Export();
}
@@ -110,7 +112,8 @@ protected internal virtual JToken DumpPrivKey(JArray _params)
protected internal virtual JToken GetNewAddress()
{
CheckWallet();
- WalletAccount account = wallet.CreateAccount();
+
+ var account = wallet.CreateAccount();
if (wallet is NEP6Wallet nep6)
nep6.Save();
return account.Address;
@@ -127,17 +130,16 @@ protected internal virtual JToken GetNewAddress()
/// "result": {"balance": "0"} // An integer number in string, the balance of the specified asset in the wallet
/// }
///
- /// An 1-element(UInt160) array containing the asset ID as a string.
+ /// An 1-element(UInt160) array containing the asset ID as a string.
/// A JSON object containing the balance of the specified asset.
/// Thrown when no wallet is open or the asset ID is invalid.
[RpcMethod]
- protected internal virtual JToken GetWalletBalance(JArray _params)
+ protected internal virtual JToken GetWalletBalance(UInt160 assetId)
{
CheckWallet();
- UInt160 asset_id = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset id: {_params[0]}"));
- JObject json = new();
- json["balance"] = wallet.GetAvailable(system.StoreView, asset_id).Value.ToString();
- return json;
+
+ var balance = wallet.GetAvailable(system.StoreView, assetId).Value;
+ return new JObject { ["balance"] = balance.ToString() };
}
///
@@ -155,8 +157,9 @@ protected internal virtual JToken GetWalletBalance(JArray _params)
protected internal virtual JToken GetWalletUnclaimedGas()
{
CheckWallet();
+
// Datoshi is the smallest unit of GAS, 1 GAS = 10^8 Datoshi
- BigInteger datoshi = BigInteger.Zero;
+ var datoshi = BigInteger.Zero;
using (var snapshot = system.GetSnapshotCache())
{
uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1;
@@ -179,15 +182,15 @@ protected internal virtual JToken GetWalletUnclaimedGas()
/// "result": {"address": "The Base58Check address", "haskey": true, "label": "The label", "watchonly": false}
/// }
///
- /// An 1-element(WIF-encoded private key) array containing the private key as a string.
+ /// The WIF-encoded private key to import.
/// A JSON object containing information about the imported account.
/// Thrown when no wallet is open or the private key is invalid.
[RpcMethod]
- protected internal virtual JToken ImportPrivKey(JArray _params)
+ protected internal virtual JToken ImportPrivKey(string privkey)
{
CheckWallet();
- string privkey = _params[0].AsString();
- WalletAccount account = wallet.Import(privkey);
+
+ var account = wallet.Import(privkey);
if (wallet is NEP6Wallet nep6wallet)
nep6wallet.Save();
return new JObject
@@ -208,22 +211,15 @@ protected internal virtual JToken ImportPrivKey(JArray _params)
/// Response format:
/// {"jsonrpc": "2.0", "id": 1, "result": {"networkfee": "The network fee(an integer number in string)"}}
///
- /// An array containing the Base64-encoded transaction.
+ /// The raw transaction to calculate the network fee for.
/// A JSON object containing the calculated network fee.
/// Thrown when the input parameters are invalid or the transaction is malformed.
[RpcMethod]
- protected internal virtual JToken CalculateNetworkFee(JArray _params)
+ protected internal virtual JToken CalculateNetworkFee(byte[] tx)
{
- if (_params.Count == 0)
- {
- throw new RpcException(RpcError.InvalidParams.WithData("Params array is empty, need a raw transaction."));
- }
- var tx = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid tx: {_params[0]}"));
-
- JObject account = new();
- var networkfee = Helper.CalculateNetworkFee(tx.AsSerializable(), system.StoreView, system.Settings, wallet);
- account["networkfee"] = networkfee.ToString();
- return account;
+ var transaction = Result.Ok_Or(() => tx.AsSerializable(), RpcErrorFactory.InvalidParams("Invalid tx."));
+ var networkfee = Helper.CalculateNetworkFee(transaction, system.StoreView, system.Settings, wallet);
+ return new JObject { ["networkfee"] = networkfee.ToString() };
}
///
@@ -245,12 +241,13 @@ protected internal virtual JToken ListAddress()
CheckWallet();
return wallet.GetAccounts().Select(p =>
{
- JObject account = new();
- account["address"] = p.Address;
- account["haskey"] = p.HasKey;
- account["label"] = p.Label;
- account["watchonly"] = p.WatchOnly;
- return account;
+ return new JObject
+ {
+ ["address"] = p.Address,
+ ["haskey"] = p.HasKey,
+ ["label"] = p.Label,
+ ["watchonly"] = p.WatchOnly
+ };
}).ToArray();
}
@@ -261,20 +258,15 @@ protected internal virtual JToken ListAddress()
/// Response format:
/// {"jsonrpc": "2.0", "id": 1, "result": true}
///
- ///
- /// An array containing the following elements:
- /// [0]: The path to the wallet file as a string.
- /// [1]: The password to open the wallet as a string.
- ///
+ /// The path to the wallet file.
+ /// The password to open the wallet.
/// Returns true if the wallet was successfully opened.
///
/// Thrown when the wallet file is not found, the wallet is not supported, or the password is invalid.
///
[RpcMethod]
- protected internal virtual JToken OpenWallet(JArray _params)
+ protected internal virtual JToken OpenWallet(string path, string password)
{
- string path = _params[0].AsString();
- string password = _params[1].AsString();
File.Exists(path).True_Or(RpcError.WalletNotFound);
try
{
@@ -312,7 +304,8 @@ private void ProcessInvokeWithWallet(JObject result, Signer[] signers = null)
result["exception"] = GetExceptionMessage(e);
return;
}
- ContractParametersContext context = new(system.StoreView, tx, settings.Network);
+
+ var context = new ContractParametersContext(system.StoreView, tx, settings.Network);
wallet.Sign(context);
if (context.Completed)
{
@@ -360,47 +353,33 @@ private void ProcessInvokeWithWallet(JObject result, Signer[] signers = null)
/// }
/// }
///
- ///
- /// An array containing the following elements:
- /// [0]: The asset ID as a string.
- /// [1]: The from address as a string.
- /// [2]: The to address as a string.
- /// [3]: The amount as a string.
- /// [4] (optional): An array of signers, each containing:
- /// - The address of the signer as a string.
- ///
+ /// The asset ID as a string.
+ /// The from address as a string.
+ /// The to address as a string.
+ /// The amount as a string.
+ /// An array of signers, each containing: The address of the signer as a string.
/// The transaction details if successful, or the contract parameters if signatures are incomplete.
/// Thrown when no wallet is open, parameters are invalid, or there are insufficient funds.
[RpcMethod]
- protected internal virtual JToken SendFrom(JArray _params)
+ protected internal virtual JToken SendFrom(UInt160 assetId, Address from, Address to, string amount, Address[] signers = null)
{
CheckWallet();
- var assetId = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset id: {_params[0]}"));
- var from = _params[1].AsString().AddressToScriptHash(system.Settings.AddressVersion);
- var to = _params[2].AsString().AddressToScriptHash(system.Settings.AddressVersion);
using var snapshot = system.GetSnapshotCache();
var descriptor = new AssetDescriptor(snapshot, system.Settings, assetId);
- var amount = new BigDecimal(BigInteger.Parse(_params[3].AsString()), descriptor.Decimals);
- (amount.Sign > 0).True_Or(RpcErrorFactory.InvalidParams("Amount can't be negative."));
- var signers = _params.Count >= 5
- ? ((JArray)_params[4]).Select(p => new Signer() { Account = p.AsString().AddressToScriptHash(system.Settings.AddressVersion), Scopes = WitnessScope.CalledByEntry }).ToArray()
- : null;
- var tx = Result.Ok_Or(() => wallet.MakeTransaction(snapshot,
- [
- new TransferOutput
- {
- AssetId = assetId,
- Value = amount,
- ScriptHash = to
- }
- ], from, signers), RpcError.InvalidRequest.WithData("Can not process this request.")).NotNull_Or(RpcError.InsufficientFunds);
+ var amountDecimal = new BigDecimal(BigInteger.Parse(amount), descriptor.Decimals);
+ (amountDecimal.Sign > 0).True_Or(RpcErrorFactory.InvalidParams("Amount can't be negative."));
+
+ var calls = signers.ToSigners(WitnessScope.CalledByEntry);
+ var tx = Result.Ok_Or(
+ () => wallet.MakeTransaction(snapshot, [new() { AssetId = assetId, Value = amountDecimal, ScriptHash = to.ScriptHash }], from.ScriptHash, calls),
+ RpcError.InvalidRequest.WithData("Can not process this request.")).NotNull_Or(RpcError.InsufficientFunds);
var transContext = new ContractParametersContext(snapshot, tx, settings.Network);
wallet.Sign(transContext);
- if (!transContext.Completed)
- return transContext.ToJson();
+
+ if (!transContext.Completed) return transContext.ToJson();
tx.Witnesses = transContext.GetWitnesses();
if (tx.Size > 1024)
@@ -476,41 +455,46 @@ protected internal virtual JToken SendFrom(JArray _params)
protected internal virtual JToken SendMany(JArray _params)
{
CheckWallet();
- int to_start = 0;
+
+ int toStart = 0;
+ var addressVersion = system.Settings.AddressVersion;
UInt160 from = null;
if (_params[0] is JString)
{
- from = _params[0].AsString().AddressToScriptHash(system.Settings.AddressVersion);
- to_start = 1;
+ from = _params[0].AsString().AddressToScriptHash(addressVersion);
+ toStart = 1;
}
- JArray to = Result.Ok_Or(() => (JArray)_params[to_start], RpcError.InvalidParams.WithData($"Invalid 'to' parameter: {_params[to_start]}"));
+ JArray to = Result.Ok_Or(() => (JArray)_params[toStart], RpcError.InvalidParams.WithData($"Invalid 'to' parameter: {_params[toStart]}"));
(to.Count != 0).True_Or(RpcErrorFactory.InvalidParams("Argument 'to' can't be empty."));
- var signers = _params.Count >= to_start + 2
- ? ((JArray)_params[to_start + 1]).Select(p => new Signer() { Account = p.AsString().AddressToScriptHash(system.Settings.AddressVersion), Scopes = WitnessScope.CalledByEntry }).ToArray()
+ var signers = _params.Count >= toStart + 2
+ ? ((JArray)_params[toStart + 1])
+ .Select(p => new Signer() { Account = p.ToAddress(addressVersion).ScriptHash, Scopes = WitnessScope.CalledByEntry })
+ .ToArray()
: null;
- TransferOutput[] outputs = new TransferOutput[to.Count];
+ var outputs = new TransferOutput[to.Count];
using var snapshot = system.GetSnapshotCache();
for (int i = 0; i < to.Count; i++)
{
- UInt160 asset_id = UInt160.Parse(to[i]["asset"].AsString());
- AssetDescriptor descriptor = new(snapshot, system.Settings, asset_id);
+ var assetId = UInt160.Parse(to[i]["asset"].AsString());
+ var descriptor = new AssetDescriptor(snapshot, system.Settings, assetId);
outputs[i] = new TransferOutput
{
- AssetId = asset_id,
+ AssetId = assetId,
Value = new BigDecimal(BigInteger.Parse(to[i]["value"].AsString()), descriptor.Decimals),
ScriptHash = to[i]["address"].AsString().AddressToScriptHash(system.Settings.AddressVersion)
};
- (outputs[i].Value.Sign > 0).True_Or(RpcErrorFactory.InvalidParams($"Amount of '{asset_id}' can't be negative."));
+ (outputs[i].Value.Sign > 0).True_Or(RpcErrorFactory.InvalidParams($"Amount of '{assetId}' can't be negative."));
}
- Transaction tx = wallet.MakeTransaction(snapshot, outputs, from, signers).NotNull_Or(RpcError.InsufficientFunds);
- ContractParametersContext transContext = new(snapshot, tx, settings.Network);
+ var tx = wallet.MakeTransaction(snapshot, outputs, from, signers).NotNull_Or(RpcError.InsufficientFunds);
+ var transContext = new ContractParametersContext(snapshot, tx, settings.Network);
wallet.Sign(transContext);
- if (!transContext.Completed)
- return transContext.ToJson();
+
+ if (!transContext.Completed) return transContext.ToJson();
+
tx.Witnesses = transContext.GetWitnesses();
if (tx.Size > 1024)
{
@@ -551,35 +535,23 @@ protected internal virtual JToken SendMany(JArray _params)
/// }
/// }
///
- ///
- /// An array containing the following elements:
- /// [0]: The asset ID as a string.
- /// [1]: The to address as a string.
- /// [2]: The amount as a string.
- ///
+ /// The asset ID as a string.
+ /// The to address as a string.
+ /// The amount as a string.
/// The transaction details if successful, or the contract parameters if signatures are incomplete.
/// Thrown when no wallet is open, parameters are invalid, or there are insufficient funds.
[RpcMethod]
- protected internal virtual JToken SendToAddress(JArray _params)
+ protected internal virtual JToken SendToAddress(UInt160 assetId, Address to, string amount)
{
CheckWallet();
- var assetId = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()),
- RpcError.InvalidParams.WithData($"Invalid asset hash: {_params[0]}"));
- var to = _params[1].AsString().AddressToScriptHash(system.Settings.AddressVersion);
using var snapshot = system.GetSnapshotCache();
var descriptor = new AssetDescriptor(snapshot, system.Settings, assetId);
- var amount = new BigDecimal(BigInteger.Parse(_params[2].AsString()), descriptor.Decimals);
- (amount.Sign > 0).True_Or(RpcError.InvalidParams);
- var tx = wallet.MakeTransaction(snapshot,
- [
- new TransferOutput
- {
- AssetId = assetId,
- Value = amount,
- ScriptHash = to
- }
- ]).NotNull_Or(RpcError.InsufficientFunds);
+ var amountDecimal = new BigDecimal(BigInteger.Parse(amount), descriptor.Decimals);
+ (amountDecimal.Sign > 0).True_Or(RpcErrorFactory.InvalidParams("Amount can't be negative."));
+
+ var tx = wallet.MakeTransaction(snapshot, [new() { AssetId = assetId, Value = amountDecimal, ScriptHash = to.ScriptHash }])
+ .NotNull_Or(RpcError.InsufficientFunds);
var transContext = new ContractParametersContext(snapshot, tx, settings.Network);
wallet.Sign(transContext);
@@ -630,46 +602,43 @@ protected internal virtual JToken SendToAddress(JArray _params)
/// }
/// }
///
- ///
- /// An array containing the following elements:
- /// [0]: The transaction ID to cancel as a string.
- /// [1]: The signers as an array of strings.
- /// [2]: The extra fee as a string.
- ///
+ /// The transaction ID to cancel as a string.
+ /// The signers as an array of strings.
+ /// The extra fee as a string.
/// The details of the cancellation transaction.
///
/// Thrown when no wallet is open, the transaction is already confirmed, or there are insufficient funds for the cancellation fee.
///
[RpcMethod]
- protected internal virtual JToken CancelTransaction(JArray _params)
+ protected internal virtual JToken CancelTransaction(UInt256 txid, Address[] signers, string extraFee = null)
{
CheckWallet();
- var txid = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid txid: {_params[0]}"));
- NativeContract.Ledger.GetTransactionState(system.StoreView, txid).Null_Or(RpcErrorFactory.AlreadyExists("This tx is already confirmed, can't be cancelled."));
+ NativeContract.Ledger.GetTransactionState(system.StoreView, txid)
+ .Null_Or(RpcErrorFactory.AlreadyExists("This tx is already confirmed, can't be cancelled."));
+
+ if (signers is null || signers.Length == 0) throw new RpcException(RpcErrorFactory.BadRequest("No signer."));
var conflict = new TransactionAttribute[] { new Conflicts() { Hash = txid } };
- var signers = _params.Count >= 2
- ? ((JArray)_params[1]).Select(j => new Signer() { Account = j.AsString().AddressToScriptHash(system.Settings.AddressVersion), Scopes = WitnessScope.None }).ToArray()
- : [];
- signers.Any().True_Or(RpcErrorFactory.BadRequest("No signer."));
- Transaction tx = new Transaction
+ var noneSigners = signers.ToSigners(WitnessScope.None);
+ var tx = new Transaction
{
- Signers = signers,
+ Signers = noneSigners,
Attributes = conflict,
- Witnesses = Array.Empty(),
+ Witnesses = [],
};
- tx = Result.Ok_Or(() => wallet.MakeTransaction(system.StoreView, new[] { (byte)OpCode.RET }, signers[0].Account, signers, conflict), RpcError.InsufficientFunds, true);
-
- if (system.MemPool.TryGetValue(txid, out Transaction conflictTx))
+ tx = Result.Ok_Or(
+ () => wallet.MakeTransaction(system.StoreView, new[] { (byte)OpCode.RET }, noneSigners[0].Account, noneSigners, conflict),
+ RpcError.InsufficientFunds, true);
+ if (system.MemPool.TryGetValue(txid, out var conflictTx))
{
tx.NetworkFee = Math.Max(tx.NetworkFee, conflictTx.NetworkFee) + 1;
}
- else if (_params.Count >= 3)
+ else if (extraFee is not null)
{
- var extraFee = _params[2].AsString();
- AssetDescriptor descriptor = new(system.StoreView, system.Settings, NativeContract.GAS.Hash);
- (BigDecimal.TryParse(extraFee, descriptor.Decimals, out BigDecimal decimalExtraFee) && decimalExtraFee.Sign > 0).True_Or(RpcErrorFactory.InvalidParams("Incorrect amount format."));
+ var descriptor = new AssetDescriptor(system.StoreView, system.Settings, NativeContract.GAS.Hash);
+ (BigDecimal.TryParse(extraFee, descriptor.Decimals, out var decimalExtraFee) && decimalExtraFee.Sign > 0)
+ .True_Or(RpcErrorFactory.InvalidParams("Incorrect amount format."));
tx.NetworkFee += (long)decimalExtraFee.Value;
}
@@ -715,29 +684,19 @@ protected internal virtual JToken CancelTransaction(JArray _params)
/// }
/// }
///
- ///
- /// An array containing the following elements:
- /// [0]: The script hash as a string.
- /// [1]: The arguments as an array of strings.
- /// [2]: The JSON array of signers and witnesses. Optional.
- ///
+ /// The script hash as a string.
+ /// The arguments as an array of strings.
+ /// The JSON array of signers and witnesses. Optional.
/// A JSON object containing the result of the verification.
///
/// Thrown when the script hash is invalid, the contract is not found, or the verification fails.
///
[RpcMethod]
- protected internal virtual JToken InvokeContractVerify(JArray _params)
+ protected internal virtual JToken InvokeContractVerify(UInt160 scriptHash,
+ ContractParameter[] args = null, SignersAndWitnesses signersAndWitnesses = default)
{
- var scriptHash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()),
- RpcError.InvalidParams.WithData($"Invalid script hash: {_params[0]}"));
-
- var args = _params.Count >= 2
- ? ((JArray)_params[1]).Select(p => ContractParameter.FromJson((JObject)p)).ToArray()
- : [];
-
- var (signers, witnesses) = _params.Count >= 3
- ? ((JArray)_params[2]).ToSignersAndWitnesses(system.Settings.AddressVersion)
- : default;
+ args ??= [];
+ var (signers, witnesses) = signersAndWitnesses;
return GetVerificationResult(scriptHash, args, signers, witnesses);
}
@@ -752,17 +711,24 @@ protected internal virtual JToken InvokeContractVerify(JArray _params)
private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] args, Signer[] signers = null, Witness[] witnesses = null)
{
using var snapshot = system.GetSnapshotCache();
- var contract = NativeContract.ContractManagement.GetContract(snapshot, scriptHash).NotNull_Or(RpcError.UnknownContract);
- var md = contract.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, args.Count()).NotNull_Or(RpcErrorFactory.InvalidContractVerification(contract.Hash, args.Count()));
- (md.ReturnType == ContractParameterType.Boolean).True_Or(RpcErrorFactory.InvalidContractVerification("The verify method doesn't return boolean value."));
- Transaction tx = new()
+ var contract = NativeContract.ContractManagement.GetContract(snapshot, scriptHash)
+ .NotNull_Or(RpcError.UnknownContract);
+
+ var md = contract.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, args.Count())
+ .NotNull_Or(RpcErrorFactory.InvalidContractVerification(contract.Hash, args.Count()));
+
+ (md.ReturnType == ContractParameterType.Boolean)
+ .True_Or(RpcErrorFactory.InvalidContractVerification("The verify method doesn't return boolean value."));
+
+ var tx = new Transaction
{
- Signers = signers ?? new Signer[] { new() { Account = scriptHash } },
- Attributes = Array.Empty(),
+ Signers = signers ?? [new() { Account = scriptHash }],
+ Attributes = [],
Witnesses = witnesses,
Script = new[] { (byte)OpCode.RET }
};
- using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CloneCache(), settings: system.Settings);
+
+ using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CloneCache(), settings: system.Settings);
engine.LoadContract(contract, md, CallFlags.ReadOnly);
var invocationScript = Array.Empty();
@@ -773,15 +739,19 @@ private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] ar
sb.EmitPush(args[i]);
invocationScript = sb.ToArray();
- tx.Witnesses ??= new Witness[] { new() { InvocationScript = invocationScript } };
+ tx.Witnesses ??= [new() { InvocationScript = invocationScript }];
engine.LoadScript(new Script(invocationScript), configureState: p => p.CallFlags = CallFlags.None);
}
- JObject json = new();
- json["script"] = Convert.ToBase64String(invocationScript);
- json["state"] = engine.Execute();
- // Gas consumed in the unit of datoshi, 1 GAS = 1e8 datoshi
- json["gasconsumed"] = engine.FeeConsumed.ToString();
- json["exception"] = GetExceptionMessage(engine.FaultException);
+
+ var json = new JObject()
+ {
+ ["script"] = Convert.ToBase64String(invocationScript),
+ ["state"] = engine.Execute(),
+ // Gas consumed in the unit of datoshi, 1 GAS = 1e8 datoshi
+ ["gasconsumed"] = engine.FeeConsumed.ToString(),
+ ["exception"] = GetExceptionMessage(engine.FaultException)
+ };
+
try
{
json["stack"] = new JArray(engine.ResultStack.Select(p => p.ToJson(settings.MaxStackSize)));
@@ -801,7 +771,7 @@ private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] ar
/// A JSON object containing the transaction details.
private JObject SignAndRelay(DataCache snapshot, Transaction tx)
{
- ContractParametersContext context = new(snapshot, tx, settings.Network);
+ var context = new ContractParametersContext(snapshot, tx, settings.Network);
wallet.Sign(context);
if (context.Completed)
{
diff --git a/src/Plugins/RpcServer/RpcServer.cs b/src/Plugins/RpcServer/RpcServer.cs
index 63968ee5d2..2d72e95b62 100644
--- a/src/Plugins/RpcServer/RpcServer.cs
+++ b/src/Plugins/RpcServer/RpcServer.cs
@@ -28,7 +28,6 @@
using System.Net.Security;
using System.Reflection;
using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Address = Neo.Plugins.RpcServer.Model.Address;
@@ -66,6 +65,7 @@ public RpcServer(NeoSystem system, RpcServersSettings settings)
// An address can be either UInt160 or Base58Check format.
// If only UInt160 format is allowed, use UInt160 as parameter type.
ParameterConverter.RegisterConversion(token => token.ToAddress(addressVersion));
+ ParameterConverter.RegisterConversion(token => token.ToAddresses(addressVersion));
localNode = system.LocalNode.Ask(new LocalNode.GetInstance()).Result;
RegisterMethods(this);
diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs
index f0870c680a..eab4dd3ba2 100644
--- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs
+++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs
@@ -17,7 +17,6 @@
using Neo.SmartContract;
using Neo.SmartContract.Native;
using Neo.UnitTests;
-using Neo.UnitTests.Extensions;
using Neo.VM;
using Neo.Wallets;
using System;
@@ -59,8 +58,7 @@ public void TestOpenWallet()
const string Password = "123456";
File.WriteAllText(Path, WalletJson);
- var paramsArray = new JArray(Path, Password);
- var res = _rpcServer.OpenWallet(paramsArray);
+ var res = _rpcServer.OpenWallet(Path, Password);
Assert.IsTrue(res.AsBoolean());
Assert.IsNotNull(_rpcServer.wallet);
Assert.AreEqual("NVizn8DiExdmnpTQfjiVY3dox8uXg3Vrxv", _rpcServer.wallet.GetAccounts().FirstOrDefault()!.Address);
@@ -77,20 +75,26 @@ public void TestOpenInvalidWallet()
const string Password = "password";
File.Delete(Path);
- var paramsArray = new JArray(Path, Password);
- var exception = Assert.ThrowsExactly(() => _ = _rpcServer.OpenWallet(paramsArray), "Should throw RpcException for unsupported wallet");
+ var exception = Assert.ThrowsExactly(
+ () => _ = _rpcServer.OpenWallet(Path, Password),
+ "Should throw RpcException for unsupported wallet");
Assert.AreEqual(RpcError.WalletNotFound.Code, exception.HResult);
File.WriteAllText(Path, "{}");
- exception = Assert.ThrowsExactly(() => _ = _rpcServer.OpenWallet(paramsArray), "Should throw RpcException for unsupported wallet");
+ exception = Assert.ThrowsExactly(
+ () => _ = _rpcServer.OpenWallet(Path, Password),
+ "Should throw RpcException for unsupported wallet");
File.Delete(Path);
Assert.AreEqual(RpcError.WalletNotSupported.Code, exception.HResult);
+
var result = _rpcServer.CloseWallet();
Assert.IsTrue(result.AsBoolean());
Assert.IsNull(_rpcServer.wallet);
File.WriteAllText(Path, WalletJson);
- exception = Assert.ThrowsExactly(() => _ = _rpcServer.OpenWallet(paramsArray), "Should throw RpcException for unsupported wallet");
+ exception = Assert.ThrowsExactly(
+ () => _ = _rpcServer.OpenWallet(Path, Password),
+ "Should throw RpcException for unsupported wallet");
Assert.AreEqual(RpcError.WalletNotSupported.Code, exception.HResult);
Assert.AreEqual("Wallet not supported - Invalid password.", exception.Message);
File.Delete(Path);
@@ -102,9 +106,10 @@ public void TestDumpPrivKey()
TestUtilOpenWallet();
var account = _rpcServer.wallet.GetAccounts().FirstOrDefault();
Assert.IsNotNull(account);
+
var privKey = account.GetKey().Export();
var address = account.Address;
- var result = _rpcServer.DumpPrivKey(new JArray(address));
+ var result = _rpcServer.DumpPrivKey(new JString(address).ToAddress(ProtocolSettings.Default.AddressVersion));
Assert.AreEqual(privKey, result.AsString());
TestUtilCloseWallet();
}
@@ -117,9 +122,9 @@ public void TestDumpPrivKey_AddressNotInWallet()
var key = new KeyPair(RandomNumberGenerator.GetBytes(32));
// Correct way to get ScriptHash from PublicKey
var scriptHashNotInWallet = Contract.CreateSignatureRedeemScript(key.PublicKey).ToScriptHash();
- var addressNotInWallet = scriptHashNotInWallet.ToAddress(ProtocolSettings.Default.AddressVersion);
+ var notFound = scriptHashNotInWallet.ToAddress(ProtocolSettings.Default.AddressVersion);
- var ex = Assert.ThrowsExactly(() => _rpcServer.DumpPrivKey(new JArray(addressNotInWallet)));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.DumpPrivKey(new JString(notFound).AsParameter()));
Assert.AreEqual(RpcError.UnknownAccount.Code, ex.HResult);
Assert.Contains($"Unknown account - {scriptHashNotInWallet}", ex.Message);
TestUtilCloseWallet();
@@ -130,7 +135,7 @@ public void TestDumpPrivKey_InvalidAddressFormat()
{
TestUtilOpenWallet();
var invalidAddress = "NotAValidAddress";
- var ex = Assert.ThrowsExactly(() => _rpcServer.DumpPrivKey(new JArray(invalidAddress)));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.DumpPrivKey(new JString(invalidAddress).AsParameter()));
TestUtilCloseWallet();
}
@@ -149,9 +154,9 @@ public void TestGetWalletBalance()
{
TestUtilOpenWallet();
var assetId = NativeContract.NEO.Hash;
- var paramsArray = new JArray(assetId.ToString());
- var result = _rpcServer.GetWalletBalance(paramsArray);
+ var result = _rpcServer.GetWalletBalance(assetId);
Assert.IsInstanceOfType(result, typeof(JObject));
+
var json = (JObject)result;
Assert.IsTrue(json.ContainsProperty("balance"));
TestUtilCloseWallet();
@@ -162,9 +167,9 @@ public void TestGetWalletBalanceInvalidAsset()
{
TestUtilOpenWallet();
var assetId = UInt160.Zero;
- var paramsArray = new JArray(assetId.ToString());
- var result = _rpcServer.GetWalletBalance(paramsArray);
+ var result = _rpcServer.GetWalletBalance(assetId);
Assert.IsInstanceOfType(result, typeof(JObject));
+
var json = (JObject)result;
Assert.IsTrue(json.ContainsProperty("balance"));
TestUtilCloseWallet();
@@ -175,11 +180,10 @@ public void TestGetWalletBalance_InvalidAssetIdFormat()
{
TestUtilOpenWallet();
var invalidAssetId = "NotAValidAssetID";
- var paramsArray = new JArray(invalidAssetId);
- var ex = Assert.ThrowsExactly(() => _rpcServer.GetWalletBalance(paramsArray));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.GetWalletBalance(new JString(invalidAssetId).AsParameter()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
- Assert.Contains("Invalid asset id", ex.Message);
+ Assert.Contains("Invalid UInt160", ex.Message);
TestUtilCloseWallet();
}
@@ -197,9 +201,9 @@ public void TestImportPrivKey()
{
TestUtilOpenWallet();
var privKey = _walletAccount.GetKey().Export();
- var paramsArray = new JArray(privKey);
- var result = _rpcServer.ImportPrivKey(paramsArray);
+ var result = _rpcServer.ImportPrivKey(privKey);
Assert.IsInstanceOfType(result, typeof(JObject));
+
var json = (JObject)result;
Assert.IsTrue(json.ContainsProperty("address"));
Assert.IsTrue(json.ContainsProperty("haskey"));
@@ -212,8 +216,7 @@ public void TestImportPrivKey()
public void TestImportPrivKeyNoWallet()
{
var privKey = _walletAccount.GetKey().Export();
- var paramsArray = new JArray(privKey);
- var exception = Assert.ThrowsExactly(() => _ = _rpcServer.ImportPrivKey(paramsArray));
+ var exception = Assert.ThrowsExactly(() => _ = _rpcServer.ImportPrivKey(privKey));
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
}
@@ -222,10 +225,9 @@ public void TestImportPrivKey_InvalidWIF()
{
TestUtilOpenWallet();
var invalidWif = "ThisIsAnInvalidWIFString";
- var paramsArray = new JArray(invalidWif);
// Expect FormatException during WIF decoding
- var ex = Assert.ThrowsExactly(() => _rpcServer.ImportPrivKey(paramsArray));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.ImportPrivKey(invalidWif));
TestUtilCloseWallet();
}
@@ -237,10 +239,9 @@ public void TestImportPrivKey_KeyAlreadyExists()
// Get a key already in the default test wallet
var existingAccount = _rpcServer.wallet.GetAccounts().First(a => a.HasKey);
var existingWif = existingAccount.GetKey().Export();
- var paramsArray = new JArray(existingWif);
// Import the existing key
- var result = (JObject)_rpcServer.ImportPrivKey(paramsArray);
+ var result = (JObject)_rpcServer.ImportPrivKey(existingWif);
// Verify the returned account details match the existing one
Assert.AreEqual(existingAccount.Address, result["address"].AsString());
@@ -260,9 +261,7 @@ public void TestCalculateNetworkFee()
{
var snapshot = _neoSystem.GetSnapshotCache();
var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount);
- var txBase64 = Convert.ToBase64String(tx.ToArray());
- var paramsArray = new JArray(txBase64);
- var result = _rpcServer.CalculateNetworkFee(paramsArray);
+ var result = _rpcServer.CalculateNetworkFee(tx.ToArray());
Assert.IsInstanceOfType(result, typeof(JObject));
var json = (JObject)result;
@@ -299,11 +298,12 @@ public void TestListAddress()
public void TestSendFromNoWallet()
{
var assetId = NativeContract.GAS.Hash;
- var from = _walletAccount.Address;
- var to = _walletAccount.Address;
+ var from = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
+ var to = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var amount = "1";
- var paramsArray = new JArray(assetId.ToString(), from, to, amount);
- var exception = Assert.ThrowsExactly(() => _ = _rpcServer.SendFrom(paramsArray), "Should throw RpcException for insufficient funds");
+ var exception = Assert.ThrowsExactly(
+ () => _ = _rpcServer.SendFrom(assetId, from, to, amount),
+ "Should throw RpcException for insufficient funds");
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
}
@@ -311,20 +311,22 @@ public void TestSendFromNoWallet()
public void TestSendFrom()
{
TestUtilOpenWallet();
+
var assetId = NativeContract.GAS.Hash;
- var from = _walletAccount.Address;
- var to = _walletAccount.Address;
+ var from = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
+ var to = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var amount = "1";
- var paramsArray = new JArray(assetId.ToString(), from, to, amount);
- var exception = Assert.ThrowsExactly(() => _ = _rpcServer.SendFrom(paramsArray));
+ var exception = Assert.ThrowsExactly(() => _ = _rpcServer.SendFrom(assetId, from, to, amount));
Assert.AreEqual(exception.HResult, RpcError.InvalidRequest.Code);
+
TestUtilCloseWallet();
_rpcServer.wallet = _wallet;
- JObject resp = (JObject)_rpcServer.SendFrom(paramsArray);
+ var resp = (JObject)_rpcServer.SendFrom(assetId, from, to, amount);
Assert.AreEqual(12, resp.Count);
Assert.AreEqual(resp["sender"], ValidatorAddress);
- JArray signers = (JArray)resp["signers"];
+
+ var signers = (JArray)resp["signers"];
Assert.HasCount(1, signers);
Assert.AreEqual(signers[0]["account"], ValidatorScriptHash.ToString());
Assert.AreEqual(nameof(WitnessScope.CalledByEntry), signers[0]["scopes"]);
@@ -338,15 +340,18 @@ public void TestSendMany()
var to = new JArray {
new JObject { ["asset"] = NativeContract.GAS.Hash.ToString(), ["value"] = "1", ["address"] = _walletAccount.Address }
};
- var paramsArray = new JArray(from, to);
- var exception = Assert.ThrowsExactly(() => _ = _rpcServer.SendMany(paramsArray), "Should throw RpcException for insufficient funds");
+
+ var exception = Assert.ThrowsExactly(
+ () => _ = _rpcServer.SendMany(new JArray(from, to)),
+ "Should throw RpcException for insufficient funds");
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
_rpcServer.wallet = _wallet;
- JObject resp = (JObject)_rpcServer.SendMany(paramsArray);
+ var resp = (JObject)_rpcServer.SendMany(new JArray(from, to));
Assert.AreEqual(12, resp.Count);
Assert.AreEqual(resp["sender"], ValidatorAddress);
- JArray signers = (JArray)resp["signers"];
+
+ var signers = (JArray)resp["signers"];
Assert.HasCount(1, signers);
Assert.AreEqual(signers[0]["account"], ValidatorScriptHash.ToString());
Assert.AreEqual(nameof(WitnessScope.CalledByEntry), signers[0]["scopes"]);
@@ -357,17 +362,19 @@ public void TestSendMany()
public void TestSendToAddress()
{
var assetId = NativeContract.GAS.Hash;
- var to = _walletAccount.Address;
+ var to = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var amount = "1";
- var paramsArray = new JArray(assetId.ToString(), to, amount);
- var exception = Assert.ThrowsExactly(() => _ = _rpcServer.SendToAddress(paramsArray), "Should throw RpcException for insufficient funds");
+ var exception = Assert.ThrowsExactly(
+ () => _ = _rpcServer.SendToAddress(assetId, to, amount),
+ "Should throw RpcException for insufficient funds");
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
_rpcServer.wallet = _wallet;
- JObject resp = (JObject)_rpcServer.SendToAddress(paramsArray);
+ var resp = (JObject)_rpcServer.SendToAddress(assetId, to, amount);
Assert.AreEqual(12, resp.Count);
Assert.AreEqual(resp["sender"], ValidatorAddress);
- JArray signers = (JArray)resp["signers"];
+
+ var signers = (JArray)resp["signers"];
Assert.HasCount(1, signers);
Assert.AreEqual(signers[0]["account"], ValidatorScriptHash.ToString());
Assert.AreEqual(nameof(WitnessScope.CalledByEntry), signers[0]["scopes"]);
@@ -379,13 +386,13 @@ public void TestSendToAddress_InvalidAssetId()
{
TestUtilOpenWallet();
var invalidAssetId = "NotAnAssetId";
- var to = _walletAccount.Address;
+ var to = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var amount = "1";
- var paramsArray = new JArray(invalidAssetId, to, amount);
- var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(paramsArray));
+ var ex = Assert.ThrowsExactly(
+ () => _rpcServer.SendToAddress(new JString(invalidAssetId).AsParameter(), to, amount));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
- Assert.Contains("Invalid asset hash", ex.Message);
+ Assert.Contains("Invalid UInt160", ex.Message);
TestUtilCloseWallet();
}
@@ -396,10 +403,12 @@ public void TestSendToAddress_InvalidToAddress()
var assetId = NativeContract.GAS.Hash;
var invalidToAddress = "NotAnAddress";
var amount = "1";
- var paramsArray = new JArray(assetId.ToString(), invalidToAddress, amount);
- var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(paramsArray));
+ var ex = Assert.ThrowsExactly(
+ () => _rpcServer.SendToAddress(assetId, new JString(invalidToAddress).AsParameter(), amount));
+
// Expect FormatException from AddressToScriptHash
+ Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
TestUtilCloseWallet();
}
@@ -408,11 +417,10 @@ public void TestSendToAddress_NegativeAmount()
{
TestUtilOpenWallet();
var assetId = NativeContract.GAS.Hash;
- var to = _walletAccount.Address;
+ var to = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var amount = "-1";
- var paramsArray = new JArray(assetId.ToString(), to, amount);
- var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(paramsArray));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(assetId, to, amount));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
TestUtilCloseWallet();
}
@@ -422,11 +430,10 @@ public void TestSendToAddress_ZeroAmount()
{
TestUtilOpenWallet();
var assetId = NativeContract.GAS.Hash;
- var to = _walletAccount.Address;
+ var to = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var amount = "0";
- var paramsArray = new JArray(assetId.ToString(), to, amount);
- var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(paramsArray));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(assetId, to, amount));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
// Implementation checks amount.Sign > 0
TestUtilCloseWallet();
@@ -437,13 +444,13 @@ public void TestSendToAddress_InsufficientFunds()
{
TestUtilOpenWallet();
var assetId = NativeContract.GAS.Hash;
- var to = _walletAccount.Address;
+
+ var to = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var hugeAmount = "100000000000000000"; // Exceeds likely balance
- var paramsArray = new JArray(assetId.ToString(), to, hugeAmount);
// With a huge amount, MakeTransaction might throw InvalidOperationException internally
// before returning null to trigger the InsufficientFunds RpcException.
- var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(paramsArray));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.SendToAddress(assetId, to, hugeAmount));
TestUtilCloseWallet();
}
@@ -455,9 +462,8 @@ public void TestSendMany_InvalidFromAddress()
var to = new JArray {
new JObject { ["asset"] = NativeContract.GAS.Hash.ToString(), ["value"] = "1", ["address"] = _walletAccount.Address }
};
- var paramsArray = new JArray(invalidFrom, to);
- var ex = Assert.ThrowsExactly(() => _rpcServer.SendMany(paramsArray));
+ var ex = Assert.ThrowsExactly(() => _rpcServer.SendMany(new JArray(invalidFrom, to)));
TestUtilCloseWallet();
}
@@ -488,7 +494,7 @@ public void TestDumpPrivKey_WhenWalletNotOpen()
{
_rpcServer.wallet = null;
var exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.DumpPrivKey(new JArray(_walletAccount.Address)),
+ () => _ = _rpcServer.DumpPrivKey(new JString(_walletAccount.Address).AsParameter()),
"Should throw RpcException for no opened wallet");
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
}
@@ -508,7 +514,7 @@ public void TestGetWalletBalance_WhenWalletNotOpen()
{
_rpcServer.wallet = null;
var exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.GetWalletBalance(new JArray(NativeContract.NEO.Hash.ToString())),
+ () => _ = _rpcServer.GetWalletBalance(NativeContract.NEO.Hash),
"Should throw RpcException for no opened wallet");
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
}
@@ -529,7 +535,7 @@ public void TestImportPrivKey_WhenWalletNotOpen()
_rpcServer.wallet = null;
var privKey = _walletAccount.GetKey().Export();
var exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.ImportPrivKey(new JArray(privKey)),
+ () => _ = _rpcServer.ImportPrivKey(privKey),
"Should throw RpcException for no opened wallet");
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
}
@@ -538,9 +544,8 @@ public void TestImportPrivKey_WhenWalletNotOpen()
public void TestCalculateNetworkFee_InvalidTransactionFormat()
{
var invalidTxBase64 = "invalid_base64";
- var paramsArray = new JArray(invalidTxBase64);
var exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.CalculateNetworkFee(paramsArray),
+ () => _ = _rpcServer.CalculateNetworkFee(invalidTxBase64.ToStrictUtf8Bytes()),
"Should throw RpcException for invalid transaction format");
Assert.AreEqual(exception.HResult, RpcError.InvalidParams.Code);
}
@@ -563,49 +568,50 @@ public void TestListAddress_WhenWalletNotOpen()
public void TestCancelTransaction()
{
TestUtilOpenWallet();
+
var snapshot = _neoSystem.GetSnapshotCache();
var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount);
snapshot.Commit();
- var paramsArray = new JArray(tx.Hash.ToString(), new JArray(_walletAccount.Address));
+ var address = new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion);
var exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.CancelTransaction(paramsArray),
+ () => _ = _rpcServer.CancelTransaction(tx.Hash, [address]),
"Should throw RpcException for non-existing transaction");
Assert.AreEqual(RpcError.InsufficientFunds.Code, exception.HResult);
// Test with invalid transaction id
- var invalidParamsArray = new JArray("invalid_txid", new JArray(_walletAccount.Address));
+ var invalidTxHash = "invalid_txid";
exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.CancelTransaction(invalidParamsArray),
+ () => _ = _rpcServer.CancelTransaction(new JString(invalidTxHash).AsParameter(), [address]),
"Should throw RpcException for invalid txid");
Assert.AreEqual(exception.HResult, RpcError.InvalidParams.Code);
// Test with no signer
- invalidParamsArray = new JArray(tx.Hash.ToString());
exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.CancelTransaction(invalidParamsArray),
+ () => _ = _rpcServer.CancelTransaction(tx.Hash, []),
"Should throw RpcException for invalid txid");
Assert.AreEqual(exception.HResult, RpcError.BadRequest.Code);
// Test with null wallet
_rpcServer.wallet = null;
exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.CancelTransaction(paramsArray),
+ () => _ = _rpcServer.CancelTransaction(tx.Hash, [address]),
"Should throw RpcException for no opened wallet");
Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code);
TestUtilCloseWallet();
// Test valid cancel
_rpcServer.wallet = _wallet;
- var resp = (JObject)_rpcServer.SendFrom([
- NativeContract.GAS.Hash.ToString(),
- _walletAccount.Address,
- _walletAccount.Address,
+ var resp = (JObject)_rpcServer.SendFrom(
+ NativeContract.GAS.Hash,
+ new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion),
+ new Address(_walletAccount.ScriptHash, ProtocolSettings.Default.AddressVersion),
"1"
- ]);
+ );
- var txHash = resp["hash"].AsString();
- resp = (JObject)_rpcServer.CancelTransaction(new JArray(txHash, new JArray(ValidatorAddress), "1"));
+ var txHash = resp["hash"];
+ resp = (JObject)_rpcServer.CancelTransaction(
+ txHash.AsParameter(), new JArray(ValidatorAddress).AsParameter(), "1");
Assert.AreEqual(12, resp.Count);
Assert.AreEqual(resp["sender"], ValidatorAddress);
@@ -621,16 +627,14 @@ public void TestCancelTransaction()
public void TestInvokeContractVerify()
{
var scriptHash = UInt160.Parse("0x70cde1619e405cdef363ab66a1e8dce430d798d5");
- var paramsArray = new JArray(scriptHash.ToString());
var exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.InvokeContractVerify(paramsArray),
+ () => _ = _rpcServer.InvokeContractVerify(scriptHash),
"Should throw RpcException for unknown contract");
Assert.AreEqual(exception.HResult, RpcError.UnknownContract.Code);
// Test with invalid script hash
- var invalidParamsArray = new JArray("invalid_script_hash");
exception = Assert.ThrowsExactly(
- () => _ = _rpcServer.InvokeContractVerify(invalidParamsArray),
+ () => _ = _rpcServer.InvokeContractVerify(new JString("invalid_script_hash").AsParameter()),
"Should throw RpcException for invalid script hash");
Assert.AreEqual(exception.HResult, RpcError.InvalidParams.Code);
@@ -700,43 +704,47 @@ public void TestInvokeContractVerify()
engine.SnapshotCache.Commit();
// invoke verify without signer; should return false
- JObject resp = (JObject)_rpcServer.InvokeContractVerify([deployedScriptHash.ToString()]);
- Assert.AreEqual(nameof(VMState.HALT), resp["state"]);
- Assert.IsFalse(resp["stack"][0]["value"].AsBoolean());
+ var resp = (JObject)_rpcServer.InvokeContractVerify(deployedScriptHash);
+ Assert.AreEqual(resp["state"], nameof(VMState.HALT));
+ Assert.AreEqual(false, resp["stack"][0]["value"].AsBoolean());
// invoke verify with signer; should return true
- resp = (JObject)_rpcServer.InvokeContractVerify([deployedScriptHash.ToString(), new JArray([]), validatorSigner]);
- Assert.AreEqual(nameof(VMState.HALT), resp["state"]);
- Assert.IsTrue(resp["stack"][0]["value"].AsBoolean());
+ resp = (JObject)_rpcServer.InvokeContractVerify(deployedScriptHash, [], validatorSigner.AsParameter());
+ Assert.AreEqual(resp["state"], nameof(VMState.HALT));
+ Assert.AreEqual(true, resp["stack"][0]["value"].AsBoolean());
// invoke verify with wrong input value; should FAULT
- resp = (JObject)_rpcServer.InvokeContractVerify([
- deployedScriptHash.ToString(),
- new JArray([new JObject() { ["type"] = nameof(ContractParameterType.Integer), ["value"] = "0" }]),
- validatorSigner
- ]);
- Assert.AreEqual(nameof(VMState.FAULT), resp["state"]);
- Assert.AreEqual("Object reference not set to an instance of an object.", resp["exception"]);
+ resp = (JObject)_rpcServer.InvokeContractVerify(
+ deployedScriptHash,
+ new JArray([
+ new JObject() { ["type"] = nameof(ContractParameterType.Integer), ["value"] = "0" }
+ ]).AsParameter(),
+ validatorSigner.AsParameter()
+ );
+ Assert.AreEqual(resp["state"], nameof(VMState.FAULT));
+ Assert.AreEqual(resp["exception"], "Object reference not set to an instance of an object.");
// invoke verify with 1 param and signer; should return true
- resp = (JObject)_rpcServer.InvokeContractVerify([
+ resp = (JObject)_rpcServer.InvokeContractVerify(
deployedScriptHash.ToString(),
- new JArray([new JObject() { ["type"] = nameof(ContractParameterType.Integer), ["value"] = "32" }]),
- validatorSigner,
- ]);
- Assert.AreEqual(nameof(VMState.HALT), resp["state"]);
- Assert.IsTrue(resp["stack"][0]["value"].AsBoolean());
+ new JArray([
+ new JObject() { ["type"] = nameof(ContractParameterType.Integer), ["value"] = "32" }
+ ]).AsParameter(),
+ validatorSigner.AsParameter()
+ );
+ Assert.AreEqual(resp["state"], nameof(VMState.HALT));
+ Assert.AreEqual(true, resp["stack"][0]["value"].AsBoolean());
// invoke verify with 2 param (which does not exist); should throw Exception
Assert.ThrowsExactly(
- () => _ = _rpcServer.InvokeContractVerify([
+ () => _ = _rpcServer.InvokeContractVerify(
deployedScriptHash.ToString(),
new JArray([
new JObject() { ["type"] = nameof(ContractParameterType.Integer), ["value"] = "32" },
new JObject() { ["type"] = nameof(ContractParameterType.Integer), ["value"] = "32" }
- ]),
- validatorSigner
- ]),
+ ]).AsParameter(),
+ validatorSigner.AsParameter()
+ ),
$"Invalid contract verification function - The smart contract {deployedScriptHash} haven't got verify method with 2 input parameters.",
[]
);
@@ -750,8 +758,7 @@ private void TestUtilOpenWallet([CallerMemberName] string callerMemberName = "")
var path = $"wallet_{callerMemberName}.json";
File.WriteAllText(path, WalletJson);
- var paramsArray = new JArray(path, Password);
- _rpcServer.OpenWallet(paramsArray);
+ _rpcServer.OpenWallet(path, Password);
}
private void TestUtilCloseWallet()
@@ -761,26 +768,5 @@ private void TestUtilCloseWallet()
_rpcServer.CloseWallet();
File.Delete(Path);
}
-
- private UInt160 TestUtilAddTestContract()
- {
- var state = TestUtils.GetContract();
- var storageKey = new StorageKey
- {
- Id = state.Id,
- Key = new byte[] { 0x01 }
- };
-
- var storageItem = new StorageItem
- {
- Value = new byte[] { 0x01, 0x02, 0x03, 0x04 }
- };
-
- var snapshot = _neoSystem.GetSnapshotCache();
- snapshot.AddContract(state.Hash, state);
- snapshot.Add(storageKey, storageItem);
- snapshot.Commit();
- return state.Hash;
- }
}
}