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 +#include +#include +#include +#include +#include +#include + +#include + +uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees) { + std::promise 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 +#include + +/** 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 #include #include -#include +#include #include #include #include @@ -24,13 +24,11 @@ #include