Skip to content

Commit cb06edf

Browse files
committed
Fix wallet RPC race by waiting for callbacks in sendrawtransaction
1 parent e545ded commit cb06edf

File tree

1 file changed

+22
-1
lines changed

1 file changed

+22
-1
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "init.h"
1212
#include "keystore.h"
1313
#include "validation.h"
14+
#include "validationinterface.h"
1415
#include "merkleblock.h"
1516
#include "net.h"
1617
#include "policy/policy.h"
@@ -30,6 +31,7 @@
3031
#include "wallet/wallet.h"
3132
#endif
3233

34+
#include <future>
3335
#include <stdint.h>
3436

3537
#include <univalue.h>
@@ -917,7 +919,9 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
917919
);
918920

919921
ObserveSafeMode();
920-
LOCK(cs_main);
922+
923+
std::promise<void> promise;
924+
921925
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
922926

923927
// parse hex string from parameter
@@ -931,6 +935,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
931935
if (!request.params[1].isNull() && request.params[1].get_bool())
932936
nMaxRawTxFee = 0;
933937

938+
{ // cs_main scope
939+
LOCK(cs_main);
934940
CCoinsViewCache &view = *pcoinsTip;
935941
bool fHaveChain = false;
936942
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
@@ -952,10 +958,24 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
952958
}
953959
throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());
954960
}
961+
} else {
962+
// If wallet is enabled, ensure that the wallet has been made aware
963+
// of the new transaction prior to returning. This prevents a race
964+
// where a user might call sendrawtransaction with a transaction
965+
// to/from their wallet, immediately call some wallet RPC, and get
966+
// a stale result because callbacks have not yet been processed.
967+
CallFunctionInValidationInterfaceQueue([&promise] {
968+
promise.set_value();
969+
});
955970
}
956971
} else if (fHaveChain) {
957972
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
958973
}
974+
975+
} // cs_main
976+
977+
promise.get_future().wait();
978+
959979
if(!g_connman)
960980
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
961981

@@ -964,6 +984,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
964984
{
965985
pnode->PushInventory(inv);
966986
});
987+
967988
return hashTx.GetHex();
968989
}
969990

0 commit comments

Comments
 (0)