diff --git a/Makefile.am b/Makefile.am index c50421dfc33..eec498dc0e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -310,6 +310,10 @@ EXTRA_DIST += \ test/util/data/txcreatesignv1.hex \ test/util/data/txcreatesignv1.json \ test/util/data/txcreatesignv2.hex \ + test/util/data/txreplace1.hex \ + test/util/data/txreplacenoinputs.hex \ + test/util/data/txreplaceomittedn.hex \ + test/util/data/txreplacesingleinput.hex \ test/util/rpcauth-test.py CLEANFILES = $(OSX_ZIP) $(BITCOIN_WIN_INSTALLER) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 8fe2881f6f2..320624c419b 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -66,7 +66,9 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman) argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. " "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("replaceable(=N)", "Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); + argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. " + "If N is not provided, the command attempts to opt-in all available inputs for RBF. " + "If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. " "This command requires JSON registers:" "prevtxs=JSON object, " @@ -223,8 +225,8 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal) static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx) { // parse requested index - int64_t inIdx; - if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast(tx.vin.size())) { + int64_t inIdx = -1; + if (strInIdx != "" && (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast(tx.vin.size()))) { throw std::runtime_error("Invalid TX input index '" + strInIdx + "'"); } diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json index c9c64274c62..83b3c430d53 100644 --- a/test/util/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json @@ -163,7 +163,85 @@ "replaceable=0foo"], "return_code": 1, "error_txt": "error: Invalid TX input index", - "description": "Tests the check for an invalid input index with replaceable" + "description": "Tests the check for an invalid string input index with replaceable" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "replaceable=-1"], + "return_code": 1, + "error_txt": "error: Invalid TX input index", + "description": "Tests the check for an invalid negative input index with replaceable" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "replaceable=1"], + "return_code": 1, + "error_txt": "error: Invalid TX input index", + "description": "Tests the check for an invalid positive out-of-bounds input index with replaceable" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "replaceable=0"], + "output_cmp": "txreplacesingleinput.hex", + "description": "Tests that the 'SEQUENCE' value for a single input is set to fdffffff for single input" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "replaceable="], + "output_cmp": "txreplacesingleinput.hex", + "description": "Tests that the 'SEQUENCE' value for a single input is set to fdffffff when N omitted" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18", + "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1", + "replaceable=1"], + "output_cmp": "txreplace1.hex", + "description": "Tests that only the 'SEQUENCE' value of input[1] is set to fdffffff" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", + "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18", + "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1", + "replaceable="], + "output_cmp": "txreplaceomittedn.hex", + "description": "Tests that the 'SEQUENCE' value for each input is set to fdffffff when N omitted" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "replaceable="], + "output_cmp": "txreplacenoinputs.hex", + "description": "Tests behavior when no inputs are provided in the transaction" + }, + { + "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0:abcdef00", + "replaceable="], + "return_code": 1, + "error_txt": "error: invalid TX sequence id 'abcdef00'", + "description": "Try to make invalid input replaceable" }, { "exec": "./bitcoin-tx", "args": diff --git a/test/util/data/txreplace1.hex b/test/util/data/txreplace1.hex new file mode 100644 index 00000000000..7401c4e5dd4 --- /dev/null +++ b/test/util/data/txreplace1.hex @@ -0,0 +1 @@ +02000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fdfffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0000000000 diff --git a/test/util/data/txreplacenoinputs.hex b/test/util/data/txreplacenoinputs.hex new file mode 100644 index 00000000000..22d830eda15 --- /dev/null +++ b/test/util/data/txreplacenoinputs.hex @@ -0,0 +1 @@ +02000000000000000000 diff --git a/test/util/data/txreplaceomittedn.hex b/test/util/data/txreplaceomittedn.hex new file mode 100644 index 00000000000..a687836a099 --- /dev/null +++ b/test/util/data/txreplaceomittedn.hex @@ -0,0 +1 @@ +02000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fdfffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000fdffffff0000000000 diff --git a/test/util/data/txreplacesingleinput.hex b/test/util/data/txreplacesingleinput.hex new file mode 100644 index 00000000000..b3e442795ed --- /dev/null +++ b/test/util/data/txreplacesingleinput.hex @@ -0,0 +1 @@ +02000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000fdffffff0000000000