mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-02-28 18:25:48 +01:00
After refactoring general-purpose PSBT and transaction code out of RPC code, for use in the GUI, it's no longer appropriate to throw exceptions. Instead we now return bools for success, and take an output parameter for an error object. We still use JSONRPCError() for the error objects, since only RPC callers actually care about the error codes.
114 lines
3.9 KiB
C++
114 lines
3.9 KiB
C++
// 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::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;
|
|
}
|