diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 9e956f680..eb281ef10 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -1,89 +1,117 @@ // 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 #include #include #include #include -#include #include #include #include #include -TxId BroadcastTransaction(const Config &config, const CTransactionRef tx, - const bool allowhighfees) { +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 Config &config, const CTransactionRef tx, + TxId &txid, TransactionError &error, + std::string &err_string, const bool allowhighfees) { std::promise promise; - const TxId &txid = tx->GetId(); + txid = tx->GetId(); Amount nMaxRawTxFee = maxTxFee; if (allowhighfees) { nMaxRawTxFee = Amount::zero(); } { // 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(txid, o)); fHaveChain = !existingCoin.IsSpent(); } bool fHaveMempool = g_mempool.exists(txid); if (!fHaveMempool && !fHaveChain) { // Push to local node and sync with wallets. CValidationState state; bool fMissingInputs; if (!AcceptToMemoryPool(config, g_mempool, state, std::move(tx), &fMissingInputs, false /* bypass_limits */, nMaxRawTxFee)) { if (state.IsInvalid()) { - throw JSONRPCError(RPC_TRANSACTION_REJECTED, - FormatStateMessage(state)); + err_string = FormatStateMessage(state); + error = TransactionError::MEMPOOL_REJECTED; + return false; } if (fMissingInputs) { - throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); + error = TransactionError::MISSING_INPUTS; + return false; } - throw JSONRPCError(RPC_TRANSACTION_ERROR, - FormatStateMessage(state)); + 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) { - throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, - "transaction already in block chain"); + 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) { - throw JSONRPCError( - RPC_CLIENT_P2P_DISABLED, - "Error: Peer-to-peer functionality missing or disabled"); + error = TransactionError::P2P_DISABLED; + return false; } CInv inv(MSG_TX, txid); g_connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); - return txid; + return true; } diff --git a/src/node/transaction.h b/src/node/transaction.h index c8eea037d..dad94689e 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -1,17 +1,47 @@ // Copyright (c) 2017-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. #ifndef BITCOIN_NODE_TRANSACTION_H #define BITCOIN_NODE_TRANSACTION_H #include class Config; struct TxId; -/** Broadcast a transaction */ -TxId BroadcastTransaction(const Config &config, CTransactionRef tx, +enum class TransactionError { + OK = 0, + UNKNOWN_ERROR, + + MISSING_INPUTS, + ALREADY_IN_CHAIN, + P2P_DISABLED, + MEMPOOL_REJECTED, + MEMPOOL_ERROR, + INVALID_PSBT, + SIGHASH_MISMATCH, + + ERROR_COUNT +}; + +#define TRANSACTION_ERR_LAST TransactionError::ERROR_COUNT + +const char *TransactionErrorString(const TransactionError error); + +/** + * Broadcast a transaction + * + * @param[in] tx the transaction to broadcast + * @param[out] &txid the txid of the transaction, if successfully broadcast + * @param[out] &error reference to UniValue to fill with error info on failure + * @param[out] &err_string reference to std::string to fill with error string if + * available + * @param[in] allowhighfees whether to allow fees exceeding maxTxFee + * return true on success, false on error (and fills in `error`) + */ +bool BroadcastTransaction(const Config &config, CTransactionRef tx, TxId &txid, + TransactionError &error, std::string &err_string, bool allowhighfees = false); #endif // BITCOIN_NODE_TRANSACTION_H diff --git a/src/psbt.h b/src/psbt.h index 7650539a7..4beb4221a 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -1,481 +1,482 @@ // 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. #ifndef BITCOIN_PSBT_H #define BITCOIN_PSBT_H #include +#include #include #include #include