aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/blockchain.cpp38
-rw-r--r--src/rpc/mining.cpp16
-rw-r--r--src/rpc/rawtransaction.cpp90
-rw-r--r--src/rpc/server.cpp11
-rw-r--r--src/rpc/server.h8
5 files changed, 96 insertions, 67 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f2a1fd048f..2077723af5 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -709,10 +709,10 @@ UniValue getblockheader(const JSONRPCRequest& request)
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
- if (mapBlockIndex.count(hash) == 0)
+ const CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
-
- CBlockIndex* pblockindex = mapBlockIndex[hash];
+ }
if (!fVerbose)
{
@@ -788,12 +788,12 @@ UniValue getblock(const JSONRPCRequest& request)
verbosity = request.params[1].get_bool() ? 1 : 0;
}
- if (mapBlockIndex.count(hash) == 0)
+ const CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
CBlock block;
- CBlockIndex* pblockindex = mapBlockIndex[hash];
-
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
@@ -858,7 +858,7 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
stats.hashBlock = pcursor->GetBestBlock();
{
LOCK(cs_main);
- stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
+ stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight;
}
ss << stats.hashBlock;
uint256 prevkey;
@@ -1041,8 +1041,7 @@ UniValue gettxout(const JSONRPCRequest& request)
}
}
- BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
- CBlockIndex *pindex = it->second;
+ const CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
if (coin.nHeight == MEMPOOL_HEIGHT) {
ret.pushKV("confirmations", 0);
@@ -1436,10 +1435,10 @@ UniValue preciousblock(const JSONRPCRequest& request)
{
LOCK(cs_main);
- if (mapBlockIndex.count(hash) == 0)
+ pblockindex = LookupBlockIndex(hash);
+ if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
-
- pblockindex = mapBlockIndex[hash];
+ }
}
CValidationState state;
@@ -1472,10 +1471,11 @@ UniValue invalidateblock(const JSONRPCRequest& request)
{
LOCK(cs_main);
- if (mapBlockIndex.count(hash) == 0)
+ CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
- CBlockIndex* pblockindex = mapBlockIndex[hash];
InvalidateBlock(state, Params(), pblockindex);
}
@@ -1510,10 +1510,11 @@ UniValue reconsiderblock(const JSONRPCRequest& request)
{
LOCK(cs_main);
- if (mapBlockIndex.count(hash) == 0)
+ CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
- CBlockIndex* pblockindex = mapBlockIndex[hash];
ResetBlockFailureFlags(pblockindex);
}
@@ -1560,11 +1561,10 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
} else {
uint256 hash = uint256S(request.params[1].get_str());
LOCK(cs_main);
- auto it = mapBlockIndex.find(hash);
- if (it == mapBlockIndex.end()) {
+ pindex = LookupBlockIndex(hash);
+ if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- pindex = it->second;
if (!chainActive.Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 3073a49d0d..0537628763 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -396,9 +396,8 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
uint256 hash = block.GetHash();
- BlockMap::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end()) {
- CBlockIndex *pindex = mi->second;
+ const CBlockIndex* pindex = LookupBlockIndex(hash);
+ if (pindex) {
if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
return "duplicate";
if (pindex->nStatus & BLOCK_FAILED_MASK)
@@ -727,9 +726,8 @@ UniValue submitblock(const JSONRPCRequest& request)
bool fBlockPresent = false;
{
LOCK(cs_main);
- BlockMap::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end()) {
- CBlockIndex *pindex = mi->second;
+ const CBlockIndex* pindex = LookupBlockIndex(hash);
+ if (pindex) {
if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) {
return "duplicate";
}
@@ -743,9 +741,9 @@ UniValue submitblock(const JSONRPCRequest& request)
{
LOCK(cs_main);
- BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
- if (mi != mapBlockIndex.end()) {
- UpdateUncommittedBlockStructures(block, mi->second, Params().GetConsensus());
+ const CBlockIndex* pindex = LookupBlockIndex(block.hashPrevBlock);
+ if (pindex) {
+ UpdateUncommittedBlockStructures(block, pindex, Params().GetConsensus());
}
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 8dcfb48e9a..20bfd3f355 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -48,9 +48,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
if (!hashBlock.IsNull()) {
entry.pushKV("blockhash", hashBlock.GetHex());
- BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
- if (mi != mapBlockIndex.end() && (*mi).second) {
- CBlockIndex* pindex = (*mi).second;
+ CBlockIndex* pindex = LookupBlockIndex(hashBlock);
+ if (pindex) {
if (chainActive.Contains(pindex)) {
entry.pushKV("confirmations", 1 + chainActive.Height() - pindex->nHeight);
entry.pushKV("time", pindex->GetBlockTime());
@@ -160,11 +159,10 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
if (!request.params[2].isNull()) {
uint256 blockhash = ParseHashV(request.params[2], "parameter 3");
- BlockMap::iterator it = mapBlockIndex.find(blockhash);
- if (it == mapBlockIndex.end()) {
+ blockindex = LookupBlockIndex(blockhash);
+ if (!blockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
}
- blockindex = it->second;
in_active_chain = chainActive.Contains(blockindex);
}
@@ -238,9 +236,10 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
if (!request.params[1].isNull())
{
hashBlock = uint256S(request.params[1].get_str());
- if (!mapBlockIndex.count(hashBlock))
+ pblockindex = LookupBlockIndex(hashBlock);
+ if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
- pblockindex = mapBlockIndex[hashBlock];
+ }
} else {
// Loop through txids and try to find which block they're in. Exit loop once a block is found.
for (const auto& tx : setTxids) {
@@ -257,9 +256,10 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
CTransactionRef tx;
if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
- if (!mapBlockIndex.count(hashBlock))
+ pblockindex = LookupBlockIndex(hashBlock);
+ if (!pblockindex) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
- pblockindex = mapBlockIndex[hashBlock];
+ }
}
CBlock block;
@@ -306,8 +306,10 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
LOCK(cs_main);
- if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
+ const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
+ if (!pindex || !chainActive.Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
+ }
for (const uint256& hash : vMatch)
res.push_back(hash.GetHex());
@@ -316,9 +318,10 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
UniValue createrawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
throw std::runtime_error(
- "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime ) ( replaceable )\n"
+ // clang-format off
+ "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
"Returns hex-encoded raw transaction.\n"
@@ -329,18 +332,23 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
"1. \"inputs\" (array, required) A json array of json objects\n"
" [\n"
" {\n"
- " \"txid\":\"id\", (string, required) The transaction id\n"
+ " \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n, (numeric, required) The output number\n"
" \"sequence\":n (numeric, optional) The sequence number\n"
" } \n"
" ,...\n"
" ]\n"
- "2. \"outputs\" (object, required) a json object with outputs\n"
+ "2. \"outputs\" (array, required) a json array with outputs (key-value pairs)\n"
+ " [\n"
" {\n"
- " \"address\": x.xxx, (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n"
- " \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n"
- " ,...\n"
+ " \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n"
+ " },\n"
+ " {\n"
+ " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n"
" }\n"
+ " ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
+ " accepted as second parameter.\n"
+ " ]\n"
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
"4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
@@ -348,18 +356,29 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
"\"transaction\" (string) hex string of the transaction\n"
"\nExamples:\n"
- + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"")
- + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"data\\\":\\\"00010203\\\"}\"")
- + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
- + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
+ + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")
+ + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
+ + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"")
+ + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
+ // clang-format on
);
+ }
- RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ, UniValue::VNUM, UniValue::VBOOL}, true);
+ RPCTypeCheck(request.params, {
+ UniValue::VARR,
+ UniValueType(), // ARR or OBJ, checked later
+ UniValue::VNUM,
+ UniValue::VBOOL
+ }, true
+ );
if (request.params[0].isNull() || request.params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
UniValue inputs = request.params[0].get_array();
- UniValue sendTo = request.params[1].get_obj();
+ const bool outputs_is_obj = request.params[1].isObject();
+ UniValue outputs = outputs_is_obj ?
+ request.params[1].get_obj() :
+ request.params[1].get_array();
CMutableTransaction rawTx;
@@ -411,11 +430,24 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
}
std::set<CTxDestination> destinations;
- std::vector<std::string> addrList = sendTo.getKeys();
- for (const std::string& name_ : addrList) {
-
+ if (!outputs_is_obj) {
+ // Translate array of key-value pairs into dict
+ UniValue outputs_dict = UniValue(UniValue::VOBJ);
+ for (size_t i = 0; i < outputs.size(); ++i) {
+ const UniValue& output = outputs[i];
+ if (!output.isObject()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair not an object as expected");
+ }
+ if (output.size() != 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair must contain exactly one key");
+ }
+ outputs_dict.pushKVs(output);
+ }
+ outputs = std::move(outputs_dict);
+ }
+ for (const std::string& name_ : outputs.getKeys()) {
if (name_ == "data") {
- std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
+ std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
CTxOut out(0, CScript() << OP_RETURN << data);
rawTx.vout.push_back(out);
@@ -430,7 +462,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
}
CScript scriptPubKey = GetScriptForDestination(destination);
- CAmount nAmount = AmountFromValue(sendTo[name_]);
+ CAmount nAmount = AmountFromValue(outputs[name_]);
CTxOut out(nAmount, scriptPubKey);
rawTx.vout.push_back(out);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 35401bf876..54995ef000 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -50,12 +50,11 @@ void RPCServer::OnStopped(std::function<void ()> slot)
}
void RPCTypeCheck(const UniValue& params,
- const std::list<UniValue::VType>& typesExpected,
+ const std::list<UniValueType>& typesExpected,
bool fAllowNull)
{
unsigned int i = 0;
- for (UniValue::VType t : typesExpected)
- {
+ for (const UniValueType& t : typesExpected) {
if (params.size() <= i)
break;
@@ -67,10 +66,10 @@ void RPCTypeCheck(const UniValue& params,
}
}
-void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
+void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
{
- if (value.type() != typeExpected) {
- throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected), uvTypeName(value.type())));
+ if (!typeExpected.typeAny && value.type() != typeExpected.type) {
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
}
}
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 075940cb90..8b32924fbc 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -28,9 +28,9 @@ namespace RPCServer
}
/** Wrapper for UniValue::VType, which includes typeAny:
- * Used to denote don't care type. Only used by RPCTypeCheckObj */
+ * Used to denote don't care type. */
struct UniValueType {
- explicit UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
+ UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
UniValueType() : typeAny(true) {}
bool typeAny;
UniValue::VType type;
@@ -69,12 +69,12 @@ bool RPCIsInWarmup(std::string *outStatus);
* the right number of arguments are passed, just that any passed are the correct type.
*/
void RPCTypeCheck(const UniValue& params,
- const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
+ const std::list<UniValueType>& typesExpected, bool fAllowNull=false);
/**
* Type-check one argument; throws JSONRPCError if wrong type given.
*/
-void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected);
+void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected);
/*
Check for expected keys/value types in an Object.