aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2021-06-04 20:31:04 -0400
committerAndrew Chow <achow101-github@achow101.com>2021-06-10 15:45:47 -0400
commitfbf485c9b2bf1d056bfea77345a15cf56a9cd786 (patch)
tree3b4e510a4e0bfa9871eec7548a2505c70dc7065c
parent346e52afd6d5e317c96fc506bb54cde13e87c8b2 (diff)
downloadbitcoin-fbf485c9b2bf1d056bfea77345a15cf56a9cd786.tar.xz
Allow tr() import only when Taproot is active
To avoid issues around fund loss, only allow descriptor wallets to import tr() descriptors after taproot has activated.
-rw-r--r--src/interfaces/chain.h3
-rw-r--r--src/node/interfaces.cpp6
-rw-r--r--src/wallet/rpcdump.cpp12
-rwxr-xr-xtest/functional/wallet_taproot.py26
4 files changed, 45 insertions, 2 deletions
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 3395741b1b..7cac435e96 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -277,6 +277,9 @@ public:
//! to be prepared to handle this by ignoring notifications about unknown
//! removed transactions and already added new transactions.
virtual void requestMempoolTransactions(Notifications& notifications) = 0;
+
+ //! Check if Taproot has activated
+ virtual bool isTaprootActive() const = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 8befbf5e30..e88594f7d6 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -709,6 +709,12 @@ public:
notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
}
}
+ bool isTaprootActive() const override
+ {
+ LOCK(::cs_main);
+ const CBlockIndex* tip = Assert(m_node.chainman)->ActiveChain().Tip();
+ return VersionBitsState(tip, Params().GetConsensus(), Consensus::DEPLOYMENT_TAPROOT, versionbitscache) == ThresholdState::ACTIVE;
+ }
NodeContext& m_node;
};
} // namespace
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 726b13beac..4e9ba83ead 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1530,6 +1530,18 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
}
}
+ // Taproot descriptors cannot be imported if Taproot is not yet active.
+ // Check if this is a Taproot descriptor
+ CTxDestination dest;
+ ExtractDestination(scripts[0], dest);
+ if (std::holds_alternative<WitnessV1Taproot>(dest)) {
+ // Check if Taproot is active
+ if (!wallet.chain().isTaprootActive()) {
+ // Taproot is not active, raise an error
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import tr() descriptor when Taproot is not active");
+ }
+ }
+
// If private keys are enabled, check some things.
if (!wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (keys.keys.empty()) {
diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py
index 65ca7bdef7..5803c0cf54 100755
--- a/test/functional/wallet_taproot.py
+++ b/test/functional/wallet_taproot.py
@@ -172,9 +172,9 @@ class WalletTaprootTest(BitcoinTestFramework):
"""Test generation and spending of P2TR address outputs."""
def set_test_params(self):
- self.num_nodes = 2
+ self.num_nodes = 3
self.setup_clean_chain = True
- self.extra_args = [['-keypool=100'], ['-keypool=100']]
+ self.extra_args = [['-keypool=100'], ['-keypool=100'], ["-vbparams=taproot:1:1"]]
self.supports_cli = False
def skip_test_if_missing_module(self):
@@ -230,12 +230,34 @@ class WalletTaprootTest(BitcoinTestFramework):
addr_r = self.make_addr(treefn, keys, i)
assert_equal(addr_g, addr_r)
+ # tr descriptors cannot be imported when Taproot is not active
+ result = self.privs_tr_enabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ assert(result[0]["success"])
+ result = self.privs_tr_disabled.importdescriptors([{"desc": desc, "timestamp": "now"}])
+ assert(not result[0]["success"])
+ assert_equal(result[0]["error"]["code"], -4)
+ assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
+ result = self.pubs_tr_enabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
+ assert(result[0]["success"])
+ result = self.pubs_tr_disabled.importdescriptors([{"desc": desc_pub, "timestamp": "now"}])
+ assert(not result[0]["success"])
+ assert_equal(result[0]["error"]["code"], -4)
+ assert_equal(result[0]["error"]["message"], "Cannot import tr() descriptor when Taproot is not active")
+
def do_test(self, comment, pattern, privmap, treefn, nkeys):
keys = self.rand_keys(nkeys)
self.do_test_addr(comment, pattern, privmap, treefn, keys)
def run_test(self):
self.log.info("Creating wallets...")
+ self.nodes[0].createwallet(wallet_name="privs_tr_enabled", descriptors=True, blank=True)
+ self.privs_tr_enabled = self.nodes[0].get_wallet_rpc("privs_tr_enabled")
+ self.nodes[2].createwallet(wallet_name="privs_tr_disabled", descriptors=True, blank=True)
+ self.privs_tr_disabled=self.nodes[2].get_wallet_rpc("privs_tr_disabled")
+ self.nodes[0].createwallet(wallet_name="pubs_tr_enabled", descriptors=True, blank=True, disable_private_keys=True)
+ self.pubs_tr_enabled = self.nodes[0].get_wallet_rpc("pubs_tr_enabled")
+ self.nodes[2].createwallet(wallet_name="pubs_tr_disabled", descriptors=True, blank=True, disable_private_keys=True)
+ self.pubs_tr_disabled=self.nodes[2].get_wallet_rpc("pubs_tr_disabled")
self.nodes[0].createwallet(wallet_name="addr_gen", descriptors=True, disable_private_keys=True, blank=True)
self.addr_gen = self.nodes[0].get_wallet_rpc("addr_gen")