diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/node/transaction.cpp | 79 | ||||
-rw-r--r-- | src/node/transaction.h | 14 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 69 |
4 files changed, 99 insertions, 65 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index a57fcb0711..9a87af2efc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -152,6 +152,7 @@ BITCOIN_CORE_H = \ netaddress.h \ netbase.h \ netmessagemaker.h \ + node/transaction.h \ noui.h \ optional.h \ outputtype.h \ @@ -255,6 +256,7 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ net_processing.cpp \ + node/transaction.cpp \ noui.cpp \ outputtype.cpp \ policy/fees.cpp \ diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp new file mode 100644 index 0000000000..47c0323f14 --- /dev/null +++ b/src/node/transaction.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <consensus/validation.h> +#include <net.h> +#include <rpc/server.h> +#include <txmempool.h> +#include <validation.h> +#include <validationinterface.h> +#include <node/transaction.h> + +#include <future> + +uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees) { + std::promise<void> promise; + const uint256& hashTx = tx->GetHash(); + + CAmount nMaxRawTxFee = maxTxFee; + if (allowhighfees) + 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++) { + const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o)); + fHaveChain = !existingCoin.IsSpent(); + } + bool fHaveMempool = mempool.exists(hashTx); + if (!fHaveMempool && !fHaveChain) { + // push to local node and sync with wallets + CValidationState state; + bool fMissingInputs; + if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs, + nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) { + if (state.IsInvalid()) { + throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state)); + } else { + if (fMissingInputs) { + throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); + } + throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state)); + } + } 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"); + } else { + // Make sure we don't block forever if re-sending + // a transaction already in mempool. + promise.set_value(); + } + + } // cs_main + + promise.get_future().wait(); + + if(!g_connman) + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + + CInv inv(MSG_TX, hashTx); + g_connman->ForEachNode([&inv](CNode* pnode) + { + pnode->PushInventory(inv); + }); + + return hashTx; +} diff --git a/src/node/transaction.h b/src/node/transaction.h new file mode 100644 index 0000000000..1916c6db26 --- /dev/null +++ b/src/node/transaction.h @@ -0,0 +1,14 @@ +// Copyright (c) 2017-2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_NODE_TRANSACTION_H +#define BITCOIN_NODE_TRANSACTION_H + +#include <primitives/transaction.h> +#include <uint256.h> + +/** Broadcast a transaction */ +uint256 BroadcastTransaction(CTransactionRef tx, bool allowhighfees = false); + +#endif // BITCOIN_NODE_TRANSACTION_H diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 9dac989b97..8e561c6184 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -13,7 +13,7 @@ #include <key_io.h> #include <keystore.h> #include <merkleblock.h> -#include <net.h> +#include <node/transaction.h> #include <policy/policy.h> #include <policy/rbf.h> #include <primitives/transaction.h> @@ -24,13 +24,11 @@ #include <script/script_error.h> #include <script/sign.h> #include <script/standard.h> -#include <txmempool.h> #include <uint256.h> #include <util/strencodings.h> #include <validation.h> #include <validationinterface.h> -#include <future> #include <stdint.h> #include <univalue.h> @@ -1041,8 +1039,6 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) }, }.ToString()); - std::promise<void> promise; - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); // parse hex string from parameter @@ -1050,67 +1046,10 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) if (!DecodeHexTx(mtx, request.params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); CTransactionRef tx(MakeTransactionRef(std::move(mtx))); - const uint256& hashTx = tx->GetHash(); - - CAmount nMaxRawTxFee = maxTxFee; - 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++) { - const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o)); - fHaveChain = !existingCoin.IsSpent(); - } - bool fHaveMempool = mempool.exists(hashTx); - if (!fHaveMempool && !fHaveChain) { - // push to local node and sync with wallets - CValidationState state; - bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs, - nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) { - if (state.IsInvalid()) { - throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state)); - } else { - if (fMissingInputs) { - throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); - } - throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state)); - } - } 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"); - } else { - // Make sure we don't block forever if re-sending - // a transaction already in mempool. - promise.set_value(); - } - - } // cs_main - - promise.get_future().wait(); - - if(!g_connman) - throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - - CInv inv(MSG_TX, hashTx); - g_connman->ForEachNode([&inv](CNode* pnode) - { - pnode->PushInventory(inv); - }); - return hashTx.GetHex(); + bool allowhighfees = false; + if (!request.params[1].isNull()) allowhighfees = request.params[1].get_bool(); + return BroadcastTransaction(tx, allowhighfees).GetHex(); } static UniValue testmempoolaccept(const JSONRPCRequest& request) |