Skip to content

Commit ffaac6e

Browse files
committed
Merge #16378: The ultimate send RPC
92326d8 [rpc] add send method (Sjors Provoost) 2c2a144 [rpc] add snake case aliases for transaction methods (Sjors Provoost) 1bc8d0f [rpc] walletcreatefundedpsbt: allow inputs to be null (Sjors Provoost) Pull request description: `walletcreatefundedpsbt` has some interesting features that `sendtoaddress` and `sendmany` don't have: * manual coin selection * outputting a PSBT (it was controversial to add this, see #18201) * create a transaction without adding to wallet (which leads to broadcasting, unless `-walletbroadcast=0`) At the same time `walletcreatefundedpsbt` can't broadcast a transaction, which is inconvenient for simple use cases. This PR introduces a new `send` RPC method which creates a PSBT, signs it if possible and adds it to the wallet by default. If it can't sign all inputs, it outputs a PSBT. If `add_to_wallet` is set to `false` it will return the transaction in both PSBT and hex format. Because it uses a PSBT internally, it will much easier to add hardware wallet support to this method (see #16546). For `bitcoin-cli` users, it tries to keep the simplest use case easy to use: ```sh bitcoin-cli -regtest send '{"ADDRESS": 0.1}' 1 sat/b ``` This paves the way for deprecating `sendtoaddress` and `sendmany` though there's no rush. The only missing feature compared to these older methods is adding labels to a destination address. Depends on: - [x] #16377 (`[rpc] don't automatically append inputs in walletcreatefundedpsbt`) - [x] #11413 (`[wallet] [rpc] sendtoaddress/sendmany: Add explicit feerate option`) - [x] #18244 (`[rpc] have lockUnspents also lock manually selected coins`) ACKs for top commit: meshcollider: Light re-utACK 92326d8 achow101: ACK 92326d8 Reviewed code and test, ran tests. kallewoof: utACK 92326d8 Tree-SHA512: 7552ef1b193d4c06e381c44932fdb0d54f64383e4c7d6b988f49d059c7d4bba45ce6aa7813e03df86360ad9dad6f3010eb76ee7da480551742d5fd98c2251c0f
2 parents 06dbbe7 + 92326d8 commit ffaac6e

File tree

8 files changed

+568
-18
lines changed

8 files changed

+568
-18
lines changed

doc/release-notes-16378.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
RPC
2+
---
3+
- A new `send` RPC with similar syntax to `walletcreatefundedpsbt`, including
4+
support for coin selection and a custom fee rate. Using the new `send` method
5+
is encouraged: `sendmany` and `sendtoaddress` may be deprecated in a future release.

src/rpc/client.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
125125
{ "gettxoutproof", 0, "txids" },
126126
{ "lockunspent", 0, "unlock" },
127127
{ "lockunspent", 1, "transactions" },
128+
{ "send", 0, "outputs" },
129+
{ "send", 1, "conf_target" },
130+
{ "send", 3, "options" },
128131
{ "importprivkey", 2, "rescan" },
129132
{ "importaddress", 2, "rescan" },
130133
{ "importaddress", 3, "p2sh" },

src/rpc/rawtransaction_util.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@
2121

2222
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
2323
{
24-
if (inputs_in.isNull() || outputs_in.isNull())
25-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
24+
if (outputs_in.isNull())
25+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
26+
27+
UniValue inputs;
28+
if (inputs_in.isNull())
29+
inputs = UniValue::VARR;
30+
else
31+
inputs = inputs_in.get_array();
2632

27-
UniValue inputs = inputs_in.get_array();
2833
const bool outputs_is_obj = outputs_in.isObject();
2934
UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
3035

src/wallet/rpcwallet.cpp

Lines changed: 208 additions & 14 deletions
Large diffs are not rendered by default.

test/functional/rpc_fundrawtransaction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ def test_invalid_change_address(self):
224224
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
225225
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
226226

227-
assert_raises_rpc_error(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})
227+
assert_raises_rpc_error(-5, "Change address must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})
228228

229229
def test_valid_change_address(self):
230230
self.log.info("Test fundrawtxn with a provided change address")

test/functional/rpc_psbt.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ def run_test(self):
9494
psbtx1 = self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():90}, 0, {"add_inputs": True})['psbt']
9595
assert_equal(len(self.nodes[0].decodepsbt(psbtx1)['tx']['vin']), 2)
9696

97+
# Inputs argument can be null
98+
self.nodes[0].walletcreatefundedpsbt(None, {self.nodes[2].getnewaddress():10})
99+
97100
# Node 1 should not be able to add anything to it but still return the psbtx same as before
98101
psbtx = self.nodes[1].walletprocesspsbt(psbtx1)['psbt']
99102
assert_equal(psbtx1, psbtx)

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@
225225
'rpc_estimatefee.py',
226226
'rpc_getblockstats.py',
227227
'wallet_create_tx.py',
228+
'wallet_send.py',
228229
'p2p_fingerprint.py',
229230
'feature_uacomment.py',
230231
'wallet_coinbase_category.py',

test/functional/wallet_send.py

Lines changed: 339 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)