Skip to content

Commit 9349817

Browse files
kwvggades
authored andcommitted
partial bitcoin#14978: Factor BroadcastTransaction out of sendrawtransaction
1 parent 9223d69 commit 9349817

File tree

4 files changed

+96
-64
lines changed

4 files changed

+96
-64
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ BITCOIN_CORE_H = \
224224
netfulfilledman.h \
225225
netmessagemaker.h \
226226
node/coinstats.h \
227+
node/transaction.h \
227228
noui.h \
228229
policy/feerate.h \
229230
policy/fees.h \
@@ -375,6 +376,7 @@ libcosanta_server_a_SOURCES = \
375376
netfulfilledman.cpp \
376377
net_processing.cpp \
377378
node/coinstats.cpp \
379+
node/transaction.cpp \
378380
noui.cpp \
379381
policy/fees.cpp \
380382
policy/policy.cpp \

src/node/transaction.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright (c) 2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2018 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#include <consensus/validation.h>
7+
#include <net.h>
8+
#include <rpc/server.h>
9+
#include <txmempool.h>
10+
#include <validation.h>
11+
#include <validationinterface.h>
12+
#include <node/transaction.h>
13+
#include <util/validation.h>
14+
15+
#include <future>
16+
17+
uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees) {
18+
std::promise<void> promise;
19+
const uint256& hashTx = tx->GetHash();
20+
21+
CAmount nMaxRawTxFee = maxTxFee;
22+
if (allowhighfees)
23+
nMaxRawTxFee = 0;
24+
25+
{ // cs_main scope
26+
LOCK(cs_main);
27+
CCoinsViewCache &view = *pcoinsTip;
28+
bool fHaveChain = false;
29+
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
30+
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
31+
fHaveChain = !existingCoin.IsSpent();
32+
}
33+
bool fHaveMempool = mempool.exists(hashTx);
34+
if (!fHaveMempool && !fHaveChain) {
35+
// push to local node and sync with wallets
36+
CValidationState state;
37+
bool fMissingInputs;
38+
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
39+
false /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
40+
if (state.IsInvalid()) {
41+
throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state));
42+
} else {
43+
if (fMissingInputs) {
44+
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
45+
}
46+
throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state));
47+
}
48+
} else {
49+
// If wallet is enabled, ensure that the wallet has been made aware
50+
// of the new transaction prior to returning. This prevents a race
51+
// where a user might call sendrawtransaction with a transaction
52+
// to/from their wallet, immediately call some wallet RPC, and get
53+
// a stale result because callbacks have not yet been processed.
54+
CallFunctionInValidationInterfaceQueue([&promise] {
55+
promise.set_value();
56+
});
57+
}
58+
} else if (fHaveChain) {
59+
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
60+
} else {
61+
// Make sure we don't block forever if re-sending
62+
// a transaction already in mempool.
63+
promise.set_value();
64+
}
65+
66+
} // cs_main
67+
68+
promise.get_future().wait();
69+
70+
if(!g_connman)
71+
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
72+
73+
g_connman->RelayTransaction(*tx);
74+
75+
return hashTx;
76+
}

src/node/transaction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2017-2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_NODE_TRANSACTION_H
6+
#define BITCOIN_NODE_TRANSACTION_H
7+
8+
#include <primitives/transaction.h>
9+
#include <uint256.h>
10+
11+
/** Broadcast a transaction */
12+
uint256 BroadcastTransaction(CTransactionRef tx, bool allowhighfees = false);
13+
14+
#endif // BITCOIN_NODE_TRANSACTION_H

src/rpc/rawtransaction.cpp

Lines changed: 4 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <key_io.h>
1919
#include <merkleblock.h>
2020
#include <net.h>
21+
#include <node/transaction.h>
2122
#include <policy/policy.h>
2223
#include <primitives/transaction.h>
2324
#include <rpc/rawtransaction.h>
@@ -42,7 +43,6 @@
4243
#include <llmq/quorums_commitment.h>
4344
#include <llmq/quorums_instantsend.h>
4445

45-
#include <future>
4646
#include <stdint.h>
4747

4848
#include <univalue.h>
@@ -1097,76 +1097,16 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
10971097
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
10981098
);
10991099

1100-
std::promise<void> promise;
1101-
11021100
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL});
11031101

11041102
// parse hex string from parameter
11051103
CMutableTransaction mtx;
11061104
if (!DecodeHexTx(mtx, request.params[0].get_str()))
11071105
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
11081106
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
1109-
const uint256& hashTx = tx->GetHash();
1110-
1111-
CAmount nMaxRawTxFee = maxTxFee;
1112-
if (!request.params[1].isNull() && request.params[1].get_bool())
1113-
nMaxRawTxFee = 0;
1114-
1115-
bool fBypassLimits = false;
1116-
if (!request.params[3].isNull())
1117-
fBypassLimits = request.params[3].get_bool();
1118-
1119-
{ // cs_main scope
1120-
LOCK(cs_main);
1121-
CCoinsViewCache &view = *pcoinsTip;
1122-
bool fHaveChain = false;
1123-
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
1124-
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
1125-
fHaveChain = !existingCoin.IsSpent();
1126-
}
1127-
bool fHaveMempool = mempool.exists(hashTx);
1128-
if (!fHaveMempool && !fHaveChain) {
1129-
// push to local node and sync with wallets
1130-
CValidationState state;
1131-
bool fMissingInputs;
1132-
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
1133-
fBypassLimits /* bypass_limits */, nMaxRawTxFee)) {
1134-
if (state.IsInvalid()) {
1135-
throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state));
1136-
} else {
1137-
if (fMissingInputs) {
1138-
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
1139-
}
1140-
throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state));
1141-
}
1142-
} else {
1143-
// If wallet is enabled, ensure that the wallet has been made aware
1144-
// of the new transaction prior to returning. This prevents a race
1145-
// where a user might call sendrawtransaction with a transaction
1146-
// to/from their wallet, immediately call some wallet RPC, and get
1147-
// a stale result because callbacks have not yet been processed.
1148-
CallFunctionInValidationInterfaceQueue([&promise] {
1149-
promise.set_value();
1150-
});
1151-
}
1152-
} else if (fHaveChain) {
1153-
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
1154-
} else {
1155-
// Make sure we don't block forever if re-sending
1156-
// a transaction already in mempool.
1157-
promise.set_value();
1158-
}
1159-
1160-
} // cs_main
1161-
1162-
promise.get_future().wait();
1163-
1164-
if(!g_connman)
1165-
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
1166-
1167-
g_connman->RelayTransaction(*tx);
1168-
1169-
return hashTx.GetHex();
1107+
bool allowhighfees = false;
1108+
if (!request.params[1].isNull()) allowhighfees = request.params[1].get_bool();
1109+
return BroadcastTransaction(tx, allowhighfees).GetHex();
11701110
}
11711111

11721112
static UniValue testmempoolaccept(const JSONRPCRequest& request)

0 commit comments

Comments
 (0)