mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 10:43:19 -03:00
allow send rpc take external inputs and solving data
This commit is contained in:
parent
e39b5a5e7a
commit
928af61cdb
2 changed files with 65 additions and 1 deletions
|
@ -4286,6 +4286,26 @@ static RPCHelpMan send()
|
|||
},
|
||||
{"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
|
||||
"Allows this transaction to be replaced by a transaction with higher fees"},
|
||||
{"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
|
||||
"Used for fee estimation during coin selection.",
|
||||
{
|
||||
{"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Public keys involved in this transaction.",
|
||||
{
|
||||
{"pubkey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A public key"},
|
||||
},
|
||||
},
|
||||
{"scripts", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Scripts involved in this transaction.",
|
||||
{
|
||||
{"script", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A script"},
|
||||
},
|
||||
},
|
||||
{"descriptors", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Descriptors that provide solving data for this transaction.",
|
||||
{
|
||||
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A descriptor"},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"options"},
|
||||
},
|
||||
|
|
|
@ -9,6 +9,7 @@ from itertools import product
|
|||
|
||||
from test_framework.authproxy import JSONRPCException
|
||||
from test_framework.descriptors import descsum_create
|
||||
from test_framework.key import ECKey
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
|
@ -16,6 +17,7 @@ from test_framework.util import (
|
|||
assert_greater_than,
|
||||
assert_raises_rpc_error,
|
||||
)
|
||||
from test_framework.wallet_util import bytes_to_wif
|
||||
|
||||
class WalletSendTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
|
@ -35,7 +37,7 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
conf_target=None, estimate_mode=None, fee_rate=None, add_to_wallet=None, psbt=None,
|
||||
inputs=None, add_inputs=None, include_unsafe=None, change_address=None, change_position=None, change_type=None,
|
||||
include_watching=None, locktime=None, lock_unspents=None, replaceable=None, subtract_fee_from_outputs=None,
|
||||
expect_error=None):
|
||||
expect_error=None, solving_data=None):
|
||||
assert (amount is None) != (data is None)
|
||||
|
||||
from_balance_before = from_wallet.getbalances()["mine"]["trusted"]
|
||||
|
@ -94,6 +96,8 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
options["replaceable"] = replaceable
|
||||
if subtract_fee_from_outputs is not None:
|
||||
options["subtract_fee_from_outputs"] = subtract_fee_from_outputs
|
||||
if solving_data is not None:
|
||||
options["solving_data"] = solving_data
|
||||
|
||||
if len(options.keys()) == 0:
|
||||
options = None
|
||||
|
@ -476,6 +480,46 @@ class WalletSendTest(BitcoinTestFramework):
|
|||
res = self.test_send(from_wallet=w5, to_wallet=w0, amount=1, include_unsafe=True)
|
||||
assert res["complete"]
|
||||
|
||||
self.log.info("External outputs")
|
||||
eckey = ECKey()
|
||||
eckey.generate()
|
||||
privkey = bytes_to_wif(eckey.get_bytes())
|
||||
|
||||
self.nodes[1].createwallet("extsend")
|
||||
ext_wallet = self.nodes[1].get_wallet_rpc("extsend")
|
||||
self.nodes[1].createwallet("extfund")
|
||||
ext_fund = self.nodes[1].get_wallet_rpc("extfund")
|
||||
|
||||
# Make a weird but signable script. sh(pkh()) descriptor accomplishes this
|
||||
desc = descsum_create("sh(pkh({}))".format(privkey))
|
||||
if self.options.descriptors:
|
||||
res = ext_fund.importdescriptors([{"desc": desc, "timestamp": "now"}])
|
||||
else:
|
||||
res = ext_fund.importmulti([{"desc": desc, "timestamp": "now"}])
|
||||
assert res[0]["success"]
|
||||
addr = self.nodes[0].deriveaddresses(desc)[0]
|
||||
addr_info = ext_fund.getaddressinfo(addr)
|
||||
|
||||
self.nodes[0].sendtoaddress(addr, 10)
|
||||
self.nodes[0].sendtoaddress(ext_wallet.getnewaddress(), 10)
|
||||
self.nodes[0].generate(6)
|
||||
ext_utxo = ext_fund.listunspent(addresses=[addr])[0]
|
||||
|
||||
# An external input without solving data should result in an error
|
||||
self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, expect_error=(-4, "Insufficient funds"))
|
||||
|
||||
# But funding should work when the solving data is provided
|
||||
res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, solving_data={"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]})
|
||||
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
||||
signed = ext_fund.walletprocesspsbt(res["psbt"])
|
||||
assert signed["complete"]
|
||||
self.nodes[0].finalizepsbt(signed["psbt"])
|
||||
|
||||
res = self.test_send(from_wallet=ext_wallet, to_wallet=self.nodes[0], amount=15, inputs=[ext_utxo], add_inputs=True, psbt=True, include_watching=True, solving_data={"descriptors": [desc]})
|
||||
signed = ext_wallet.walletprocesspsbt(res["psbt"])
|
||||
signed = ext_fund.walletprocesspsbt(res["psbt"])
|
||||
assert signed["complete"]
|
||||
self.nodes[0].finalizepsbt(signed["psbt"])
|
||||
|
||||
if __name__ == '__main__':
|
||||
WalletSendTest().main()
|
||||
|
|
Loading…
Add table
Reference in a new issue