Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/rawtransaction.cpp
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (!hashBlock.IsNull()) { | ||||
entry.pushKV("confirmations", 0); | entry.pushKV("confirmations", 0); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static UniValue getrawtransaction(const Config &config, | static UniValue getrawtransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 1 || | RPCHelpMan{ | ||||
request.params.size() > 3) { | |||||
throw std::runtime_error(RPCHelpMan{ | |||||
"getrawtransaction", | "getrawtransaction", | ||||
"\nBy default this function only works for mempool " | "\nBy default this function only works for mempool transactions. When " | ||||
"transactions. When called with a blockhash\n" | "called with a blockhash\n" | ||||
"argument, getrawtransaction will return the transaction if " | "argument, getrawtransaction will return the transaction if the " | ||||
"the specified block is available and\n" | "specified block is available and\n" | ||||
"the transaction is found in that block. When called without a " | "the transaction is found in that block. When called without a " | ||||
"blockhash argument, getrawtransaction\n" | "blockhash argument, getrawtransaction\n" | ||||
"will return the transaction if it is in the mempool, or if " | "will return the transaction if it is in the mempool, or if -txindex " | ||||
"-txindex is enabled and the transaction\n" | "is enabled and the transaction\n" | ||||
"is in a block in the blockchain.\n" | "is in a block in the blockchain.\n" | ||||
"\nReturn the raw transaction data.\n" | "\nReturn the raw transaction data.\n" | ||||
"\nIf verbose is 'true', returns an Object with information " | "\nIf verbose is 'true', returns an Object with information about " | ||||
"about 'txid'.\n" | "'txid'.\n" | ||||
"If verbose is 'false' or omitted, returns a string that is " | "If verbose is 'false' or omitted, returns a string that is " | ||||
"serialized, hex-encoded data for 'txid'.\n", | "serialized, hex-encoded data for 'txid'.\n", | ||||
{ | { | ||||
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"The transaction id"}, | "The transaction id"}, | ||||
{"verbose", RPCArg::Type::BOOL, /* default */ "false", | {"verbose", RPCArg::Type::BOOL, /* default */ "false", | ||||
"If false, return a string, otherwise return a json " | "If false, return a string, otherwise return a json object"}, | ||||
"object"}, | |||||
{"blockhash", RPCArg::Type::STR_HEX, | {"blockhash", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::OMITTED_NAMED_ARG, | RPCArg::Optional::OMITTED_NAMED_ARG, | ||||
"The block in which to look for the transaction"}, | "The block in which to look for the transaction"}, | ||||
}, | }, | ||||
{ | { | ||||
RPCResult{"if verbose is not set or set to false", | RPCResult{"if verbose is not set or set to false", | ||||
"\"data\" (string) The serialized, hex-encoded " | "\"data\" (string) The serialized, hex-encoded data " | ||||
"data for 'txid'\n"}, | "for 'txid'\n"}, | ||||
RPCResult{ | RPCResult{ | ||||
"if verbose is set to true", | "if verbose is set to true", | ||||
"{\n" | "{\n" | ||||
" \"in_active_chain\": b, (bool) Whether specified block " | " \"in_active_chain\": b, (bool) Whether specified block is " | ||||
"is in the active chain or not (only present with explicit " | "in the active chain or not (only present with explicit " | ||||
"\"blockhash\" argument)\n" | "\"blockhash\" argument)\n" | ||||
" \"hex\" : \"data\", (string) The serialized, " | " \"hex\" : \"data\", (string) The serialized, " | ||||
"hex-encoded data for 'txid'\n" | "hex-encoded data for 'txid'\n" | ||||
" \"txid\" : \"id\", (string) The transaction id " | " \"txid\" : \"id\", (string) The transaction id (same " | ||||
"(same as provided)\n" | "as provided)\n" | ||||
" \"hash\" : \"id\", (string) The transaction hash " | " \"hash\" : \"id\", (string) The transaction hash " | ||||
"(differs from txid for witness transactions)\n" | "(differs from txid for witness transactions)\n" | ||||
" \"size\" : n, (numeric) The serialized " | " \"size\" : n, (numeric) The serialized " | ||||
"transaction size\n" | "transaction size\n" | ||||
" \"version\" : n, (numeric) The version\n" | " \"version\" : n, (numeric) The version\n" | ||||
" \"locktime\" : ttt, (numeric) The lock time\n" | " \"locktime\" : ttt, (numeric) The lock time\n" | ||||
" \"vin\" : [ (array of json objects)\n" | " \"vin\" : [ (array of json objects)\n" | ||||
" {\n" | " {\n" | ||||
" \"txid\": \"id\", (string) The transaction id\n" | " \"txid\": \"id\", (string) The transaction id\n" | ||||
" \"vout\": n, (numeric) \n" | " \"vout\": n, (numeric) \n" | ||||
" \"scriptSig\": { (json object) The script\n" | " \"scriptSig\": { (json object) The script\n" | ||||
" \"asm\": \"asm\", (string) asm\n" | " \"asm\": \"asm\", (string) asm\n" | ||||
" \"hex\": \"hex\" (string) hex\n" | " \"hex\": \"hex\" (string) hex\n" | ||||
" },\n" | " },\n" | ||||
" \"sequence\": n (numeric) The script sequence " | " \"sequence\": n (numeric) The script sequence " | ||||
"number\n" | "number\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ],\n" | " ],\n" | ||||
" \"vout\" : [ (array of json objects)\n" | " \"vout\" : [ (array of json objects)\n" | ||||
" {\n" | " {\n" | ||||
" \"value\" : x.xxx, (numeric) The value " | " \"value\" : x.xxx, (numeric) The value in " + | ||||
"in " + | |||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
"\n" | "\n" | ||||
" \"n\" : n, (numeric) index\n" | " \"n\" : n, (numeric) index\n" | ||||
" \"scriptPubKey\" : { (json object)\n" | " \"scriptPubKey\" : { (json object)\n" | ||||
" \"asm\" : \"asm\", (string) the " | " \"asm\" : \"asm\", (string) the asm\n" | ||||
"asm\n" | " \"hex\" : \"hex\", (string) the hex\n" | ||||
" \"hex\" : \"hex\", (string) the " | |||||
"hex\n" | |||||
" \"reqSigs\" : n, (numeric) The " | " \"reqSigs\" : n, (numeric) The " | ||||
"required sigs\n" | "required sigs\n" | ||||
" \"type\" : \"pubkeyhash\", (string) The " | " \"type\" : \"pubkeyhash\", (string) The type, " | ||||
"type, eg 'pubkeyhash'\n" | "eg 'pubkeyhash'\n" | ||||
" \"addresses\" : [ (json array of " | " \"addresses\" : [ (json array of " | ||||
"string)\n" | "string)\n" | ||||
" \"address\" (string) bitcoin " | " \"address\" (string) bitcoin address\n" | ||||
"address\n" | |||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
" }\n" | " }\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ],\n" | " ],\n" | ||||
" \"blockhash\" : \"hash\", (string) the block " | " \"blockhash\" : \"hash\", (string) the block hash\n" | ||||
"hash\n" | |||||
" \"confirmations\" : n, (numeric) The " | " \"confirmations\" : n, (numeric) The " | ||||
"confirmations\n" | "confirmations\n" | ||||
" \"time\" : ttt, (numeric) The " | " \"time\" : ttt, (numeric) The transaction " | ||||
"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" | "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"}, | "}\n"}, | ||||
}, | }, | ||||
RPCExamples{ | RPCExamples{HelpExampleCli("getrawtransaction", "\"mytxid\"") + | ||||
HelpExampleCli("getrawtransaction", "\"mytxid\"") + | |||||
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\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
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; | ||||
const CChainParams ¶ms = config.GetChainParams(); | const CChainParams ¶ms = config.GetChainParams(); | ||||
if (txid == params.GenesisBlock().hashMerkleRoot) { | if (txid == params.GenesisBlock().hashMerkleRoot) { | ||||
// Special exception for the genesis block coinbase transaction | // Special exception for the genesis block coinbase transaction | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if (blockindex) { | ||||
result.pushKV("in_active_chain", in_active_chain); | result.pushKV("in_active_chain", in_active_chain); | ||||
} | } | ||||
TxToJSON(*tx, hash_block, result); | TxToJSON(*tx, hash_block, result); | ||||
return result; | return result; | ||||
} | } | ||||
static UniValue gettxoutproof(const Config &config, | static UniValue gettxoutproof(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || | RPCHelpMan{ | ||||
(request.params.size() != 1 && request.params.size() != 2)) { | |||||
throw std::runtime_error(RPCHelpMan{ | |||||
"gettxoutproof", | "gettxoutproof", | ||||
"\nReturns a hex-encoded proof that \"txid\" was " | "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" | ||||
"included in a block.\n" | |||||
"\nNOTE: By default this function only works sometimes. " | "\nNOTE: By default this function only works sometimes. " | ||||
"This is when there is an\n" | "This is when there is an\n" | ||||
"unspent output in the utxo for this transaction. To " | "unspent output in the utxo for this transaction. To make it always " | ||||
"make it always work,\n" | "work,\n" | ||||
"you need to maintain a transaction index, using the " | "you need to maintain a transaction index, using the -txindex command " | ||||
"-txindex command line option or\n" | "line option or\n" | ||||
"specify the block in which the transaction is included " | "specify the block in which the transaction is included manually (by " | ||||
"manually (by blockhash).\n", | "blockhash).\n", | ||||
{ | { | ||||
{ | { | ||||
"txids", | "txids", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A json array of txids to filter", | "A json array of txids to filter", | ||||
{ | { | ||||
{"txid", RPCArg::Type::STR_HEX, | {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, | ||||
RPCArg::Optional::OMITTED, "A transaction hash"}, | "A transaction hash"}, | ||||
}, | }, | ||||
}, | }, | ||||
{"blockhash", RPCArg::Type::STR_HEX, | {"blockhash", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::OMITTED_NAMED_ARG, | RPCArg::Optional::OMITTED_NAMED_ARG, | ||||
"If specified, looks for txid in the block with this hash"}, | "If specified, looks for txid in the block with this hash"}, | ||||
}, | }, | ||||
RPCResult{"\"data\" (string) A string that is a " | RPCResult{"\"data\" (string) A string that is a serialized, " | ||||
"serialized, hex-encoded data for the proof.\n"}, | "hex-encoded data for the proof.\n"}, | ||||
RPCExamples{""}, | RPCExamples{""}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
std::set<TxId> setTxIds; | std::set<TxId> setTxIds; | ||||
TxId oneTxId; | TxId oneTxId; | ||||
UniValue txids = request.params[0].get_array(); | UniValue txids = request.params[0].get_array(); | ||||
for (unsigned int idx = 0; idx < txids.size(); idx++) { | for (unsigned int idx = 0; idx < txids.size(); idx++) { | ||||
const UniValue &utxid = txids[idx]; | const UniValue &utxid = txids[idx]; | ||||
TxId txid(ParseHashV(utxid, "txid")); | TxId txid(ParseHashV(utxid, "txid")); | ||||
if (setTxIds.count(txid)) { | if (setTxIds.count(txid)) { | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | static UniValue gettxoutproof(const Config &config, | ||||
CMerkleBlock mb(block, setTxIds); | CMerkleBlock mb(block, setTxIds); | ||||
ssMB << mb; | ssMB << mb; | ||||
std::string strHex = HexStr(ssMB.begin(), ssMB.end()); | std::string strHex = HexStr(ssMB.begin(), ssMB.end()); | ||||
return strHex; | return strHex; | ||||
} | } | ||||
static UniValue verifytxoutproof(const Config &config, | static UniValue verifytxoutproof(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"verifytxoutproof", | "verifytxoutproof", | ||||
"\nVerifies that a proof points to a transaction in a " | "\nVerifies that a proof points to a transaction in a block, returning " | ||||
"block, returning the transaction it commits to\n" | "the transaction it commits to\n" | ||||
"and throwing an RPC error if the block is not in our " | "and throwing an RPC error if the block is not in our best chain\n", | ||||
"best chain\n", | |||||
{ | { | ||||
{"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"The hex-encoded proof generated by gettxoutproof"}, | "The hex-encoded proof generated by gettxoutproof"}, | ||||
}, | }, | ||||
RPCResult{"[\"txid\"] (array, strings) The txid(s) which the " | RPCResult{ | ||||
"proof commits to, or empty array if the proof can not " | "[\"txid\"] (array, strings) The txid(s) which the proof " | ||||
"be validated.\n"}, | "commits to, or empty array if the proof can not be validated.\n"}, | ||||
RPCExamples{""}, | RPCExamples{""}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, | CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, | ||||
PROTOCOL_VERSION); | PROTOCOL_VERSION); | ||||
CMerkleBlock merkleBlock; | CMerkleBlock merkleBlock; | ||||
ssMB >> merkleBlock; | ssMB >> merkleBlock; | ||||
UniValue res(UniValue::VARR); | UniValue res(UniValue::VARR); | ||||
Show All 19 Lines | if (pindex->nTx == merkleBlock.txn.GetNumTransactions()) { | ||||
} | } | ||||
} | } | ||||
return res; | return res; | ||||
} | } | ||||
static UniValue createrawtransaction(const Config &config, | static UniValue createrawtransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 2 || | RPCHelpMan{ | ||||
request.params.size() > 3) { | |||||
throw std::runtime_error(RPCHelpMan{ | |||||
"createrawtransaction", | "createrawtransaction", | ||||
"\nCreate a transaction spending the given inputs and creating " | "\nCreate a transaction spending the given inputs and creating new " | ||||
"new outputs.\n" | "outputs.\n" | ||||
"Outputs can be addresses or data.\n" | "Outputs can be addresses or data.\n" | ||||
"Returns hex-encoded raw transaction.\n" | "Returns hex-encoded raw transaction.\n" | ||||
"Note that the transaction's inputs are not signed, and\n" | "Note that the transaction's inputs are not signed, and\n" | ||||
"it is not stored in the wallet or transmitted to the network.\n", | "it is not stored in the wallet or transmitted to the network.\n", | ||||
{ | { | ||||
{ | { | ||||
"inputs", | "inputs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A json array of json objects", | "A json array of json objects", | ||||
{ | { | ||||
{ | { | ||||
"", | "", | ||||
RPCArg::Type::OBJ, | RPCArg::Type::OBJ, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"", | "", | ||||
{ | { | ||||
{"txid", RPCArg::Type::STR_HEX, | {"txid", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::NO, "The transaction id"}, | RPCArg::Optional::NO, "The transaction id"}, | ||||
{"vout", RPCArg::Type::NUM, | {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, | ||||
RPCArg::Optional::NO, "The output number"}, | "The output number"}, | ||||
{"sequence", RPCArg::Type::NUM, /* default */ | {"sequence", RPCArg::Type::NUM, /* default */ | ||||
"depends on the value of the 'locktime' " | "depends on the value of the 'locktime' argument", | ||||
"argument", | |||||
"The sequence number"}, | "The sequence number"}, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
{ | { | ||||
"outputs", | "outputs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"a json array with outputs (key-value pairs).\n" | "a json array with outputs (key-value pairs).\n" | ||||
"For compatibility reasons, a dictionary, which holds " | "For compatibility reasons, a dictionary, which holds the " | ||||
"the key-value pairs directly, is also\n" | "key-value pairs directly, is also\n" | ||||
" accepted as second " | " accepted as second parameter.", | ||||
"parameter.", | |||||
{ | { | ||||
{ | { | ||||
"", | "", | ||||
RPCArg::Type::OBJ, | RPCArg::Type::OBJ, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"", | "", | ||||
{ | { | ||||
{"address", RPCArg::Type::AMOUNT, | {"address", RPCArg::Type::AMOUNT, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A key-value pair. The key (string) is " | "A key-value pair. The key (string) is the " | ||||
"the bitcoin address, the value (float or " | "bitcoin address, the value (float or string) is " | ||||
"string) is the amount in " + | "the amount in " + | ||||
CURRENCY_UNIT}, | CURRENCY_UNIT}, | ||||
}, | }, | ||||
}, | }, | ||||
{ | { | ||||
"", | "", | ||||
RPCArg::Type::OBJ, | RPCArg::Type::OBJ, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"", | "", | ||||
{ | { | ||||
{"data", RPCArg::Type::STR_HEX, | {"data", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A key-value pair. The key must be " | "A key-value pair. The key must be \"data\", the " | ||||
"\"data\", the value is hex-encoded data"}, | "value is hex-encoded data"}, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
{"locktime", RPCArg::Type::NUM, /* default */ "0", | {"locktime", RPCArg::Type::NUM, /* default */ "0", | ||||
"Raw locktime. Non-0 value also locktime-activates " | "Raw locktime. Non-0 value also locktime-activates inputs"}, | ||||
"inputs"}, | |||||
}, | }, | ||||
RPCResult{"\"transaction\" (string) hex string of the " | RPCResult{"\"transaction\" (string) hex string of the " | ||||
"transaction\n"}, | "transaction\n"}, | ||||
RPCExamples{ | RPCExamples{ | ||||
HelpExampleCli("createrawtransaction", | HelpExampleCli("createrawtransaction", | ||||
"\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | ||||
"\" \"[{\\\"address\\\":0.01}]\"") + | "\" \"[{\\\"address\\\":0.01}]\"") + | ||||
HelpExampleCli("createrawtransaction", | HelpExampleCli("createrawtransaction", | ||||
"\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | ||||
"\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + | "\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + | ||||
HelpExampleRpc("createrawtransaction", | HelpExampleRpc("createrawtransaction", | ||||
"\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | ||||
"\", \"[{\\\"address\\\":0.01}]\"") + | "\", \"[{\\\"address\\\":0.01}]\"") + | ||||
HelpExampleRpc("createrawtransaction", | HelpExampleRpc("createrawtransaction", | ||||
"\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | ||||
"\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")}, | "\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, | RPCTypeCheck(request.params, | ||||
{UniValue::VARR, | {UniValue::VARR, | ||||
UniValueType(), // ARR or OBJ, checked later | UniValueType(), // ARR or OBJ, checked later | ||||
UniValue::VNUM}, | UniValue::VNUM}, | ||||
true); | true); | ||||
CMutableTransaction rawTx = | CMutableTransaction rawTx = | ||||
ConstructTransaction(config.GetChainParams(), request.params[0], | ConstructTransaction(config.GetChainParams(), request.params[0], | ||||
request.params[1], request.params[2]); | request.params[1], request.params[2]); | ||||
return EncodeHexTx(CTransaction(rawTx)); | return EncodeHexTx(CTransaction(rawTx)); | ||||
} | } | ||||
static UniValue decoderawtransaction(const Config &config, | static UniValue decoderawtransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"decoderawtransaction", | "decoderawtransaction", | ||||
"\nReturn a JSON object representing the serialized, " | "\nReturn a JSON object representing the serialized, hex-encoded " | ||||
"hex-encoded transaction.\n", | "transaction.\n", | ||||
{ | { | ||||
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"The transaction hex string"}, | "The transaction hex string"}, | ||||
}, | }, | ||||
RPCResult{ | RPCResult{ | ||||
"{\n" | "{\n" | ||||
" \"txid\" : \"id\", (string) The transaction id\n" | " \"txid\" : \"id\", (string) The transaction id\n" | ||||
" \"hash\" : \"id\", (string) The transaction hash " | " \"hash\" : \"id\", (string) The transaction hash " | ||||
"(differs from txid for witness transactions)\n" | "(differs from txid for witness transactions)\n" | ||||
" \"size\" : n, (numeric) The transaction size\n" | " \"size\" : n, (numeric) The transaction size\n" | ||||
" \"version\" : n, (numeric) The version\n" | " \"version\" : n, (numeric) The version\n" | ||||
" \"locktime\" : ttt, (numeric) The lock time\n" | " \"locktime\" : ttt, (numeric) The lock time\n" | ||||
" \"vin\" : [ (array of json objects)\n" | " \"vin\" : [ (array of json objects)\n" | ||||
" {\n" | " {\n" | ||||
" \"txid\": \"id\", (string) The transaction id\n" | " \"txid\": \"id\", (string) The transaction id\n" | ||||
" \"vout\": n, (numeric) The output number\n" | " \"vout\": n, (numeric) The output number\n" | ||||
" \"scriptSig\": { (json object) The script\n" | " \"scriptSig\": { (json object) The script\n" | ||||
" \"asm\": \"asm\", (string) asm\n" | " \"asm\": \"asm\", (string) asm\n" | ||||
" \"hex\": \"hex\" (string) hex\n" | " \"hex\": \"hex\" (string) hex\n" | ||||
" },\n" | " },\n" | ||||
" \"sequence\": n (numeric) The script sequence " | " \"sequence\": n (numeric) The script sequence number\n" | ||||
"number\n" | |||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ],\n" | " ],\n" | ||||
" \"vout\" : [ (array of json objects)\n" | " \"vout\" : [ (array of json objects)\n" | ||||
" {\n" | " {\n" | ||||
" \"value\" : x.xxx, (numeric) The value in " + | " \"value\" : x.xxx, (numeric) The value in " + | ||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
"\n" | "\n" | ||||
" \"n\" : n, (numeric) index\n" | " \"n\" : n, (numeric) index\n" | ||||
" \"scriptPubKey\" : { (json object)\n" | " \"scriptPubKey\" : { (json object)\n" | ||||
" \"asm\" : \"asm\", (string) the asm\n" | " \"asm\" : \"asm\", (string) the asm\n" | ||||
" \"hex\" : \"hex\", (string) the hex\n" | " \"hex\" : \"hex\", (string) the hex\n" | ||||
" \"reqSigs\" : n, (numeric) The required " | " \"reqSigs\" : n, (numeric) The required sigs\n" | ||||
"sigs\n" | |||||
" \"type\" : \"pubkeyhash\", (string) The type, eg " | " \"type\" : \"pubkeyhash\", (string) The type, eg " | ||||
"'pubkeyhash'\n" | "'pubkeyhash'\n" | ||||
" \"addresses\" : [ (json array of string)\n" | " \"addresses\" : [ (json array of string)\n" | ||||
" \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) " | " \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) " | ||||
"bitcoin address\n" | "bitcoin address\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
" }\n" | " }\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ],\n" | " ],\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{ | RPCExamples{HelpExampleCli("decoderawtransaction", "\"hexstring\"") + | ||||
HelpExampleCli("decoderawtransaction", "\"hexstring\"") + | |||||
HelpExampleRpc("decoderawtransaction", "\"hexstring\"")}, | HelpExampleRpc("decoderawtransaction", "\"hexstring\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VSTR}); | RPCTypeCheck(request.params, {UniValue::VSTR}); | ||||
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"); | ||||
} | } | ||||
UniValue result(UniValue::VOBJ); | UniValue result(UniValue::VOBJ); | ||||
TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false); | TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false); | ||||
return result; | return result; | ||||
} | } | ||||
static UniValue decodescript(const Config &config, | static UniValue decodescript(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"decodescript", | "decodescript", | ||||
"\nDecode a hex-encoded script.\n", | "\nDecode a hex-encoded script.\n", | ||||
{ | { | ||||
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"the hex-encoded script"}, | "the hex-encoded script"}, | ||||
}, | }, | ||||
RPCResult{"{\n" | RPCResult{"{\n" | ||||
" \"asm\":\"asm\", (string) Script public key\n" | " \"asm\":\"asm\", (string) Script public key\n" | ||||
" \"hex\":\"hex\", (string) hex-encoded public key\n" | " \"hex\":\"hex\", (string) hex-encoded public key\n" | ||||
" \"type\":\"type\", (string) The output type\n" | " \"type\":\"type\", (string) The output type\n" | ||||
" \"reqSigs\": n, (numeric) The required signatures\n" | " \"reqSigs\": n, (numeric) The required signatures\n" | ||||
" \"addresses\": [ (json array of string)\n" | " \"addresses\": [ (json array of string)\n" | ||||
" \"address\" (string) bitcoin address\n" | " \"address\" (string) bitcoin address\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ],\n" | " ],\n" | ||||
" \"p2sh\",\"address\" (string) address of P2SH script " | " \"p2sh\",\"address\" (string) address of P2SH script " | ||||
"wrapping this redeem script (not returned if the script " | "wrapping this redeem script (not returned if the script is " | ||||
"is already a P2SH).\n" | "already a P2SH).\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{HelpExampleCli("decodescript", "\"hexstring\"") + | RPCExamples{HelpExampleCli("decodescript", "\"hexstring\"") + | ||||
HelpExampleRpc("decodescript", "\"hexstring\"")}, | HelpExampleRpc("decodescript", "\"hexstring\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VSTR}); | RPCTypeCheck(request.params, {UniValue::VSTR}); | ||||
UniValue r(UniValue::VOBJ); | UniValue r(UniValue::VOBJ); | ||||
CScript script; | CScript script; | ||||
if (request.params[0].get_str().size() > 0) { | if (request.params[0].get_str().size() > 0) { | ||||
std::vector<uint8_t> scriptData( | std::vector<uint8_t> scriptData( | ||||
ParseHexV(request.params[0], "argument")); | ParseHexV(request.params[0], "argument")); | ||||
Show All 13 Lines | if (type.isStr() && type.get_str() != "scripthash") { | ||||
r.pushKV("p2sh", EncodeDestination(ScriptHash(script), config)); | r.pushKV("p2sh", EncodeDestination(ScriptHash(script), config)); | ||||
} | } | ||||
return r; | return r; | ||||
} | } | ||||
static UniValue combinerawtransaction(const Config &config, | static UniValue combinerawtransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"combinerawtransaction", | "combinerawtransaction", | ||||
"\nCombine multiple partially signed transactions into one " | "\nCombine multiple partially signed transactions into one " | ||||
"transaction.\n" | "transaction.\n" | ||||
"The combined transaction may be another partially signed " | "The combined transaction may be another partially signed transaction " | ||||
"transaction or a \n" | "or a \n" | ||||
"fully signed transaction.", | "fully signed transaction.", | ||||
{ | { | ||||
{ | { | ||||
"txs", | "txs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A json array of hex strings of partially signed " | "A json array of hex strings of partially signed " | ||||
"transactions", | "transactions", | ||||
{ | { | ||||
{"hexstring", RPCArg::Type::STR_HEX, | {"hexstring", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::OMITTED, "A transaction hash"}, | RPCArg::Optional::OMITTED, "A transaction hash"}, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
RPCResult{"\"hex\" (string) The hex-encoded raw " | RPCResult{"\"hex\" (string) The hex-encoded raw transaction " | ||||
"transaction with signature(s)\n"}, | "with signature(s)\n"}, | ||||
RPCExamples{HelpExampleCli("combinerawtransaction", | RPCExamples{HelpExampleCli("combinerawtransaction", | ||||
"[\"myhex1\", \"myhex2\", \"myhex3\"]")}, | "[\"myhex1\", \"myhex2\", \"myhex3\"]")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
UniValue txs = request.params[0].get_array(); | UniValue txs = request.params[0].get_array(); | ||||
std::vector<CMutableTransaction> txVariants(txs.size()); | std::vector<CMutableTransaction> txVariants(txs.size()); | ||||
for (unsigned int idx = 0; idx < txs.size(); idx++) { | for (unsigned int idx = 0; idx < txs.size(); idx++) { | ||||
if (!DecodeHexTx(txVariants[idx], txs[idx].get_str())) { | if (!DecodeHexTx(txVariants[idx], txs[idx].get_str())) { | ||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | ||||
strprintf("TX decode failed for tx %d", idx)); | strprintf("TX decode failed for tx %d", idx)); | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < mergedTx.vin.size(); i++) { | ||||
UpdateInput(txin, sigdata); | UpdateInput(txin, sigdata); | ||||
} | } | ||||
return EncodeHexTx(CTransaction(mergedTx)); | return EncodeHexTx(CTransaction(mergedTx)); | ||||
} | } | ||||
static UniValue signrawtransactionwithkey(const Config &config, | static UniValue signrawtransactionwithkey(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 2 || | RPCHelpMan{ | ||||
request.params.size() > 4) { | |||||
throw std::runtime_error(RPCHelpMan{ | |||||
"signrawtransactionwithkey", | "signrawtransactionwithkey", | ||||
"\nSign inputs for raw transaction (serialized, hex-encoded).\n" | "\nSign inputs for raw transaction (serialized, hex-encoded).\n" | ||||
"The second argument is an array of base58-encoded private\n" | "The second argument is an array of base58-encoded private\n" | ||||
"keys that will be the only keys used to sign the transaction.\n" | "keys that will be the only keys used to sign the transaction.\n" | ||||
"The third optional argument (may be null) is an array of previous " | "The third optional argument (may be null) is an array of previous " | ||||
"transaction outputs that\n" | "transaction outputs that\n" | ||||
"this transaction depends on but may not yet be in the block " | "this transaction depends on but may not yet be in the block chain.\n", | ||||
"chain.\n", | |||||
{ | { | ||||
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"The transaction hex string"}, | "The transaction hex string"}, | ||||
{ | { | ||||
"privkeys", | "privkeys", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A json array of base58-encoded private keys for signing", | "A json array of base58-encoded private keys for signing", | ||||
{ | { | ||||
{"privatekey", RPCArg::Type::STR, | {"privatekey", RPCArg::Type::STR, RPCArg::Optional::OMITTED, | ||||
RPCArg::Optional::OMITTED, | |||||
"private key in base58-encoding"}, | "private key in base58-encoding"}, | ||||
}, | }, | ||||
}, | }, | ||||
{ | { | ||||
"prevtxs", | "prevtxs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::OMITTED_NAMED_ARG, | RPCArg::Optional::OMITTED_NAMED_ARG, | ||||
"A json array of previous dependent transaction outputs", | "A json array of previous dependent transaction outputs", | ||||
{ | { | ||||
{ | { | ||||
"", | "", | ||||
RPCArg::Type::OBJ, | RPCArg::Type::OBJ, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"", | "", | ||||
{ | { | ||||
{"txid", RPCArg::Type::STR_HEX, | {"txid", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::NO, "The transaction id"}, | RPCArg::Optional::NO, "The transaction id"}, | ||||
{"vout", RPCArg::Type::NUM, | {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, | ||||
RPCArg::Optional::NO, "The output number"}, | "The output number"}, | ||||
{"scriptPubKey", RPCArg::Type::STR_HEX, | {"scriptPubKey", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::NO, "script key"}, | RPCArg::Optional::NO, "script key"}, | ||||
{"redeemScript", RPCArg::Type::STR_HEX, | {"redeemScript", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"(required for P2SH) redeem script"}, | "(required for P2SH) redeem script"}, | ||||
{"amount", RPCArg::Type::AMOUNT, | {"amount", RPCArg::Type::AMOUNT, | ||||
RPCArg::Optional::NO, "The amount spent"}, | RPCArg::Optional::NO, "The amount spent"}, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
{"sighashtype", RPCArg::Type::STR, /* default */ "ALL|FORKID", | {"sighashtype", RPCArg::Type::STR, /* default */ "ALL|FORKID", | ||||
"The signature hash type. Must be one of:\n" | "The signature hash type. Must be one of:\n" | ||||
" \"ALL|FORKID\"\n" | " \"ALL|FORKID\"\n" | ||||
" \"NONE|FORKID\"\n" | " \"NONE|FORKID\"\n" | ||||
" \"SINGLE|FORKID\"\n" | " \"SINGLE|FORKID\"\n" | ||||
" \"ALL|FORKID|ANYONECANPAY\"\n" | " \"ALL|FORKID|ANYONECANPAY\"\n" | ||||
" \"NONE|FORKID|ANYONECANPAY\"\n" | " \"NONE|FORKID|ANYONECANPAY\"\n" | ||||
" \"SINGLE|FORKID|ANYONECANPAY\""}, | " \"SINGLE|FORKID|ANYONECANPAY\""}, | ||||
}, | }, | ||||
RPCResult{"{\n" | RPCResult{ | ||||
" \"hex\" : \"value\", (string) The " | "{\n" | ||||
"hex-encoded raw transaction with signature(s)\n" | " \"hex\" : \"value\", (string) The hex-encoded raw " | ||||
" \"complete\" : true|false, (boolean) If the " | "transaction with signature(s)\n" | ||||
"transaction has a complete set of signatures\n" | " \"complete\" : true|false, (boolean) If the transaction has a " | ||||
" \"errors\" : [ (json array of " | "complete set of signatures\n" | ||||
"objects) Script verification errors (if there are any)\n" | " \"errors\" : [ (json array of objects) Script " | ||||
"verification errors (if there are any)\n" | |||||
" {\n" | " {\n" | ||||
" \"txid\" : \"hash\", (string) The " | " \"txid\" : \"hash\", (string) The hash of the " | ||||
"hash of the referenced, previous transaction\n" | "referenced, previous transaction\n" | ||||
" \"vout\" : n, (numeric) The " | " \"vout\" : n, (numeric) The index of the output " | ||||
"index of the output to spent and used as input\n" | "to spent and used as input\n" | ||||
" \"scriptSig\" : \"hex\", (string) The " | " \"scriptSig\" : \"hex\", (string) The hex-encoded signature " | ||||
"hex-encoded signature script\n" | "script\n" | ||||
" \"sequence\" : n, (numeric) Script " | " \"sequence\" : n, (numeric) Script sequence number\n" | ||||
"sequence number\n" | " \"error\" : \"text\" (string) Verification or signing " | ||||
" \"error\" : \"text\" (string) " | "error related to the input\n" | ||||
"Verification or signing error related to the input\n" | |||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{ | RPCExamples{HelpExampleCli("signrawtransactionwithkey", "\"myhex\"") + | ||||
HelpExampleCli("signrawtransactionwithkey", "\"myhex\"") + | |||||
HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"")}, | HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck( | RPCTypeCheck( | ||||
request.params, | request.params, | ||||
{UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); | {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); | ||||
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"); | ||||
Show All 20 Lines | static UniValue signrawtransactionwithkey(const Config &config, | ||||
FindCoins(coins); | FindCoins(coins); | ||||
return SignTransaction(mtx, request.params[2], &keystore, coins, true, | return SignTransaction(mtx, request.params[2], &keystore, coins, true, | ||||
request.params[3]); | request.params[3]); | ||||
} | } | ||||
static UniValue sendrawtransaction(const Config &config, | static UniValue sendrawtransaction(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
const RPCHelpMan help{ | RPCHelpMan{ | ||||
"sendrawtransaction", | "sendrawtransaction", | ||||
"\nSubmits raw transaction (serialized, hex-encoded) to local node and " | "\nSubmits raw transaction (serialized, hex-encoded) to local node and " | ||||
"network.\n" | "network.\n" | ||||
"\nAlso see createrawtransaction and " | "\nAlso see createrawtransaction and " | ||||
"signrawtransactionwithkey calls.\n", | "signrawtransactionwithkey calls.\n", | ||||
{ | { | ||||
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"The hex string of the raw transaction"}, | "The hex string of the raw transaction"}, | ||||
Show All 11 Lines | RPCHelpMan{ | ||||
"\"[{\\\"txid\\\" : \\\"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("signrawtransactionwithwallet", "\"myhex\"") + | HelpExampleCli("signrawtransactionwithwallet", "\"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\"")}, | ||||
}; | |||||
if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { | |||||
throw std::runtime_error(help.ToString()); | |||||
} | } | ||||
.Check(request); | |||||
RPCTypeCheck(request.params, { | RPCTypeCheck(request.params, { | ||||
UniValue::VSTR, | UniValue::VSTR, | ||||
// NUM or BOOL, checked later | // NUM or BOOL, checked later | ||||
UniValueType(), | UniValueType(), | ||||
}); | }); | ||||
// parse hex string from parameter | // parse hex string from parameter | ||||
Show All 28 Lines | if (err != TransactionError::OK) { | ||||
throw JSONRPCTransactionError(err, err_string); | throw JSONRPCTransactionError(err, err_string); | ||||
} | } | ||||
return tx->GetHash().GetHex(); | return tx->GetHash().GetHex(); | ||||
} | } | ||||
static UniValue testmempoolaccept(const Config &config, | static UniValue testmempoolaccept(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
const RPCHelpMan help{ | RPCHelpMan{ | ||||
"testmempoolaccept", | "testmempoolaccept", | ||||
"\nReturns if raw transaction (serialized, hex-encoded) would be " | "\nReturns if raw transaction (serialized, hex-encoded) would be " | ||||
"accepted by mempool.\n" | "accepted by mempool.\n" | ||||
"\nThis checks if the transaction violates the consensus or policy " | "\nThis checks if the transaction violates the consensus or policy " | ||||
"rules.\n" | "rules.\n" | ||||
"\nSee sendrawtransaction call.\n", | "\nSee sendrawtransaction call.\n", | ||||
{ | { | ||||
{ | { | ||||
"rawtxs", | "rawtxs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"An array of hex strings of raw transactions.\n" | "An array of hex strings of raw transactions.\n" | ||||
" Length must be one " | " Length must be one for now.", | ||||
"for now.", | |||||
{ | { | ||||
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, | {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, | ||||
""}, | ""}, | ||||
}, | }, | ||||
}, | }, | ||||
{"maxfeerate", RPCArg::Type::AMOUNT, | {"maxfeerate", RPCArg::Type::AMOUNT, | ||||
/* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE), | /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE), | ||||
"Reject transactions whose fee rate is higher than the specified " | "Reject transactions whose fee rate is higher than the specified " | ||||
"value, expressed in " + | "value, expressed in " + | ||||
CURRENCY_UNIT + "/kB\n"}, | CURRENCY_UNIT + "/kB\n"}, | ||||
}, | }, | ||||
RPCResult{ | RPCResult{ | ||||
"[ (array) The result of the mempool acceptance " | "[ (array) The result of the mempool acceptance " | ||||
"test for each raw transaction in the input array.\n" | "test for each raw transaction in the input array.\n" | ||||
" Length is exactly one for now.\n" | " Length is exactly one for now.\n" | ||||
" {\n" | " {\n" | ||||
" \"txid\" (string) The transaction hash in hex\n" | " \"txid\" (string) The transaction hash in hex\n" | ||||
" \"allowed\" (boolean) If the mempool allows this tx to " | " \"allowed\" (boolean) If the mempool allows this tx to be " | ||||
"be inserted\n" | "inserted\n" | ||||
" \"reject-reason\" (string) Rejection string (only present when " | " \"reject-reason\" (string) Rejection string (only present when " | ||||
"'allowed' is false)\n" | "'allowed' is false)\n" | ||||
" }\n" | " }\n" | ||||
"]\n"}, | "]\n"}, | ||||
RPCExamples{ | RPCExamples{ | ||||
"\nCreate a transaction\n" + | "\nCreate a transaction\n" + | ||||
HelpExampleCli( | HelpExampleCli( | ||||
"createrawtransaction", | "createrawtransaction", | ||||
"\"[{\\\"txid\\\" : \\\"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("signrawtransactionwithwallet", "\"myhex\"") + | HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") + | ||||
"\nTest acceptance of the transaction (signed hex)\n" + | "\nTest acceptance of the transaction (signed hex)\n" + | ||||
HelpExampleCli("testmempoolaccept", "[\"signedhex\"]") + | HelpExampleCli("testmempoolaccept", "[\"signedhex\"]") + | ||||
"\nAs a JSON-RPC call\n" + | "\nAs a JSON-RPC call\n" + | ||||
HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")}, | HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")}, | ||||
}; | |||||
if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { | |||||
throw std::runtime_error(help.ToString()); | |||||
} | } | ||||
.Check(request); | |||||
RPCTypeCheck(request.params, { | RPCTypeCheck(request.params, { | ||||
UniValue::VARR, | UniValue::VARR, | ||||
// NUM or BOOL, checked later | // NUM or BOOL, checked later | ||||
UniValueType(), | UniValueType(), | ||||
}); | }); | ||||
if (request.params[0].get_array().size() != 1) { | if (request.params[0].get_array().size() != 1) { | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | for (uint32_t num : keypath) { | ||||
keypath_str += "'"; | keypath_str += "'"; | ||||
} | } | ||||
} | } | ||||
return keypath_str; | return keypath_str; | ||||
} | } | ||||
static UniValue decodepsbt(const Config &config, | static UniValue decodepsbt(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"decodepsbt", | "decodepsbt", | ||||
"\nReturn a JSON object representing the serialized, " | "\nReturn a JSON object representing the serialized, base64-encoded " | ||||
"base64-encoded partially signed Bitcoin transaction.\n", | "partially signed Bitcoin transaction.\n", | ||||
{ | { | ||||
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"The PSBT base64 string"}, | "The PSBT base64 string"}, | ||||
}, | }, | ||||
RPCResult{ | RPCResult{ | ||||
"{\n" | "{\n" | ||||
" \"tx\" : { (json object) The decoded " | " \"tx\" : { (json object) The decoded " | ||||
"network-serialized unsigned transaction.\n" | "network-serialized unsigned transaction.\n" | ||||
" ... The layout is " | " ... The layout is the " | ||||
"the same as the output of decoderawtransaction.\n" | "same as the output of decoderawtransaction.\n" | ||||
" },\n" | " },\n" | ||||
" \"unknown\" : { (json object) The unknown " | " \"unknown\" : { (json object) The unknown global " | ||||
"global fields\n" | "fields\n" | ||||
" \"key\" : \"value\" (key-value pair) An " | " \"key\" : \"value\" (key-value pair) An unknown " | ||||
"unknown key-value pair\n" | "key-value pair\n" | ||||
" ...\n" | " ...\n" | ||||
" },\n" | " },\n" | ||||
" \"inputs\" : [ (array of json objects)\n" | " \"inputs\" : [ (array of json objects)\n" | ||||
" {\n" | " {\n" | ||||
" \"utxo\" : { (json object, optional) " | " \"utxo\" : { (json object, optional) Transaction " | ||||
"Transaction output for UTXOs\n" | "output for UTXOs\n" | ||||
" \"amount\" : x.xxx, (numeric) The value " | " \"amount\" : x.xxx, (numeric) The value in " + | ||||
"in " + | |||||
CURRENCY_UNIT + | CURRENCY_UNIT + | ||||
"\n" | "\n" | ||||
" \"scriptPubKey\" : { (json object)\n" | " \"scriptPubKey\" : { (json object)\n" | ||||
" \"asm\" : \"asm\", (string) The asm\n" | " \"asm\" : \"asm\", (string) The asm\n" | ||||
" \"hex\" : \"hex\", (string) The hex\n" | " \"hex\" : \"hex\", (string) The hex\n" | ||||
" \"type\" : \"pubkeyhash\", (string) The type, eg " | " \"type\" : \"pubkeyhash\", (string) The type, eg " | ||||
"'pubkeyhash'\n" | "'pubkeyhash'\n" | ||||
" \"address\" : \"address\" (string) Bitcoin " | " \"address\" : \"address\" (string) Bitcoin address " | ||||
"address if there is one\n" | "if there is one\n" | ||||
" }\n" | " }\n" | ||||
" },\n" | " },\n" | ||||
" \"partial_signatures\" : { (json object, " | " \"partial_signatures\" : { (json object, " | ||||
"optional)\n" | "optional)\n" | ||||
" \"pubkey\" : \"signature\", (string) The " | " \"pubkey\" : \"signature\", (string) The public " | ||||
"public key and signature that corresponds to it.\n" | "key and signature that corresponds to it.\n" | ||||
" ,...\n" | " ,...\n" | ||||
" }\n" | " }\n" | ||||
" \"sighash\" : \"type\", (string, " | " \"sighash\" : \"type\", (string, optional) " | ||||
"optional) The sighash type to be used\n" | "The sighash type to be used\n" | ||||
" \"redeem_script\" : { (json object, optional)\n" | " \"redeem_script\" : { (json object, optional)\n" | ||||
" \"asm\" : \"asm\", (string) The asm\n" | " \"asm\" : \"asm\", (string) The asm\n" | ||||
" \"hex\" : \"hex\", (string) The hex\n" | " \"hex\" : \"hex\", (string) The hex\n" | ||||
" \"type\" : \"pubkeyhash\", (string) The type, eg " | " \"type\" : \"pubkeyhash\", (string) The type, eg " | ||||
"'pubkeyhash'\n" | "'pubkeyhash'\n" | ||||
" }\n" | " }\n" | ||||
" \"bip32_derivs\" : { (json object, optional)\n" | " \"bip32_derivs\" : { (json object, optional)\n" | ||||
" \"pubkey\" : { (json object, " | " \"pubkey\" : { (json object, " | ||||
"optional) The public key with the derivation path as the " | "optional) The public key with the derivation path as the value.\n" | ||||
"value.\n" | " \"master_fingerprint\" : \"fingerprint\" (string) " | ||||
" \"master_fingerprint\" : \"fingerprint\" " | "The fingerprint of the master key\n" | ||||
"(string) The fingerprint of the master key\n" | " \"path\" : \"path\", (string) " | ||||
" \"path\" : \"path\", " | "The path\n" | ||||
"(string) The path\n" | |||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" }\n" | " }\n" | ||||
" \"final_scriptsig\" : { (json object, optional)\n" | " \"final_scriptsig\" : { (json object, optional)\n" | ||||
" \"asm\" : \"asm\", (string) The asm\n" | " \"asm\" : \"asm\", (string) The asm\n" | ||||
" \"hex\" : \"hex\", (string) The hex\n" | " \"hex\" : \"hex\", (string) The hex\n" | ||||
" }\n" | " }\n" | ||||
" \"unknown\" : { (json object) The " | " \"unknown\" : { (json object) The unknown " | ||||
"unknown global fields\n" | "global fields\n" | ||||
" \"key\" : \"value\" (key-value pair) An " | " \"key\" : \"value\" (key-value pair) An " | ||||
"unknown key-value pair\n" | "unknown key-value pair\n" | ||||
" ...\n" | " ...\n" | ||||
" },\n" | " },\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
" \"outputs\" : [ (array of json objects)\n" | " \"outputs\" : [ (array of json objects)\n" | ||||
" {\n" | " {\n" | ||||
" \"redeem_script\" : { (json object, optional)\n" | " \"redeem_script\" : { (json object, optional)\n" | ||||
" \"asm\" : \"asm\", (string) The asm\n" | " \"asm\" : \"asm\", (string) The asm\n" | ||||
" \"hex\" : \"hex\", (string) The hex\n" | " \"hex\" : \"hex\", (string) The hex\n" | ||||
" \"type\" : \"pubkeyhash\", (string) The type, eg " | " \"type\" : \"pubkeyhash\", (string) The type, eg " | ||||
"'pubkeyhash'\n" | "'pubkeyhash'\n" | ||||
" }\n" | " }\n" | ||||
" \"bip32_derivs\" : [ (array of json objects, " | " \"bip32_derivs\" : [ (array of json objects, " | ||||
"optional)\n" | "optional)\n" | ||||
" {\n" | " {\n" | ||||
" \"pubkey\" : \"pubkey\", " | " \"pubkey\" : \"pubkey\", (string) " | ||||
"(string) The public key this path corresponds to\n" | "The public key this path corresponds to\n" | ||||
" \"master_fingerprint\" : \"fingerprint\" " | " \"master_fingerprint\" : \"fingerprint\" (string) " | ||||
"(string) The fingerprint of the master key\n" | "The fingerprint of the master key\n" | ||||
" \"path\" : \"path\", " | " \"path\" : \"path\", (string) " | ||||
"(string) The path\n" | "The path\n" | ||||
" }\n" | " }\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ],\n" | " ],\n" | ||||
" \"unknown\" : { (json object) The " | " \"unknown\" : { (json object) The unknown " | ||||
"unknown global fields\n" | "global fields\n" | ||||
" \"key\" : \"value\" (key-value pair) An " | " \"key\" : \"value\" (key-value pair) An " | ||||
"unknown key-value pair\n" | "unknown key-value pair\n" | ||||
" ...\n" | " ...\n" | ||||
" },\n" | " },\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
" \"fee\" : fee (numeric, optional) The " | " \"fee\" : fee (numeric, optional) The " | ||||
"transaction fee paid if all UTXOs slots in the PSBT have been " | "transaction fee paid if all UTXOs slots in the PSBT have been " | ||||
"filled.\n" | "filled.\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{HelpExampleCli("decodepsbt", "\"psbt\"")}, | RPCExamples{HelpExampleCli("decodepsbt", "\"psbt\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VSTR}); | RPCTypeCheck(request.params, {UniValue::VSTR}); | ||||
// Unserialize the transactions | // Unserialize the transactions | ||||
PartiallySignedTransaction psbtx; | PartiallySignedTransaction psbtx; | ||||
std::string error; | std::string error; | ||||
if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | ||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | if (have_all_utxos) { | ||||
result.pushKV("fee", ValueFromAmount(total_in - output_value)); | result.pushKV("fee", ValueFromAmount(total_in - output_value)); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
static UniValue combinepsbt(const Config &config, | static UniValue combinepsbt(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"combinepsbt", | "combinepsbt", | ||||
"\nCombine multiple partially signed Bitcoin transactions into " | "\nCombine multiple partially signed Bitcoin transactions into one " | ||||
"one transaction.\n" | "transaction.\n" | ||||
"Implements the Combiner role.\n", | "Implements the Combiner role.\n", | ||||
{ | { | ||||
{ | { | ||||
"txs", | "txs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A json array of base64 strings of partially signed " | "A json array of base64 strings of partially signed " | ||||
"transactions", | "transactions", | ||||
{ | { | ||||
{"psbt", RPCArg::Type::STR, RPCArg::Optional::OMITTED, | {"psbt", RPCArg::Type::STR, RPCArg::Optional::OMITTED, | ||||
"A base64 string of a PSBT"}, | "A base64 string of a PSBT"}, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
RPCResult{" \"psbt\" (string) The base64-encoded " | RPCResult{" \"psbt\" (string) The base64-encoded partially " | ||||
"partially signed transaction\n"}, | "signed transaction\n"}, | ||||
RPCExamples{HelpExampleCli( | RPCExamples{HelpExampleCli( | ||||
"combinepsbt", | "combinepsbt", "[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]")}, | ||||
"[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]")}, | |||||
} | |||||
.ToString()); | |||||
} | } | ||||
.Check(request); | |||||
RPCTypeCheck(request.params, {UniValue::VARR}, true); | RPCTypeCheck(request.params, {UniValue::VARR}, true); | ||||
// Unserialize the transactions | // Unserialize the transactions | ||||
std::vector<PartiallySignedTransaction> psbtxs; | std::vector<PartiallySignedTransaction> psbtxs; | ||||
UniValue txs = request.params[0].get_array(); | UniValue txs = request.params[0].get_array(); | ||||
for (size_t i = 0; i < txs.size(); ++i) { | for (size_t i = 0; i < txs.size(); ++i) { | ||||
PartiallySignedTransaction psbtx; | PartiallySignedTransaction psbtx; | ||||
Show All 14 Lines | static UniValue combinepsbt(const Config &config, | ||||
UniValue result(UniValue::VOBJ); | UniValue result(UniValue::VOBJ); | ||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | ||||
ssTx << merged_psbt; | ssTx << merged_psbt; | ||||
return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | ||||
} | } | ||||
static UniValue finalizepsbt(const Config &config, | static UniValue finalizepsbt(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 1 || | RPCHelpMan{ | ||||
request.params.size() > 2) { | |||||
throw std::runtime_error(RPCHelpMan{ | |||||
"finalizepsbt", | "finalizepsbt", | ||||
"Finalize the inputs of a PSBT. If the transaction is " | "Finalize the inputs of a PSBT. If the transaction is fully signed, it " | ||||
"fully signed, it will produce a\n" | "will produce a\n" | ||||
"network serialized transaction which can be broadcast " | "network serialized transaction which can be broadcast with " | ||||
"with sendrawtransaction. Otherwise a PSBT will be\n" | "sendrawtransaction. Otherwise a PSBT will be\n" | ||||
"created which has the final_scriptSigfields filled for " | "created which has the final_scriptSigfields filled for inputs that " | ||||
"inputs that are complete.\n" | "are complete.\n" | ||||
"Implements the Finalizer and Extractor roles.\n", | "Implements the Finalizer and Extractor roles.\n", | ||||
{ | { | ||||
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"A base64 string of a PSBT"}, | "A base64 string of a PSBT"}, | ||||
{"extract", RPCArg::Type::BOOL, /* default */ "true", | {"extract", RPCArg::Type::BOOL, /* default */ "true", | ||||
"If true and the transaction is complete,\n" | "If true and the transaction is complete,\n" | ||||
" extract and return the complete " | " extract and return the complete " | ||||
"transaction in normal network serialization instead of the " | "transaction in normal network serialization instead of the " | ||||
"PSBT."}, | "PSBT."}, | ||||
}, | }, | ||||
RPCResult{ | RPCResult{ | ||||
"{\n" | "{\n" | ||||
" \"psbt\" : \"value\", (string) The base64-encoded " | " \"psbt\" : \"value\", (string) The base64-encoded " | ||||
"partially signed transaction if not extracted\n" | "partially signed transaction if not extracted\n" | ||||
" \"hex\" : \"value\", (string) The hex-encoded " | " \"hex\" : \"value\", (string) The hex-encoded network " | ||||
"network transaction if extracted\n" | "transaction if extracted\n" | ||||
" \"complete\" : true|false, (boolean) If the transaction " | " \"complete\" : true|false, (boolean) If the transaction has a " | ||||
"has a complete set of signatures\n" | "complete set of signatures\n" | ||||
" ]\n" | " ]\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{HelpExampleCli("finalizepsbt", "\"psbt\"")}, | RPCExamples{HelpExampleCli("finalizepsbt", "\"psbt\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); | RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); | ||||
// Unserialize the transactions | // Unserialize the transactions | ||||
PartiallySignedTransaction psbtx; | PartiallySignedTransaction psbtx; | ||||
std::string error; | std::string error; | ||||
if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | ||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | ||||
Show All 21 Lines | static UniValue finalizepsbt(const Config &config, | ||||
} | } | ||||
result.pushKV("complete", complete); | result.pushKV("complete", complete); | ||||
return result; | return result; | ||||
} | } | ||||
static UniValue createpsbt(const Config &config, | static UniValue createpsbt(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 2 || | RPCHelpMan{ | ||||
request.params.size() > 3) { | |||||
throw std::runtime_error(RPCHelpMan{ | |||||
"createpsbt", | "createpsbt", | ||||
"\nCreates a transaction in the Partially Signed Transaction " | "\nCreates a transaction in the Partially Signed Transaction format.\n" | ||||
"format.\n" | |||||
"Implements the Creator role.\n", | "Implements the Creator role.\n", | ||||
{ | { | ||||
{ | { | ||||
"inputs", | "inputs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A json array of json objects", | "A json array of json objects", | ||||
{ | { | ||||
{ | { | ||||
"", | "", | ||||
RPCArg::Type::OBJ, | RPCArg::Type::OBJ, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"", | "", | ||||
{ | { | ||||
{"txid", RPCArg::Type::STR_HEX, | {"txid", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::NO, "The transaction id"}, | RPCArg::Optional::NO, "The transaction id"}, | ||||
{"vout", RPCArg::Type::NUM, | {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, | ||||
RPCArg::Optional::NO, "The output number"}, | "The output number"}, | ||||
{"sequence", RPCArg::Type::NUM, /* default */ | {"sequence", RPCArg::Type::NUM, /* default */ | ||||
"depends on the value of the 'locktime' " | "depends on the value of the 'locktime' argument", | ||||
"argument", | |||||
"The sequence number"}, | "The sequence number"}, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
{ | { | ||||
"outputs", | "outputs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"a json array with outputs (key-value pairs).\n" | "a json array with outputs (key-value pairs).\n" | ||||
"For compatibility reasons, a dictionary, which holds " | "For compatibility reasons, a dictionary, which holds the " | ||||
"the key-value pairs directly, is also\n" | "key-value pairs directly, is also\n" | ||||
" accepted as second " | " accepted as second parameter.", | ||||
"parameter.", | |||||
{ | { | ||||
{ | { | ||||
"", | "", | ||||
RPCArg::Type::OBJ, | RPCArg::Type::OBJ, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"", | "", | ||||
{ | { | ||||
{"address", RPCArg::Type::AMOUNT, | {"address", RPCArg::Type::AMOUNT, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A key-value pair. The key (string) is " | "A key-value pair. The key (string) is the " | ||||
"the bitcoin address, the value (float or " | "bitcoin address, the value (float or string) is " | ||||
"string) is the amount in " + | "the amount in " + | ||||
CURRENCY_UNIT}, | CURRENCY_UNIT}, | ||||
}, | }, | ||||
}, | }, | ||||
{ | { | ||||
"", | "", | ||||
RPCArg::Type::OBJ, | RPCArg::Type::OBJ, | ||||
RPCArg::Optional::OMITTED, | RPCArg::Optional::OMITTED, | ||||
"", | "", | ||||
{ | { | ||||
{"data", RPCArg::Type::STR_HEX, | {"data", RPCArg::Type::STR_HEX, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A key-value pair. The key must be " | "A key-value pair. The key must be \"data\", the " | ||||
"\"data\", the value is hex-encoded data"}, | "value is hex-encoded data"}, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
{"locktime", RPCArg::Type::NUM, /* default */ "0", | {"locktime", RPCArg::Type::NUM, /* default */ "0", | ||||
"Raw locktime. Non-0 value also locktime-activates inputs"}, | "Raw locktime. Non-0 value also locktime-activates inputs"}, | ||||
}, | }, | ||||
RPCResult{" \"psbt\" (string) The resulting raw " | RPCResult{" \"psbt\" (string) The resulting raw transaction " | ||||
"transaction (base64-encoded string)\n"}, | "(base64-encoded string)\n"}, | ||||
RPCExamples{HelpExampleCli( | RPCExamples{HelpExampleCli( | ||||
"createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | "createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | ||||
"\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")}, | "\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, | RPCTypeCheck(request.params, | ||||
{ | { | ||||
UniValue::VARR, | UniValue::VARR, | ||||
UniValueType(), // ARR or OBJ, checked later | UniValueType(), // ARR or OBJ, checked later | ||||
UniValue::VNUM, | UniValue::VNUM, | ||||
}, | }, | ||||
true); | true); | ||||
Show All 16 Lines | static UniValue createpsbt(const Config &config, | ||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | ||||
ssTx << psbtx; | ssTx << psbtx; | ||||
return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | ||||
} | } | ||||
static UniValue converttopsbt(const Config &config, | static UniValue converttopsbt(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() < 1 || | RPCHelpMan{ | ||||
request.params.size() > 2) { | |||||
throw std::runtime_error(RPCHelpMan{ | |||||
"converttopsbt", | "converttopsbt", | ||||
"\nConverts a network serialized transaction to a PSBT. " | "\nConverts a network serialized transaction to a PSBT. " | ||||
"This should be used only with createrawtransaction and " | "This should be used only with createrawtransaction and " | ||||
"fundrawtransaction\n" | "fundrawtransaction\n" | ||||
"createpsbt and walletcreatefundedpsbt should be used for new " | "createpsbt and walletcreatefundedpsbt should be used for new " | ||||
"applications.\n", | "applications.\n", | ||||
{ | { | ||||
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, | ||||
"The hex string of a raw transaction"}, | "The hex string of a raw transaction"}, | ||||
{"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", | {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", | ||||
"If true, any signatures in the input will be discarded and " | "If true, any signatures in the input will be discarded and " | ||||
"conversion.\n" | "conversion.\n" | ||||
" will continue. If false, RPC " | " will continue. If false, RPC will " | ||||
"will fail if any signatures are present."}, | "fail if any signatures are present."}, | ||||
}, | }, | ||||
RPCResult{" \"psbt\" (string) The resulting raw " | RPCResult{" \"psbt\" (string) The resulting raw " | ||||
"transaction (base64-encoded string)\n"}, | "transaction (base64-encoded string)\n"}, | ||||
RPCExamples{ | RPCExamples{ | ||||
"\nCreate a transaction\n" + | "\nCreate a transaction\n" + | ||||
HelpExampleCli("createrawtransaction", | HelpExampleCli("createrawtransaction", | ||||
"\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]" | ||||
"\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + | "\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + | ||||
"\nConvert the transaction to a PSBT\n" + | "\nConvert the transaction to a PSBT\n" + | ||||
HelpExampleCli("converttopsbt", "\"rawtransaction\"")}, | HelpExampleCli("converttopsbt", "\"rawtransaction\"")}, | ||||
} | } | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); | RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); | ||||
// parse hex string from parameter | // parse hex string from parameter | ||||
CMutableTransaction tx; | CMutableTransaction tx; | ||||
bool permitsigdata = | bool permitsigdata = | ||||
request.params[1].isNull() ? false : request.params[1].get_bool(); | request.params[1].isNull() ? false : request.params[1].get_bool(); | ||||
if (!DecodeHexTx(tx, request.params[0].get_str())) { | if (!DecodeHexTx(tx, request.params[0].get_str())) { | ||||
Show All 22 Lines | static UniValue converttopsbt(const Config &config, | ||||
// Serialize the PSBT | // Serialize the PSBT | ||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | ||||
ssTx << psbtx; | ssTx << psbtx; | ||||
return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | ||||
} | } | ||||
UniValue utxoupdatepsbt(const Config &config, const JSONRPCRequest &request) { | UniValue utxoupdatepsbt(const Config &config, const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{"utxoupdatepsbt", | ||||
throw std::runtime_error(RPCHelpMan{ | "\nUpdates a PSBT with witness UTXOs retrieved from the UTXO " | ||||
"utxoupdatepsbt", | "set or the mempool.\n", | ||||
"\nUpdates a PSBT with witness UTXOs retrieved from the UTXO set " | |||||
"or the mempool.\n", | |||||
{{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | {{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"A base64 string of a PSBT"}}, | "A base64 string of a PSBT"}}, | ||||
RPCResult{" \"psbt\" (string) The base64-encoded " | RPCResult{" \"psbt\" (string) The base64-encoded " | ||||
"partially signed transaction with inputs updated\n"}, | "partially signed transaction with inputs updated\n"}, | ||||
RPCExamples{HelpExampleCli("utxoupdatepsbt", "\"psbt\"")}} | RPCExamples{HelpExampleCli("utxoupdatepsbt", "\"psbt\"")}} | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VSTR}, true); | RPCTypeCheck(request.params, {UniValue::VSTR}, true); | ||||
// Unserialize the transactions | // Unserialize the transactions | ||||
PartiallySignedTransaction psbtx; | PartiallySignedTransaction psbtx; | ||||
std::string error; | std::string error; | ||||
if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | ||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | ||||
Show All 31 Lines | UniValue utxoupdatepsbt(const Config &config, const JSONRPCRequest &request) { | ||||
} | } | ||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | ||||
ssTx << psbtx; | ssTx << psbtx; | ||||
return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | ||||
} | } | ||||
UniValue joinpsbts(const Config &config, const JSONRPCRequest &request) { | UniValue joinpsbts(const Config &config, const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"joinpsbts", | "joinpsbts", | ||||
"\nJoins multiple distinct PSBTs with different inputs and outputs " | "\nJoins multiple distinct PSBTs with different inputs and outputs " | ||||
"into one PSBT with inputs and outputs from all of the PSBTs\n" | "into one PSBT with inputs and outputs from all of the PSBTs\n" | ||||
"No input in any of the PSBTs can be in more than one of the " | "No input in any of the PSBTs can be in more than one of the PSBTs.\n", | ||||
"PSBTs.\n", | |||||
{{"txs", | {{"txs", | ||||
RPCArg::Type::ARR, | RPCArg::Type::ARR, | ||||
RPCArg::Optional::NO, | RPCArg::Optional::NO, | ||||
"A json array of base64 strings of partially signed transactions", | "A json array of base64 strings of partially signed transactions", | ||||
{{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | {{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"A base64 string of a PSBT"}}}}, | "A base64 string of a PSBT"}}}}, | ||||
RPCResult{" \"psbt\" (string) The base64-encoded " | RPCResult{" \"psbt\" (string) The base64-encoded partially " | ||||
"partially signed transaction\n"}, | "signed transaction\n"}, | ||||
RPCExamples{HelpExampleCli("joinpsbts", "\"psbt\"")}} | RPCExamples{HelpExampleCli("joinpsbts", "\"psbt\"")}} | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VARR}, true); | RPCTypeCheck(request.params, {UniValue::VARR}, true); | ||||
// Unserialize the transactions | // Unserialize the transactions | ||||
std::vector<PartiallySignedTransaction> psbtxs; | std::vector<PartiallySignedTransaction> psbtxs; | ||||
UniValue txs = request.params[0].get_array(); | UniValue txs = request.params[0].get_array(); | ||||
if (txs.size() <= 1) { | if (txs.size() <= 1) { | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | UniValue joinpsbts(const Config &config, const JSONRPCRequest &request) { | ||||
} | } | ||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | ||||
ssTx << merged_psbt; | ssTx << merged_psbt; | ||||
return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | return EncodeBase64((uint8_t *)ssTx.data(), ssTx.size()); | ||||
} | } | ||||
UniValue analyzepsbt(const Config &config, const JSONRPCRequest &request) { | UniValue analyzepsbt(const Config &config, const JSONRPCRequest &request) { | ||||
if (request.fHelp || request.params.size() != 1) { | RPCHelpMan{ | ||||
throw std::runtime_error(RPCHelpMan{ | |||||
"analyzepsbt", | "analyzepsbt", | ||||
"\nAnalyzes and provides information about the current status of a " | "\nAnalyzes and provides information about the current status of a " | ||||
"PSBT and its inputs\n", | "PSBT and its inputs\n", | ||||
{{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | {{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"A base64 string of a PSBT"}}, | "A base64 string of a PSBT"}}, | ||||
RPCResult{ | RPCResult{ | ||||
"{\n" | "{\n" | ||||
" \"inputs\" : [ (array of json " | " \"inputs\" : [ (array of json objects)\n" | ||||
"objects)\n" | |||||
" {\n" | " {\n" | ||||
" \"has_utxo\" : true|false (boolean) Whether a UTXO " | " \"has_utxo\" : true|false (boolean) Whether a UTXO is " | ||||
"is provided\n" | "provided\n" | ||||
" \"is_final\" : true|false (boolean) Whether the " | " \"is_final\" : true|false (boolean) Whether the input " | ||||
"input is finalized\n" | "is finalized\n" | ||||
" \"missing\" : { (json object, optional) " | " \"missing\" : { (json object, optional) " | ||||
"Things that are missing that are required to complete this " | "Things that are missing that are required to complete this input\n" | ||||
"input\n" | |||||
" \"pubkeys\" : [ (array)\n" | " \"pubkeys\" : [ (array)\n" | ||||
" \"keyid\" (string) Public key ID, " | " \"keyid\" (string) Public key ID, " | ||||
"hash160 of the public key, of a public key whose BIP 32 " | "hash160 of the public key, of a public key whose BIP 32 " | ||||
"derivation path is missing\n" | "derivation path is missing\n" | ||||
" ]\n" | " ]\n" | ||||
" \"signatures\" : [ (array)\n" | " \"signatures\" : [ (array)\n" | ||||
" \"keyid\" (string) Public key ID, " | " \"keyid\" (string) Public key ID, " | ||||
"hash160 of the public key, of a public key whose signature is " | "hash160 of the public key, of a public key whose signature is " | ||||
"missing\n" | "missing\n" | ||||
" ]\n" | " ]\n" | ||||
" \"redeemscript\" : \"hash\" (string) Hash160 of the " | " \"redeemscript\" : \"hash\" (string) Hash160 of the " | ||||
"redeemScript that is missing\n" | "redeemScript that is missing\n" | ||||
" }\n" | " }\n" | ||||
" \"next\" : \"role\" (string) Role of the next " | " \"next\" : \"role\" (string) Role of the next " | ||||
"person that this input needs to go to\n" | "person that this input needs to go to\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
" \"estimated_vsize\" : vsize (numeric) Estimated vsize " | " \"estimated_vsize\" : vsize (numeric) Estimated vsize of " | ||||
"of the final signed transaction\n" | "the final signed transaction\n" | ||||
" \"estimated_feerate\" : feerate (numeric, optional) " | " \"estimated_feerate\" : feerate (numeric, optional) Estimated " | ||||
"Estimated feerate of the final signed transaction. Shown only " | "feerate of the final signed transaction. Shown only if all UTXO " | ||||
"if all UTXO slots in the PSBT have been filled.\n" | "slots in the PSBT have been filled.\n" | ||||
" \"fee\" : fee (numeric, optional) The " | " \"fee\" : fee (numeric, optional) The " | ||||
"transaction fee paid. Shown only if all UTXO slots in the " | "transaction fee paid. Shown only if all UTXO slots in the PSBT " | ||||
"PSBT have been filled.\n" | "have been filled.\n" | ||||
" \"next\" : \"role\" (string) Role of the " | " \"next\" : \"role\" (string) Role of the next " | ||||
"next person that this psbt needs to go to\n" | "person that this psbt needs to go to\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{HelpExampleCli("analyzepsbt", "\"psbt\"")}} | RPCExamples{HelpExampleCli("analyzepsbt", "\"psbt\"")}} | ||||
.ToString()); | .Check(request); | ||||
} | |||||
RPCTypeCheck(request.params, {UniValue::VSTR}); | RPCTypeCheck(request.params, {UniValue::VSTR}); | ||||
// Unserialize the transaction | // Unserialize the transaction | ||||
PartiallySignedTransaction psbtx; | PartiallySignedTransaction psbtx; | ||||
std::string error; | std::string error; | ||||
if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) { | ||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, | ||||
▲ Show 20 Lines • Show All 84 Lines • Show Last 20 Lines |