Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/rawtransaction.cpp
Show All 21 Lines | |||||
#include <script/script.h> | #include <script/script.h> | ||||
#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 <txmempool.h> | ||||
#include <uint256.h> | #include <uint256.h> | ||||
#include <utilstrencodings.h> | #include <utilstrencodings.h> | ||||
#include <validation.h> | #include <validation.h> | ||||
#include <validationinterface.h> | |||||
#ifdef ENABLE_WALLET | #ifdef ENABLE_WALLET | ||||
#include <wallet/rpcwallet.h> | #include <wallet/rpcwallet.h> | ||||
#endif | #endif | ||||
#include <cstdint> | #include <cstdint> | ||||
#include <future> | |||||
#include <univalue.h> | #include <univalue.h> | ||||
static void TxToJSON(const CTransaction &tx, const uint256 hashBlock, | static void TxToJSON(const CTransaction &tx, const uint256 hashBlock, | ||||
UniValue &entry) { | UniValue &entry) { | ||||
// Call into TxToUniv() in bitcoin-common to decode the transaction hex. | // Call into TxToUniv() in bitcoin-common to decode the transaction hex. | ||||
// | // | ||||
// Blockchain contextual information (confirmations and blocktime) is not | // Blockchain contextual information (confirmations and blocktime) is not | ||||
▲ Show 20 Lines • Show All 1,241 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() < 1 || | ||||
"1. \"hexstring\" (string, required) The hex string of the raw " | "1. \"hexstring\" (string, required) The hex string of the raw " | ||||
"transaction)\n" | "transaction)\n" | ||||
"2. allowhighfees (boolean, optional, default=false) Allow high " | "2. allowhighfees (boolean, optional, default=false) Allow high " | ||||
"fees\n" | "fees\n" | ||||
"\nResult:\n" | "\nResult:\n" | ||||
"\"hex\" (string) The transaction hash in hex\n" | "\"hex\" (string) The transaction hash in hex\n" | ||||
"\nExamples:\n" | "\nExamples:\n" | ||||
"\nCreate a transaction\n" + | "\nCreate a transaction\n" + | ||||
HelpExampleCli("createrawtransaction", | HelpExampleCli( | ||||
"\"[{\\\"txid\\\" : " | "createrawtransaction", | ||||
"\\\"mytxid\\\",\\\"vout\\\":0}]\" " | "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" " | ||||
"\"{\\\"myaddress\\\":0.01}\"") + | "\"{\\\"myaddress\\\":0.01}\"") + | ||||
"Sign the transaction, and get back the hex\n" + | "Sign the transaction, and get back the hex\n" + | ||||
HelpExampleCli("signrawtransaction", "\"myhex\"") + | HelpExampleCli("signrawtransaction", "\"myhex\"") + | ||||
"\nSend the transaction (signed hex)\n" + | "\nSend the transaction (signed hex)\n" + | ||||
HelpExampleCli("sendrawtransaction", "\"signedhex\"") + | HelpExampleCli("sendrawtransaction", "\"signedhex\"") + | ||||
"\nAs a json rpc call\n" + | "\nAs a json rpc call\n" + | ||||
HelpExampleRpc("sendrawtransaction", "\"signedhex\"")); | HelpExampleRpc("sendrawtransaction", "\"signedhex\"")); | ||||
} | } | ||||
LOCK(cs_main); | 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 | ||||
CMutableTransaction mtx; | CMutableTransaction mtx; | ||||
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 &txid = tx->GetId(); | const uint256 &txid = tx->GetId(); | ||||
bool fLimitFree = false; | bool fLimitFree = false; | ||||
Amount nMaxRawTxFee = maxTxFee; | Amount nMaxRawTxFee = maxTxFee; | ||||
if (request.params.size() > 1 && request.params[1].get_bool()) { | if (request.params.size() > 1 && request.params[1].get_bool()) { | ||||
nMaxRawTxFee = Amount::zero(); | nMaxRawTxFee = Amount::zero(); | ||||
} | } | ||||
{ // cs_main scope | |||||
LOCK(cs_main); | |||||
CCoinsViewCache &view = *pcoinsTip; | CCoinsViewCache &view = *pcoinsTip; | ||||
bool fHaveChain = false; | bool fHaveChain = false; | ||||
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { | for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { | ||||
const Coin &existingCoin = view.AccessCoin(COutPoint(txid, o)); | const Coin &existingCoin = view.AccessCoin(COutPoint(txid, o)); | ||||
fHaveChain = !existingCoin.IsSpent(); | fHaveChain = !existingCoin.IsSpent(); | ||||
} | } | ||||
bool fHaveMempool = g_mempool.exists(txid); | bool fHaveMempool = g_mempool.exists(txid); | ||||
if (!fHaveMempool && !fHaveChain) { | if (!fHaveMempool && !fHaveChain) { | ||||
// Push to local node and sync with wallets. | // Push to local node and sync with wallets. | ||||
CValidationState state; | CValidationState state; | ||||
bool fMissingInputs; | bool fMissingInputs; | ||||
if (!AcceptToMemoryPool(config, g_mempool, state, std::move(tx), | if (!AcceptToMemoryPool(config, g_mempool, state, std::move(tx), | ||||
fLimitFree, &fMissingInputs, false, | fLimitFree, &fMissingInputs, false, | ||||
nMaxRawTxFee)) { | nMaxRawTxFee)) { | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
throw JSONRPCError(RPC_TRANSACTION_REJECTED, | throw JSONRPCError(RPC_TRANSACTION_REJECTED, | ||||
strprintf("%i: %s", state.GetRejectCode(), | strprintf("%i: %s", | ||||
state.GetRejectCode(), | |||||
state.GetRejectReason())); | state.GetRejectReason())); | ||||
} else { | } | ||||
if (fMissingInputs) { | if (fMissingInputs) { | ||||
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); | throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); | ||||
} | } | ||||
throw JSONRPCError(RPC_TRANSACTION_ERROR, | throw JSONRPCError(RPC_TRANSACTION_ERROR, | ||||
state.GetRejectReason()); | state.GetRejectReason()); | ||||
} | } 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) { | } else if (fHaveChain) { | ||||
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, | throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, | ||||
"transaction already in block 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) { | if (!g_connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
CInv inv(MSG_TX, txid); | CInv inv(MSG_TX, txid); | ||||
g_connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); | g_connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); | ||||
return txid.GetHex(); | return txid.GetHex(); | ||||
} | } | ||||
UniValue testmempoolaccept(const Config &config, | UniValue testmempoolaccept(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 1 || | if (request.fHelp || request.params.size() < 1 || | ||||
request.params.size() > 2) { | request.params.size() > 2) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
▲ Show 20 Lines • Show All 106 Lines • Show Last 20 Lines |