Files
thehub/libs/server/rpcrawtransaction.cpp
T

866 lines
36 KiB
C++
Raw Permalink Normal View History

2017-11-09 19:34:51 +01:00
/*
* This file is part of the Flowee project
* Copyright (C) 2010 Satoshi Nakamoto
* Copyright (C) 2009-2015 The Bitcoin Core developers
2021-01-20 19:21:53 +01:00
* Copyright (C) 2016-2021 Tom Zander <tom@flowee.org>
2017-11-09 19:34:51 +01:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2012-05-31 16:01:16 -04:00
2017-07-24 22:40:28 +02:00
#include <Application.h>
2019-04-11 11:33:27 +02:00
#include "encodings_legacy.h"
2015-07-05 14:17:46 +02:00
#include "chain.h"
2018-01-15 15:26:12 +00:00
#include <validation/Engine.h>
#include "consensus/validation.h"
#include "core_io.h"
2014-01-11 18:14:29 +01:00
#include "init.h"
2013-11-29 16:04:29 +01:00
#include "keystore.h"
2014-01-11 18:14:29 +01:00
#include "main.h"
#include "merkleblock.h"
2014-01-11 18:14:29 +01:00
#include "net.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
2014-01-11 18:14:29 +01:00
#include "rpcserver.h"
#include "primitives/script.h"
#include "script/script_error.h"
2014-08-27 17:22:33 +02:00
#include "script/sign.h"
2014-09-14 12:43:56 +02:00
#include "script/standard.h"
2015-07-05 14:17:46 +02:00
#include "txmempool.h"
2017-02-14 11:17:46 +01:00
#include "BlocksDB.h"
2014-01-11 18:14:29 +01:00
#include "uint256.h"
2015-07-05 14:17:46 +02:00
#include "utilstrencodings.h"
#include <utxo/UnspentOutputDatabase.h>
#include "UnspentOutputData.h"
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
2013-11-29 16:04:29 +01:00
#endif
2012-05-31 16:01:16 -04:00
2013-04-13 00:13:08 -05:00
#include <boost/assign/list_of.hpp>
2018-12-30 15:33:11 +01:00
#include <boost/foreach.hpp>
2019-05-08 12:49:33 +02:00
#include <primitives/FastBlock.h>
2013-04-13 00:13:08 -05:00
2015-09-04 16:11:34 +02:00
#include <univalue.h>
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
2012-05-31 16:01:16 -04:00
{
2019-06-06 21:37:49 +02:00
Script::TxnOutType type;
2017-08-02 19:53:22 +05:30
std::vector<CTxDestination> addresses;
2012-05-31 16:01:16 -04:00
int nRequired;
2015-07-30 19:56:00 -04:00
out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey)));
2013-07-15 01:22:10 -04:00
if (fIncludeHex)
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
2012-05-31 16:01:16 -04:00
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
2019-06-06 21:37:49 +02:00
out.push_back(Pair("type", Script::getTxnOutputType(type)));
2012-05-31 16:01:16 -04:00
return;
}
out.push_back(Pair("reqSigs", nRequired));
2019-06-06 21:37:49 +02:00
out.push_back(Pair("type", Script::getTxnOutputType(type)));
2012-05-31 16:01:16 -04:00
UniValue a(UniValue::VARR);
2012-05-31 16:01:16 -04:00
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
out.push_back(Pair("addresses", a));
}
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
2012-05-31 16:01:16 -04:00
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
2015-11-21 05:35:11 +03:00
entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
2012-05-31 16:01:16 -04:00
entry.push_back(Pair("version", tx.nVersion));
2014-05-05 20:08:13 +02:00
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
UniValue vin(UniValue::VARR);
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
UniValue in(UniValue::VOBJ);
2012-05-31 16:01:16 -04:00
if (tx.IsCoinBase())
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
else {
2012-05-31 16:01:16 -04:00
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
2014-05-05 20:08:13 +02:00
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
UniValue o(UniValue::VOBJ);
2015-07-30 19:56:00 -04:00
o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true)));
2012-05-31 16:01:16 -04:00
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in.push_back(Pair("scriptSig", o));
}
2014-05-05 20:08:13 +02:00
in.push_back(Pair("sequence", (int64_t)txin.nSequence));
2012-05-31 16:01:16 -04:00
vin.push_back(in);
}
entry.push_back(Pair("vin", vin));
UniValue vout(UniValue::VARR);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
2012-05-31 16:01:16 -04:00
const CTxOut& txout = tx.vout[i];
UniValue out(UniValue::VOBJ);
2012-05-31 16:01:16 -04:00
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
2014-05-05 20:08:13 +02:00
out.push_back(Pair("n", (int64_t)i));
UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
2012-05-31 16:01:16 -04:00
out.push_back(Pair("scriptPubKey", o));
vout.push_back(out);
}
entry.push_back(Pair("vout", vout));
if (!hashBlock.IsNull()) {
2012-05-31 16:01:16 -04:00
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
2018-01-15 15:26:12 +00:00
CBlockIndex* pindex = Blocks::Index::get(hashBlock);
if (pindex) {
if (chainActive.Contains(pindex)) {
entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
2014-06-28 23:36:06 +02:00
entry.push_back(Pair("time", pindex->GetBlockTime()));
entry.push_back(Pair("blocktime", pindex->GetBlockTime()));
2012-05-31 16:01:16 -04:00
}
else
entry.push_back(Pair("confirmations", 0));
}
}
}
UniValue getrawtransaction(const UniValue& params, bool fHelp)
2012-05-31 16:01:16 -04:00
{
if (fHelp || params.size() < 1 || params.size() > 2)
2017-08-02 19:53:22 +05:30
throw std::runtime_error(
2013-10-29 22:29:44 +11:00
"getrawtransaction \"txid\" ( verbose )\n"
2014-10-04 01:48:12 +02:00
"\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
2019-05-08 12:49:33 +02:00
"or there is an unspent output in the utxo for this transaction.\n"
2013-10-29 22:29:44 +11:00
"\nReturn the raw transaction data.\n"
"\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n"
"If verbose is non-zero, returns an Object with information about 'txid'.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"2. verbose (numeric, optional, default=0) If 0, return a string, other return a json object\n"
"\nResult (if verbose is not set or set to 0):\n"
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
"\nResult (if verbose > 0):\n"
"{\n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
2015-11-21 05:35:11 +03:00
" \"size\" : n, (numeric) The transaction size\n"
2013-10-29 22:29:44 +11:00
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
" {\n"
" \"txid\": \"id\", (string) The transaction id\n"
" \"vout\": n, (numeric) \n"
" \"scriptSig\": { (json object) The script\n"
" \"asm\": \"asm\", (string) asm\n"
" \"hex\": \"hex\" (string) hex\n"
" },\n"
" \"sequence\": n (numeric) The script sequence number\n"
" }\n"
" ,...\n"
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
2021-01-20 19:21:53 +01:00
" \"value\" : x.xxx, (numeric) The value in BCH\n"
2013-10-29 22:29:44 +11:00
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
" \"hex\" : \"hex\", (string) the hex\n"
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
" \"bitcoinaddress\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
" }\n"
" }\n"
" ,...\n"
" ],\n"
" \"blockhash\" : \"hash\", (string) the block hash\n"
" \"confirmations\" : n, (numeric) The confirmations\n"
" \"time\" : ttt, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getrawtransaction", "\"mytxid\"")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" 1")
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
);
2012-05-31 16:01:16 -04:00
LOCK(cs_main);
uint256 hash = ParseHashV(params[0], "parameter 1");
2012-05-31 16:01:16 -04:00
bool fVerbose = false;
2020-01-13 23:23:49 +01:00
if (!params[1].isNull()) {
fVerbose = params[1].isNum() ? (params[1].get_int() != 0) : params[1].get_bool();
}
2012-05-31 16:01:16 -04:00
CTransaction tx;
2019-05-08 12:49:33 +02:00
bool success = flApp->mempool()->lookup(hash, tx);
if (!success) {
auto block = chainActive.Tip();
for (int i = 0; !success && block && i < 6; ++i) {
FastBlock fb = Blocks::DB::instance()->loadBlock(block->GetBlockPos());
Tx::Iterator iter(fb);
bool endFound = false;
while (iter.next()){
if (iter.tag() == Tx::End) {
if (endFound)
break;
int comp = iter.prevTx().createHash().Compare(hash);
if (comp == 0) {
tx = iter.prevTx().createOldTransaction();
success = true;
break;
} else if (comp > 0) {
break; // use CTOR, stop searching in sorted list
}
endFound = true;
continue;
}
endFound = false;
}
block = block->pprev;
}
}
2019-05-22 23:12:44 +02:00
if (!success)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
2012-05-31 16:01:16 -04:00
2017-08-02 19:53:22 +05:30
std::string strHex = EncodeHexTx(tx);
2012-05-31 16:01:16 -04:00
if (!fVerbose)
return strHex;
UniValue result(UniValue::VOBJ);
2012-05-31 16:01:16 -04:00
result.push_back(Pair("hex", strHex));
uint256 hashBlock;
2012-05-31 16:01:16 -04:00
TxToJSON(tx, hashBlock, result);
return result;
}
UniValue verifytxoutproof(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
2017-08-02 19:53:22 +05:30
throw std::runtime_error(
"verifytxoutproof \"proof\"\n"
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
"and throwing an RPC error if the block is not in our best chain\n"
"\nArguments:\n"
"1. \"proof\" (string, required) The hex-encoded proof\n"
"\nResult:\n"
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
);
CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
UniValue res(UniValue::VARR);
2017-08-02 19:53:22 +05:30
std::vector<uint256> vMatch;
if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
return res;
2018-01-15 15:26:12 +00:00
auto item = Blocks::Index::get(merkleBlock.header.GetHash());
if (!item || !chainActive.Contains(item))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
BOOST_FOREACH(const uint256& hash, vMatch)
res.push_back(hash.GetHex());
return res;
}
UniValue createrawtransaction(const UniValue& params, bool fHelp)
2012-05-31 16:01:16 -04:00
{
if (fHelp || params.size() < 2 || params.size() > 4)
2017-08-02 19:53:22 +05:30
throw std::runtime_error(
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime, txversion )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
2012-05-31 16:01:16 -04:00
"Returns hex-encoded raw transaction.\n"
"Note that the transaction's inputs are not signed, and\n"
2013-10-29 22:29:44 +11:00
"it is not stored in the wallet or transmitted to the network.\n"
"\nArguments:\n"
"1. \"transactions\" (string, required) A json array of json objects\n"
" [\n"
" {\n"
" \"txid\":\"id\", (string, required) The transaction id\n"
2013-10-29 22:29:44 +11:00
" \"vout\":n (numeric, required) The output number\n"
" }\n"
" ,...\n"
" ]\n"
"2. \"outputs\" (string, required) a json object with outputs\n"
2013-10-29 22:29:44 +11:00
" {\n"
2021-01-20 19:21:53 +01:00
" \"address\": x.xxx (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the BCH amount\n"
" \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n"
" ...\n"
2013-10-29 22:29:44 +11:00
" }\n"
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
"4. txversion (numeric, optional, default=1) Specifies the transaction format version\n"
2013-10-29 22:29:44 +11:00
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
"\nExamples\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"")
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"data\\\":\\\"00010203\\\"}\"")
2013-10-29 22:29:44 +11:00
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
2013-10-29 22:29:44 +11:00
);
2012-05-31 16:01:16 -04:00
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
if (params[0].isNull() || params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
2012-05-31 16:01:16 -04:00
2015-05-13 21:29:19 +02:00
UniValue inputs = params[0].get_array();
UniValue sendTo = params[1].get_obj();
2012-05-31 16:01:16 -04:00
CMutableTransaction rawTx;
2012-05-31 16:01:16 -04:00
if (params.size() > 2 && !params[2].isNull()) {
int64_t nLockTime = params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
}
if (params.size() > 3 && !params[3].isNull()) {
int version = params[3].get_int();
if (version != 1 && version != 4)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, txversion can only be 1 or 4");
rawTx.nVersion = version;
}
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj();
2012-05-31 16:01:16 -04:00
uint256 txid = ParseHashO(o, "txid");
2012-05-31 16:01:16 -04:00
const UniValue& vout_v = find_value(o, "vout");
if (!vout_v.isNum())
2012-10-04 09:34:44 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
2012-05-31 16:01:16 -04:00
int nOutput = vout_v.get_int();
if (nOutput < 0)
2012-10-04 09:34:44 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2012-05-31 16:01:16 -04:00
uint32_t nSequence = (rawTx.nLockTime ? std::numeric_limits<uint32_t>::max() - 1 : std::numeric_limits<uint32_t>::max());
CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
2012-05-31 16:01:16 -04:00
rawTx.vin.push_back(in);
}
2017-08-02 19:53:22 +05:30
std::set<CBitcoinAddress> setAddress;
std::vector<std::string> addrList = sendTo.getKeys();
BOOST_FOREACH(const std::string& name_, addrList) {
2012-05-31 16:01:16 -04:00
if (name_ == "data") {
std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
2012-05-31 16:01:16 -04:00
CTxOut out(0, CScript() << OP_RETURN << data);
rawTx.vout.push_back(out);
} else {
CBitcoinAddress address(name_);
if (!address.IsValid())
2017-08-02 19:53:22 +05:30
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
2012-05-31 16:01:16 -04:00
if (setAddress.count(address))
2017-08-02 19:53:22 +05:30
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
2021-01-20 19:21:53 +01:00
int64_t nAmount = AmountFromValue(sendTo[name_]);
CTxOut out(nAmount, scriptPubKey);
rawTx.vout.push_back(out);
}
2012-05-31 16:01:16 -04:00
}
return EncodeHexTx(rawTx);
2012-05-31 16:01:16 -04:00
}
UniValue decoderawtransaction(const UniValue& params, bool fHelp)
2012-05-31 16:01:16 -04:00
{
if (fHelp || params.size() != 1)
2017-08-02 19:53:22 +05:30
throw std::runtime_error(
2013-10-29 22:29:44 +11:00
"decoderawtransaction \"hexstring\"\n"
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
"\nArguments:\n"
"1. \"hex\" (string, required) The transaction hex string\n"
2013-10-29 22:29:44 +11:00
"\nResult:\n"
"{\n"
" \"txid\" : \"id\", (string) The transaction id\n"
2015-11-21 05:35:11 +03:00
" \"size\" : n, (numeric) The transaction size\n"
2013-10-29 22:29:44 +11:00
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
" {\n"
" \"txid\": \"id\", (string) The transaction id\n"
" \"vout\": n, (numeric) The output number\n"
" \"scriptSig\": { (json object) The script\n"
" \"asm\": \"asm\", (string) asm\n"
" \"hex\": \"hex\" (string) hex\n"
" },\n"
" \"sequence\": n (numeric) The script sequence number\n"
" }\n"
" ,...\n"
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
2021-01-20 19:21:53 +01:00
" \"value\" : x.xxx, (numeric) The value in BCH\n"
2013-10-29 22:29:44 +11:00
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
" \"hex\" : \"hex\", (string) the hex\n"
" \"reqSigs\" : n, (numeric) The required sigs\n"
" \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n"
" \"addresses\" : [ (json array of string)\n"
" \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
" }\n"
" }\n"
" ,...\n"
" ],\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("decoderawtransaction", "\"hexstring\"")
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
);
2012-05-31 16:01:16 -04:00
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2012-05-31 16:01:16 -04:00
CTransaction tx;
if (!DecodeHexTx(tx, params[0].get_str()))
2012-10-04 09:34:44 +02:00
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2012-05-31 16:01:16 -04:00
2015-05-10 13:35:44 +02:00
UniValue result(UniValue::VOBJ);
TxToJSON(tx, uint256(), result);
2012-05-31 16:01:16 -04:00
return result;
}
UniValue decodescript(const UniValue& params, bool fHelp)
2013-07-15 01:22:10 -04:00
{
if (fHelp || params.size() != 1)
2017-08-02 19:53:22 +05:30
throw std::runtime_error(
2013-10-29 22:29:44 +11:00
"decodescript \"hex\"\n"
"\nDecode a hex-encoded script.\n"
"\nArguments:\n"
"1. \"hex\" (string) the hex encoded script\n"
"\nResult:\n"
"{\n"
" \"asm\":\"asm\", (string) Script public key\n"
" \"hex\":\"hex\", (string) hex encoded public key\n"
" \"type\":\"type\", (string) The output type\n"
" \"reqSigs\": n, (numeric) The required signatures\n"
" \"addresses\": [ (json array of string)\n"
" \"address\" (string) bitcoin address\n"
" ,...\n"
" ],\n"
" \"p2sh\",\"address\" (string) script address\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
2013-07-15 01:22:10 -04:00
2015-05-10 13:35:44 +02:00
RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2013-07-15 01:22:10 -04:00
UniValue r(UniValue::VOBJ);
2013-07-15 01:22:10 -04:00
CScript script;
if (params[0].get_str().size() > 0){
2017-08-02 19:53:22 +05:30
std::vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
2013-07-15 01:22:10 -04:00
script = CScript(scriptData.begin(), scriptData.end());
} else {
// Empty scripts are valid
}
ScriptPubKeyToJSON(script, r, false);
r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
2013-07-15 01:22:10 -04:00
return r;
}
/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
{
UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("txid", txin.prevout.hash.ToString()));
entry.push_back(Pair("vout", (uint64_t)txin.prevout.n));
entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
entry.push_back(Pair("sequence", (uint64_t)txin.nSequence));
entry.push_back(Pair("error", strMessage));
vErrorsRet.push_back(entry);
}
UniValue signrawtransaction(const UniValue& params, bool fHelp)
2012-05-31 16:01:16 -04:00
{
if (fHelp || params.size() < 1 || params.size() > 4)
2017-08-02 19:53:22 +05:30
throw std::runtime_error(
2013-10-29 22:29:44 +11:00
"signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
"The second optional argument (may be null) is an array of previous transaction outputs that\n"
2012-10-05 19:22:21 +02:00
"this transaction depends on but may not yet be in the block chain.\n"
2013-10-29 22:29:44 +11:00
"The third optional argument (may be null) is an array of base58-encoded private\n"
2012-05-31 16:01:16 -04:00
"keys that, if given, will be the only keys used to sign the transaction.\n"
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
2013-10-29 22:29:44 +11:00
+ HelpRequiringPassphrase() + "\n"
2013-11-29 16:04:29 +01:00
#endif
2013-10-29 22:29:44 +11:00
"\nArguments:\n"
"1. \"hexstring\" (string, required) The transaction hex string\n"
"2. \"prevtxs\" (string, optional) An json array of previous dependent transaction outputs\n"
" [ (json array of json objects, or 'null' if none provided)\n"
2013-10-29 22:29:44 +11:00
" {\n"
" \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n, (numeric, required) The output number\n"
" \"scriptPubKey\": \"hex\", (string, required) script key\n"
2014-07-12 09:21:02 +01:00
" \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n"
" \"amount\": \"value\" (numeric, required) amount spent\n"
2013-10-29 22:29:44 +11:00
" }\n"
" ,...\n"
" ]\n"
"3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n"
" [ (json array of strings, or 'null' if none provided)\n"
2013-10-29 22:29:44 +11:00
" \"privatekey\" (string) private key in base58-encoding\n"
" ,...\n"
" ]\n"
2014-04-08 22:53:41 +07:00
"4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n"
2013-10-29 22:29:44 +11:00
" \"ALL\"\n"
" \"NONE\"\n"
" \"SINGLE\"\n"
" \"ALL|ANYONECANPAY\"\n"
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\"\n"
"\nResult:\n"
"{\n"
" \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
" \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
" \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n"
" {\n"
" \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n"
" \"vout\" : n, (numeric) The index of the output to spent and used as input\n"
" \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n"
" \"sequence\" : n, (numeric) Script sequence number\n"
" \"error\" : \"text\" (string) Verification or signing error related to the input\n"
" }\n"
" ,...\n"
" ]\n"
2013-10-29 22:29:44 +11:00
"}\n"
"\nExamples:\n"
+ HelpExampleCli("signrawtransaction", "\"myhex\"")
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
2012-05-31 16:01:16 -04:00
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
2012-05-31 16:01:16 -04:00
2017-08-02 19:53:22 +05:30
std::vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
2012-05-31 16:01:16 -04:00
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
2017-08-02 19:53:22 +05:30
std::vector<CMutableTransaction> txVariants;
while (!ssData.empty()) {
2012-05-31 16:01:16 -04:00
try {
CMutableTransaction tx;
2012-05-31 16:01:16 -04:00
ssData >> tx;
txVariants.push_back(tx);
}
2016-08-16 16:51:22 +02:00
catch (const std::exception &e) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, std::string("TX decode failed with ") + e.what());
2012-05-31 16:01:16 -04:00
}
}
if (txVariants.empty())
2012-10-04 09:34:44 +02:00
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
2012-05-31 16:01:16 -04:00
// mergedTx will end up with all the signatures; it
// starts as a clone of the rawtx:
CMutableTransaction mergedTx(txVariants[0]);
2012-05-31 16:01:16 -04:00
// First, fish required transactions out of the mempool
2019-04-01 15:34:13 +02:00
typedef boost::unordered_map<uint256, Tx, HashShortener> TXMap;
TXMap txMap;
2012-05-31 16:01:16 -04:00
{
2018-01-16 16:40:34 +00:00
CTxMemPool *mempool = flApp->mempool();
for (const CTxIn &txin : mergedTx.vin) {
auto ti = txMap.find(txin.prevout.hash);
if (ti != txMap.end()) // Spending multiple outputs from one tx
continue;
Tx prevTx;
if (mempool->lookup(txin.prevout.hash, prevTx)) {
txMap.insert(std::make_pair(txin.prevout.hash, prevTx));
}
2012-05-31 16:01:16 -04:00
}
}
// Fetch previous transactions (inputs) given in the RPC call:
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
if (params.size() > 2 && !params[2].isNull()) {
2015-05-13 21:29:19 +02:00
UniValue keys = params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
2015-05-13 21:29:19 +02:00
UniValue k = keys[idx];
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
2013-05-01 06:52:05 +02:00
CKey key = vchSecret.GetKey();
2014-12-11 16:06:23 +01:00
if (!key.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range");
tempKeystore.AddKey(key);
fGivenKeys = true;
}
}
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
else if (pwalletMain)
EnsureWalletIsUnlocked();
2013-11-29 16:04:29 +01:00
#endif
typedef boost::unordered_map<Tx::Input, Tx::Output> InputMap;
InputMap inputMap;
2012-05-31 16:01:16 -04:00
// Add previous txouts given in the RPC call:
if (params.size() > 1 && !params[1].isNull()) {
2015-05-13 21:29:19 +02:00
UniValue prevTxs = params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
if (!p.isObject())
2012-10-04 09:34:44 +02:00
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
2012-05-31 16:01:16 -04:00
2015-05-13 21:29:19 +02:00
UniValue prevOut = p.get_obj();
2012-05-31 16:01:16 -04:00
RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR));
2012-05-31 16:01:16 -04:00
Tx::Input input;
input.txid = ParseHashO(prevOut, "txid");
2012-05-31 16:01:16 -04:00
input.index = find_value(prevOut, "vout").get_int();
if (input.index < 0)
2012-10-04 09:34:44 +02:00
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
2012-05-31 16:01:16 -04:00
Tx::Output output;
2018-10-12 23:55:49 +02:00
output.outputValue = 0;
const UniValue &amountObj = find_value(prevOut, "amount");
if (amountObj.isNum())
output.outputValue = AmountFromValue(amountObj);
if (output.outputValue <= 0 || (!amountObj.isNull() && !amountObj.isNum()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "amount must be a positive number");
2017-08-02 19:53:22 +05:30
std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
2019-10-05 15:59:39 +02:00
output.outputScript = Streaming::ConstBuffer::create(pkData);
2012-05-31 16:01:16 -04:00
inputMap.insert(std::make_pair(input, output));
// {
// CCoinsModifier coins = view.ModifyCoins(txid);
// if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
// std::string err("Previous output scriptPubKey mismatch:\n");
// err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
// ScriptToAsmStr(scriptPubKey);
// throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
// }
// if ((unsigned int)nOut >= coins->vout.size())
// coins->vout.resize(nOut+1);
// coins->vout[nOut].scriptPubKey = scriptPubKey;
// coins->vout[nOut].nValue = amount;
// }
2012-05-31 16:01:16 -04:00
// if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed:
2019-10-05 15:59:39 +02:00
CScript outScript = output.outputScript;
if (fGivenKeys && outScript.IsPayToScriptHash()) {
RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR));
2015-05-13 21:29:19 +02:00
UniValue v = find_value(prevOut, "redeemScript");
if (!v.isNull()) {
2017-08-02 19:53:22 +05:30
std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
}
}
2012-05-31 16:01:16 -04:00
}
}
2013-11-29 16:04:29 +01:00
#ifdef ENABLE_WALLET
const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
2013-11-29 16:04:29 +01:00
#else
const CKeyStore& keystore = tempKeystore;
#endif
2012-05-31 16:01:16 -04:00
int nHashType = SIGHASH_ALL;
if (params.size() > 3 && !params[3].isNull()) {
2017-08-02 19:53:22 +05:30
static std::map<std::string, int> mapSigHashValues =
boost::assign::map_list_of
2017-08-02 19:53:22 +05:30
(std::string("ALL"), int(SIGHASH_ALL))
(std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
(std::string("NONE"), int(SIGHASH_NONE))
(std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
(std::string("SINGLE"), int(SIGHASH_SINGLE))
(std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
;
2017-08-02 19:53:22 +05:30
std::string strHashType = params[3].get_str();
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
2012-10-04 09:34:44 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
}
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
2019-06-02 13:57:47 +02:00
uint32_t validationFlags = STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_ENABLE_SIGHASH_FORKID;
nHashType |= SIGHASH_FORKID;
// Script verification errors
UniValue vErrors(UniValue::VARR);
// Use CTransaction for the constant parts of the
// transaction to avoid rehashing.
const CTransaction txConst(mergedTx);
2012-05-31 16:01:16 -04:00
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
2012-05-31 16:01:16 -04:00
CTxIn& txin = mergedTx.vin[i];
CScript outputScript;
2021-01-20 19:21:53 +01:00
int64_t amount = 0;
2020-04-11 18:35:43 +02:00
bool found = false;
Tx::Input input;
input.index = txin.prevout.n;
input.txid = txin.prevout.hash;
auto inIter = inputMap.find(input);
if (inIter != inputMap.end()) {
outputScript = inIter->second.outputScript;
amount = inIter->second.outputValue;
found = true;
}
if (!found) {
auto txIter = txMap.find(input.txid);
if (txIter != txMap.end()) {
Tx::Output out = txIter->second.output(input.index);
if (out.outputValue >= 0) {
outputScript = out.outputScript;
amount = out.outputValue;
found = true;
}
}
}
if (!found) {
UnspentOutputData uo(g_utxo->find(input.txid, input.index));
if (uo.isValid()) {
outputScript = uo.outputScript();
amount = uo.outputValue();
found = true;
}
}
if (!found) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
2012-05-31 16:01:16 -04:00
continue;
}
txin.scriptSig.clear();
// Only sign SIGHASH_SINGLE if there's a corresponding output:
2016-11-07 11:58:00 +01:00
if (!fHashSingle || i < mergedTx.vout.size())
SignSignature(keystore, outputScript, mergedTx, i, amount, nHashType);
2012-05-31 16:01:16 -04:00
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(outputScript, TransactionSignatureChecker(&txConst, i, amount), txin.scriptSig, txv.vin[i].scriptSig);
2012-05-31 16:01:16 -04:00
}
2020-04-11 18:35:43 +02:00
Script::State state(validationFlags);
if (!Script::verify(txin.scriptSig, outputScript, TransactionSignatureChecker(&txConst, i, amount), state)) {
TxInErrorToJSON(txin, vErrors, state.errorString());
}
2012-05-31 16:01:16 -04:00
}
bool fComplete = vErrors.empty();
2012-05-31 16:01:16 -04:00
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
2012-05-31 16:01:16 -04:00
result.push_back(Pair("complete", fComplete));
if (!vErrors.empty()) {
result.push_back(Pair("errors", vErrors));
}
2012-05-31 16:01:16 -04:00
return result;
}
UniValue sendrawtransaction(const UniValue& params, bool fHelp)
2012-05-31 16:01:16 -04:00
{
if (fHelp || params.size() < 1 || params.size() > 2)
2017-08-02 19:53:22 +05:30
throw std::runtime_error(
2013-10-29 22:29:44 +11:00
"sendrawtransaction \"hexstring\" ( allowhighfees )\n"
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nAlso see createrawtransaction and signrawtransaction calls.\n"
"\nArguments:\n"
"1. \"hexstring\" (string, required) The hex string of the raw transaction)\n"
"2. allowhighfees (boolean, optional, default=false) Allow high fees\n"
"\nResult:\n"
"\"hex\" (string) The transaction hash in hex\n"
"\nExamples:\n"
"\nCreate a transaction\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
"Sign the transaction, and get back the hex\n"
+ HelpExampleCli("signrawtransaction", "\"myhex\"") +
"\nSend the transaction (signed hex)\n"
+ HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
2018-01-15 15:26:12 +00:00
std::future<std::string> future;
uint256 hashTx;
{
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
2012-05-31 16:01:16 -04:00
// parse hex string from parameter
CTransaction tx;
if (!DecodeHexTx(tx, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2018-01-15 15:26:12 +00:00
hashTx = tx.GetHash();
2012-05-31 16:01:16 -04:00
bool fOverrideFees = false;
if (params.size() > 1)
fOverrideFees = params[1].get_bool();
auto utxo = g_utxo->find(hashTx, 0);
2014-02-22 12:02:42 +01:00
bool fHaveMempool = mempool.exists(hashTx);
bool fHaveChain = utxo.isValid() && utxo.blockHeight() < 1000000000;
2014-02-22 12:02:42 +01:00
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
2018-01-15 15:26:12 +00:00
uint32_t flags = Validation::ForwardGoodToPeers;
if (!fOverrideFees)
flags |= Validation::RejectAbsurdFeeTx;
future = Application::instance()->validation()->addTransaction(Tx::fromOldTransaction(tx), flags);
2014-02-22 12:02:42 +01:00
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
2018-01-15 15:26:12 +00:00
}
if (future.valid()) {
const std::string result = future.get();
if (!result.empty()) {
2018-01-25 09:33:19 +00:00
if (result == "16: missing-inputs")
throw JSONRPCError(RPC_TRANSACTION_ERROR, result);
2018-01-15 15:26:12 +00:00
throw JSONRPCError(RPC_TRANSACTION_REJECTED, result);
}
}
return hashTx.GetHex();
2012-05-31 16:01:16 -04:00
}