2019-01-08 22:16:50 -08:00
|
|
|
// Copyright (c) 2010 Satoshi Nakamoto
|
2020-12-31 09:48:25 +01:00
|
|
|
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
2019-01-08 22:16:50 -08:00
|
|
|
// 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>
|
2019-07-24 17:27:49 -04:00
|
|
|
#include <net_processing.h>
|
2019-09-17 18:28:03 -04:00
|
|
|
#include <node/context.h>
|
2019-01-08 22:16:50 -08:00
|
|
|
#include <validation.h>
|
|
|
|
#include <validationinterface.h>
|
|
|
|
#include <node/transaction.h>
|
|
|
|
|
|
|
|
#include <future>
|
|
|
|
|
2020-10-08 14:10:43 -07:00
|
|
|
static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out)
|
|
|
|
{
|
2020-07-25 10:05:15 -07:00
|
|
|
err_string_out = state.ToString();
|
|
|
|
if (state.IsInvalid()) {
|
|
|
|
if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
|
|
|
|
return TransactionError::MISSING_INPUTS;
|
|
|
|
}
|
|
|
|
return TransactionError::MEMPOOL_REJECTED;
|
|
|
|
} else {
|
|
|
|
return TransactionError::MEMPOOL_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 18:28:03 -04:00
|
|
|
TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
|
2019-02-09 20:51:33 -08:00
|
|
|
{
|
2019-07-30 18:08:03 -04:00
|
|
|
// BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs.
|
2021-01-27 22:18:52 +00:00
|
|
|
// node.peerman is assigned both before chain clients and before RPC server is accepting calls,
|
|
|
|
// and reset after chain clients and RPC sever are stopped. node.peerman should never be null here.
|
2021-01-27 22:05:13 +00:00
|
|
|
assert(node.peerman);
|
2019-11-22 16:24:38 -05:00
|
|
|
assert(node.mempool);
|
2019-01-08 22:16:50 -08:00
|
|
|
std::promise<void> promise;
|
2019-04-11 14:37:30 +00:00
|
|
|
uint256 hashTx = tx->GetHash();
|
|
|
|
bool callback_set = false;
|
2019-01-08 22:16:50 -08:00
|
|
|
|
|
|
|
{ // cs_main scope
|
2021-03-17 16:58:22 -04:00
|
|
|
assert(node.chainman);
|
2019-01-08 22:16:50 -08:00
|
|
|
LOCK(cs_main);
|
2020-10-14 14:12:04 -04:00
|
|
|
assert(std::addressof(::ChainstateActive()) == std::addressof(node.chainman->ActiveChainstate()));
|
2019-07-23 11:49:53 -04:00
|
|
|
// If the transaction is already confirmed in the chain, don't do anything
|
|
|
|
// and return early.
|
2020-10-14 14:12:04 -04:00
|
|
|
CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
|
2019-07-23 11:49:53 -04:00
|
|
|
for (size_t o = 0; o < tx->vout.size(); o++) {
|
2019-01-08 22:16:50 -08:00
|
|
|
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
|
2019-11-04 04:22:53 -05:00
|
|
|
// IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
|
2019-07-23 11:49:53 -04:00
|
|
|
// So if the output does exist, then this transaction exists in the chain.
|
|
|
|
if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN;
|
2019-01-08 22:16:50 -08:00
|
|
|
}
|
2019-11-22 16:24:38 -05:00
|
|
|
if (!node.mempool->exists(hashTx)) {
|
2020-07-25 10:05:15 -07:00
|
|
|
// Transaction is not already in the mempool.
|
2020-10-08 14:10:43 -07:00
|
|
|
if (max_tx_fee > 0) {
|
2020-07-25 10:05:15 -07:00
|
|
|
// First, call ATMP with test_accept and check the fee. If ATMP
|
|
|
|
// fails here, return error immediately.
|
2020-10-14 14:12:04 -04:00
|
|
|
const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
|
2021-01-19 05:29:40 -08:00
|
|
|
true /* test_accept */);
|
|
|
|
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
|
|
|
return HandleATMPError(result.m_state, err_string);
|
|
|
|
} else if (result.m_base_fees.value() > max_tx_fee) {
|
2020-07-25 10:05:15 -07:00
|
|
|
return TransactionError::MAX_FEE_EXCEEDED;
|
2019-01-08 22:16:50 -08:00
|
|
|
}
|
2019-07-23 11:49:53 -04:00
|
|
|
}
|
2020-07-25 10:05:15 -07:00
|
|
|
// Try to submit the transaction to the mempool.
|
2020-10-14 14:12:04 -04:00
|
|
|
const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
|
2021-01-19 05:29:40 -08:00
|
|
|
false /* test_accept */);
|
|
|
|
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
|
|
|
return HandleATMPError(result.m_state, err_string);
|
2020-07-25 10:05:15 -07:00
|
|
|
}
|
2019-07-23 11:49:53 -04:00
|
|
|
|
|
|
|
// Transaction was accepted to the mempool.
|
|
|
|
|
|
|
|
if (wait_callback) {
|
|
|
|
// For transactions broadcast from outside the wallet, make sure
|
|
|
|
// that the wallet has been notified of the transaction before
|
|
|
|
// continuing.
|
|
|
|
//
|
|
|
|
// 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.
|
2019-01-08 22:16:50 -08:00
|
|
|
CallFunctionInValidationInterfaceQueue([&promise] {
|
|
|
|
promise.set_value();
|
|
|
|
});
|
2019-04-11 14:37:30 +00:00
|
|
|
callback_set = true;
|
2019-01-08 22:16:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // cs_main
|
|
|
|
|
2019-04-11 14:37:30 +00:00
|
|
|
if (callback_set) {
|
2019-07-23 11:49:53 -04:00
|
|
|
// Wait until Validation Interface clients have been notified of the
|
|
|
|
// transaction entering the mempool.
|
2019-04-11 14:37:30 +00:00
|
|
|
promise.get_future().wait();
|
2019-02-09 20:51:33 -08:00
|
|
|
}
|
2019-01-08 22:16:50 -08:00
|
|
|
|
2019-04-11 14:37:30 +00:00
|
|
|
if (relay) {
|
2020-01-29 08:12:59 -08:00
|
|
|
// the mempool tracks locally submitted transactions to make a
|
|
|
|
// best-effort of initial broadcast
|
2020-07-27 21:30:50 -07:00
|
|
|
node.mempool->AddUnbroadcastTx(hashTx);
|
2020-01-29 08:12:59 -08:00
|
|
|
|
2020-01-30 09:35:00 -05:00
|
|
|
LOCK(cs_main);
|
2021-01-27 22:18:52 +00:00
|
|
|
node.peerman->RelayTransaction(hashTx, tx->GetWitnessHash());
|
2019-04-11 14:37:30 +00:00
|
|
|
}
|
2019-01-08 22:16:50 -08:00
|
|
|
|
2019-02-14 10:01:06 -05:00
|
|
|
return TransactionError::OK;
|
|
|
|
}
|