diff options
author | Matt Corallo <git@bluematt.me> | 2017-06-20 21:21:36 -0400 |
---|---|---|
committer | Matt Corallo <git@bluematt.me> | 2017-10-13 19:30:15 -0400 |
commit | cb06edf938302166030db19017c27889ea5b10b6 (patch) | |
tree | a11872ce2488f5780ecf07025549edad4fc0f76b /src/rpc | |
parent | e545dedf72bff2bd41c93c93eb576929fce37112 (diff) |
Fix wallet RPC race by waiting for callbacks in sendrawtransaction
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/rawtransaction.cpp | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index d860dbc244..8f8cdf80ed 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -11,6 +11,7 @@ #include "init.h" #include "keystore.h" #include "validation.h" +#include "validationinterface.h" #include "merkleblock.h" #include "net.h" #include "policy/policy.h" @@ -30,6 +31,7 @@ #include "wallet/wallet.h" #endif +#include <future> #include <stdint.h> #include <univalue.h> @@ -917,7 +919,9 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) ); ObserveSafeMode(); - LOCK(cs_main); + + std::promise<void> promise; + RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); // parse hex string from parameter @@ -931,6 +935,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) if (!request.params[1].isNull() && request.params[1].get_bool()) nMaxRawTxFee = 0; + { // cs_main scope + LOCK(cs_main); CCoinsViewCache &view = *pcoinsTip; bool fHaveChain = false; for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { @@ -952,10 +958,24 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) } throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason()); } + } else { + // If wallet is enabled, ensure that the wallet has been made aware + // of the new transaction prior to returning. This prevents a race + // where a user might call sendrawtransaction with a transaction + // to/from their wallet, immediately call some wallet RPC, and get + // a stale result because callbacks have not yet been processed. + CallFunctionInValidationInterfaceQueue([&promise] { + promise.set_value(); + }); } } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); } + + } // cs_main + + promise.get_future().wait(); + if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -964,6 +984,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) { pnode->PushInventory(inv); }); + return hashTx.GetHex(); } |