Changeset View
Changeset View
Standalone View
Standalone View
src/node/transaction.cpp
Show All 22 Lines | TransactionError BroadcastTransaction(NodeContext &node, const Config &config, | ||||
std::string &err_string, | std::string &err_string, | ||||
const Amount max_tx_fee, bool relay, | const Amount max_tx_fee, bool relay, | ||||
bool wait_callback) { | bool wait_callback) { | ||||
// BroadcastTransaction can be called by either sendrawtransaction RPC or | // BroadcastTransaction can be called by either sendrawtransaction RPC or | ||||
// wallet RPCs. node.connman is assigned both before chain clients and | // wallet RPCs. node.connman is assigned both before chain clients and | ||||
// before RPC server is accepting calls, and reset after chain clients and | // before RPC server is accepting calls, and reset after chain clients and | ||||
// RPC sever are stopped. node.connman should never be null here. | // RPC sever are stopped. node.connman should never be null here. | ||||
assert(node.connman); | assert(node.connman); | ||||
assert(node.mempool); | |||||
std::promise<void> promise; | std::promise<void> promise; | ||||
TxId txid = tx->GetId(); | TxId txid = tx->GetId(); | ||||
bool callback_set = false; | bool callback_set = false; | ||||
{ // cs_main scope | { // cs_main scope | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// If the transaction is already confirmed in the chain, don't do | // If the transaction is already confirmed in the chain, don't do | ||||
// anything and return early. | // anything and return early. | ||||
CCoinsViewCache &view = ::ChainstateActive().CoinsTip(); | CCoinsViewCache &view = ::ChainstateActive().CoinsTip(); | ||||
for (size_t o = 0; o < tx->vout.size(); o++) { | for (size_t o = 0; o < tx->vout.size(); o++) { | ||||
const Coin &existingCoin = view.AccessCoin(COutPoint(txid, o)); | const Coin &existingCoin = view.AccessCoin(COutPoint(txid, o)); | ||||
// IsSpent doesnt mean the coin is spent, it means the output | // IsSpent doesnt mean the coin is spent, it means the output | ||||
// doesnt' exist. So if the output does exist, then this transaction | // doesnt' exist. So if the output does exist, then this transaction | ||||
// exists in the chain. | // exists in the chain. | ||||
if (!existingCoin.IsSpent()) { | if (!existingCoin.IsSpent()) { | ||||
return TransactionError::ALREADY_IN_CHAIN; | return TransactionError::ALREADY_IN_CHAIN; | ||||
} | } | ||||
} | } | ||||
if (!g_mempool.exists(txid)) { | if (!node.mempool->exists(txid)) { | ||||
// Transaction is not already in the mempool. Submit it. | // Transaction is not already in the mempool. Submit it. | ||||
TxValidationState state; | TxValidationState state; | ||||
if (!AcceptToMemoryPool(config, g_mempool, state, std::move(tx), | if (!AcceptToMemoryPool(config, *node.mempool, state, std::move(tx), | ||||
false /* bypass_limits */, max_tx_fee)) { | false /* bypass_limits */, max_tx_fee)) { | ||||
err_string = FormatStateMessage(state); | err_string = FormatStateMessage(state); | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
if (state.GetResult() == | if (state.GetResult() == | ||||
TxValidationResult::TX_MISSING_INPUTS) { | TxValidationResult::TX_MISSING_INPUTS) { | ||||
return TransactionError::MISSING_INPUTS; | return TransactionError::MISSING_INPUTS; | ||||
} | } | ||||
return TransactionError::MEMPOOL_REJECTED; | return TransactionError::MEMPOOL_REJECTED; | ||||
Show All 34 Lines |