Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement RPC errors proposal #156 #815

Merged
merged 61 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
20d5643
implemente RPC errors proposal #156
Jim8y Aug 29, 2023
8af6a53
fix debug
Jim8y Aug 29, 2023
3128001
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Aug 30, 2023
cf687c6
Apply suggestions from code review
shargon Aug 31, 2023
f5d082e
fix typo
Jim8y Sep 1, 2023
45e0a67
Format code
shargon Sep 1, 2023
d43fe32
one class per file
Jim8y Sep 1, 2023
814fda1
Merge branch 'Add-error-codes-and-response-errors' of github.com:Liao…
Jim8y Sep 1, 2023
0afc30e
code format
Jim8y Sep 1, 2023
a5be5b5
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Sep 8, 2023
603527f
Clean code
shargon Sep 11, 2023
62c1dd7
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Sep 15, 2023
e378e13
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Sep 15, 2023
e7fac0c
Merge branch 'master' into Add-error-codes-and-response-errors
shargon Nov 12, 2023
b73dda6
fix error
Jim8y Nov 13, 2023
724bca9
Unify namespace
shargon Nov 13, 2023
c8b6554
Update .editorconfig
shargon Nov 13, 2023
2196c62
adopt old namespace style
Jim8y Nov 13, 2023
98be42f
format
Jim8y Nov 13, 2023
7df4a79
Merge branch 'Add-error-codes-and-response-errors' of github.com:Liao…
Jim8y Nov 13, 2023
41f3e01
Fix .editorconfig
shargon Nov 13, 2023
52e2b6d
Remove .editorconfig
shargon Nov 13, 2023
4024f84
Shargon's review
shargon Nov 13, 2023
ab1fb6b
Merge branches 'Add-error-codes-and-response-errors' and 'Add-error-c…
shargon Nov 13, 2023
6b0a4cd
Optimize code reusing static objects
shargon Nov 13, 2023
4a7ed21
Some uts
shargon Nov 13, 2023
c657526
Fix ut
shargon Nov 13, 2023
2bf8dfb
Remove cast
shargon Nov 13, 2023
c13494f
Remove static
shargon Nov 14, 2023
3a8d279
Comment not used
shargon Nov 14, 2023
4678745
Update src/StateService/StatePlugin.cs
shargon Nov 14, 2023
0fbce32
Some Anna's feedback
shargon Nov 14, 2023
e7a1c35
fix ut
shargon Nov 14, 2023
6bd3174
More info
shargon Nov 14, 2023
f887529
Add . at the end to all of them
shargon Nov 14, 2023
a55a7ea
Merge branch 'master' into Add-error-codes-and-response-errors
shargon Nov 17, 2023
2452299
update error code
Jim8y Nov 22, 2023
4048a69
add 600 error code and add extra parameter checks. update exception t…
Jim8y Nov 22, 2023
8e019f8
optimize code and fix ut
Jim8y Nov 22, 2023
513787f
use result to replace try-catch
Jim8y Nov 22, 2023
c96655b
update result with data parameter
Jim8y Nov 22, 2023
118cd7c
address more anna's comments
Jim8y Nov 22, 2023
ae408c9
fix oracle exception
Jim8y Nov 22, 2023
3191c2f
fix GetRelayResult
Jim8y Nov 22, 2023
c939556
fix iterator with result
Jim8y Nov 22, 2023
daa3f93
Update src/RpcServer/RpcError.cs
Jim8y Nov 22, 2023
46f524b
Update src/RpcServer/RpcServer.Node.cs
Jim8y Nov 22, 2023
015dab1
Update src/RpcServer/Result.cs
Jim8y Nov 24, 2023
ce6c0b0
add more result checking function and simplify the process of checkin…
Jim8y Nov 24, 2023
af121a3
add more params check
Jim8y Nov 24, 2023
635fa16
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Dec 13, 2023
88a2e95
update exception
Jim8y Dec 13, 2023
5f0c5bd
Merge branch 'master' into Add-error-codes-and-response-errors
shargon Jan 8, 2024
f6ef535
all good now
Jim8y Jan 10, 2024
9704327
Merge branch 'master' into Add-error-codes-and-response-errors
shargon Jan 10, 2024
fccd69a
runs dotnet format. and fix errors
Jim8y Jan 10, 2024
25016f7
update Can't get next block validators
Jim8y Jan 11, 2024
68f577a
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Jan 11, 2024
a744755
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Feb 15, 2024
89c125b
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Feb 16, 2024
2765606
Merge branch 'master' into Add-error-codes-and-response-errors
Jim8y Mar 13, 2024
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 src/ApplicationLogs/LogReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public JToken GetApplicationLog(JArray _params)
UInt256 hash = UInt256.Parse(_params[0].AsString());
byte[] value = _db.TryGet(hash.ToArray());
if (value is null)
throw new RpcException(-100, "Unknown transaction/blockhash");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownStorageItem));

