From b696fb16c79ae6a7055266d65d0ef5a852f5712e Mon Sep 17 00:00:00 2001 From: fanquake Date: Fri, 4 Oct 2019 14:25:15 -0400 Subject: [PATCH 01/15] Merge #17049: contrib: Bump gitian descriptors for 0.20 fa1ad8f06eba5e120c30f07263250bc382891179 build: Bump gitian descriptor versions (MarcoFalke) Pull request description: Bump the gitian descriptor versions as a follow-up to #17007. Also fixes #17027 with a cherry-pick, and bump the manpages. ACKs for top commit: fanquake: ACK fa1ad8f06eba5e120c30f07263250bc382891179 Tree-SHA512: c3b669c3797e5febb51a8dd01e2621a7544a291e080d73c47a2a12ea9da84ff904533e68792e2e869ebbdc2226b2fee7517214549e6cc7e988f175098f7c412c --- contrib/gitian-descriptors/gitian-linux.yml | 2 +- contrib/gitian-descriptors/gitian-osx.yml | 2 +- contrib/gitian-descriptors/gitian-win.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 35d9beb1db..d8af2c9e52 100755 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -1,5 +1,5 @@ --- -name: "dash-linux-19" +name: "dash-linux-20" enable_cache: true distro: "ubuntu" suites: diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 769d65dad1..9ea53a8e30 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -1,5 +1,5 @@ --- -name: "dash-osx-19" +name: "dash-osx-20" enable_cache: true distro: "ubuntu" suites: diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 9faa6057bd..393a18e4e1 100755 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -1,5 +1,5 @@ --- -name: "dash-win-19" +name: "dash-win-20" enable_cache: true distro: "ubuntu" suites: From a5add5a87e6060efdbd4bba4834c8ab0b9a919c8 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Sep 2018 14:50:55 +0200 Subject: [PATCH 02/15] Merge #14096: Add reference documentation for descriptors language 2b5d6f8df24b381d35b75187c97ae0cc9f7c3ed0 Replace duplcate reference with reference to reference doc (Pieter Wuille) 89709db7a2710456011eac9dcd6a60d5e87b97ae Adjust TODO link (Pieter Wuille) 9254ffcf2d910ecb0f9ecbeef6d40a2008a44870 Add descriptor reference documentation (Pieter Wuille) Pull request description: Tree-SHA512: 1ca0d537f9bcbb23266e9a4a02a60013ef8309958fb701f638283887585b5ddea6bc9dab859454ec3a373b1a12a4fd69836e7030417bb2ca43fef26b104c0d65 --- doc/descriptors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/descriptors.md b/doc/descriptors.md index 8a2a0f588b..ea18a94d5f 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -35,6 +35,7 @@ Output descriptors currently support: ## Examples - `pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` represents a P2PK output. +- `combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` represents a P2PK, P2PKH - `multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` represents a bare *1-of-2* multisig. - `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2)` refers to a single P2PKH output, using 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'`. From b10e68ab8c1956697cea20e5399d1baa19685b2f Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sat, 20 Oct 2018 23:13:19 -0300 Subject: [PATCH 03/15] Merge #14161: doc/descriptors.md tweaks eeeaa29214 descriptors.md: Refer to descriptors as describing instead of matching (Russell Yanofsky) eb49412562 doc/descriptors.md tweaks (Russell Yanofsky) Pull request description: Add some implementation details, and tweak phrasing in examples section to be more explicit about how expressions are used for matching. Tree-SHA512: a9dc7bc0fc370548189a789f31c04bd11103cdd2a99bcb909fa1b1dfa4e78509813dad5d5c9e3db98d66929f45cb5704f5c46ab4cbd800fef22cd8465f80ef33 --- doc/descriptors.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/descriptors.md b/doc/descriptors.md index ea18a94d5f..da27ab7430 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -34,10 +34,10 @@ Output descriptors currently support: ## Examples -- `pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` represents a P2PK output. -- `combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` represents a P2PK, P2PKH -- `multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` represents a bare *1-of-2* multisig. -- `pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1'/2)` refers to a single P2PKH output, using child key *1'/2* of the specified xpub. +- `pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` describes a P2PK output with the specified public key. +- `combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` describes any P2PK, P2PKH with the specified public key. +- `multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` describes a bare *1-of-2* multisig with the specified public key. +- `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'`. ## Reference @@ -96,6 +96,15 @@ on Bitcoin's OP_CHECKMULTISIG opcode. To support these, we introduce the multisig policy, where any *k* out of the *n* provided public keys must sign. +Key order is significant. A `multi()` expression describes a multisig script +with keys in the specified order, and in a search for TXOs, it will not match +outputs with multisig scriptPubKeys that have the same keys in a different +order. Also, to prevent a combinatorial explosion of the search space, if more +than one of the `multi()` key arguments is a BIP32 wildcard path ending in `/*` +or `*'`, the `multi()` expression only matches multisig scripts with the `i`th +child key from each wildcard path in lockstep, rather than scripts with any +combination of child keys from each wildcard path. + ### BIP32 derived keys and chains Most modern wallet software and hardware uses keys that are derived using @@ -106,7 +115,7 @@ path consists of a sequence of 0 or more integers (in the range *0..231-1*) each optionally followed by `'` or `h`, and separated by `/` characters. The string may optionally end with the literal `/*` or `/*'` (or `/*h`) to refer to all unhardened or hardened -child keys instead. +child keys in a configurable range (by default `0-1000`, inclusive). Whenever a public key is described using a hardened derivation step, the script cannot be computed without access to the corresponding private @@ -151,7 +160,7 @@ steps, or for dumping wallet descriptors including private key material. In order to easily represent the sets of scripts currently supported by existing Dash Core wallets, a convenience function `combo` is -provided, which takes as input a public key, and constructs the P2PK and +provided, which takes as input a public key, and describes a set of P2PK and P2PKH scripts for that key. ### Checksums From 2690ef07aeb138d48dbdd06214e35ce1ac6c6383 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 13 Jul 2018 20:26:42 -0700 Subject: [PATCH 04/15] Merge #13072: Update createmultisig RPC to support segwit f40b3b82df [tests] functional test for createmultisig RPC (Anthony Towns) b9024fdda3 segwit support for createmultisig RPC (Anthony Towns) d58055d25f Move AddAndGetDestinationForScript from wallet to outputype module (Anthony Towns) 9a44db2e46 Add outputtype module (Anthony Towns) Pull request description: Adds an "address_type" parameter that accepts "legacy", "p2sh-segwit", and "bech32" to choose the type of address created. Defaults to "legacy" rather than the value of the `-address-type` option for backwards compatibility. As part of implementing this, OutputType is moved from wallet into its own module, and `AddAndGetDestinationForScript` is changed to apply to a `CKeyStore` rather than a wallet, and to invoke `keystore.AddCScript(script)` itself rather than expecting the caller to have done that. Fixes #12502 Tree-SHA512: a08c1cfa89976e4fd7d29caa90919ebd34a446354d17abb862e99f2ee60ed9bc19d8a21a18547c51dc3812cb9fbed86af0bef2f1e971f62bf95cade4a7d86237 --- test/functional/rpc_createmultisig.py | 98 +++++++++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 99 insertions(+) create mode 100755 test/functional/rpc_createmultisig.py diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py new file mode 100755 index 0000000000..97e614c888 --- /dev/null +++ b/test/functional/rpc_createmultisig.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test transaction signing using the signrawtransaction* RPCs.""" + +from test_framework.test_framework import BitcoinTestFramework +import decimal + +class RpcCreateMultiSigTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 3 + + def get_keys(self): + node0,node1,node2 = self.nodes + self.add = [node1.getnewaddress() for _ in range(self.nkeys)] + self.pub = [node1.getaddressinfo(a)["pubkey"] for a in self.add] + self.priv = [node1.dumpprivkey(a) for a in self.add] + self.final = node2.getnewaddress() + + def run_test(self): + node0,node1,node2 = self.nodes + + # 50 BTC each, rest will be 25 BTC each + node0.generate(149) + self.sync_all() + + self.moved = 0 + for self.nkeys in [3,5]: + for self.nsigs in [2,3]: + for self.output_type in ["bech32", "p2sh-segwit", "legacy"]: + self.get_keys() + self.do_multisig() + + self.checkbalances() + + def checkbalances(self): + node0,node1,node2 = self.nodes + node0.generate(100) + self.sync_all() + + bal0 = node0.getbalance() + bal1 = node1.getbalance() + bal2 = node2.getbalance() + + height = node0.getblockchaininfo()["blocks"] + assert 150 < height < 350 + total = 149*50 + (height-149-100)*25 + assert bal1 == 0 + assert bal2 == self.moved + assert bal0+bal1+bal2 == total + + def do_multisig(self): + node0,node1,node2 = self.nodes + + msig = node2.createmultisig(self.nsigs, self.pub, self.output_type) + madd = msig["address"] + mredeem = msig["redeemScript"] + if self.output_type == 'bech32': + assert madd[0:4] == "bcrt" # actually a bech32 address + + # compare against addmultisigaddress + msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type) + maddw = msigw["address"] + mredeemw = msigw["redeemScript"] + # addmultisigiaddress and createmultisig work the same + assert maddw == madd + assert mredeemw == mredeem + + txid = node0.sendtoaddress(madd, 40) + + tx = node0.getrawtransaction(txid, True) + vout = [v["n"] for v in tx["vout"] if madd in v["scriptPubKey"].get("addresses",[])] + assert len(vout) == 1 + vout = vout[0] + scriptPubKey = tx["vout"][vout]["scriptPubKey"]["hex"] + value = tx["vout"][vout]["value"] + prevtxs = [{"txid": txid, "vout": vout, "scriptPubKey": scriptPubKey, "redeemScript": mredeem, "amount": value}] + + node0.generate(1) + + outval = value - decimal.Decimal("0.00001000") + rawtx = node2.createrawtransaction([{"txid": txid, "vout": vout}], [{self.final: outval}]) + + rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], prevtxs) + rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs) + + self.moved += outval + tx = node0.sendrawtransaction(rawtx3["hex"], True) + blk = node0.generate(1)[0] + assert tx in node0.getblock(blk)["tx"] + + txinfo = node0.getrawtransaction(tx, True, blk) + self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"])) + +if __name__ == '__main__': + RpcCreateMultiSigTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 312d4c1d24..7d32468938 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -197,6 +197,7 @@ BASE_SCRIPTS = [ 'feature_utxo_set_hash.py', 'mempool_packages.py', 'mempool_package_onemore.py', + 'rpc_createmultisig.py', 'feature_versionbits_warning.py', 'rpc_preciousblock.py', 'wallet_importprunedfunds.py', From 08b1df65091ef3d3dbac514f3e41d83a5c696912 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 24 Mar 2023 15:05:10 +0700 Subject: [PATCH 05/15] backport: follow-up new rpc_createmultisig.py (bitcoin#13072) - changes from bitcoin#14180 --- test/functional/rpc_createmultisig.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 97e614c888..3cc35a7b9a 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2017 The Bitcoin Core developers +# Copyright (c) 2015-2018 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test transaction signing using the signrawtransaction* RPCs.""" @@ -12,8 +12,11 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 3 + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + def get_keys(self): - node0,node1,node2 = self.nodes + node0, node1, node2 = self.nodes self.add = [node1.getnewaddress() for _ in range(self.nkeys)] self.pub = [node1.getaddressinfo(a)["pubkey"] for a in self.add] self.priv = [node1.dumpprivkey(a) for a in self.add] From c76d2ecdae632781617d6a14fa7c5612e9feaa6d Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 24 Mar 2023 15:07:49 +0700 Subject: [PATCH 06/15] backport: follow-up new rpc_createmultisig.py (bitcoin#13072) - changes from bitcoin#13541 --- test/functional/rpc_createmultisig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 3cc35a7b9a..17dbf59a8c 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -90,7 +90,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs) self.moved += outval - tx = node0.sendrawtransaction(rawtx3["hex"], True) + tx = node0.sendrawtransaction(rawtx3["hex"], 0) blk = node0.generate(1)[0] assert tx in node0.getblock(blk)["tx"] From 3d3bdb4fc165993b9b5d1e6cd192b438df3f4ac1 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 17 Apr 2019 11:40:03 -0400 Subject: [PATCH 07/15] Merge #15831: test: Add test that addmultisigaddress fails for watchonly addresses fab6a0a659 test: Add test that addmultisigaddress fails for watchonly addresses (MarcoFalke) fad81d870a test: Fixup creatmultisig documentation and whitespace (MarcoFalke) Pull request description: Just to make sure this is not regressed on accidentally in the future ACKs for commit fab6a0: jonatack: ACK https://github.com/bitcoin/bitcoin/pull/15831/commits/fab6a0a659bb856e4598af3e0679fc37d5239478 Tree-SHA512: bf8dcbc752f8910902a995e55ce486621156aa01f112990344815c4aab980298dfecc108e78245a8986a00c3871338ad16fc818a1bce9dfc6b37b9c88851e39d --- test/functional/rpc_createmultisig.py | 46 ++++++++++++++++++--------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 17dbf59a8c..7abcd71bb8 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -1,12 +1,16 @@ #!/usr/bin/env python3 -# Copyright (c) 2015-2018 The Bitcoin Core developers +# Copyright (c) 2015-2019 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test transaction signing using the signrawtransaction* RPCs.""" +"""Test multisig RPCs""" from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_raises_rpc_error, +) import decimal + class RpcCreateMultiSigTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True @@ -17,29 +21,40 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): def get_keys(self): node0, node1, node2 = self.nodes - self.add = [node1.getnewaddress() for _ in range(self.nkeys)] - self.pub = [node1.getaddressinfo(a)["pubkey"] for a in self.add] - self.priv = [node1.dumpprivkey(a) for a in self.add] + add = [node1.getnewaddress() for _ in range(self.nkeys)] + self.pub = [node1.getaddressinfo(a)["pubkey"] for a in add] + self.priv = [node1.dumpprivkey(a) for a in add] self.final = node2.getnewaddress() def run_test(self): - node0,node1,node2 = self.nodes + node0, node1, node2 = self.nodes - # 50 BTC each, rest will be 25 BTC each + self.check_addmultisigaddress_errors() + + self.log.info('Generating blocks ...') node0.generate(149) self.sync_all() self.moved = 0 - for self.nkeys in [3,5]: - for self.nsigs in [2,3]: + for self.nkeys in [3, 5]: + for self.nsigs in [2, 3]: for self.output_type in ["bech32", "p2sh-segwit", "legacy"]: self.get_keys() self.do_multisig() self.checkbalances() + def check_addmultisigaddress_errors(self): + self.log.info('Check that addmultisigaddress fails when the private keys are missing') + addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)] + assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses)) + for a in addresses: + # Importing all addresses should not change the result + self.nodes[0].importaddress(a) + assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses)) + def checkbalances(self): - node0,node1,node2 = self.nodes + node0, node1, node2 = self.nodes node0.generate(100) self.sync_all() @@ -49,13 +64,13 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): height = node0.getblockchaininfo()["blocks"] assert 150 < height < 350 - total = 149*50 + (height-149-100)*25 + total = 149 * 50 + (height - 149 - 100) * 25 assert bal1 == 0 assert bal2 == self.moved - assert bal0+bal1+bal2 == total + assert bal0 + bal1 + bal2 == total def do_multisig(self): - node0,node1,node2 = self.nodes + node0, node1, node2 = self.nodes msig = node2.createmultisig(self.nsigs, self.pub, self.output_type) madd = msig["address"] @@ -74,7 +89,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): txid = node0.sendtoaddress(madd, 40) tx = node0.getrawtransaction(txid, True) - vout = [v["n"] for v in tx["vout"] if madd in v["scriptPubKey"].get("addresses",[])] + vout = [v["n"] for v in tx["vout"] if madd in v["scriptPubKey"].get("addresses", [])] assert len(vout) == 1 vout = vout[0] scriptPubKey = tx["vout"][vout]["scriptPubKey"]["hex"] @@ -86,7 +101,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): outval = value - decimal.Decimal("0.00001000") rawtx = node2.createrawtransaction([{"txid": txid, "vout": vout}], [{self.final: outval}]) - rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], prevtxs) + rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs - 1], prevtxs) rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs) self.moved += outval @@ -97,5 +112,6 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): txinfo = node0.getrawtransaction(tx, True, blk) self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"])) + if __name__ == '__main__': RpcCreateMultiSigTest().main() From 144ad9eb413bce1359b1c5a44cbdd4e64b803eea Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 24 Mar 2023 15:13:37 +0700 Subject: [PATCH 08/15] backport: follow-up new rpc_createmultisig.py (bitcoin#13072) - changes from bitcoin#16026 --- test/functional/rpc_createmultisig.py | 30 ++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 7abcd71bb8..58010f7c2e 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -7,9 +7,13 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_raises_rpc_error, + assert_equal, ) -import decimal +from test_framework.key import ECPubKey +import binascii +import decimal +import itertools class RpcCreateMultiSigTest(BitcoinTestFramework): def set_test_params(self): @@ -44,6 +48,30 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): self.checkbalances() + # Test mixed compressed and uncompressed pubkeys + self.log.info('Mixed compressed and uncompressed multisigs are not allowed') + pk0 = node0.getaddressinfo(node0.getnewaddress())['pubkey'] + pk1 = node1.getaddressinfo(node1.getnewaddress())['pubkey'] + pk2 = node2.getaddressinfo(node2.getnewaddress())['pubkey'] + + # decompress pk2 + pk_obj = ECPubKey() + pk_obj.set(binascii.unhexlify(pk2)) + pk_obj.compressed = False + pk2 = binascii.hexlify(pk_obj.get_bytes()).decode() + + # Check all permutations of keys because order matters apparently + for keys in itertools.permutations([pk0, pk1, pk2]): + # Results should be the same as this legacy one + legacy_addr = node0.createmultisig(2, keys, 'legacy')['address'] + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'legacy')['address']) + + # Generate addresses with the segwit types. These should all make legacy addresses + assert_equal(legacy_addr, node0.createmultisig(2, keys, 'bech32')['address']) + assert_equal(legacy_addr, node0.createmultisig(2, keys, 'p2sh-segwit')['address']) + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address']) + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address']) + def check_addmultisigaddress_errors(self): self.log.info('Check that addmultisigaddress fails when the private keys are missing') addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)] From b44eb215915561c7091799dcde4375aa6b0d493e Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 2 Jul 2019 17:20:58 -0400 Subject: [PATCH 09/15] Merge #16250: signrawtransactionwithkey: report error when missing redeemScript/witnessScript 01174596e69568c434198a86f54cb9ea6740e6c2 signrawtransactionwithkey: report error when missing redeemScript/witnessScript param (Anthony Towns) Pull request description: Adding support for "witnessScript" as an alternative to "redeemScript" when using "signrawtransactionwithkey" meant that the `RPCTypeCheckObj()` call in `SignTransaction` can't error out just because either parameter is missing -- it's only a problem if both are missing, which isn't a state `RPCTypeCheckObj()` tests for. This results in the regression described in #16249. This patch adds some code to test for this case and give a similar error, namely: error code: -8 error message: Missing redeemScript/witnessScript Fixes: #16249 ACKs for top commit: meshcollider: utACK https://github.com/bitcoin/bitcoin/pull/16250/commits/01174596e69568c434198a86f54cb9ea6740e6c2 promag: ACK 01174596e. Could also write test without `dict`/`del`: Tree-SHA512: cf51346b7dea551b7f18f2a93c2a336a293b2535c62c03a5263cd2be8c58cf0cc302891da659c167e88ad1a68a756472c3c07e99f71627c61d32886fc5a3a353 --- test/functional/rpc_createmultisig.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 58010f7c2e..62f3843756 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -129,6 +129,11 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): outval = value - decimal.Decimal("0.00001000") rawtx = node2.createrawtransaction([{"txid": txid, "vout": vout}], [{self.final: outval}]) + prevtx_err = dict(prevtxs[0]) + del prevtx_err["redeemScript"] + + assert_raises_rpc_error(-8, "Missing redeemScript/witnessScript", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs - 1], prevtxs) rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs) From 993418041c8740fc0779af4f162bd1a4fe198355 Mon Sep 17 00:00:00 2001 From: fanquake Date: Wed, 11 Sep 2019 15:21:12 +1000 Subject: [PATCH 10/15] Merge #16251: Improve signrawtransaction error reporting ec4c79326bb670c2cc1757ecfb1900f8460c5257 signrawtransaction*: improve error for partial signing (Anthony Towns) 3c481f8921bbc587cf287329f39243abe703b868 signrawtransactionwithkey: better error messages for bad redeemScript/witnessScript (Anthony Towns) Pull request description: Two fixes for `signrawtransactionwith{key,wallet}` (in addition to #16250): one that checks redeemScript/witnessScript matches scriptPubKey (and if both are provided that they match each other sanely), and the other changes the warning when some-but-not-all the signatures for a CHECKMULTISIG are provided to something that suggests more signatures may be all that's required. Fixes: #13218 Fixes: #14823 ACKs for top commit: instagibbs: utACK https://github.com/bitcoin/bitcoin/pull/16251/commits/ec4c79326bb670c2cc1757ecfb1900f8460c5257 achow101: Code Review ACK ec4c79326bb670c2cc1757ecfb1900f8460c5257 meshcollider: utACK ec4c79326bb670c2cc1757ecfb1900f8460c5257 Tree-SHA512: 0c95c91d498e85b834662b9e5c83f336ed5fd306be7701ce1dbfa0836fbeb448a267a796585512f7496e820be668b07c2a0a2f45e52dc23f09ee7d9c87e42b35 --- test/functional/rpc_createmultisig.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 62f3843756..056e193d55 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -134,6 +134,27 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): assert_raises_rpc_error(-8, "Missing redeemScript/witnessScript", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + # if witnessScript specified, all ok + prevtx_err["witnessScript"] = prevtxs[0]["redeemScript"] + node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + + # both specified, also ok + prevtx_err["redeemScript"] = prevtxs[0]["redeemScript"] + node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + + # redeemScript mismatch to witnessScript + prevtx_err["redeemScript"] = "6a" # OP_RETURN + assert_raises_rpc_error(-8, "redeemScript does not correspond to witnessScript", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + + # redeemScript does not match scriptPubKey + del prevtx_err["witnessScript"] + assert_raises_rpc_error(-8, "redeemScript/witnessScript does not match scriptPubKey", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + + # witnessScript does not match scriptPubKey + prevtx_err["witnessScript"] = prevtx_err["redeemScript"] + del prevtx_err["redeemScript"] + assert_raises_rpc_error(-8, "redeemScript/witnessScript does not match scriptPubKey", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs - 1], prevtxs) rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs) From be3b359fa3e6125f9900965554d610361938c7f5 Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 8 Oct 2019 14:14:37 -0400 Subject: [PATCH 11/15] Merge #17056: descriptors: Introduce sortedmulti descriptor 4bb660be90a2811b53855bf1fd33a8dd9ba3db47 Add release note (Andrew Chow) ed96b295d747738334459490c79b7360ab85aaf7 Update descriptors.md to include sortedmulti (Andrew Chow) 80be78ea75ac9833ee3db3d468ed09fc4fe6274c Test sortedmulti descriptor using BIP 67 tests (Andrew Chow) 6f588fd2276e5b713c6d36e3b01288484ddb59c0 Add sortedmulti descriptor and unit tests (Andrew Chow) Pull request description: Adds a `sortedmulti()` descriptor as mentioned in https://github.com/bitcoin/bitcoin/pull/17023#issuecomment-537596416. `sortedmulti()` works in the same way as `multi` does but sorts the pubkeys in the resulting scripts in lexicographic order as described in [BIP67](https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki). Note that this does not add support for BIP67 nor is BIP67 fully supported by this descriptor (which is why it is not named `multi67()`) as it does not require compressed pubkeys. Tests from BIP67 were added and documentation was updated. ACKs for top commit: instagibbs: re-ACK https://github.com/bitcoin/bitcoin/pull/17056/commits/4bb660be90a2811b53855bf1fd33a8dd9ba3db47 Sjors: re-ACK 4bb660be90a2811b53855bf1fd33a8dd9ba3db47 Tree-SHA512: 93b21112a74ebe0bf316d8f3e0291f69fd975cf0a29332f9728e7b880cad312b8b14007e86adcd7899f117b9303cbcf4cb35f3bb2f2f648d1a446f83f75a70a5 --- doc/descriptors.md | 12 +++++- doc/release-notes-17056.md | 4 ++ src/script/descriptor.cpp | 19 ++++++--- src/test/descriptor_tests.cpp | 3 ++ test/functional/data/rpc_bip67.json | 58 +++++++++++++++++++++++++++ test/functional/rpc_createmultisig.py | 15 +++++++ 6 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 doc/release-notes-17056.md create mode 100644 test/functional/data/rpc_bip67.json diff --git a/doc/descriptors.md b/doc/descriptors.md index da27ab7430..5758140cda 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -28,6 +28,7 @@ Output descriptors currently support: - Pay-to-pubkey-hash scripts (P2PKH), through the `pkh` function. - Pay-to-script-hash scripts (P2SH), through the `sh` function. - Multisig scripts, through the `multi` function. +- Multisig scripts where the public keys are sorted lexicographically, through the `sortedmulti` 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. @@ -37,6 +38,7 @@ Output descriptors currently support: - `pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` describes a P2PK output with the specified public key. - `combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)` describes any P2PK, P2PKH with the specified public key. - `multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)` describes a bare *1-of-2* multisig with the specified public key. +- `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'`. @@ -50,6 +52,7 @@ Descriptors consist of several types of expressions. The top level expression is - `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. - `addr(ADDR)` (top level only): the script which ADDR expands to. - `raw(HEX)` (top level only): the script whose hex encoding is HEX. @@ -92,11 +95,12 @@ not contain "p2" for brevity. Several pieces of software use multi-signature (multisig) scripts based on Bitcoin's OP_CHECKMULTISIG opcode. To support these, we introduce the -`multi(k,key_1,key_2,...,key_n)` function. It represents a *k-of-n* +`multi(k,key_1,key_2,...,key_n)` and `sortedmulti(k,key_1,key_2,...,key_n)` +functions. They represents a *k-of-n* multisig policy, where any *k* out of the *n* provided public keys must sign. -Key order is significant. A `multi()` expression describes a multisig script +Key order is significant for `multi()`. A `multi()` expression describes a multisig script with keys in the specified order, and in a search for TXOs, it will not match outputs with multisig scriptPubKeys that have the same keys in a different order. Also, to prevent a combinatorial explosion of the search space, if more @@ -105,6 +109,10 @@ or `*'`, the `multi()` expression only matches multisig scripts with the `i`th child key from each wildcard path in lockstep, rather than scripts with any combination of child keys from each wildcard path. +Key order does not matter for `sortedmulti()`. `sortedmulti()` behaves in the same way +as `multi()` does but the keys are reordered in the resulting script such that they +are lexicographically ordered as described in BIP67. + ### BIP32 derived keys and chains Most modern wallet software and hardware uses keys that are derived using diff --git a/doc/release-notes-17056.md b/doc/release-notes-17056.md new file mode 100644 index 0000000000..23d5a8c8cd --- /dev/null +++ b/doc/release-notes-17056.md @@ -0,0 +1,4 @@ +Low-level RPC Changes +=== + +- A new descriptor type `sortedmulti(...)` has been added to support multisig scripts where the public keys are sorted lexicographically in the resulting script. diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 5b4d542fed..4a4ae250a2 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -605,15 +605,23 @@ public: PKHDescriptor(std::unique_ptr prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} }; -/** A parsed multi(...) descriptor. */ +/** A parsed multi(...) or sortedmulti(...) descriptor */ class MultisigDescriptor final : public DescriptorImpl { const int m_threshold; + const bool m_sorted; protected: std::string ToStringExtra() const override { return strprintf("%i", m_threshold); } - std::vector MakeScripts(const std::vector& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForMultisig(m_threshold, keys)); } + std::vector MakeScripts(const std::vector& keys, const CScript*, FlatSigningProvider&) const override { + if (m_sorted) { + std::vector sorted_keys(keys); + std::sort(sorted_keys.begin(), sorted_keys.end()); + return Singleton(GetScriptForMultisig(m_threshold, sorted_keys)); + } + return Singleton(GetScriptForMultisig(m_threshold, keys)); + } public: - MultisigDescriptor(int threshold, std::vector> providers) : DescriptorImpl(std::move(providers), {}, "multi"), m_threshold(threshold) {} + MultisigDescriptor(int threshold, std::vector> providers, bool sorted = false) : DescriptorImpl(std::move(providers), {}, sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {} }; /** A parsed sh(...) descriptor. */ @@ -784,6 +792,7 @@ std::unique_ptr ParseScript(uint32_t key_exp_index, Span ParseScript(uint32_t key_exp_index, Span> providers; @@ -845,7 +854,7 @@ std::unique_ptr ParseScript(uint32_t key_exp_index, Span(thres, std::move(providers)); + return std::make_unique(thres, std::move(providers), sorted_multi); } if (ctx == ParseScriptContext::TOP && Func("sh", expr)) { auto desc = ParseScript(key_exp_index, expr, ParseScriptContext::P2SH, out, error); diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 0e7356a678..d8c0dcd098 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -304,7 +304,10 @@ BOOST_AUTO_TEST_CASE(descriptor_test) // Multisig constructions Check("multi(1,XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2,7sH936MDoVPFVk2VoaCM5yW8P3BfPyffnZECyaHrZwfLgWpS13e)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); + Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); + Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, {{0x8000006FUL,222},{0}}); + Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}}); CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))", "P2SH script is too large, 547 bytes is larger than 520 bytes"); // P2SH does not fit 16 compressed pubkeys in a redeemscript CheckUnparsable("multi(a,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(a,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multi threshold 'a' is not valid"); // Invalid threshold CheckUnparsable("multi(0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", "Multisig threshold cannot be 0, must be at least 1"); // Threshold of 0 diff --git a/test/functional/data/rpc_bip67.json b/test/functional/data/rpc_bip67.json new file mode 100644 index 0000000000..4d6f793d4a --- /dev/null +++ b/test/functional/data/rpc_bip67.json @@ -0,0 +1,58 @@ +[ + { + "keys": [ + "02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8", + "02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f" + ], + "sorted_keys": [ + "02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f", + "02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8" + ], + "script": "522102fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f2102ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f852ae", + "address": "2N19tNw3Ss4L9QDERtCw7FhXb6jBsYmeXNu" + }, + { + "keys": [ + "02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed0", + "027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e77", + "02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b404" + ], + "sorted_keys": [ + "02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed0", + "027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e77", + "02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b404" + ], + "script": "522102632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed021027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e772102e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b40453ae", + "address": "2N3sVXU7MZefmYnZhrVX2bA7LyH6vygFZZ7" + }, + { + "keys": [ + "030000000000000000000000000000000000004141414141414141414141414141", + "020000000000000000000000000000000000004141414141414141414141414141", + "020000000000000000000000000000000000004141414141414141414141414140", + "030000000000000000000000000000000000004141414141414141414141414140" + ], + "sorted_keys": [ + "020000000000000000000000000000000000004141414141414141414141414140", + "020000000000000000000000000000000000004141414141414141414141414141", + "030000000000000000000000000000000000004141414141414141414141414140", + "030000000000000000000000000000000000004141414141414141414141414141" + ], + "script": "522102000000000000000000000000000000000000414141414141414141414141414021020000000000000000000000000000000000004141414141414141414141414141210300000000000000000000000000000000000041414141414141414141414141402103000000000000000000000000000000000000414141414141414141414141414154ae", + "address": "2Mt3L9TcDUAfLpSoyB3SNYtJGLiU49DKEWJ" + }, + { + "keys": [ + "022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da", + "03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9", + "021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18" + ], + "sorted_keys": [ + "021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18", + "022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da", + "03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9" + ], + "script": "5221021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc1821022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da2103e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e953ae", + "address": "2NFd5JqpwmQNz3gevZJ3rz9ofuHvqaP9Cye" + } +] diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 056e193d55..2a64a29967 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test multisig RPCs""" +from test_framework.descriptors import descsum_create from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_raises_rpc_error, @@ -14,6 +15,8 @@ from test_framework.key import ECPubKey import binascii import decimal import itertools +import json +import os class RpcCreateMultiSigTest(BitcoinTestFramework): def set_test_params(self): @@ -72,6 +75,18 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address']) assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address']) + self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors') + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json'), encoding='utf-8') as f: + vectors = json.load(f) + + for t in vectors: + key_str = ','.join(t['keys']) + desc = descsum_create('sh(sortedmulti(2,{}))'.format(key_str)) + assert_equal(self.nodes[0].deriveaddresses(desc)[0], t['address']) + sorted_key_str = ','.join(t['sorted_keys']) + sorted_key_desc = descsum_create('sh(multi(2,{}))'.format(sorted_key_str)) + assert_equal(self.nodes[0].deriveaddresses(sorted_key_desc)[0], t['address']) + def check_addmultisigaddress_errors(self): self.log.info('Check that addmultisigaddress fails when the private keys are missing') addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)] From dceee33ebe036ec9ad345b55a4466f218b18dbe2 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 9 Feb 2020 04:55:29 -0800 Subject: [PATCH 12/15] Merge #18032: rpc: Output a descriptor in createmultisig and addmultisigaddress 19a354b11f85a3c6c81ff83bf702bf7a40cf5046 Output a descriptor in createmultisig and addmultisigaddress (Andrew Chow) Pull request description: Give a descriptor from `createmultisig` and `addmultisigaddress`. Extracted from #16528 with `addmultisgaddress` and tests added. ACKs for top commit: Sjors: tACK 19a354b11f85a3c6c81ff83bf702bf7a40cf5046 MarcoFalke: ACK 19a354b11f85a3c6c81ff83bf702bf7a40cf5046 promag: Code review ACK 19a354b11f85a3c6c81ff83bf702bf7a40cf5046. meshcollider: utACK 19a354b11f85a3c6c81ff83bf702bf7a40cf5046 Tree-SHA512: e813125fbbc358ea8d45b1748de16a29a94efd83175b748fb8fa3b0bfc8e783ed36b6c554d84f5d4ead1ba252a83a3e937b6c3f75da7b8d3b4e55f94d6013771 --- doc/descriptors.md | 1 + src/rpc/misc.cpp | 5 +++++ src/wallet/rpcwallet.cpp | 5 +++++ test/functional/rpc_createmultisig.py | 14 +++++++++++++- test/functional/test_framework/descriptors.py | 9 +++++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/descriptors.md b/doc/descriptors.md index 5758140cda..f8040e823d 100644 --- a/doc/descriptors.md +++ b/doc/descriptors.md @@ -17,6 +17,7 @@ Supporting RPCs are: (`regtest` only, since v0.19). - `utxoupdatepsbt` takes as input descriptors to add information to the psbt (since v0.19). +- `createmultisig` and `addmultisigaddress` return descriptors as well (since v0.20) This document describes the language. For the specifics on usage, see the RPC documentation for the functions mentioned above. diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index fa92165710..8776aa4908 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -255,6 +255,7 @@ static UniValue createmultisig(const JSONRPCRequest& request) { {RPCResult::Type::STR, "address", "The value of the new multisig address."}, {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script."}, + {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig."}, } }, RPCExamples{ @@ -283,9 +284,13 @@ static UniValue createmultisig(const JSONRPCRequest& request) CScript inner; const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, keystore, inner); + // Make the descriptor + std::unique_ptr descriptor = InferDescriptor(GetScriptForDestination(dest), keystore); + UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(dest)); result.pushKV("redeemScript", HexStr(inner)); + result.pushKV("descriptor", descriptor->ToString()); return result; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4bd5a4cc74..6c68ce3e48 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -980,6 +980,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) { {RPCResult::Type::STR, "address", "The value of the new multisig address"}, {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script"}, + {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig."}, } }, RPCExamples{ @@ -1020,9 +1021,13 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, spk_man, inner); pwallet->SetAddressBook(dest, label, "send"); + // Make the descriptor + std::unique_ptr descriptor = InferDescriptor(GetScriptForDestination(dest), spk_man); + UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(dest)); result.pushKV("redeemScript", HexStr(inner)); + result.pushKV("descriptor", descriptor->ToString()); return result; } diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 2a64a29967..3f1558cbbb 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test multisig RPCs""" -from test_framework.descriptors import descsum_create +from test_framework.descriptors import descsum_create, drop_origins from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_raises_rpc_error, @@ -115,9 +115,20 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): def do_multisig(self): node0, node1, node2 = self.nodes + # Construct the expected descriptor + desc = 'multi({},{})'.format(self.nsigs, ','.join(self.pub)) + if self.output_type == 'legacy': + desc = 'sh({})'.format(desc) + elif self.output_type == 'p2sh-segwit': + desc = 'sh(wsh({}))'.format(desc) + elif self.output_type == 'bech32': + desc = 'wsh({})'.format(desc) + desc = descsum_create(desc) + msig = node2.createmultisig(self.nsigs, self.pub, self.output_type) madd = msig["address"] mredeem = msig["redeemScript"] + assert_equal(desc, msig['descriptor']) if self.output_type == 'bech32': assert madd[0:4] == "bcrt" # actually a bech32 address @@ -125,6 +136,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type) maddw = msigw["address"] mredeemw = msigw["redeemScript"] + assert_equal(desc, drop_origins(msigw['descriptor'])) # addmultisigiaddress and createmultisig work the same assert maddw == madd assert mredeemw == mredeem diff --git a/test/functional/test_framework/descriptors.py b/test/functional/test_framework/descriptors.py index 29482ce01e..46b405749b 100644 --- a/test/functional/test_framework/descriptors.py +++ b/test/functional/test_framework/descriptors.py @@ -4,6 +4,8 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Utility functions related to output descriptors""" +import re + INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ " CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" GENERATOR = [0xf5dee51989, 0xa9fdca3312, 0x1bab10e32d, 0x3706b1677a, 0x644d626ffd] @@ -53,3 +55,10 @@ def descsum_check(s, require=True): return False symbols = descsum_expand(s[:-9]) + [CHECKSUM_CHARSET.find(x) for x in s[-8:]] return descsum_polymod(symbols) == 1 + +def drop_origins(s): + '''Drop the key origins from a descriptor''' + desc = re.sub(r'\[.+?\]', '', s) + if '#' in s: + desc = desc[:desc.index('#')] + return descsum_create(desc) From 4e19d00773624fc71a4cb1a7fd56399d671ec922 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 24 Mar 2023 16:50:28 +0700 Subject: [PATCH 13/15] backport: follow-up new rpc_createmultisig.py (bitcoin#13072) - changes from bitcoin#17675 --- test/functional/rpc_createmultisig.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 3f1558cbbb..a983716177 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -22,6 +22,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 + self.supports_cli = False def skip_test_if_missing_module(self): self.skip_if_no_wallet() From d82ec8bb6bb817c4578958668a9a065b420de1f8 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 24 Mar 2023 18:18:05 +0700 Subject: [PATCH 14/15] fix: dashification for rpc_createmultisig introduced in bitcoin#13072 - updated data file with dash addresses - removed witness/bench32 support from rpc_createmultisig.py - other specific changes, such as wallet balances after N mined blocks - updated descriptors for multisort sign (fixes for bitcoin#17056) --- src/test/descriptor_tests.cpp | 5 ++- test/functional/data/rpc_bip67.json | 8 ++-- test/functional/rpc_createmultisig.py | 58 ++++++++------------------- 3 files changed, 23 insertions(+), 48 deletions(-) diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index d8c0dcd098..709b14d6a8 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -304,8 +304,9 @@ BOOST_AUTO_TEST_CASE(descriptor_test) // Multisig constructions Check("multi(1,XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2,7sH936MDoVPFVk2VoaCM5yW8P3BfPyffnZECyaHrZwfLgWpS13e)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); - Check("sortedmulti(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); - Check("sortedmulti(1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); + Check("sortedmulti(1,XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2,7sH936MDoVPFVk2VoaCM5yW8P3BfPyffnZECyaHrZwfLgWpS13e)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); + Check("sortedmulti(1,XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2,7sH936MDoVPFVk2VoaCM5yW8P3BfPyffnZECyaHrZwfLgWpS13e)", "sortedmulti(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); + Check("sortedmulti(1,7sH936MDoVPFVk2VoaCM5yW8P3BfPyffnZECyaHrZwfLgWpS13e,XJvEUEcFWCHCyruc8ZX5exPZaGe4UR7gC5FHrhwPnQGDs1uWCsT2)", "sortedmulti(1,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}}); Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, {{0x8000006FUL,222},{0}}); Check("sortedmulti(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/*,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0/0/*)", "sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/*)", RANGE, {{"5221025d5fc65ebb8d44a5274b53bac21ff8307fec2334a32df05553459f8b1f7fe1b62102fbd47cc8034098f0e6a94c6aeee8528abf0a2153a5d8e46d325b7284c046784652ae"}, {"52210264fd4d1f5dea8ded94c61e9641309349b62f27fbffe807291f664e286bfbe6472103f4ece6dfccfa37b211eb3d0af4d0c61dba9ef698622dc17eecdf764beeb005a652ae"}, {"5221022ccabda84c30bad578b13c89eb3b9544ce149787e5b538175b1d1ba259cbb83321024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c52ae"}}, {{0}, {1}, {2}, {0, 0, 0}, {0, 0, 1}, {0, 0, 2}}); CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))", "P2SH script is too large, 547 bytes is larger than 520 bytes"); // P2SH does not fit 16 compressed pubkeys in a redeemscript diff --git a/test/functional/data/rpc_bip67.json b/test/functional/data/rpc_bip67.json index 4d6f793d4a..362523131a 100644 --- a/test/functional/data/rpc_bip67.json +++ b/test/functional/data/rpc_bip67.json @@ -9,7 +9,7 @@ "02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8" ], "script": "522102fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f2102ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f852ae", - "address": "2N19tNw3Ss4L9QDERtCw7FhXb6jBsYmeXNu" + "address": "8nL86iHTC8K4eVZ6YwyhRWMLhSauj8XQAK" }, { "keys": [ @@ -23,7 +23,7 @@ "02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b404" ], "script": "522102632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed021027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e772102e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b40453ae", - "address": "2N3sVXU7MZefmYnZhrVX2bA7LyH6vygFZZ7" + "address": "8q3jFFMMtiego4tNXEZckxw6ZzVy95pnPr" }, { "keys": [ @@ -39,7 +39,7 @@ "030000000000000000000000000000000000004141414141414141414141414141" ], "script": "522102000000000000000000000000000000000000414141414141414141414141414021020000000000000000000000000000000000004141414141414141414141414141210300000000000000000000000000000000000041414141414141414141414141402103000000000000000000000000000000000000414141414141414141414141414154ae", - "address": "2Mt3L9TcDUAfLpSoyB3SNYtJGLiU49DKEWJ" + "address": "8fDZsErDoEeG4j8dqnUxih81wRs6PKRwEs" }, { "keys": [ @@ -53,6 +53,6 @@ "03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9" ], "script": "5221021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc1821022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da2103e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e953ae", - "address": "2NFd5JqpwmQNz3gevZJ3rz9ofuHvqaP9Cye" + "address": "92oK2d4x6UMuHxybE36T9xdRW1KsfkXF4Q" } ] diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index a983716177..56e18ec11c 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -46,9 +46,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): self.moved = 0 for self.nkeys in [3, 5]: for self.nsigs in [2, 3]: - for self.output_type in ["bech32", "p2sh-segwit", "legacy"]: - self.get_keys() - self.do_multisig() + self.get_keys() + self.do_multisig() self.checkbalances() @@ -67,14 +66,8 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): # Check all permutations of keys because order matters apparently for keys in itertools.permutations([pk0, pk1, pk2]): # Results should be the same as this legacy one - legacy_addr = node0.createmultisig(2, keys, 'legacy')['address'] - assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'legacy')['address']) - - # Generate addresses with the segwit types. These should all make legacy addresses - assert_equal(legacy_addr, node0.createmultisig(2, keys, 'bech32')['address']) - assert_equal(legacy_addr, node0.createmultisig(2, keys, 'p2sh-segwit')['address']) - assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address']) - assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address']) + legacy_addr = node0.createmultisig(2, keys)['address'] + assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '')['address']) self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors') with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json'), encoding='utf-8') as f: @@ -90,7 +83,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): def check_addmultisigaddress_errors(self): self.log.info('Check that addmultisigaddress fails when the private keys are missing') - addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)] + addresses = [self.nodes[1].getnewaddress() for _ in range(2)] assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses)) for a in addresses: # Importing all addresses should not change the result @@ -99,7 +92,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): def checkbalances(self): node0, node1, node2 = self.nodes - node0.generate(100) + node0.generate(1) self.sync_all() bal0 = node0.getbalance() @@ -108,9 +101,10 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): height = node0.getblockchaininfo()["blocks"] assert 150 < height < 350 - total = 149 * 50 + (height - 149 - 100) * 25 + total = (height - 99 - 1) * 500 - decimal.Decimal("0.00001223") * 4 assert bal1 == 0 assert bal2 == self.moved + assert bal0 + bal1 + bal2 == total def do_multisig(self): @@ -118,23 +112,16 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): # Construct the expected descriptor desc = 'multi({},{})'.format(self.nsigs, ','.join(self.pub)) - if self.output_type == 'legacy': - desc = 'sh({})'.format(desc) - elif self.output_type == 'p2sh-segwit': - desc = 'sh(wsh({}))'.format(desc) - elif self.output_type == 'bech32': - desc = 'wsh({})'.format(desc) + desc = 'sh({})'.format(desc) desc = descsum_create(desc) - msig = node2.createmultisig(self.nsigs, self.pub, self.output_type) + msig = node2.createmultisig(self.nsigs, self.pub) madd = msig["address"] mredeem = msig["redeemScript"] assert_equal(desc, msig['descriptor']) - if self.output_type == 'bech32': - assert madd[0:4] == "bcrt" # actually a bech32 address # compare against addmultisigaddress - msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type) + msigw = node1.addmultisigaddress(self.nsigs, self.pub, None) maddw = msigw["address"] mredeemw = msigw["redeemScript"] assert_equal(desc, drop_origins(msigw['descriptor'])) @@ -160,28 +147,15 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): prevtx_err = dict(prevtxs[0]) del prevtx_err["redeemScript"] - assert_raises_rpc_error(-8, "Missing redeemScript/witnessScript", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + assert_raises_rpc_error(-3, "Missing redeemScript", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) - # if witnessScript specified, all ok - prevtx_err["witnessScript"] = prevtxs[0]["redeemScript"] - node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) - - # both specified, also ok + # if redeemScript specified, all ok prevtx_err["redeemScript"] = prevtxs[0]["redeemScript"] node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) - # redeemScript mismatch to witnessScript - prevtx_err["redeemScript"] = "6a" # OP_RETURN - assert_raises_rpc_error(-8, "redeemScript does not correspond to witnessScript", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) - # redeemScript does not match scriptPubKey - del prevtx_err["witnessScript"] - assert_raises_rpc_error(-8, "redeemScript/witnessScript does not match scriptPubKey", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) - - # witnessScript does not match scriptPubKey - prevtx_err["witnessScript"] = prevtx_err["redeemScript"] - del prevtx_err["redeemScript"] - assert_raises_rpc_error(-8, "redeemScript/witnessScript does not match scriptPubKey", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) + prevtx_err["redeemScript"] = "6a" # OP_RETURN + assert_raises_rpc_error(-8, "redeemScript does not match scriptPubKey", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err]) rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs - 1], prevtxs) rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs) @@ -192,7 +166,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): assert tx in node0.getblock(blk)["tx"] txinfo = node0.getrawtransaction(tx, True, blk) - self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"])) + self.log.info("n/m=%d/%d size=%d" % (self.nsigs, self.nkeys, txinfo["size"])) if __name__ == '__main__': From baa37c345cc46a5c2f8ba04f2076b07e73fc5395 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 15 Oct 2019 14:59:36 -0400 Subject: [PATCH 15/15] Merge #17138: Remove wallet access to some node arguments This backports also includes extra changes that were missing from bitcoin#14711 They are required, otherwise impossible to remove validaion.h dependency as it meant in #17138 b96ed0396294fc4fa89d83ceab6bc169dd09f002 [wallet] Remove pruning check for -rescan option (John Newbery) eea462de9c652dca556ad241d2126b10790f67f8 [wallet] Remove package limit config access from wallet (John Newbery) Pull request description: Removes wallet access to `-limitancestorcount`, `-limitdescendantcount` and `-prune`: - `-limitancestorcount` and `-limitdescendantcount` are now accessed with a method `getPackageLimits` in the `Chain` interface. - `-prune` is not required. It was only used in wallet component initiation to prevent running `-rescan` when pruning was enabled. This check is not required. Partially addresses #17137. ACKs for top commit: MarcoFalke: Tested ACK b96ed0396294fc4fa89d83ceab6bc169dd09f002 ryanofsky: Code review ACK b96ed0396294fc4fa89d83ceab6bc169dd09f002 promag: Code review ACK b96ed0396294fc4fa89d83ceab6bc169dd09f002. ariard: ACK b96ed03, check there isn't left anymore wallet access to node arguments. Tree-SHA512: 90c8e3e083acbd37724f1bccf63dab642cf9ae95cc5e684872a67443ae048b4fdbf57b52ea47c5a1da6489fd277278fe2d9bbe95e17f3d4965a1a0fbdeb815bf --- src/wallet/wallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f4aa3e22f8..42ff8da965 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #ifdef USE_BDB #include #endif @@ -3150,6 +3149,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain) */ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain) { + uint32_t const height = chain.getHeight().value_or(-1); uint32_t locktime; // Discourage fee sniping. // @@ -3172,7 +3172,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain) // now we ensure code won't be written that makes assumptions about // nLockTime that preclude a fix later. if (IsCurrentForAntiFeeSniping(chain)) { - locktime = chain.getHeight().value_or(-1); + locktime = height; // Secondly occasionally randomly pick a nLockTime even further back, so // that transactions that are delayed after signing for whatever reason, @@ -3187,7 +3187,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain) locktime = 0; } - assert(locktime <= (unsigned int)::ChainActive().Height()); + assert(locktime <= height); assert(locktime < LOCKTIME_THRESHOLD); return locktime; }