Skip to content

Commit b0e5fbf

Browse files
committed
Merge bitcoin#22156: Allow tr() import only when Taproot is active
fbf485c Allow tr() import only when Taproot is active (Andrew Chow) Pull request description: To avoid issues around fund loss, only allow descriptor wallets to import `tr()` descriptors after taproot has activated. ACKs for top commit: sipa: utACK fbf485c fjahr: Code review ACK fbf485c laanwj: Code review ACK fbf485c prayank23: utACK bitcoin@fbf485c Tree-SHA512: 83c43376515eea523dbc89bc5a0fde53e54aec492e49a40c2a33d80fc94aac459e232ae07b024b4bd75b58078c8d090bc7a2d69541c5d3d4834d2f4cfc9c8208
2 parents 6f3fbc0 + fbf485c commit b0e5fbf

File tree

4 files changed

+45
-2
lines changed

4 files changed

+45
-2
lines changed

src/interfaces/chain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,9 @@ class Chain
277277
//! to be prepared to handle this by ignoring notifications about unknown
278278
//! removed transactions and already added new transactions.
279279
virtual void requestMempoolTransactions(Notifications& notifications) = 0;
280+
281+
//! Check if Taproot has activated
282+
virtual bool isTaprootActive() const = 0;
280283
};
281284

282285
//! Interface to let node manage chain clients (wallets, or maybe tools for

src/node/interfaces.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,12 @@ class ChainImpl : public Chain
679679
notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
680680
}
681681
}
682+
bool isTaprootActive() const override
683+
{
684+
LOCK(::cs_main);
685+
const CBlockIndex* tip = Assert(m_node.chainman)->ActiveChain().Tip();
686+
return VersionBitsState(tip, Params().GetConsensus(), Consensus::DEPLOYMENT_TAPROOT, versionbitscache) == ThresholdState::ACTIVE;
687+
}
682688
NodeContext& m_node;
683689
};
684690
} // namespace

src/wallet/rpcdump.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,6 +1530,18 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
15301530
}
15311531
}
15321532

1533+
// Taproot descriptors cannot be imported if Taproot is not yet active.
1534+
// Check if this is a Taproot descriptor
1535+
CTxDestination dest;
1536+
ExtractDestination(scripts[0], dest);
1537+
if (std::holds_alternative<WitnessV1Taproot>(dest)) {
1538+
// Check if Taproot is active
1539+
if (!wallet.chain().isTaprootActive()) {
1540+
// Taproot is not active, raise an error
1541+
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import tr() descriptor when Taproot is not active");
1542+
}
1543+
}
1544+
15331545
// If private keys are enabled, check some things.
15341546
if (!wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
15351547
if (keys.keys.empty()) {

test/functional/wallet_taproot.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ class WalletTaprootTest(BitcoinTestFramework):
172172
"""Test generation and spending of P2TR address outputs."""
173173

174174
def set_test_params(self):
175-
self.num_nodes = 2
175+
self.num_nodes = 3
176176
self.setup_clean_chain = True
177-
self.extra_args = [['-keypool=100'], ['-keypool=100']]
177+
self.extra_args = [['-keypool=100'], ['-keypool=100'], ["-vbparams=taproot:1:1"]]
178178
self.supports_cli = False
179179

180180
def skip_test_if_missing_module(self):
@@ -230,12 +230,34 @@ def do_test_addr(self, comment, pattern, privmap, treefn, keys):
230230
addr_r = self.make_addr(treefn, keys, i)
231231
assert_equal(addr_g, addr_r)
232232

233+
# tr descriptors cannot be imported when Taproot is not active
234+
result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
235+
assert(result[0]["success"])
236+
result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
237+
assert(not result[0]["success"])
238+
assert_equal(result[0]["error"]["code"], -4)
239+
assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
240+
result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
241+
assert(result[0]["success"])
242+
result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
243+
assert(not result[0]["success"])
244+
assert_equal(result[0]["error"]["code"], -4)
245+
assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
246+
233247
def do_test(self, comment, pattern, privmap, treefn, nkeys):
234248
keys = self.rand_keys(nkeys)
235249
self.do_test_addr(comment, pattern, privmap, treefn, keys)
236250

237251
def run_test(self):
238252
self.log.info("Creating wallets...")
253+
self.nodes[0].createwallet(wallet_name="privs_tr_enabled", descriptors=True, blank=True)
254+
self.privs_tr_enabled = self.nodes[0].get_wallet_rpc("privs_tr_enabled")
255+
self.nodes[2].createwallet(wallet_name="privs_tr_disabled", descriptors=True, blank=True)
256+
self.privs_tr_disabled=self.nodes[2].get_wallet_rpc("privs_tr_disabled")
257+
self.nodes[0].createwallet(wallet_name="pubs_tr_enabled", descriptors=True, blank=True, disable_private_keys=True)
258+
self.pubs_tr_enabled = self.nodes[0].get_wallet_rpc("pubs_tr_enabled")
259+
self.nodes[2].createwallet(wallet_name="pubs_tr_disabled", descriptors=True, blank=True, disable_private_keys=True)
260+
self.pubs_tr_disabled=self.nodes[2].get_wallet_rpc("pubs_tr_disabled")
239261
self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
240262
self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen")
241263

0 commit comments

Comments
 (0)