JObject raw = (JObject)JToken.Parse(Neo.Utility.StrictUTF8.GetString(value));
//Additional optional "trigger" parameter to getapplicationlog for clients to be able to get just one execution result for a block.
Expand Down
10 changes: 5 additions & 5 deletions src/OracleService/OracleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,17 @@ public JObject SubmitOracleResponse(JArray _params)
byte[] txSign = Convert.FromBase64String(_params[2].AsString());
byte[] msgSign = Convert.FromBase64String(_params[3].AsString());

if (finishedCache.ContainsKey(requestId)) throw new RpcException(-100, "Request has already finished");
if (finishedCache.ContainsKey(requestId)) throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.OracleRequestFinished));

using (var snapshot = System.GetSnapshot())
{
uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1;
var oracles = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height);
if (!oracles.Any(p => p.Equals(oraclePub))) throw new RpcException(-100, $"{oraclePub} isn't an oracle node");
if (!oracles.Any(p => p.Equals(oraclePub))) throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.OracleNotDesignatedNode, $"{oraclePub} isn't an oracle node"));
if (NativeContract.Oracle.GetRequest(snapshot, requestId) is null)
throw new RpcException(-100, "Request is not found");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.OracleRequestNotFound));
var data = Neo.Helper.Concat(oraclePub.ToArray(), BitConverter.GetBytes(requestId), txSign);
if (!Crypto.VerifySignature(data, msgSign, oraclePub)) throw new RpcException(-100, "Invalid sign");
if (!Crypto.VerifySignature(data, msgSign, oraclePub)) throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.InvalidSignature));

AddResponseTxSign(snapshot, requestId, oraclePub, txSign);
}
Expand Down Expand Up @@ -496,7 +496,7 @@ private void AddResponseTxSign(DataCache snapshot, ulong requestId, ECPoint orac
else if (Crypto.VerifySignature(task.BackupTx.GetSignData(System.Settings.Network), sign, oraclePub))
task.BackupSigns.TryAdd(oraclePub, sign);
else
throw new RpcException(-100, "Invalid response transaction sign");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.InvalidSignature, "Invalid response transaction sign"));

