aboutsummaryrefslogtreecommitdiff
path: root/src/node/transaction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/node/transaction.cpp')
-rw-r--r--src/node/transaction.cpp115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
new file mode 100644
index 0000000000..c9cdd0d1cd
--- /dev/null
+++ b/src/node/transaction.cpp
@@ -0,0 +1,115 @@
+// 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 <txmempool.h>
+#include <validation.h>
+#include <validationinterface.h>
+#include <node/transaction.h>
+
+#include <future>
+
+const char* TransactionErrorString(const TransactionError err)
+{
+ switch (err) {
+ case TransactionError::OK:
+ return "No error";
+ case TransactionError::MISSING_INPUTS:
+ return "Missing inputs";
+ case TransactionError::ALREADY_IN_CHAIN:
+ return "Transaction already in block chain";
+ case TransactionError::P2P_DISABLED:
+ return "Peer-to-peer functionality missing or disabled";
+ case TransactionError::MEMPOOL_REJECTED:
+ return "Transaction rejected by AcceptToMemoryPool";
+ case TransactionError::MEMPOOL_ERROR:
+ return "AcceptToMemoryPool failed";
+ case TransactionError::INVALID_PSBT:
+ return "PSBT is not sane";
+ case TransactionError::PSBT_MISMATCH:
+ return "PSBTs not compatible (different transactions)";
+ case TransactionError::SIGHASH_MISMATCH:
+ return "Specified sighash value does not match existing value";
+
+ case TransactionError::UNKNOWN_ERROR:
+ default: break;
+ }
+ return "Unknown error";
+}
+
+bool BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, TransactionError& error, std::string& err_string, const bool allowhighfees)
+{
+ std::promise<void> promise;
+ 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()) {
+ err_string = FormatStateMessage(state);
+ error = TransactionError::MEMPOOL_REJECTED;
+ return false;
+ } else {
+ if (fMissingInputs) {
+ error = TransactionError::MISSING_INPUTS;
+ return false;
+ }
+ err_string = FormatStateMessage(state);
+ error = TransactionError::MEMPOOL_ERROR;
+ return false;
+ }
+ } 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) {
+ error = TransactionError::ALREADY_IN_CHAIN;
+ return false;
+ } 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) {
+ error = TransactionError::P2P_DISABLED;
+ return false;
+ }
+
+ CInv inv(MSG_TX, hashTx);
+ g_connman->ForEachNode([&inv](CNode* pnode)
+ {
+ pnode->PushInventory(inv);
+ });
+
+ return true;
+ }