Add BroadcastTransaction utility usage in Chain interface
Access through a broadcastTransaction method. Add a wait_callback flag to turn off race protection when wallet already track its tx being in mempool Standardise highfee, absurdfee variable name to max_tx_fee We drop the P2P check in BroadcastTransaction as g_connman is only called by RPCs and the wallet scheduler, both of which are initialized after g_connman is assigned and stopped before g_connman is reset.
This commit is contained in:
parent
7821821a23
commit
8c8aa19b4b
5 changed files with 34 additions and 19 deletions
|
@ -11,6 +11,7 @@
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
#include <net_processing.h>
|
#include <net_processing.h>
|
||||||
#include <node/coin.h>
|
#include <node/coin.h>
|
||||||
|
#include <node/transaction.h>
|
||||||
#include <policy/fees.h>
|
#include <policy/fees.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <policy/rbf.h>
|
#include <policy/rbf.h>
|
||||||
|
@ -295,6 +296,14 @@ public:
|
||||||
{
|
{
|
||||||
RelayTransaction(txid, *g_connman);
|
RelayTransaction(txid, *g_connman);
|
||||||
}
|
}
|
||||||
|
bool broadcastTransaction(const CTransactionRef& tx, std::string& err_string, const CAmount& max_tx_fee, bool relay) override
|
||||||
|
{
|
||||||
|
const TransactionError err = BroadcastTransaction(tx, err_string, max_tx_fee, relay, /*wait_callback*/ false);
|
||||||
|
// Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
|
||||||
|
// Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
|
||||||
|
// that Chain clients do not need to know about.
|
||||||
|
return TransactionError::OK == err;
|
||||||
|
}
|
||||||
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
|
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
|
||||||
{
|
{
|
||||||
::mempool.GetTransactionAncestry(txid, ancestors, descendants);
|
::mempool.GetTransactionAncestry(txid, ancestors, descendants);
|
||||||
|
|
|
@ -167,6 +167,11 @@ public:
|
||||||
//! Relay transaction.
|
//! Relay transaction.
|
||||||
virtual void relayTransaction(const uint256& txid) = 0;
|
virtual void relayTransaction(const uint256& txid) = 0;
|
||||||
|
|
||||||
|
//! Transaction is added to memory pool, if the transaction fee is below the
|
||||||
|
//! amount specified by max_tx_fee, and broadcast to all peers if relay is set to true.
|
||||||
|
//! Return false if the transaction could not be added due to the fee or for another reason.
|
||||||
|
virtual bool broadcastTransaction(const CTransactionRef& tx, std::string& err_string, const CAmount& max_tx_fee, bool relay) = 0;
|
||||||
|
|
||||||
//! Calculate mempool ancestor and descendant counts for the given transaction.
|
//! Calculate mempool ancestor and descendant counts for the given transaction.
|
||||||
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0;
|
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0;
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,12 @@
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, std::string& err_string, const CAmount& highfee)
|
TransactionError BroadcastTransaction(const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
|
||||||
{
|
{
|
||||||
|
assert(g_connman);
|
||||||
std::promise<void> promise;
|
std::promise<void> promise;
|
||||||
hashTx = tx->GetHash();
|
uint256 hashTx = tx->GetHash();
|
||||||
|
bool callback_set = false;
|
||||||
|
|
||||||
{ // cs_main scope
|
{ // cs_main scope
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
@ -33,7 +35,7 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx,
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool fMissingInputs;
|
bool fMissingInputs;
|
||||||
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
|
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
|
||||||
nullptr /* plTxnReplaced */, false /* bypass_limits */, highfee)) {
|
nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
err_string = FormatStateMessage(state);
|
err_string = FormatStateMessage(state);
|
||||||
return TransactionError::MEMPOOL_REJECTED;
|
return TransactionError::MEMPOOL_REJECTED;
|
||||||
|
@ -44,7 +46,7 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx,
|
||||||
err_string = FormatStateMessage(state);
|
err_string = FormatStateMessage(state);
|
||||||
return TransactionError::MEMPOOL_ERROR;
|
return TransactionError::MEMPOOL_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (wait_callback) {
|
||||||
// If wallet is enabled, ensure that the wallet has been made aware
|
// If wallet is enabled, ensure that the wallet has been made aware
|
||||||
// of the new transaction prior to returning. This prevents a race
|
// of the new transaction prior to returning. This prevents a race
|
||||||
// where a user might call sendrawtransaction with a transaction
|
// where a user might call sendrawtransaction with a transaction
|
||||||
|
@ -53,24 +55,21 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx,
|
||||||
CallFunctionInValidationInterfaceQueue([&promise] {
|
CallFunctionInValidationInterfaceQueue([&promise] {
|
||||||
promise.set_value();
|
promise.set_value();
|
||||||
});
|
});
|
||||||
|
callback_set = true;
|
||||||
}
|
}
|
||||||
} else if (fHaveChain) {
|
} else if (fHaveChain) {
|
||||||
return TransactionError::ALREADY_IN_CHAIN;
|
return TransactionError::ALREADY_IN_CHAIN;
|
||||||
} else {
|
|
||||||
// Make sure we don't block forever if re-sending
|
|
||||||
// a transaction already in mempool.
|
|
||||||
promise.set_value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // cs_main
|
} // cs_main
|
||||||
|
|
||||||
promise.get_future().wait();
|
if (callback_set) {
|
||||||
|
promise.get_future().wait();
|
||||||
if (!g_connman) {
|
|
||||||
return TransactionError::P2P_DISABLED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RelayTransaction(hashTx, *g_connman);
|
if (relay) {
|
||||||
|
RelayTransaction(hashTx, *g_connman);
|
||||||
|
}
|
||||||
|
|
||||||
return TransactionError::OK;
|
return TransactionError::OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,13 @@
|
||||||
* Broadcast a transaction
|
* Broadcast a transaction
|
||||||
*
|
*
|
||||||
* @param[in] tx the transaction to broadcast
|
* @param[in] tx the transaction to broadcast
|
||||||
* @param[out] &txid the txid of the transaction, if successfully broadcast
|
|
||||||
* @param[out] &err_string reference to std::string to fill with error string if available
|
* @param[out] &err_string reference to std::string to fill with error string if available
|
||||||
* @param[in] highfee Reject txs with fees higher than this (if 0, accept any fee)
|
* @param[in] max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
|
||||||
|
* @param[in] relay flag if both mempool insertion and p2p relay are requested
|
||||||
|
* @param[in] wait_callback, wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
|
||||||
|
* It MUST NOT be set while cs_main, cs_mempool or cs_wallet are held to avoid deadlock
|
||||||
* return error
|
* return error
|
||||||
*/
|
*/
|
||||||
NODISCARD TransactionError BroadcastTransaction(CTransactionRef tx, uint256& txid, std::string& err_string, const CAmount& highfee);
|
NODISCARD TransactionError BroadcastTransaction(CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback);
|
||||||
|
|
||||||
#endif // BITCOIN_NODE_TRANSACTION_H
|
#endif // BITCOIN_NODE_TRANSACTION_H
|
||||||
|
|
|
@ -810,14 +810,14 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
|
||||||
max_raw_tx_fee = fr.GetFee((weight+3)/4);
|
max_raw_tx_fee = fr.GetFee((weight+3)/4);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 txid;
|
|
||||||
std::string err_string;
|
std::string err_string;
|
||||||
const TransactionError err = BroadcastTransaction(tx, txid, err_string, max_raw_tx_fee);
|
AssertLockNotHeld(cs_main);
|
||||||
|
const TransactionError err = BroadcastTransaction(tx, err_string, max_raw_tx_fee, /*relay*/ true, /*wait_callback*/ true);
|
||||||
if (TransactionError::OK != err) {
|
if (TransactionError::OK != err) {
|
||||||
throw JSONRPCTransactionError(err, err_string);
|
throw JSONRPCTransactionError(err, err_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
return txid.GetHex();
|
return tx->GetHash().GetHex();
|
||||||
}
|
}
|
||||||
|
|
||||||
static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
||||||
|
|
Loading…
Add table
Reference in a new issue