if (CheckTxSign(snapshot, task.Tx, task.Signs) || CheckTxSign(snapshot, task.BackupTx, task.BackupSigns))
{
Expand Down
130 changes: 130 additions & 0 deletions src/RpcServer/RpcError.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright (C) 2015-2023 The Neo Project.
//
// The Neo.Network.RPC is free software distributed under the MIT software license,
// see the accompanying file LICENSE in the main directory of the
// project 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 System.Collections.Generic;
namespace Neo.Plugins;

public class RpcError
{
public int Code { get; set; }
public string Message { get; set; }
public string Data { get; set; }
public RpcError(int code, string message, string data = "")
{
Code = code;
Message = message;
Data = data;
}

public static RpcError ParseError(string data) => new RpcError(RpcErrorCode.BadRequest, "Parse RpcError", data);

// Missing helper methods
public static RpcError InvalidRequestError(string data) => new RpcError(RpcErrorCode.InvalidRequest, "Invalid request", data);

public static RpcError MethodNotFoundError(string data) => new RpcError(RpcErrorCode.MethodNotFound, "Method not found", data);

public static RpcError InvalidParamsError(string data) => new RpcError(RpcErrorCode.InvalidParams, "Invalid params", data);

public static RpcError InternalServerError(string data) => new RpcError(RpcErrorCode.InternalServerError, "Internal RpcError", data);

public static RpcError ErrorWithCode(int code, string message) => new RpcError(code, message);

// Helper to wrap an existing RpcError with data
public static RpcError WrapErrorWithData(RpcError error, string data) => new RpcError(error.Code, error.Message, data);


public override string ToString()
{
if (string.IsNullOrEmpty(Data))
{
return $"{Message} ({Code})";
}
return $"{Message} ({Code}) - {Data}";
}

public string ErrorMessage => string.IsNullOrEmpty(Data) ? $"{Message}" : $"{Message} - {Data}";

}

public static class RpcErrorFactor
{
private static readonly Dictionary<int, string> DefaultMessages = new Dictionary<int, string> {

{RpcErrorCode.InternalServerError, "Internal server RpcError"},
{RpcErrorCode.BadRequest, "Bad request"},
{RpcErrorCode.InvalidRequest, "Invalid request"},
{RpcErrorCode.MethodNotFound, "Method not found"},
{RpcErrorCode.InvalidParams, "Invalid params"},

{RpcErrorCode.UnknownBlock, "Unknown block"},
{RpcErrorCode.UnknownContract, "Unknown contract"},
{RpcErrorCode.UnknownTransaction, "Unknown transaction"},
{RpcErrorCode.UnknownStorageItem, "Unknown storage item"},
{RpcErrorCode.UnknownScriptContainer, "Unknown script container"},
{RpcErrorCode.UnknownStateRoot, "Unknown state root"},
{RpcErrorCode.UnknownSession, "Unknown session"},
{RpcErrorCode.UnknownIterator, "Unknown iterator"},
{RpcErrorCode.UnknownHeight, "Unknown height"},

{RpcErrorCode.InsufficientFundsWallet, "Insufficient funds in wallet"},
{RpcErrorCode.WalletFeeLimit, "Wallet fee limit exceeded"},
{RpcErrorCode.NoOpenedWallet, "No opened wallet"},
{RpcErrorCode.WalletNotFound, "Wallet not found"},
{RpcErrorCode.WalletNotSupported, "Wallet not supported"},

{ RpcErrorCode.AccessDenied, "Access denied"},

{RpcErrorCode.VerificationFailed, "Inventory verification failed"},
{RpcErrorCode.AlreadyExists, "Inventory already exists"},
{RpcErrorCode.MempoolCapReached, "Memory pool capacity reached"},
{RpcErrorCode.AlreadyInPool, "Already in transaction pool"},
{RpcErrorCode.InsufficientNetworkFee, "Insufficient network fee"},
{RpcErrorCode.PolicyFailed, "Policy check failed"},
{RpcErrorCode.InvalidScript, "Invalid transaction script"},
{RpcErrorCode.InvalidAttribute, "Invalid transaction attribute"},
{RpcErrorCode.InvalidSignature, "Invalid transaction signature"},
{RpcErrorCode.InvalidSize, "Invalid inventory size"},
{RpcErrorCode.ExpiredTransaction, "Expired transaction"},
{RpcErrorCode.InsufficientFunds, "Insufficient funds for fee"},
{RpcErrorCode.InvalidVerificationFunction, "Invalid contract verification"},

{RpcErrorCode.SessionsDisabled, "State iterator sessions disabled"},
{RpcErrorCode.OracleDisabled, "Oracle service disabled"},
{RpcErrorCode.OracleRequestFinished, "Oracle request already finished"},
{RpcErrorCode.OracleRequestNotFound, "Oracle request not found"},
{RpcErrorCode.OracleNotDesignatedNode, "Not a designated oracle node"},
{RpcErrorCode.UnsupportedState, "Old state not supported"},
{RpcErrorCode.InvalidProof, "Invalid state proof"},
{RpcErrorCode.ExecutionFailed, "Contract execution failed"}

};

public static RpcError NewError(int code, string message = null, string data = "")
{
message ??= DefaultMessages[code];
return new RpcError(code, message, data);
}

public static RpcError NewCustomError(int code, string message)
{
return new RpcError(code, message, null);
}

public static bool Contains(int code)
{
return DefaultMessages.ContainsKey(code);
}

public static readonly RpcError ErrInvalidParams = NewError(RpcErrorCode.InvalidParams);

public static readonly RpcError ErrUnknownBlock = NewError(RpcErrorCode.UnknownBlock);

public static readonly RpcError ErrUnknownContract = NewError(RpcErrorCode.UnknownContract);
}
63 changes: 63 additions & 0 deletions src/RpcServer/RpcErrorCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (C) 2015-2023 The Neo Project.
//
// The Neo.Network.RPC is free software distributed under the MIT software license,
// see the accompanying file LICENSE in the main directory of the
// project 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 System.Collections.Generic;
namespace Neo.Plugins;
Jim8y marked this conversation as resolved.
Show resolved Hide resolved
public static class RpcErrorCode
{

public const int InternalServerError = -32603;
public const int BadRequest = -32700;
public const int InvalidRequest = -32600;
public const int MethodNotFound = -32601;
public const int InvalidParams = -32602;

public const int UnknownBlock = -101;
public const int UnknownContract = -102;
public const int UnknownTransaction = -103;
public const int UnknownStorageItem = -104;
public const int UnknownScriptContainer = -105;
public const int UnknownStateRoot = -106;
public const int UnknownSession = -107;
public const int UnknownIterator = -108;
public const int UnknownHeight = -109;

public const int InsufficientFundsWallet = -300;
public const int WalletFeeLimit = -301;
public const int NoOpenedWallet = -302;
public const int WalletNotFound = -303;
public const int WalletNotSupported = -304;

public const int AccessDenied = -400;

public const int VerificationFailed = -500;
public const int AlreadyExists = -501;
public const int MempoolCapReached = -502;
public const int AlreadyInPool = -503;
public const int InsufficientNetworkFee = -504;
public const int PolicyFailed = -505;
public const int InvalidScript = -506;
public const int InvalidAttribute = -507;
public const int InvalidSignature = -508;
public const int InvalidSize = -509;
public const int ExpiredTransaction = -510;
public const int InsufficientFunds = -511;
public const int InvalidVerificationFunction = -512;

public const int SessionsDisabled = -601;
public const int OracleDisabled = -602;
public const int OracleRequestFinished = -603;
public const int OracleRequestNotFound = -604;
public const int OracleNotDesignatedNode = -605;
public const int UnsupportedState = -606;
public const int InvalidProof = -607;
public const int ExecutionFailed = -608;

}
4 changes: 2 additions & 2 deletions src/RpcServer/RpcException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ namespace Neo.Plugins
{
public class RpcException : Exception
{
public RpcException(int code, string message) : base(message)
public RpcException(RpcError error) : base(error.ErrorMessage)
{
HResult = code;
HResult = (int)error.Code;
}
}
}
20 changes: 10 additions & 10 deletions src/RpcServer/RpcServer.Blockchain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ protected virtual JToken GetBlock(JArray _params)
block = NativeContract.Ledger.GetBlock(snapshot, hash);
}
if (block == null)
throw new RpcException(-100, "Unknown block");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownBlock));
if (verbose)
{
JObject json = Utility.BlockToJson(block, system.Settings);
Expand Down Expand Up @@ -81,7 +81,7 @@ protected virtual JToken GetBlockHash(JArray _params)
{
return NativeContract.Ledger.GetBlockHash(snapshot, height).ToString();
}
throw new RpcException(-100, "Invalid Height");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownHeight));
}

