mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-06 08:10:37 +01:00
rpc: bumpfee signer support
This commit is contained in:
parent
304ece9945
commit
7e02a33297
3 changed files with 42 additions and 3 deletions
|
@ -239,7 +239,22 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
|
||||||
|
|
||||||
bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {
|
bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {
|
||||||
LOCK(wallet.cs_wallet);
|
LOCK(wallet.cs_wallet);
|
||||||
|
|
||||||
|
if (wallet.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
|
||||||
|
// Make a blank psbt
|
||||||
|
PartiallySignedTransaction psbtx(mtx);
|
||||||
|
|
||||||
|
// First fill transaction with our data without signing,
|
||||||
|
// so external signers are not asked to sign more than once.
|
||||||
|
bool complete;
|
||||||
|
wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */);
|
||||||
|
const TransactionError err = wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true /* sign */, false /* bip32derivs */);
|
||||||
|
if (err != TransactionError::OK) return false;
|
||||||
|
complete = FinalizeAndExtractPSBT(psbtx, mtx);
|
||||||
|
return complete;
|
||||||
|
} else {
|
||||||
return wallet.SignTransaction(mtx);
|
return wallet.SignTransaction(mtx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid)
|
Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid)
|
||||||
|
|
|
@ -1010,7 +1010,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
|
||||||
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
|
||||||
if (!pwallet) return NullUniValue;
|
if (!pwallet) return NullUniValue;
|
||||||
|
|
||||||
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
|
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER) && !want_psbt) {
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
|
throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,6 +1088,9 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
|
||||||
// For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction.
|
// For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction.
|
||||||
if (!want_psbt) {
|
if (!want_psbt) {
|
||||||
if (!feebumper::SignTransaction(*pwallet, mtx)) {
|
if (!feebumper::SignTransaction(*pwallet, mtx)) {
|
||||||
|
if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction incomplete. Try psbtbumpfee instead.");
|
||||||
|
}
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
|
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import platform
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
|
assert_greater_than,
|
||||||
assert_raises_rpc_error,
|
assert_raises_rpc_error,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -150,7 +151,7 @@ class WalletSignerTest(BitcoinTestFramework):
|
||||||
assert_equal(result[1], {'success': True})
|
assert_equal(result[1], {'success': True})
|
||||||
assert_equal(mock_wallet.getwalletinfo()["txcount"], 1)
|
assert_equal(mock_wallet.getwalletinfo()["txcount"], 1)
|
||||||
dest = self.nodes[0].getnewaddress(address_type='bech32')
|
dest = self.nodes[0].getnewaddress(address_type='bech32')
|
||||||
mock_psbt = mock_wallet.walletcreatefundedpsbt([], {dest:0.5}, 0, {}, True)['psbt']
|
mock_psbt = mock_wallet.walletcreatefundedpsbt([], {dest:0.5}, 0, {'replaceable': True}, True)['psbt']
|
||||||
mock_psbt_signed = mock_wallet.walletprocesspsbt(psbt=mock_psbt, sign=True, sighashtype="ALL", bip32derivs=True)
|
mock_psbt_signed = mock_wallet.walletprocesspsbt(psbt=mock_psbt, sign=True, sighashtype="ALL", bip32derivs=True)
|
||||||
mock_psbt_final = mock_wallet.finalizepsbt(mock_psbt_signed["psbt"])
|
mock_psbt_final = mock_wallet.finalizepsbt(mock_psbt_signed["psbt"])
|
||||||
mock_tx = mock_psbt_final["hex"]
|
mock_tx = mock_psbt_final["hex"]
|
||||||
|
@ -190,6 +191,7 @@ class WalletSignerTest(BitcoinTestFramework):
|
||||||
|
|
||||||
self.log.info('Test send using hww1')
|
self.log.info('Test send using hww1')
|
||||||
|
|
||||||
|
# Don't broadcast transaction yet so the RPC returns the raw hex
|
||||||
res = hww.send(outputs={dest:0.5},options={"add_to_wallet": False})
|
res = hww.send(outputs={dest:0.5},options={"add_to_wallet": False})
|
||||||
assert(res["complete"])
|
assert(res["complete"])
|
||||||
assert_equal(res["hex"], mock_tx)
|
assert_equal(res["hex"], mock_tx)
|
||||||
|
@ -199,6 +201,25 @@ class WalletSignerTest(BitcoinTestFramework):
|
||||||
res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()],options={"add_to_wallet": False})
|
res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()],options={"add_to_wallet": False})
|
||||||
assert(res["complete"])
|
assert(res["complete"])
|
||||||
assert_equal(res["hex"], mock_tx)
|
assert_equal(res["hex"], mock_tx)
|
||||||
|
# Broadcast transaction so we can bump the fee
|
||||||
|
hww.sendrawtransaction(res["hex"])
|
||||||
|
|
||||||
|
self.log.info('Prepare fee bumped mock PSBT')
|
||||||
|
|
||||||
|
# Now that the transaction is broadcast, bump fee in mock wallet:
|
||||||
|
orig_tx_id = res["txid"]
|
||||||
|
mock_psbt_bumped = mock_wallet.psbtbumpfee(orig_tx_id)["psbt"]
|
||||||
|
mock_psbt_bumped_signed = mock_wallet.walletprocesspsbt(psbt=mock_psbt_bumped, sign=True, sighashtype="ALL", bip32derivs=True)
|
||||||
|
|
||||||
|
with open(os.path.join(self.nodes[1].cwd, "mock_psbt"), "w", encoding="utf8") as f:
|
||||||
|
f.write(mock_psbt_bumped_signed["psbt"])
|
||||||
|
|
||||||
|
self.log.info('Test bumpfee using hww1')
|
||||||
|
|
||||||
|
# Bump fee
|
||||||
|
res = hww.bumpfee(orig_tx_id)
|
||||||
|
assert_greater_than(res["fee"], res["origfee"])
|
||||||
|
assert_equal(res["errors"], [])
|
||||||
|
|
||||||
# # Handle error thrown by script
|
# # Handle error thrown by script
|
||||||
# self.set_mock_result(self.nodes[4], "2")
|
# self.set_mock_result(self.nodes[4], "2")
|
||||||
|
|
Loading…
Add table
Reference in a new issue