diff --git a/TAPROOT.md b/TAPROOT.md new file mode 100644 index 000000000000..5978b0fd2a0f --- /dev/null +++ b/TAPROOT.md @@ -0,0 +1,243 @@ +# Taproot on Dash Core: working notes for `bp-taproot` + +Agent notes. This file does not belong on the final branch; drop the commit +before opening the PR. + +## Goal and scope + +A working mockup of BIP 340/341/342 on Dash without any SegWit structure: +taproot addresses, `tr()` / `rawtr()` / `multi_a()` descriptors, raw-key and +wallet signing (key path and script path), PSBT taproot fields, Qt address +type dropdown. No witness serialization, no "fake scripts", no DIP0143/BIP143. + +Upstream PR candidates are listed in `bp-taproot.txt` (repo root). Backports +are done only with `git cherry-pick -m1 `; the upstream merge objects +are reachable via the `bitcoin` remote, and `~/bitcoin` is a checkout for +reference. + +## Design decisions (confirmed by the user) + +- **Spend encoding.** The BIP 341 "witness stack" is the sequence of pushes in + the input `scriptSig`. `VerifyScript` dispatches on + `CScript::IsPayToTaproot()` (`OP_1 <32 bytes>`) before any legacy + evaluation: `ParseTaprootStack` -> `VerifyTaprootProgram` -> + `ExecuteTapscript`. Push-only, no 520-byte element cap, no MINIMALDATA on + the stack items. A node without `SCRIPT_VERIFY_TAPROOT` evaluates the + output as a plain script and rejects pushes over 520 bytes, so activation + is a hard fork for it. Activation gate is `DEPLOYMENT_TAPROOT` (bit 15, + EHF, own deployment since 2026-11-10 because v24 had already shipped). +- **Sighash.** `SignatureHashSchnorr` writes `int32(nVersion | nType << 16)`, + `nLockTime`, and for `nVersion >= SPECIAL_VERSION && nType != + TRANSACTION_NORMAL` the serialized `vExtraPayload`, exactly like the legacy + `SignatureHash`. Python `TaprootSignatureMsg` mirrors it (length assert + includes `payload_size`). Vectors pinned in + `script_tests/bip341_dash_special_tx_sighash`. +- **OP_SUCCESSx.** BIP 342 set minus the DIP0020 opcodes (`OP_CAT`, + `OP_SPLIT`, `OP_NUM2BIN`, `OP_BIN2NUM`, `OP_AND`, `OP_OR`, `OP_XOR`, + `OP_DIV`, `OP_MOD`, `OP_CHECKDATASIG(VERIFY)`) and minus `OP_CHECKSIGADD`, + which is `0xbc` in Dash (0xba/0xbb are CHECKDATASIG). `MAX_OPCODE` stays + `OP_CHECKDATASIGVERIFY`, like upstream keeps it at `OP_NOP10`: asm parsing + of `OP_CHECKSIGADD` is an error (`script_parse_tests` checks this), and + `decodescript` names the opcode explicitly in its wrap check. +- **Limits.** `MAX_SCRIPT_SIZE` (10 kB consensus), `MAX_STANDARD_SCRIPTSIG_SIZE` + (1650 B policy) and the DIP0001 100 kB tx size all apply to taproot spends. + User: these would be lifted for BIP143, not for taproot. Consequences: + `feature_taproot` big multisig is 800-of-800 (`BIG_MULTISIG_N`), the + wallet `multi_a` case uses `MAX_STANDARD_MULTI_A_KEYS = 40`. +- **Policy.** `IsTaprootStandard` (no annex; tapscript stack items <= 80 B) + wired in `MemPoolAccept::PreChecks` after `AreInputsStandard(..., taproot_active)` + with reason `bad-taproot-nonstandard`. DISCOURAGE_* flags are in + `STANDARD_SCRIPT_VERIFY_FLAGS`. +- **Addresses.** bech32m with a dedicated L1 HRP in `CChainParams::bech32_hrp` + / `Bech32HRP()`: `dc` mainnet, `tdc` testnet, devnet and regtest (two HRPs, + same as Platform's `dash`/`tdash`). Decoding branch sits before the Platform + branch in `key_io.cpp`. Python: `output_key_to_p2tr(key, main=False)`. +- **Destination type.** `TaprootDestination : XOnlyPubKey` (renamed from + upstream `WitnessV1Taproot`, own refactor commit). `getaddressinfo` / + `validateaddress` report `isscript: true` and `output_key`. +- **Output type.** `OutputType::TAPROOT` ("taproot"). Wallet keeps one active + `ScriptPubKeyMan` per `OutputType` (`std::map` + for external and internal). On disk LEGACY keeps the bare + `activeexternalspk` / `activeinternalspk` record; other types append a + type byte (`std::make_pair(key, type)`); the loader reads the trailing byte + if present. `getnewaddress` / `getrawchangeaddress` take `address_type` + ("legacy" default via `CWallet::m_default_address_type`, or "taproot"). + Change type: legacy if the wallet can produce it, else the first type with + an internal manager (`TransactionChangeType` in `wallet/spend.cpp`). +- **Signing.** Dummy Schnorr signature is 65 bytes (wallet signs + `SIGHASH_ALL`; no `SIGHASH_DEFAULT` RPC default switch). `tr()` import is + gated on `isTaprootActive()`. +- **Qt.** Receive tab dropdown "Legacy" / "Taproot", the latter only when the + descriptor wallet has an active TAPROOT external manager + (`interfaces::Wallet::taprootEnabled()`). + +## Known gaps (document in the PR, not bugs to fix now) + +- Fee estimation for script-path spends assumes the key path whenever the + internal key is known to the signing provider, even without its private + key (e.g. a watch-only `tr(XPUB, multi_a(...))`); tests use higher fee + rates there. Outputs with the NUMS internal key H are sized correctly + since the dummy signer refuses a key path for H and unknown keys. +- Address index does not index P2TR. `CAddressIndexKey` and friends store a + `uint160`; a 32-byte output key needs a new key layout (or a uint256 + field) and therefore a reindex for `-addressindex` users. Decision pending. +- `MAX_STANDARD_SCRIPTSIG_SIZE` bounds tapscript spends; raising it for + taproot inputs is a follow-up. +- Miniscript in tapscript: Dash has no miniscript descriptors at all + (bitcoin#24148 was reverted because it was wsh-only, #24149 is partial). + Bringing it needs #24148 adapted to tr()-only, the rest of #24149, then + #27255 (MiniTapscript, ~1.4k lines; prerequisites #28244, #26567, #27997, + #28067, #28587 are already in Dash). Decision pending. +- Not taken: upstream `gen_test_vectors`, `SIGHASH_DEFAULT` RPC defaults + (#22514), MiniWallet P2TR (#23371). + +## Done after the first review round (2026-10-20) + +- bitcoin#22364: descriptor wallets created where taproot is active derive + `tr(xpub/86h/coin'h/0h/{0,1}/*)` next to `pkh()` (BIP86 purpose, + `BIP32_PURPOSE_TAPROOT` in `hdchain.h`); no tr() for CoinJoin. Gated on + `chain().isTaprootActive()` like the import path, so wallets created earlier + need `importdescriptors`. +- `-addresstype` (legacy|taproot) and `-changetype`; `DEFAULT_ADDRESS_TYPE` + in `wallet.h`. +- bitcoin#23578: external signers may return tr() descriptors; activated + when taproot is active (`IsDefaultPurposeDescriptor` accepts 44' and 86'). +- bitcoin#23789: change type follows the payment outputs + (`TransactionChangeType` in `wallet/spend.cpp`, static). Dash difference: + the "legacy default means legacy change" shortcut only applies when the + wallet has a legacy internal manager, so tr()-only wallets keep working. +- bitcoin#30048: `XOnlyPubKey::NUMS_H`; Dash commit on top fixes the dummy + signer for fee estimation. +- `wallet_taproot.py` covers all of the above; `wallet_signer.py` activates + taproot through `-vbparams` on both nodes. + +## Test activation without masternodes + +Active node: `-vbparams=taproot:0:999999999999:0:10:8:6:5:0` (trailing `0` means +`useEHF=false`), then mine through the window. Inactive node: +`-vbparams=taproot:1:1`; it cannot follow an active chain (hard fork), so +`feature_taproot` lets it mine its own coins. All wallet tests run as +`--descriptors` (no BDB on this machine). + +## Branch state (2026-11-10, after the rebase onto develop) + +Rebased onto `origin/develop` at 6271b740e9 (dash#8067). 62 commits plus two +temporary ones on top (dash#8080, the `test_dash-qt` fix for +`SharedMnWizardTests::signedSessionReservation`; drop them together with the +notes commit once #8080 is merged). No `fixup!` commits remain: every fixup +was squashed into its target, the early "disable ALL spenders"/revert pair +was dropped, and the two notes commits became one. + +How the rebase was done (two passes, so each could be verified): + +1. Squash on the old base, then `git diff` against the old head: empty. +2. Rebase onto develop. Conflicts, all in tests: `address.py` imports, + `descriptor_tests.cpp` flag constants (develop added `MIXED_PUBKEYS = 32` + from bitcoin#23171; `XONLY_KEYS = 64` and `MISSING_PRIVKEYS = 128` kept as + upstream), `wallet_signer.py` extra_args, `crypto/secp256k1.py` (develop's + `lru_cache` plus the new `test_H`), `rpc_decodescript.json` HRP. + One code adaptation: `CKey::SignSchnorr` passes `UCharCast(begin())` + because develop moved `CKey` to `std::byte` storage (bitcoin#29133); + squashed into the bitcoin#21365 commit. Second: the generated + `*.json.h` test headers are `std::string` now (bitcoin#28168), so the two + `bip341_wallet_vectors` readers use upstream's `Assert(tests.read(...))` + form (`read_json()` does not fit, the vectors are an object, not an + array); squashed into the bitcoin#23394 commit. Stale generated headers in a build tree must be + deleted by hand (`find src -name '*.json.h' -delete`), the make rule does + not depend on the Makefile. + +Backup refs in this checkout: `bp-taproot-pre-rebase` (old 91-commit head), +`bp-taproot-squashed` (pass 1 on the old base), `bp-taproot-on-4c5c0153` +(first rebase target before develop moved). + +Verification on the old develop tip (4c5c015350): build with zero warnings, +lint, `test_dash` 172 suites, and 29 functional tests (feature_taproot, +wallet_taproot, wallet_signer, rpc_psbt, rpc_decodescript, feature_block, +the descriptor-wallet set). `test_dash-qt` crashed in +`SharedMnWizardTests::signedSessionReservation` with heap corruption; that is +develop's issue dash#8075 (stale message-box timers from `AddressBookTests` +under the GLib event dispatcher), fixed by dash#8080, which is why its two +commits ride on top for now. Results on the current tip: see the end of the +file. + +This checkout had been configured for a TSAN benchmark build (the CI +`linux64_tsan` line) when the rebase started. It is back on the regular +debug configuration; the TSAN line is in the agent's scratchpad. + +## Workflow rules from the user (keep following) + +- Backports only via `git cherry-pick -m1`; Dash adaptations as own non-fixup + commits when non-trivial, otherwise `fixup!` of the backport. No uber + commits. Never squash while something is still failing. +- No big rebases unless a full recompile is coming anyway. +- Resources: at most 16 compile jobs and `-j15` for functional tests, and + less when others are building (16 GB RAM; check `uptime`, `free -g` and + `df -h /home` first). `make -j12` is the safe default when idle. +- Few parallel agents; do the work directly. +- Always full `make -jN`, never individual targets. + +## Disk-full lessons (this VM) + +`/home` (btrfs, 120 GB) fills up: `~/bc` is a mainnet datadir (~55 GB), there +are four checkouts with debug builds, ccache caps at 5 GB. One debug build +holds ~4.2 GB of linked binaries (test_dash ~1 GB, dash-qt, test_dash-qt, +fuzz, bench_dash, dashd) plus ~0.7 GB archives that `ar` rewrites through a +temporary copy. A full relink needs ~4 GB free plus headroom; 3.6 GB is not +enough. + +When a build dies with "No space left on device" in `ar`, the archive it was +writing is truncated even if its size looks normal, and make then treats it +as up to date: the next build fails with `ld: error: lib*.a: file too short` +or undefined references. Delete the archives named in the failing run +(`libbitcoin_node.a`, `libbitcoin_zmq.a`, `libtest_util.a`, +`libbitcoin_wallet_tool.a` happened) and rerun make. Only this checkout's +own stale binaries are mine to delete; never touch `~/bc`, ccache or the +other checkouts without asking. + +`make check` regenerates `clientversion.o` whenever HEAD changes and relinks +every binary; do not start functional tests while it runs or they find no +`dashd`. + +## Useful commands + +```bash +./src/test/test_dash --run_test=script_tests,script_standard_tests,descriptor_tests,key_io_tests,key_tests,transaction_tests,psbt_wallet_tests,wallet_tests,walletload_tests +test/functional/test_runner.py -j4 "feature_taproot.py --descriptors" "wallet_taproot.py --descriptors" "rpc_psbt.py --descriptors" rpc_decodescript.py +test/lint/all-lint.py +``` + +## DIP-0143 (dashpay/dips#149) versus the taproot sighash + +They are different algorithms for different signature types. DIP-0143 is +the Dash analogue of BIP143: a digest for ECDSA signatures in legacy +scripts (P2PKH/P2SH), signalled by a `SIGHASH_DIP0143` flag bit, gated by +`SCRIPT_ENABLE_DIP0143` under an EHF hard fork. The taproot digest on this +branch is BIP341's (Schnorr, key path and tapscript) with the Dash version +word and `vExtraPayload` added, exactly the two Dash additions DIP-0143 +makes. Both share the per-transaction midstate hashes that +`PrecomputedTransactionData` already computes (prevouts, sequences, +outputs; BIP341 additionally amounts and scriptPubKeys), so a DIP-0143 +implementation would reuse that cache and add a `SigVersion` for the legacy +ECDSA path: the taproot work does not replace it and does not need it. + +## Verification on develop 6271b740e9 (2026-11-10) + +Regular debug build with zero warnings; lint clean (minus the uninstalled +tools); `make check` green including `test_dash-qt` (with dash#8080 on top) +and all 172 `test_dash` suites; the functional set of 29 tests (feature_taproot, +wallet_taproot, wallet_signer, rpc_psbt, rpc_decodescript, feature_block, +feature_csv_activation, mempool_accept, rpc_createmultisig, rpc_misc, +rpc_rawtransaction, rpc_signrawtransactionwithkey, interface_bitcoin_cli, +tool_wallet and the wallet_* descriptor suite) all passed. + +## Own deployment (2026-11-10) + +v24 is released, so taproot moved from `DEPLOYMENT_V24` to its own +`DEPLOYMENT_TAPROOT` (bit 15, `"taproot"` in `getblockchaininfo`, EHF like +v24/evo_shares, same window and thresholds). Mainnet start 2027-05-10 and +testnet/devnet start 2027-03-01 are placeholders for release time; regtest +starts at 0. Masternodes sign its MNHF signal like v24's (no `evo_shares`-style +skip in `ehf_signals.cpp`). Gating sites: `GetBlockScriptFlags` and the +mempool `AreInputsStandard` call in `validation.cpp`, and +`Chain::isTaprootActive()` for the wallet (default `tr()` descriptors, +`importdescriptors`, external signers). Tests use `-vbparams=taproot:...`. diff --git a/ci/dash/test_unittests.sh b/ci/dash/test_unittests.sh index 4ab837c0cdc3..cb8d19270ec3 100755 --- a/ci/dash/test_unittests.sh +++ b/ci/dash/test_unittests.sh @@ -16,6 +16,7 @@ if [ "$RUN_UNIT_TESTS" != "true" ] && [ "$RUN_UNIT_TESTS_SEQUENTIAL" != "true" ] exit 0 fi +export DIR_UNIT_TEST_DATA=${DIR_UNIT_TEST_DATA} export BOOST_TEST_RANDOM="${BOOST_TEST_RANDOM:-1}" export LD_LIBRARY_PATH="$DEPENDS_DIR/$HOST/lib" diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh index a586dbffb8d1..54a938a78613 100755 --- a/ci/test/00_setup_env.sh +++ b/ci/test/00_setup_env.sh @@ -51,7 +51,7 @@ export RUN_STDLIB_PATH_CHECK=${RUN_STDLIB_PATH_CHECK:-false} # By how much to scale the test_runner timeouts (option --timeout-factor). # This is needed because some ci machines have slow CPU or disk, so sanitizers # might be slow or a reindex might be waiting on disk IO. -export TEST_RUNNER_TIMEOUT_FACTOR=${TEST_RUNNER_TIMEOUT_FACTOR:-4} +export TEST_RUNNER_TIMEOUT_FACTOR=${TEST_RUNNER_TIMEOUT_FACTOR:-40} export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false} # Randomize test order. diff --git a/configure.ac b/configure.ac index 92e8f3381e12..5b0a06d05590 100644 --- a/configure.ac +++ b/configure.ac @@ -2064,7 +2064,7 @@ CPPFLAGS="$CPPFLAGS_TEMP" dnl The ECDH module is required by the wallet's Platform key provider dnl (DashPay contact request encryption, wallet/platformkeys.cpp). -ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-ecdh --disable-openssl-tests" +ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-ecdh --disable-openssl-tests --enable-module-schnorrsig" AC_CONFIG_SUBDIRS([src/dashbls src/secp256k1]) AC_OUTPUT diff --git a/doc/bips.md b/doc/bips.md index 88ad35004cb8..b20e32da8fb0 100644 --- a/doc/bips.md +++ b/doc/bips.md @@ -41,6 +41,7 @@ Versions and PRs are relevant to Bitcoin's core if not mentioned other. * [`BIP 159`](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki): The `NODE_NETWORK_LIMITED` service bit is signalled as of **v0.16.0** ([PR 11740](https://github.com/bitcoin/bitcoin/pull/11740)), and such nodes are connected to as of **v0.17.0** ([PR 10387](https://github.com/bitcoin/bitcoin/pull/10387)). * [`BIP 174`](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki): RPCs to operate on Partially Signed Bitcoin Transactions (PSBT) are present as of **v18.0** ([PR 13557](https://github.com/bitcoin/bitcoin/pull/13557)). * [`BIP 324`](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki): The v2 transport protocol specified by BIP324 and the associated `NODE_P2P_V2` service bit are supported as of **v22.0**, but off by default ([PR 28331](https://github.com/bitcoin/bitcoin/pull/28331)). On by default as of **v22.1** ([PR 29347](https://github.com/bitcoin/bitcoin/pull/29347)). +* [`BIP 340`](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) [`341`](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) [`342`](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki): Validation rules for Taproot (including Schnorr signatures and Tapscript leaves) are implemented as of **v0.21.0** ([PR 19953](https://github.com/bitcoin/bitcoin/pull/19953)), without mainnet activation. * [`BIP 380`](https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki) [`381`](https://github.com/bitcoin/bips/blob/master/bip-0381.mediawiki) [`383`](https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki) diff --git a/doc/descriptors.md b/doc/descriptors.md index c3e41b14636d..d55f0bd1cc15 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -33,8 +33,10 @@ Output descriptors currently support: - Pay-to-pubkey scripts (P2PK), through the `pk` function. - Pay-to-pubkey-hash scripts (P2PKH), through the `pkh` function. - Pay-to-script-hash scripts (P2SH), through the `sh` function. +- Pay-to-taproot outputs (P2TR), through the `tr` function. - Multisig scripts, through the `multi` function. - Multisig scripts where the public keys are sorted lexicographically, through the `sortedmulti` function. +- Multisig scripts inside taproot script trees, through the `multi_a` (and `sortedmulti_a`) function. - Any type of supported address through the `addr` function. - Raw hex scripts through the `raw` function. - Public keys (compressed and uncompressed) in hex notation, or BIP32 extended pubkeys with derivation paths. @@ -47,6 +49,8 @@ Output descriptors currently support: - `sortedmulti(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` describes a bare *1-of-2* multisig with keys sorted lexicographically in the resulting redeemScript. - `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1/2)` describes a P2PKH output with child key *1/2* of the specified xpub. - `pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*)` describes a set of P2PKH outputs, but additionally specifies that the specified xpub is a child of a master with fingerprint `d34db33f`, and derived using path `44'/0'/0'`. +- `tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,{pk(fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),pk(e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)})` describes a P2TR output with the `c6...` x-only pubkey as internal key, and two script paths. +- `tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,sortedmulti_a(2,2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc))` describes a P2TR output with the `c6...` x-only pubkey as internal key, and a single `multi_a` script that needs 2 signatures with 2 specified x-only keys, which will be sorted lexicographically. ## Reference @@ -54,13 +58,17 @@ Descriptors consist of several types of expressions. The top level expression is `SCRIPT` expressions: - `pk(KEY)` (anywhere): P2PK output for the given public key. -- `pkh(KEY)` (anywhere): P2PKH output for the given public key (use `addr` if you only know the pubkey hash). +- `pkh(KEY)` (not inside `tr`): P2PKH output for the given public key (use `addr` if you only know the pubkey hash). - `sh(SCRIPT)` (top level only): P2SH embed the argument. - `combo(KEY)` (top level only): an alias for the collection of `pk(KEY)` and `pkh(KEY)`. -- `multi(k,KEY_1,KEY_2,...,KEY_n)` (anywhere): k-of-n multisig script. -- `sortedmulti(k,KEY_1,KEY_2,...,KEY_n)` (anywhere): k-of-n multisig script with keys sorted lexicographically in the resulting script. +- `multi(k,KEY_1,KEY_2,...,KEY_n)` (not inside `tr`): k-of-n multisig script using OP_CHECKMULTISIG. +- `sortedmulti(k,KEY_1,KEY_2,...,KEY_n)` (not inside `tr`): k-of-n multisig script with keys sorted lexicographically in the resulting script. +- `multi_a(k,KEY_1,KEY_2,...,KEY_N)` (only inside `tr`): k-of-n multisig script using OP_CHECKSIG, OP_CHECKSIGADD, and OP_NUMEQUAL. +- `sortedmulti_a(k,KEY_1,KEY_2,...,KEY_N)` (only inside `tr`): similar to `multi_a`, but the (x-only) public keys in it will be sorted lexicographically. +- `tr(KEY)` or `tr(KEY,TREE)` (top level only): P2TR output with the specified key as internal key, and optionally a tree of script paths. - `addr(ADDR)` (top level only): the script which ADDR expands to. - `raw(HEX)` (top level only): the script whose hex encoding is HEX. +- `rawtr(KEY)` (top level only): P2TR output with the specified key as output key. NOTE: while it's possible to use this to construct wallets, it has several downsides, like being unable to prove no hidden script path exists. Use at your own risk. `KEY` expressions: - Optionally, key origin information, consisting of: @@ -70,12 +78,17 @@ Descriptors consist of several types of expressions. The top level expression is - A closing bracket `]` - Followed by the actual key, which is either: - Hex encoded public keys (66 characters starting with `02` or `03`, or 130 characters starting with `04`). + - Inside `tr` and `rawtr`, x-only pubkeys are also permitted (64 hex characters). - [WIF](https://en.bitcoin.it/wiki/Wallet_import_format) encoded private keys may be specified instead of the corresponding public key, with the same meaning. -`xpub` encoded extended public key or `xprv` encoded private key (as defined in [BIP 32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)). - Followed by zero or more `/NUM` unhardened and `/NUM'` hardened BIP32 derivation steps. - Optionally followed by a single `/*` or `/*'` final step to denote all (direct) unhardened or hardened children. - The usage of hardened derivation steps requires providing the private key. +`TREE` expressions: +- any `SCRIPT` expression +- An open brace `{`, a `TREE` expression, a comma `,`, a `TREE` expression, and a closing brace `}` + (Anywhere a `'` suffix is permitted to denote hardened derivation, the suffix `h` can be used instead.) `ADDR` expressions are any type of supported address: diff --git a/doc/release-notes-gui-459.md b/doc/release-notes-gui-459.md new file mode 100644 index 000000000000..fc4662fc6f18 --- /dev/null +++ b/doc/release-notes-gui-459.md @@ -0,0 +1,4 @@ +GUI changes +----------- + +- The Receive tab has an address type dropdown. Descriptor wallets with an active taproot descriptor can request Taproot (Bech32m) addresses next to the legacy ones. diff --git a/src/Makefile.test.include b/src/Makefile.test.include index a2194169c846..cc95483f5e66 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -19,6 +19,7 @@ JSON_TEST_FILES = \ test/data/blockfilters.json \ test/data/base58_encode_decode.json \ test/data/bip39_vectors.json \ + test/data/bip341_wallet_vectors.json \ test/data/key_io_valid.json \ test/data/key_io_invalid.json \ test/data/proposals_valid.json \ @@ -386,6 +387,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/script_flags.cpp \ test/fuzz/script_format.cpp \ test/fuzz/script_interpreter.cpp \ + test/fuzz/script_assets_test_minimizer.cpp \ test/fuzz/script_ops.cpp \ test/fuzz/script_sigcache.cpp \ test/fuzz/script_sign.cpp \ diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index 3e029feb2030..738048a27622 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -44,7 +44,7 @@ static void CCoinsCaching(benchmark::Bench& bench) // Benchmark. const CTransaction tx_1(t1); bench.run([&] { - bool success = AreInputsStandard(tx_1, coins); + bool success = AreInputsStandard(tx_1, coins, false); assert(success); }); ECC_Stop(); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 8d7672aeb5c9..ddbe3678c988 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -480,11 +480,12 @@ static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOut tx.vout.erase(tx.vout.begin() + outIdx); } -static const unsigned int N_SIGHASH_OPTS = 6; +static const unsigned int N_SIGHASH_OPTS = 7; static const struct { const char *flagStr; int flags; } sighashOptions[N_SIGHASH_OPTS] = { + {"DEFAULT", SIGHASH_DEFAULT}, {"ALL", SIGHASH_ALL}, {"NONE", SIGHASH_NONE}, {"SINGLE", SIGHASH_SINGLE}, diff --git a/src/consensus/params.h b/src/consensus/params.h index 59384abc67da..ea72d0993692 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -44,6 +44,7 @@ enum DeploymentPos : uint16_t { DEPLOYMENT_TESTDUMMY, DEPLOYMENT_V24, // Deployment of doubling withdrawal limit, extended addresses DEPLOYMENT_EVO_SHARES, // Deployment of EvoNode shared collateral and multiple owner payouts + DEPLOYMENT_TAPROOT, // Deployment of Taproot (BIP 340, 341, 342) outputs and tapscript // NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp MAX_VERSION_BITS_DEPLOYMENTS }; diff --git a/src/core_read.cpp b/src/core_read.cpp index d24918d73fcf..b48ad70acf1a 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -170,6 +170,7 @@ bool ParseHashStr(const std::string& strHex, uint256& result) util::Result SighashFromStr(const std::string& sighash) { static std::map map_sighash_values = { + {std::string("DEFAULT"), int(SIGHASH_DEFAULT)}, {std::string("ALL"), int(SIGHASH_ALL)}, {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)}, {std::string("NONE"), int(SIGHASH_NONE)}, diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp index d5646f3840b8..f552284b469c 100644 --- a/src/deploymentinfo.cpp +++ b/src/deploymentinfo.cpp @@ -21,6 +21,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.name =*/"evo_shares", /*.gbt_force =*/true, }, + { + /*.name =*/"taproot", + /*.gbt_force =*/true, + }, }; std::string DeploymentName(Consensus::BuriedDeployment dep) diff --git a/src/external_signer.cpp b/src/external_signer.cpp index 5faf7d41f3ae..f4986ecdc35f 100644 --- a/src/external_signer.cpp +++ b/src/external_signer.cpp @@ -81,6 +81,9 @@ bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::str for (const auto& entry : input.hd_keypaths) { if (parsed_m_fingerprint == MakeUCharSpan(entry.second.fingerprint)) return true; } + for (const auto& entry : input.m_tap_bip32_paths) { + if (parsed_m_fingerprint == MakeUCharSpan(entry.second.second.fingerprint)) return true; + } return false; }; diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 47c1199deeb5..de4af6b80990 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -284,6 +284,10 @@ class Chain //! enables version 2 asset lock transactions by consensus. virtual bool isV24Active() = 0; + //! Whether Taproot rules apply to the next block; until then P2TR + //! outputs are anyone-can-spend. + virtual bool isTaprootActive() = 0; + //! Check if any block has been pruned. virtual bool havePruned() = 0; diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 7f08ba98b510..7e190a3ab2f5 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -8,6 +8,7 @@ #include // For CAmount #include #include // For ChainClient +#include #include // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation) #include