[RpcMethod]
Expand All @@ -102,7 +102,7 @@ protected virtual JToken GetBlockHeader(JArray _params)
header = NativeContract.Ledger.GetHeader(snapshot, hash);
}
if (header == null)
throw new RpcException(-100, "Unknown block");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownBlock));

if (verbose)
{
Expand All @@ -123,13 +123,13 @@ protected virtual JToken GetContractState(JArray _params)
if (int.TryParse(_params[0].AsString(), out int contractId))
{
var contracts = NativeContract.ContractManagement.GetContractById(system.StoreView, contractId);
return contracts?.ToJson() ?? throw new RpcException(-100, "Unknown contract");
return contracts?.ToJson() ?? throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownContract));
}
else
{
UInt160 script_hash = ToScriptHash(_params[0].AsString());
ContractState contract = NativeContract.ContractManagement.GetContract(system.StoreView, script_hash);
return contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract");
return contract?.ToJson() ?? throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownContract));
}
}

Expand Down Expand Up @@ -171,7 +171,7 @@ protected virtual JToken GetRawTransaction(JArray _params)
var snapshot = system.StoreView;
TransactionState state = NativeContract.Ledger.GetTransactionState(snapshot, hash);
tx ??= state?.Transaction;
if (tx is null) throw new RpcException(-100, "Unknown transaction");
if (tx is null) throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownTransaction));
if (!verbose) return Convert.ToBase64String(tx.ToArray());
JObject json = Utility.TransactionToJson(tx, system.Settings);
if (state is not null)
Expand All @@ -192,7 +192,7 @@ protected virtual JToken GetStorage(JArray _params)
{
UInt160 hash = UInt160.Parse(_params[0].AsString());
ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash);
if (contract is null) throw new RpcException(-100, "Unknown contract");
if (contract is null) throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownContract));
id = contract.Id;
}
byte[] key = Convert.FromBase64String(_params[1].AsString());
Expand All @@ -201,7 +201,7 @@ protected virtual JToken GetStorage(JArray _params)
Id = id,
Key = key
});
if (item is null) throw new RpcException(-100, "Unknown storage");
if (item is null) throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownStorageItem));
return Convert.ToBase64String(item.Value.Span);
}

