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

Better defined RPC and HTTP errors #482

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
109 changes: 57 additions & 52 deletions src/bitcoinrpc.cpp

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions src/bitcoinrpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,68 @@ class CReserveKey;
#include "json/json_spirit_writer_template.h"
#include "json/json_spirit_utils.h"

//! HTTP status codes
enum HTTPStatusCode
{
HTTP_OK = 200,
HTTP_BAD_REQUEST = 400,
HTTP_UNAUTHORIZED = 401,
HTTP_FORBIDDEN = 403,
HTTP_NOT_FOUND = 404,
HTTP_BAD_METHOD = 405,
HTTP_INTERNAL_SERVER_ERROR = 500,
HTTP_SERVICE_UNAVAILABLE = 503,
};

//! Bitcoin RPC error codes
enum RPCErrorCode
{
//! Standard JSON-RPC 2.0 errors
RPC_INVALID_REQUEST = -32600,
RPC_METHOD_NOT_FOUND = -32601,
RPC_INVALID_PARAMS = -32602,
RPC_INTERNAL_ERROR = -32603,
RPC_PARSE_ERROR = -32700,

//! General application defined errors
RPC_MISC_ERROR = -1, //! std::exception thrown in command handling
RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode
RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter
RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key
RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation
RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter
RPC_DATABASE_ERROR = -20, //! Database error
RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format
RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission
RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules
RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain
RPC_IN_WARMUP = -28, //! Client still warming up

//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
RPC_TRANSACTION_REJECTED = RPC_VERIFY_REJECTED,
RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,

//! P2P client errors
RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected
RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet

//! Wallet errors
RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet
RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked
};

void ThreadRPCServer(void* parg);
int CommandLineRPC(int argc, char *argv[]);

Expand Down
4 changes: 2 additions & 2 deletions src/rpcblockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Value getblockhash(const Array& params, bool fHelp)

int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > nBestHeight)
throw runtime_error("Block number out of range.");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block number out of range.");

CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
return pblockindex->phashBlock->GetHex();
Expand All @@ -156,7 +156,7 @@ Value getblock(const Array& params, bool fHelp)
uint256 hash(strHash);

if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(-5, "Block not found");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block not found");

CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
Expand Down
20 changes: 9 additions & 11 deletions src/rpcdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
using namespace json_spirit;
using namespace std;

extern Object JSONRPCError(int code, const string& message);

class CTxDump
{
public:
Expand Down Expand Up @@ -54,11 +52,11 @@ Value importprivkey(const Array& params, bool fHelp)
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strSecret);

if (!fGood) throw JSONRPCError(-5,"Invalid private key");
if (!fGood) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,"Invalid private key");
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
if (fWalletUnlockMintOnly) // paycoin: no importprivkey in mint-only mode
throw JSONRPCError(-102, "Wallet is unlocked for minting only (unlock with walletpassphrase).");
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Wallet is unlocked for minting only (unlock with walletpassphrase).");

CKey key;
bool fCompressed;
Expand All @@ -72,7 +70,7 @@ Value importprivkey(const Array& params, bool fHelp)
pwalletMain->SetAddressBookName(vchAddress, strLabel);

if (!pwalletMain->AddKey(key))
throw JSONRPCError(-4,"Error adding key to wallet");
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");

pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
pwalletMain->ReacceptWalletTransactions();
Expand All @@ -93,17 +91,17 @@ Value dumpprivkey(const Array& params, bool fHelp)
string strAddress = params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
throw JSONRPCError(-5, "Invalid Paycoin address");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Paycoin address");
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
if (fWalletUnlockMintOnly) // paycoin: no dumpprivkey in mint-only mode
throw JSONRPCError(-102, "Wallet is unlocked for minting only (unlock with walletpassphrase).");
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Wallet is unlocked for minting only (unlock with walletpassphrase).");
CKeyID keyID;
if (!address.GetKeyID(keyID))
throw JSONRPCError(-3, "Address does not refer to a key");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Address does not refer to a key");
CSecret vchSecret;
bool fCompressed;
if (!pwalletMain->GetSecret(keyID, vchSecret, fCompressed))
throw JSONRPCError(-4,"Private key for address " + strAddress + " is not known");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key for address " + strAddress + " is not known");
return CBitcoinSecret(vchSecret, fCompressed).ToString();
}
6 changes: 2 additions & 4 deletions src/rpcnet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,9 @@ Value sendalert(const Array& params, bool fHelp)
vector<unsigned char> vchPrivKey = ParseHex(params[1].get_str());
key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
if (!key.Sign(Hash(alert.vchMsg.begin(), alert.vchMsg.end()), alert.vchSig))
throw runtime_error(
"Unable to sign alert, check private key?\n");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to sign alert, check private key?\n");
if(!alert.ProcessAlert())
throw runtime_error(
"Failed to process alert.\n");
throw JSONRPCError(RPC_MISC_ERROR, "Failed to process alert.\n");
// Relay alert
{
LOCK(cs_vNodes);
Expand Down
46 changes: 23 additions & 23 deletions src/rpcrawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
CTransaction tx;
uint256 hashBlock = 0;
if (!GetTransaction(hash, tx, hashBlock))
throw JSONRPCError(-5, "No information available about transaction");
throw JSONRPCError(RPC_WALLET_ERROR, "No information available about transaction");

CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
Expand Down Expand Up @@ -232,9 +232,9 @@ Value listunspent(const Array& params, bool fHelp)
{
CBitcoinAddress address(input.get_str());
if (!address.IsValid())
throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+input.get_str());
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Paycoin address: ")+input.get_str());
if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+input.get_str());
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
setAddress.insert(address);
}
}
Expand Down Expand Up @@ -301,17 +301,17 @@ Value createrawtransaction(const Array& params, bool fHelp)

