Factor BroadcastTransaction out of sendrawtransaction
Factor out a new BroadcastTransaction function, performing the core work of the sendrawtransaction rpc, so that it can be used from the GUI code. Move it from src/rpc/ to src/node/.
This commit is contained in:
parent
c734aaa15d
commit
81cd958848
4 changed files with 99 additions and 65 deletions
|
@ -152,6 +152,7 @@ BITCOIN_CORE_H = \
|
||||||
netaddress.h \
|
netaddress.h \
|
||||||
netbase.h \
|
netbase.h \
|
||||||
netmessagemaker.h \
|
netmessagemaker.h \
|
||||||
|
node/transaction.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
optional.h \
|
optional.h \
|
||||||
outputtype.h \
|
outputtype.h \
|
||||||
|
@ -255,6 +256,7 @@ libbitcoin_server_a_SOURCES = \
|
||||||
miner.cpp \
|
miner.cpp \
|
||||||
net.cpp \
|
net.cpp \
|
||||||
net_processing.cpp \
|
net_processing.cpp \
|
||||||
|
node/transaction.cpp \
|
||||||
noui.cpp \
|
noui.cpp \
|
||||||
outputtype.cpp \
|
outputtype.cpp \
|
||||||
policy/fees.cpp \
|
policy/fees.cpp \
|
||||||
|
|
79
src/node/transaction.cpp
Normal file
79
src/node/transaction.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// 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 <consensus/validation.h>
|
||||||
|
#include <net.h>
|
||||||
|
#include <rpc/server.h>
|
||||||
|
#include <txmempool.h>
|
||||||
|
#include <validation.h>
|
||||||
|
#include <validationinterface.h>
|
||||||
|
#include <node/transaction.h>
|
||||||
|
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees) {
|
||||||
|
std::promise<void> promise;
|
||||||
|
const uint256& hashTx = tx->GetHash();
|
||||||
|
|
||||||
|
CAmount nMaxRawTxFee = maxTxFee;
|
||||||
|
if (allowhighfees)
|
||||||
|
nMaxRawTxFee = 0;
|
||||||
|
|
||||||
|
{ // 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(hashTx, o));
|
||||||
|
fHaveChain = !existingCoin.IsSpent();
|
||||||
|
}
|
||||||
|
bool fHaveMempool = mempool.exists(hashTx);
|
||||||
|
if (!fHaveMempool && !fHaveChain) {
|
||||||
|
// push to local node and sync with wallets
|
||||||
|
CValidationState state;
|
||||||
|
bool fMissingInputs;
|
||||||
|
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
|
||||||
|
nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
|
||||||
|
if (state.IsInvalid()) {
|
||||||
|
throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state));
|
||||||
|
} else {
|
||||||
|
if (fMissingInputs) {
|
||||||
|
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
|
||||||
|
}
|
||||||
|
throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state));
|
||||||
|
}
|
||||||
|
} 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");
|
||||||
|
} 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");
|
||||||
|
|
||||||
|
CInv inv(MSG_TX, hashTx);
|
||||||
|
g_connman->ForEachNode([&inv](CNode* pnode)
|
||||||
|
{
|
||||||
|
pnode->PushInventory(inv);
|
||||||
|
});
|
||||||
|
|
||||||
|
return hashTx;
|
||||||
|
}
|
14
src/node/transaction.h
Normal file
14
src/node/transaction.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// 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 <primitives/transaction.h>
|
||||||
|
#include <uint256.h>
|
||||||
|
|
||||||
|
/** Broadcast a transaction */
|
||||||
|
uint256 BroadcastTransaction(CTransactionRef tx, bool allowhighfees = false);
|
||||||
|
|
||||||
|
#endif // BITCOIN_NODE_TRANSACTION_H
|
|
@ -13,7 +13,7 @@
|
||||||
#include <key_io.h>
|
#include <key_io.h>
|
||||||
#include <keystore.h>
|
#include <keystore.h>
|
||||||
#include <merkleblock.h>
|
#include <merkleblock.h>
|
||||||
#include <net.h>
|
#include <node/transaction.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <policy/rbf.h>
|
#include <policy/rbf.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
|
@ -24,13 +24,11 @@
|
||||||
#include <script/script_error.h>
|
#include <script/script_error.h>
|
||||||
#include <script/sign.h>
|
#include <script/sign.h>
|
||||||
#include <script/standard.h>
|
#include <script/standard.h>
|
||||||
#include <txmempool.h>
|
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
#include <validationinterface.h>
|
#include <validationinterface.h>
|
||||||
|
|
||||||
#include <future>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
@ -1041,8 +1039,6 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
|
||||||
},
|
},
|
||||||
}.ToString());
|
}.ToString());
|
||||||
|
|
||||||
std::promise<void> promise;
|
|
||||||
|
|
||||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
|
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
|
||||||
|
|
||||||
// parse hex string from parameter
|
// parse hex string from parameter
|
||||||
|
@ -1050,67 +1046,10 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
|
||||||
if (!DecodeHexTx(mtx, request.params[0].get_str()))
|
if (!DecodeHexTx(mtx, request.params[0].get_str()))
|
||||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
|
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
|
||||||
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
|
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
|
||||||
const uint256& hashTx = tx->GetHash();
|
|
||||||
|
|
||||||
CAmount nMaxRawTxFee = maxTxFee;
|
bool allowhighfees = false;
|
||||||
if (!request.params[1].isNull() && request.params[1].get_bool())
|
if (!request.params[1].isNull()) allowhighfees = request.params[1].get_bool();
|
||||||
nMaxRawTxFee = 0;
|
return BroadcastTransaction(tx, allowhighfees).GetHex();
|
||||||
|
|
||||||
{ // 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(hashTx, o));
|
|
||||||
fHaveChain = !existingCoin.IsSpent();
|
|
||||||
}
|
|
||||||
bool fHaveMempool = mempool.exists(hashTx);
|
|
||||||
if (!fHaveMempool && !fHaveChain) {
|
|
||||||
// push to local node and sync with wallets
|
|
||||||
CValidationState state;
|
|
||||||
bool fMissingInputs;
|
|
||||||
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
|
|
||||||
nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
|
|
||||||
if (state.IsInvalid()) {
|
|
||||||
throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state));
|
|
||||||
} else {
|
|
||||||
if (fMissingInputs) {
|
|
||||||
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
|
|
||||||
}
|
|
||||||
throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state));
|
|
||||||
}
|
|
||||||
} 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");
|
|
||||||
} 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");
|
|
||||||
|
|
||||||
CInv inv(MSG_TX, hashTx);
|
|
||||||
g_connman->ForEachNode([&inv](CNode* pnode)
|
|
||||||
{
|
|
||||||
pnode->PushInventory(inv);
|
|
||||||
});
|
|
||||||
|
|
||||||
return hashTx.GetHex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
||||||
|
|
Loading…
Reference in a new issue