Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/rawtransaction.cpp
// Copyright (c) 2010 Satoshi Nakamoto | // Copyright (c) 2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <base58.h> | #include <base58.h> | ||||
#include <chain.h> | #include <chain.h> | ||||
#include <coins.h> | #include <coins.h> | ||||
#include <config.h> | #include <config.h> | ||||
#include <consensus/validation.h> | #include <consensus/validation.h> | ||||
#include <core_io.h> | #include <core_io.h> | ||||
#include <dstencode.h> | #include <dstencode.h> | ||||
#include <index/txindex.h> | |||||
#include <init.h> | #include <init.h> | ||||
#include <keystore.h> | #include <keystore.h> | ||||
#include <merkleblock.h> | #include <merkleblock.h> | ||||
#include <net.h> | #include <net.h> | ||||
#include <policy/policy.h> | #include <policy/policy.h> | ||||
#include <primitives/transaction.h> | #include <primitives/transaction.h> | ||||
#include <rpc/rawtransaction.h> | #include <rpc/rawtransaction.h> | ||||
#include <rpc/server.h> | #include <rpc/server.h> | ||||
Show All 18 Lines | static void TxToJSON(const CTransaction &tx, const uint256 hashBlock, | ||||
// 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 | ||||
// available to code in bitcoin-common, so we query them here and push the | // available to code in bitcoin-common, so we query them here and push the | ||||
// data into the returned UniValue. | // data into the returned UniValue. | ||||
TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags()); | TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags()); | ||||
if (!hashBlock.IsNull()) { | if (!hashBlock.IsNull()) { | ||||
LOCK(cs_main); | |||||
entry.pushKV("blockhash", hashBlock.GetHex()); | entry.pushKV("blockhash", hashBlock.GetHex()); | ||||
CBlockIndex *pindex = LookupBlockIndex(hashBlock); | CBlockIndex *pindex = LookupBlockIndex(hashBlock); | ||||
if (pindex) { | if (pindex) { | ||||
if (chainActive.Contains(pindex)) { | if (chainActive.Contains(pindex)) { | ||||
entry.pushKV("confirmations", | entry.pushKV("confirmations", | ||||
1 + chainActive.Height() - pindex->nHeight); | 1 + chainActive.Height() - pindex->nHeight); | ||||
entry.pushKV("time", pindex->GetBlockTime()); | entry.pushKV("time", pindex->GetBlockTime()); | ||||
entry.pushKV("blocktime", pindex->GetBlockTime()); | entry.pushKV("blocktime", pindex->GetBlockTime()); | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() < 1 || | ||||
HelpExampleCli("getrawtransaction", "\"mytxid\" true") + | HelpExampleCli("getrawtransaction", "\"mytxid\" true") + | ||||
HelpExampleRpc("getrawtransaction", "\"mytxid\", true") + | HelpExampleRpc("getrawtransaction", "\"mytxid\", true") + | ||||
HelpExampleCli("getrawtransaction", | HelpExampleCli("getrawtransaction", | ||||
"\"mytxid\" false \"myblockhash\"") + | "\"mytxid\" false \"myblockhash\"") + | ||||
HelpExampleCli("getrawtransaction", | HelpExampleCli("getrawtransaction", | ||||
"\"mytxid\" true \"myblockhash\"")); | "\"mytxid\" true \"myblockhash\"")); | ||||
} | } | ||||
LOCK(cs_main); | |||||
bool in_active_chain = true; | bool in_active_chain = true; | ||||
TxId txid = TxId(ParseHashV(request.params[0], "parameter 1")); | TxId txid = TxId(ParseHashV(request.params[0], "parameter 1")); | ||||
CBlockIndex *blockindex = nullptr; | CBlockIndex *blockindex = nullptr; | ||||
if (txid == config.GetChainParams().GenesisBlock().hashMerkleRoot) { | if (txid == config.GetChainParams().GenesisBlock().hashMerkleRoot) { | ||||
// Special exception for the genesis block coinbase transaction | // Special exception for the genesis block coinbase transaction | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"The genesis block coinbase is not considered an " | "The genesis block coinbase is not considered an " | ||||
"ordinary transaction and cannot be retrieved"); | "ordinary transaction and cannot be retrieved"); | ||||
} | } | ||||
// Accept either a bool (true) or a num (>=1) to indicate verbose output. | // Accept either a bool (true) or a num (>=1) to indicate verbose output. | ||||
bool fVerbose = false; | bool fVerbose = false; | ||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
fVerbose = request.params[1].isNum() | fVerbose = request.params[1].isNum() | ||||
? (request.params[1].get_int() != 0) | ? (request.params[1].get_int() != 0) | ||||
: request.params[1].get_bool(); | : request.params[1].get_bool(); | ||||
} | } | ||||
if (!request.params[2].isNull()) { | if (!request.params[2].isNull()) { | ||||
LOCK(cs_main); | |||||
uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); | uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); | ||||
blockindex = LookupBlockIndex(blockhash); | blockindex = LookupBlockIndex(blockhash); | ||||
if (!blockindex) { | if (!blockindex) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Block hash not found"); | "Block hash not found"); | ||||
} | } | ||||
in_active_chain = chainActive.Contains(blockindex); | in_active_chain = chainActive.Contains(blockindex); | ||||
} | } | ||||
bool f_txindex_ready = false; | |||||
if (g_txindex && !blockindex) { | |||||
f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain(); | |||||
} | |||||
CTransactionRef tx; | CTransactionRef tx; | ||||
uint256 hash_block; | uint256 hash_block; | ||||
if (!GetTransaction(config, txid, tx, hash_block, true, blockindex)) { | if (!GetTransaction(config, txid, tx, hash_block, true, blockindex)) { | ||||
std::string errmsg; | std::string errmsg; | ||||
if (blockindex) { | if (blockindex) { | ||||
if (!blockindex->nStatus.hasData()) { | if (!blockindex->nStatus.hasData()) { | ||||
throw JSONRPCError(RPC_MISC_ERROR, "Block not available"); | throw JSONRPCError(RPC_MISC_ERROR, "Block not available"); | ||||
} | } | ||||
errmsg = "No such transaction found in the provided block"; | errmsg = "No such transaction found in the provided block"; | ||||
} else if (!g_txindex) { | |||||
errmsg = "No such mempool transaction. Use -txindex to enable " | |||||
"blockchain transaction queries"; | |||||
} else if (!f_txindex_ready) { | |||||
errmsg = "No such mempool transaction. Blockchain transactions are " | |||||
"still in the process of being indexed"; | |||||
} else { | } else { | ||||
errmsg = fTxIndex ? "No such mempool or blockchain transaction" | errmsg = "No such mempool or blockchain transaction"; | ||||
: "No such mempool transaction. Use -txindex to " | |||||
"enable blockchain transaction queries"; | |||||
} | } | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
errmsg + | errmsg + | ||||
". Use gettransaction for wallet transactions."); | ". Use gettransaction for wallet transactions."); | ||||
} | } | ||||
if (!fVerbose) { | if (!fVerbose) { | ||||
return EncodeHexTx(*tx, RPCSerializationFlags()); | return EncodeHexTx(*tx, RPCSerializationFlags()); | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | for (unsigned int idx = 0; idx < txids.size(); idx++) { | ||||
std::string("Invalid parameter, duplicated txid: ") + | std::string("Invalid parameter, duplicated txid: ") + | ||||
utxid.get_str()); | utxid.get_str()); | ||||
} | } | ||||
setTxIds.insert(txid); | setTxIds.insert(txid); | ||||
oneTxId = txid; | oneTxId = txid; | ||||
} | } | ||||
LOCK(cs_main); | |||||
CBlockIndex *pblockindex = nullptr; | CBlockIndex *pblockindex = nullptr; | ||||
uint256 hashBlock; | uint256 hashBlock; | ||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
LOCK(cs_main); | |||||
hashBlock = uint256S(request.params[1].get_str()); | hashBlock = uint256S(request.params[1].get_str()); | ||||
pblockindex = LookupBlockIndex(hashBlock); | pblockindex = LookupBlockIndex(hashBlock); | ||||
if (!pblockindex) { | if (!pblockindex) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); | ||||
} | } | ||||
} else { | } else { | ||||
LOCK(cs_main); | |||||
// Loop through txids and try to find which block they're in. Exit loop | // Loop through txids and try to find which block they're in. Exit loop | ||||
// once a block is found. | // once a block is found. | ||||
for (const auto &txid : setTxIds) { | for (const auto &txid : setTxIds) { | ||||
const Coin &coin = AccessByTxid(*pcoinsTip, txid); | const Coin &coin = AccessByTxid(*pcoinsTip, txid); | ||||
if (!coin.IsSpent()) { | if (!coin.IsSpent()) { | ||||
pblockindex = chainActive[coin.GetHeight()]; | pblockindex = chainActive[coin.GetHeight()]; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Allow txindex to catch up if we need to query it and before we acquire | |||||
// cs_main. | |||||
if (g_txindex && !pblockindex) { | |||||
g_txindex->BlockUntilSyncedToCurrentChain(); | |||||
} | |||||
LOCK(cs_main); | |||||
if (pblockindex == nullptr) { | if (pblockindex == nullptr) { | ||||
CTransactionRef tx; | CTransactionRef tx; | ||||
if (!GetTransaction(config, oneTxId, tx, hashBlock, false) || | if (!GetTransaction(config, oneTxId, tx, hashBlock, false) || | ||||
hashBlock.IsNull()) { | hashBlock.IsNull()) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Transaction not yet in block"); | "Transaction not yet in block"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,149 Lines • Show Last 20 Lines |