Expand All @@ -213,7 +213,7 @@ protected virtual JToken FindStorage(JArray _params)
{
UInt160 hash = UInt160.Parse(_params[0].AsString());
ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash);
if (contract is null) throw new RpcException(-100, "Unknown contract");
if (contract is null) throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownContract));
id = contract.Id;
}

Expand Down Expand Up @@ -261,7 +261,7 @@ protected virtual JToken GetTransactionHeight(JArray _params)
UInt256 hash = UInt256.Parse(_params[0].AsString());
uint? height = NativeContract.Ledger.GetTransactionState(system.StoreView, hash)?.BlockIndex;
if (height.HasValue) return height.Value;
throw new RpcException(-100, "Unknown transaction");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.UnknownTransaction));
}

[RpcMethod]
Expand Down
2 changes: 1 addition & 1 deletion src/RpcServer/RpcServer.Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private static JObject GetRelayResult(VerifyResult reason, UInt256 hash)
}
else
{
throw new RpcException(-500, reason.ToString());
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.VerificationFailed, reason.ToString()));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/RpcServer/RpcServer.SmartContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ protected virtual JToken GetUnclaimedGas(JArray _params)
script_hash = null;
}
if (script_hash == null)
throw new RpcException(-100, "Invalid address");
throw new RpcException(RpcErrorFactor.NewError(RpcErrorCode.InvalidParams));
var snapshot = system.StoreView;
json["unclaimed"] = NativeContract.NEO.UnclaimedGas(snapshot, script_hash, NativeContract.Ledger.CurrentIndex(snapshot) + 1).ToString();
json["address"] = script_hash.ToAddress(system.Settings.AddressVersion);
Expand Down
Loading