diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 335188a73a..3ddcc3d1e1 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -1,92 +1,83 @@ // 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 -bool BroadcastTransaction(const Config &config, const CTransactionRef tx, - TxId &txid, TransactionError &error, - std::string &err_string, const bool allowhighfees) { +TransactionError BroadcastTransaction(const Config &config, + const CTransactionRef tx, TxId &txid, + std::string &err_string, + const Amount highFee) { std::promise promise; 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)) { + highFee)) { if (state.IsInvalid()) { err_string = FormatStateMessage(state); - error = TransactionError::MEMPOOL_REJECTED; - return false; + return TransactionError::MEMPOOL_REJECTED; } if (fMissingInputs) { - error = TransactionError::MISSING_INPUTS; - return false; + return TransactionError::MISSING_INPUTS; } err_string = FormatStateMessage(state); - error = TransactionError::MEMPOOL_ERROR; - return false; + return TransactionError::MEMPOOL_ERROR; } 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; + 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 promise.get_future().wait(); if (!g_connman) { - error = TransactionError::P2P_DISABLED; - return false; + return TransactionError::P2P_DISABLED; } CInv inv(MSG_TX, txid); g_connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); - return true; + return TransactionError::OK; } diff --git a/src/node/transaction.h b/src/node/transaction.h index 98092dd51b..eeb76504ec 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -1,29 +1,31 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 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 #include #include class Config; struct TxId; /** * 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`) + * @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) + * @return error */ -bool BroadcastTransaction(const Config &config, CTransactionRef tx, TxId &txid, - TransactionError &error, std::string &err_string, - bool allowhighfees = false); +NODISCARD TransactionError BroadcastTransaction(const Config &config, + CTransactionRef tx, TxId &txid, + std::string &err_string, + Amount highfee); #endif // BITCOIN_NODE_TRANSACTION_H diff --git a/src/psbt.cpp b/src/psbt.cpp index 23d043b109..e20e46e8ff 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -1,229 +1,228 @@ // 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 PartiallySignedTransaction::PartiallySignedTransaction(const CTransaction &txIn) : tx(txIn) { inputs.resize(txIn.vin.size()); outputs.resize(txIn.vout.size()); } bool PartiallySignedTransaction::IsNull() const { return !tx && inputs.empty() && outputs.empty() && unknown.empty(); } bool PartiallySignedTransaction::Merge(const PartiallySignedTransaction &psbt) { // Prohibited to merge two PSBTs over different transactions if (tx->GetId() != psbt.tx->GetId()) { return false; } for (size_t i = 0; i < inputs.size(); ++i) { inputs[i].Merge(psbt.inputs[i]); } for (size_t i = 0; i < outputs.size(); ++i) { outputs[i].Merge(psbt.outputs[i]); } unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); return true; } bool PartiallySignedTransaction::IsSane() const { for (PSBTInput input : inputs) { if (!input.IsSane()) { return false; } } return true; } bool PSBTInput::IsNull() const { return utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty(); } void PSBTInput::FillSignatureData(SignatureData &sigdata) const { if (!final_script_sig.empty()) { sigdata.scriptSig = final_script_sig; sigdata.complete = true; } if (sigdata.complete) { return; } sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end()); if (!redeem_script.empty()) { sigdata.redeem_script = redeem_script; } for (const auto &key_pair : hd_keypaths) { sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); } } void PSBTInput::FromSignatureData(const SignatureData &sigdata) { if (sigdata.complete) { partial_sigs.clear(); hd_keypaths.clear(); redeem_script.clear(); if (!sigdata.scriptSig.empty()) { final_script_sig = sigdata.scriptSig; } return; } partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end()); if (redeem_script.empty() && !sigdata.redeem_script.empty()) { redeem_script = sigdata.redeem_script; } for (const auto &entry : sigdata.misc_pubkeys) { hd_keypaths.emplace(entry.second); } } void PSBTInput::Merge(const PSBTInput &input) { if (utxo.IsNull() && !input.utxo.IsNull()) { utxo = input.utxo; } partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end()); hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end()); unknown.insert(input.unknown.begin(), input.unknown.end()); if (redeem_script.empty() && !input.redeem_script.empty()) { redeem_script = input.redeem_script; } if (final_script_sig.empty() && !input.final_script_sig.empty()) { final_script_sig = input.final_script_sig; } } bool PSBTInput::IsSane() const { return true; } void PSBTOutput::FillSignatureData(SignatureData &sigdata) const { if (!redeem_script.empty()) { sigdata.redeem_script = redeem_script; } for (const auto &key_pair : hd_keypaths) { sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair); } } void PSBTOutput::FromSignatureData(const SignatureData &sigdata) { if (redeem_script.empty() && !sigdata.redeem_script.empty()) { redeem_script = sigdata.redeem_script; } for (const auto &entry : sigdata.misc_pubkeys) { hd_keypaths.emplace(entry.second); } } bool PSBTOutput::IsNull() const { return redeem_script.empty() && hd_keypaths.empty() && unknown.empty(); } void PSBTOutput::Merge(const PSBTOutput &output) { hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end()); unknown.insert(output.unknown.begin(), output.unknown.end()); if (redeem_script.empty() && !output.redeem_script.empty()) { redeem_script = output.redeem_script; } } bool PSBTInputSigned(PSBTInput &input) { return !input.final_script_sig.empty(); } bool SignPSBTInput(const SigningProvider &provider, PartiallySignedTransaction &psbt, int index, SigHashType sighash) { PSBTInput &input = psbt.inputs.at(index); const CMutableTransaction &tx = *psbt.tx; if (PSBTInputSigned(input)) { return true; } // Fill SignatureData with input info SignatureData sigdata; input.FillSignatureData(sigdata); // Get UTXO CTxOut utxo; // Verify input sanity if (!input.IsSane()) { return false; } if (input.utxo.IsNull()) { return false; } utxo = input.utxo; MutableTransactionSignatureCreator creator(&tx, index, utxo.nValue, sighash); bool sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata); input.FromSignatureData(sigdata); return sig_complete; } bool FinalizePSBT(PartiallySignedTransaction &psbtx) { // Finalize input signatures -- in case we have partial signatures that add // up to a complete // signature, but have not combined them yet (e.g. because the combiner // that created this PartiallySignedTransaction did not understand them), // this will combine them into a final script. bool complete = true; for (size_t i = 0; i < psbtx.tx->vin.size(); ++i) { complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, SigHashType()); } return complete; } bool FinalizeAndExtractPSBT(PartiallySignedTransaction &psbtx, CMutableTransaction &result) { // It's not safe to extract a PSBT that isn't finalized, and there's no easy // way to check // whether a PSBT is finalized without finalizing it, so we just do this. if (!FinalizePSBT(psbtx)) { return false; } result = *psbtx.tx; for (size_t i = 0; i < result.vin.size(); ++i) { result.vin[i].scriptSig = psbtx.inputs[i].final_script_sig; } return true; } -bool CombinePSBTs(PartiallySignedTransaction &out, TransactionError &error, - const std::vector &psbtxs) { +TransactionError +CombinePSBTs(PartiallySignedTransaction &out, + const std::vector &psbtxs) { // Copy the first one out = psbtxs[0]; // Merge for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) { if (!out.Merge(*it)) { - error = TransactionError::PSBT_MISMATCH; - return false; + return TransactionError::PSBT_MISMATCH; } } if (!out.IsSane()) { - error = TransactionError::INVALID_PSBT; - return false; + return TransactionError::INVALID_PSBT; } - return true; + return TransactionError::OK; } diff --git a/src/psbt.h b/src/psbt.h index be1d6ae451..8bf0af0b47 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -1,519 +1,518 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 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