const Value& txid_v = find_value(o, "txid");
if (txid_v.type() != str_type)
throw JSONRPCError(-8, "Invalid parameter, missing txid key");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
string txid = txid_v.get_str();
if (!IsHex(txid))
throw JSONRPCError(-8, "Invalid parameter, expected hex txid");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");

const Value& vout_v = find_value(o, "vout");
if (vout_v.type() != int_type)
throw JSONRPCError(-8, "Invalid parameter, missing vout key");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.get_int();
if (nOutput < 0)
throw JSONRPCError(-8, "Invalid parameter, vout must be positive");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");

CTxIn in(COutPoint(uint256(txid), nOutput));
rawTx.vin.push_back(in);
Expand All @@ -322,10 +322,10 @@ Value createrawtransaction(const Array& params, bool fHelp)
{
CBitcoinAddress address(s.name_);
if (!address.IsValid())
throw JSONRPCError(-5, string("Invalid Bitcoin address: ")+s.name_);
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Paycoin address: ")+s.name_);

if (setAddress.count(address))
throw JSONRPCError(-8, string("Invalid parameter, duplicated address: ")+s.name_);
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
setAddress.insert(address);

CScript scriptPubKey;
Expand Down Expand Up @@ -355,7 +355,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
ssData >> tx;
}
catch (std::exception &e) {
throw JSONRPCError(-22, "TX decode failed");
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}

Object result;
Expand Down Expand Up @@ -391,12 +391,12 @@ Value signrawtransaction(const Array& params, bool fHelp)
txVariants.push_back(tx);
}
catch (std::exception &e) {
throw JSONRPCError(-22, "TX decode failed");
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
}

if (txVariants.empty())
throw JSONRPCError(-22, "Missing transaction");
throw JSONRPCError(RPC_WALLET_ERROR, "Missing transaction");

// mergedTx will end up with all the signatures; it
// starts as a clone of the rawtx:
Expand Down Expand Up @@ -437,7 +437,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
throw JSONRPCError(-5,"Invalid private key");
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
CKey key;
bool fCompressed;
CSecret secret = vchSecret.GetSecret(fCompressed);
Expand All @@ -446,7 +446,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
}
else if(pwalletMain->IsCrypted())
throw runtime_error("The wallet must be unlocked with walletpassphrase first");
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "The wallet must be unlocked with walletpassphrase first");

// Add previous txouts given in the RPC call:
if (params.size() > 1 && params[1].type() != null_type)
Expand All @@ -455,23 +455,23 @@ Value signrawtransaction(const Array& params, bool fHelp)
BOOST_FOREACH(Value& p, prevTxs)
{
if (p.type() != obj_type)
throw JSONRPCError(-22, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");

Object prevOut = p.get_obj();

string txidHex = find_value(prevOut, "txid").get_str();
if (!IsHex(txidHex))
throw JSONRPCError(-22, "txid must be hexadecimal");
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "txid must be hexadecimal");
uint256 txid;
txid.SetHex(txidHex);

int nOut = find_value(prevOut, "vout").get_int();
if (nOut < 0)
throw JSONRPCError(-22, "vout must be positive");
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");

string pkHex = find_value(prevOut, "scriptPubKey").get_str();
if (!IsHex(pkHex))
throw JSONRPCError(-22, "scriptPubKey must be hexadecimal");
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "scriptPubKey must be hexadecimal");
vector<unsigned char> pkData(ParseHex(pkHex));
CScript scriptPubKey(pkData.begin(), pkData.end());

Expand All @@ -484,7 +484,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
string err("Previous output scriptPubKey mismatch:\n");
err = err + mapPrevOut[outpoint].ToString() + "\nvs:\n"+
scriptPubKey.ToString();
throw JSONRPCError(-22, err);
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
}
}
else
Expand Down Expand Up @@ -523,7 +523,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
throw JSONRPCError(-8, "Invalid sighash param");
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
}

bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
Expand Down Expand Up @@ -583,7 +583,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
ssData >> tx;
}
catch (std::exception &e) {
throw JSONRPCError(-22, "TX decode failed");
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
uint256 hashTx = tx.GetHash();

Expand All @@ -594,7 +594,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
if (GetTransaction(hashTx, existingTx, hashBlock))
{
if (hashBlock != 0)
throw JSONRPCError(-5, string("transaction already in block ")+hashBlock.GetHex());
throw JSONRPCError(RPC_VERIFY_ALREADY_IN_CHAIN, string("transaction already in block ")+hashBlock.GetHex());
// Not in block, but already in the memory pool; will drop
// through to re-relay it.
}
Expand All @@ -603,7 +603,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
// push to local node
CTxDB txdb("r");
if (!tx.AcceptToMemoryPool(txdb, fCheckInputs))
throw JSONRPCError(-22, "TX rejected");
throw JSONRPCError(RPC_VERIFY_REJECTED, "TX rejected");

SyncWithWallets(tx, NULL, true);
}
Expand Down
Loading