Skip to content

Commit 58a8e28

Browse files
committed
Refactor transaction creation and transaction funding logic
In preparation for more create transaction and fund transcation RPCs, refactor the transaction creation and funding logic into separate functions.
1 parent e9d86a4 commit 58a8e28

File tree

3 files changed

+166
-154
lines changed

3 files changed

+166
-154
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 70 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -332,80 +332,25 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
332332
return res;
333333
}
334334

335-
static UniValue createrawtransaction(const JSONRPCRequest& request)
335+
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf)
336336
{
337-
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
338-
throw std::runtime_error(
339-
// clang-format off
340-
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n"
341-
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
342-
"Outputs can be addresses or data.\n"
343-
"Returns hex-encoded raw transaction.\n"
344-
"Note that the transaction's inputs are not signed, and\n"
345-
"it is not stored in the wallet or transmitted to the network.\n"
346-
347-
"\nArguments:\n"
348-
"1. \"inputs\" (array, required) A json array of json objects\n"
349-
" [\n"
350-
" {\n"
351-
" \"txid\":\"id\", (string, required) The transaction id\n"
352-
" \"vout\":n, (numeric, required) The output number\n"
353-
" \"sequence\":n (numeric, optional) The sequence number\n"
354-
" } \n"
355-
" ,...\n"
356-
" ]\n"
357-
"2. \"outputs\" (array, required) a json array with outputs (key-value pairs)\n"
358-
" [\n"
359-
" {\n"
360-
" \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n"
361-
" },\n"
362-
" {\n"
363-
" \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n"
364-
" }\n"
365-
" ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
366-
" accepted as second parameter.\n"
367-
" ]\n"
368-
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
369-
"4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
370-
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
371-
"\nResult:\n"
372-
"\"transaction\" (string) hex string of the transaction\n"
373-
374-
"\nExamples:\n"
375-
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")
376-
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
377-
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"")
378-
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
379-
// clang-format on
380-
);
381-
}
382-
383-
RPCTypeCheck(request.params, {
384-
UniValue::VARR,
385-
UniValueType(), // ARR or OBJ, checked later
386-
UniValue::VNUM,
387-
UniValue::VBOOL
388-
}, true
389-
);
390-
if (request.params[0].isNull() || request.params[1].isNull())
337+
if (inputs_in.isNull() || outputs_in.isNull())
391338
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
392339

393-
UniValue inputs = request.params[0].get_array();
394-
const bool outputs_is_obj = request.params[1].isObject();
395-
UniValue outputs = outputs_is_obj ?
396-
request.params[1].get_obj() :
397-
request.params[1].get_array();
340+
UniValue inputs = inputs_in.get_array();
341+
const bool outputs_is_obj = outputs_in.isObject();
342+
UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
398343

399344
CMutableTransaction rawTx;
400345

401-
if (!request.params[2].isNull()) {
402-
int64_t nLockTime = request.params[2].get_int64();
346+
if (!locktime.isNull()) {
347+
int64_t nLockTime = locktime.get_int64();
403348
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
404349
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
405350
rawTx.nLockTime = nLockTime;
406351
}
407352

408-
bool rbfOptIn = request.params[3].isTrue();
353+
bool rbfOptIn = rbf.isTrue();
409354

410355
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
411356
const UniValue& input = inputs[idx];
@@ -485,10 +430,71 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
485430
}
486431
}
487432

488-
if (!request.params[3].isNull() && rbfOptIn != SignalsOptInRBF(rawTx)) {
433+
if (!rbf.isNull() && rbfOptIn != SignalsOptInRBF(rawTx)) {
489434
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
490435
}
491436

437+
return rawTx;
438+
}
439+
440+
static UniValue createrawtransaction(const JSONRPCRequest& request)
441+
{
442+
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
443+
throw std::runtime_error(
444+
// clang-format off
445+
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] [{\"address\":amount},{\"data\":\"hex\"},...] ( locktime ) ( replaceable )\n"
446+
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
447+
"Outputs can be addresses or data.\n"
448+
"Returns hex-encoded raw transaction.\n"
449+
"Note that the transaction's inputs are not signed, and\n"
450+
"it is not stored in the wallet or transmitted to the network.\n"
451+
452+
"\nArguments:\n"
453+
"1. \"inputs\" (array, required) A json array of json objects\n"
454+
" [\n"
455+
" {\n"
456+
" \"txid\":\"id\", (string, required) The transaction id\n"
457+
" \"vout\":n, (numeric, required) The output number\n"
458+
" \"sequence\":n (numeric, optional) The sequence number\n"
459+
" } \n"
460+
" ,...\n"
461+
" ]\n"
462+
"2. \"outputs\" (array, required) a json array with outputs (key-value pairs)\n"
463+
" [\n"
464+
" {\n"
465+
" \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n"
466+
" },\n"
467+
" {\n"
468+
" \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n"
469+
" }\n"
470+
" ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
471+
" accepted as second parameter.\n"
472+
" ]\n"
473+
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
474+
"4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
475+
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
476+
"\nResult:\n"
477+
"\"transaction\" (string) hex string of the transaction\n"
478+
479+
"\nExamples:\n"
480+
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")
481+
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
482+
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"")
483+
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
484+
// clang-format on
485+
);
486+
}
487+
488+
RPCTypeCheck(request.params, {
489+
UniValue::VARR,
490+
UniValueType(), // ARR or OBJ, checked later
491+
UniValue::VNUM,
492+
UniValue::VBOOL
493+
}, true
494+
);
495+
496+
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]);
497+
492498
return EncodeHexTx(rawTx);
493499
}
494500

src/rpc/rawtransaction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ class UniValue;
1212
/** Sign a transaction with the given keystore and previous transactions */
1313
UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType);
1414

15+
/** Create a transaction from univalue parameters */
16+
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf);
17+
1518
#endif // BITCOIN_RPC_RAWTRANSACTION_H

0 commit comments

Comments
 (0)