Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions src/Plugins/RpcServer/RpcException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.Json;
using System;

namespace Neo.Plugins.RpcServer
Expand Down Expand Up @@ -39,5 +40,17 @@ public static void ThrowIfNull<T>(T value, string paramName, RpcError error)
{
if (value is null) throw new RpcException(error.WithData($"Parameter '{paramName}' is null"));
}

/// <summary>
/// Throws an exception if the number of parameters is less than the required number.
/// </summary>
/// <param name="params">The parameters to check.</param>
/// <param name="requiredArgs">The required number of parameters.</param>
/// <param name="error">The error code to throw.</param>
public static void ThrowIfTooFew(JArray @params, int requiredArgs, RpcError error)
{
if ((@params is null && requiredArgs > 0) || (@params is not null && @params.Count < requiredArgs))
throw new RpcException(error.WithData($"Too few arguments. Expected at least {requiredArgs} but got {@params?.Count ?? 0}."));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this type of exception messgae is too general, would be better to specify which is missing for dedicated rpc methods. but better than nothing.

}
}
}
11 changes: 10 additions & 1 deletion src/Plugins/RpcServer/RpcServer.SmartContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ private static JObject ToJson(StackItem item, Session session)
[RpcMethod]
protected internal virtual JToken InvokeFunction(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 2, RpcError.InvalidParams); // ScriptHash, Operation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

params ? _params[2]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does params ? _params[2] mean?


var scriptHash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()),
RpcError.InvalidParams.WithData($"Invalid script hash `{_params[0]}`"));

Expand Down Expand Up @@ -327,6 +329,8 @@ protected internal virtual JToken InvokeFunction(JArray _params)
[RpcMethod]
protected internal virtual JToken InvokeScript(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // Script

var script = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()), RpcError.InvalidParams);
var (signers, witnesses) = _params.Count >= 2
? ((JArray)_params[1]).ToSignersAndWitnesses(system.Settings.AddressVersion)
Expand Down Expand Up @@ -360,6 +364,8 @@ protected internal virtual JToken InvokeScript(JArray _params)
protected internal virtual JToken TraverseIterator(JArray _params)
{
settings.SessionEnabled.True_Or(RpcError.SessionsDisabled);
RpcException.ThrowIfTooFew(_params, 3, RpcError.InvalidParams); // SessionId, IteratorId, Count

Guid sid = Result.Ok_Or(() => Guid.Parse(_params[0].GetString()), RpcError.InvalidParams.WithData($"Invalid session id {nameof(sid)}"));
Guid iid = Result.Ok_Or(() => Guid.Parse(_params[1].GetString()), RpcError.InvalidParams.WithData($"Invliad iterator id {nameof(iid)}"));
int count = _params[2].GetInt32();
Expand Down Expand Up @@ -400,8 +406,9 @@ protected internal virtual JToken TraverseIterator(JArray _params)
protected internal virtual JToken TerminateSession(JArray _params)
{
settings.SessionEnabled.True_Or(RpcError.SessionsDisabled);
Guid sid = Result.Ok_Or(() => Guid.Parse(_params[0].GetString()), RpcError.InvalidParams.WithData("Invalid session id"));
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // SessionId

var sid = Result.Ok_Or(() => Guid.Parse(_params[0].GetString()), RpcError.InvalidParams.WithData("Invalid session id"));
Session session = null;
bool result;
lock (sessions)
Expand Down Expand Up @@ -438,6 +445,8 @@ protected internal virtual JToken TerminateSession(JArray _params)
[RpcMethod]
protected internal virtual JToken GetUnclaimedGas(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // Address

var address = Result.Ok_Or(() => _params[0].AsString(),
RpcError.InvalidParams.WithData($"Invalid address `{_params[0]}`"));
var json = new JObject();
Expand Down
2 changes: 2 additions & 0 deletions src/Plugins/RpcServer/RpcServer.Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ protected internal virtual JToken ListPlugins(JArray _params)
[RpcMethod]
protected internal virtual JToken ValidateAddress(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // Address

string address = Result.Ok_Or(() => _params[0].AsString(), RpcError.InvalidParams.WithData($"Invlid address format: {_params[0]}"));
UInt160 scriptHash;
try
Expand Down
23 changes: 19 additions & 4 deletions src/Plugins/RpcServer/RpcServer.Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ protected internal virtual JToken CloseWallet(JArray _params)
[RpcMethod]
protected internal virtual JToken DumpPrivKey(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // Address
CheckWallet();

var scriptHash = _params[0].AsString().AddressToScriptHash(system.Settings.AddressVersion);
var account = wallet.GetAccount(scriptHash);
return account.GetKey().Export();
Expand Down Expand Up @@ -133,7 +135,9 @@ protected internal virtual JToken GetNewAddress(JArray _params)
[RpcMethod]
protected internal virtual JToken GetWalletBalance(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // 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();
Expand Down Expand Up @@ -186,7 +190,9 @@ protected internal virtual JToken GetWalletUnclaimedGas(JArray _params)
[RpcMethod]
protected internal virtual JToken ImportPrivKey(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // PrivateKey
CheckWallet();

string privkey = _params[0].AsString();
WalletAccount account = wallet.Import(privkey);
if (wallet is NEP6Wallet nep6wallet)
Expand Down Expand Up @@ -215,10 +221,8 @@ protected internal virtual JToken ImportPrivKey(JArray _params)
[RpcMethod]
protected internal virtual JToken CalculateNetworkFee(JArray _params)
{
if (_params.Count == 0)
{
throw new RpcException(RpcError.InvalidParams.WithData("Params array is empty, need a raw transaction."));
}
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // Tx

var tx = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid tx: {_params[0]}"));

JObject account = new();
Expand Down Expand Up @@ -275,6 +279,8 @@ protected internal virtual JToken ListAddress(JArray _params)
[RpcMethod]
protected internal virtual JToken OpenWallet(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 2, RpcError.InvalidParams); // Path, Password

string path = _params[0].AsString();
string password = _params[1].AsString();
File.Exists(path).True_Or(RpcError.WalletNotFound);
Expand Down Expand Up @@ -376,7 +382,9 @@ private void ProcessInvokeWithWallet(JObject result, Signer[] signers = null)
[RpcMethod]
protected internal virtual JToken SendFrom(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 4, RpcError.InvalidParams); // AssetId, From, To, Amount
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);
Expand Down Expand Up @@ -477,7 +485,9 @@ protected internal virtual JToken SendFrom(JArray _params)
[RpcMethod]
protected internal virtual JToken SendMany(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // From
CheckWallet();

int to_start = 0;
UInt160 from = null;
if (_params[0] is JString)
Expand Down Expand Up @@ -564,7 +574,9 @@ protected internal virtual JToken SendMany(JArray _params)
[RpcMethod]
protected internal virtual JToken SendToAddress(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 3, RpcError.InvalidParams); // AssetId, To, 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);
Expand Down Expand Up @@ -645,6 +657,7 @@ protected internal virtual JToken SendToAddress(JArray _params)
[RpcMethod]
protected internal virtual JToken CancelTransaction(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // Txid
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."));
Expand Down Expand Up @@ -730,6 +743,8 @@ protected internal virtual JToken CancelTransaction(JArray _params)
[RpcMethod]
protected internal virtual JToken InvokeContractVerify(JArray _params)
{
RpcException.ThrowIfTooFew(_params, 1, RpcError.InvalidParams); // ScriptHash

var scriptHash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()),
RpcError.InvalidParams.WithData($"Invalid script hash: {_params[0]}"));

Expand Down
1 change: 0 additions & 1 deletion tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Extensions;
using Neo.Json;
using Neo.Ledger;
using Neo.Network.P2P;
using Neo.Network.P2P.Payloads;
using Neo.Persistence.Providers;
Expand Down
27 changes: 27 additions & 0 deletions tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.SmartContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -495,5 +495,32 @@ public void TestGetUnclaimedGas_InvalidAddress()
// The underlying error is likely FormatException during AddressToScriptHash
StringAssert.Contains(ex.Message, RpcError.InvalidParams.Message); // Fix based on test output
}

[TestMethod]
public void TestSmartContractToFewArguments()
{
// InvokeFunction
var ex = Assert.ThrowsExactly<RpcException>(
() => _rpcServer.InvokeFunction(new JArray(NeoToken.NEO.Hash.ToString())));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);


// InvokeScript
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.InvokeScript(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// TraverseIterator
ex = Assert.ThrowsExactly<RpcException>(
() => _rpcServer.TraverseIterator(new JArray(Guid.NewGuid().ToString(), Guid.NewGuid().ToString())));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// TerminateSession
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.TerminateSession(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// GetUnclaimedGas
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.GetUnclaimedGas(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
}
}
}
7 changes: 7 additions & 0 deletions tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,12 @@ public void TestValidateAddress_WrongLength()
Assert.AreEqual(resp["address"], longAddr);
Assert.AreEqual(resp["isvalid"], false);
}

[TestMethod]
public void TestUtilitiesToFewArguments()
{
var ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.ValidateAddress(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
}
}
}
45 changes: 44 additions & 1 deletion tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
using Neo.Json;
using Neo.Network.P2P.Payloads;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;
using Neo.SmartContract.Native;
using Neo.UnitTests;
using Neo.UnitTests.Extensions;
Expand Down Expand Up @@ -664,5 +663,49 @@ private UInt160 TestUtilAddTestContract()
snapshot.Commit();
return state.Hash;
}

[TestMethod]
public void TestWalletsToFewArguments()
{
// DumpPrivKey
var ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.DumpPrivKey(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// GetWalletBalance
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.GetWalletBalance(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// ImportPrivKey
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.ImportPrivKey(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// CalculateNetworkFee
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.CalculateNetworkFee(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// OpenWallet
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.OpenWallet(new JArray("path/to/wallet.json")));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// SendFrom
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.SendFrom(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// SendMany
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.SendMany(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// SendToAddress
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.SendToAddress(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// CancelTransaction
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.CancelTransaction(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);

// InvokeContractVerify
ex = Assert.ThrowsExactly<RpcException>(() => _rpcServer.InvokeContractVerify(new JArray()));
Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult);
}
}
}
3 changes: 0 additions & 3 deletions tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ public partial class UT_RpcServer
private readonly NEP6Wallet _wallet = TestUtils.GenerateTestWallet("123");
private WalletAccount _walletAccount;

const byte NativePrefixAccount = 20;
const byte NativePrefixTotalSupply = 11;

[TestInitialize]
public void TestSetup()
{
Expand Down
Loading