From c7c4806e7a0613a2d50ecb37d6d4756d6d47ecc6 Mon Sep 17 00:00:00 2001 From: Xinxi Wang Date: Sun, 4 Mar 2018 18:18:50 +0000 Subject: [PATCH] Litecoin: M prefix added for script addresses --- src/key_io.cpp | 11 ++- src/test/data/key_io_valid.json | 52 +++++------ test/functional/test_framework/address.py | 2 +- test/functional/test_runner.py | 1 + test/functional/wallet_scriptaddress2.py | 101 ++++++++++++++++++++++ test/util/data/txcreatemultisig5.json | 2 +- 6 files changed, 139 insertions(+), 30 deletions(-) create mode 100755 test/functional/wallet_scriptaddress2.py diff --git a/src/key_io.cpp b/src/key_io.cpp index 0cb4d0bf7..56129699f 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -34,7 +34,7 @@ public: std::string operator()(const ScriptHash& id) const { - std::vector data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); + std::vector data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS2); data.insert(data.end(), id.begin(), id.end()); return EncodeBase58Check(data); } @@ -82,13 +82,20 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin()); return PKHash(hash); } - // Script-hash-addresses have version 5 (or 196 testnet). + // Script-hash-addresses have version 5 for 3 prefix (or 196 testnet). // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. const std::vector& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) { std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin()); return ScriptHash(hash); } + // Script-hash-addresses have version 5 for M prefix (or 196 testnet). + // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. + const std::vector& script_prefix2 = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS2); + if (data.size() == hash.size() + script_prefix2.size() && std::equal(script_prefix2.begin(), script_prefix2.end(), data.begin())) { + std::copy(data.begin() + script_prefix2.size(), data.end(), hash.begin()); + return CScriptID(hash); + } } data.clear(); const auto dec = bech32::Decode(str); diff --git a/src/test/data/key_io_valid.json b/src/test/data/key_io_valid.json index fb4f544b9..67d6fd3ca 100644 --- a/src/test/data/key_io_valid.json +++ b/src/test/data/key_io_valid.json @@ -8,8 +8,8 @@ } ], [ - "3QiEMZmknJkHxz9q2VjTCT1tvUicLvBpdZ", - "fc85afab90ad569ed50fe8771d70aff8a7eb788d", + "MDpbgJxvdDJk7YH5BVzsUfsKse3N9YCE3o", + "a91440f3ea941f260592f9c9433f0250dfe7e5fb128e87", { "chain": "main", "isPrivkey": false @@ -32,8 +32,8 @@ } ], [ - "6uyyEQaLajn2bVG4DQ9LkwKqdTLWv5fxzSgBBwFMhZnY6SHamHF", - "716bbb0c59dc95f658b169b09c9ada6b106d79ef637dc0a1361aea83b67f3281", + "Qg23fQdzYjbW3mo4MtJDMkZsWQgm3kVemM", + "a914d4f756e1a19ede4011f5839e309da0c43fbee4e887", { "chain": "signet", "isPrivkey": false @@ -136,8 +136,8 @@ } ], [ - "6w3nZ8BsJLuJwe42QpFAwCZC9EFz4e2k1ewhRT9ab2poUv8KSu7", - "fdc80a3b189a9d64a1fb8e5a9905d92922f77e135a235a06046147f10d4f09be", + "MGrt3HGGHwL5vZ3ecCzdMEbmnFKcE9EeJW", + "a914624ac89642e04d39ce36976e861a022742cc127a87", { "chain": "main", "isPrivkey": false, @@ -154,8 +154,8 @@ } ], [ - "92hDYngM3s5oLTK6Fsq1JKLLSgL5NdarzLm8r9ymzEfQzCB24cJ", - "92001dd4cb225cdc0cf9fe2f824c807ffedd5235c9c0ca014949d0793fc66868", + "QdieUEwPPkt5beUreupi9njiiqzpPqTKWP", + "a914bbbca803acbbe7a2153f0cac05491b624c72426b87", { "chain": "main", "isPrivkey": false, @@ -208,8 +208,8 @@ } ], [ - "6vfWJ2KcJLjvXXx8aZNsLcQQnxTvXA38ci22BvhprTq5QpRS6k6", - "cb30eec426333b2396d2362d4a380d7f6a4ae50a2701309a53f500fa389c166c", + "MKuuxLCpf575SnN6ouhfUmnDYbvyDTQBet", + "a91483c601cee58d9324d8797e04c360971a7222a25387", { "chain": "signet", "isPrivkey": false, @@ -226,8 +226,8 @@ } ], [ - "93C56vYXBM3XycR9M9pDNY333bTLT8KeqTpRXKSncruKpeuvfZ5", - "d3849230c2d8bd3590708a8ff485deea6a73916a664255f95179282b146854fe", + "QaRx8KN1Rnh661srYaspaq1whQPdUpq4pF", + "a91497abf24db1094d659b319fafbdb5995ffc6e5ff487", { "chain": "signet", "isPrivkey": false, @@ -280,8 +280,8 @@ } ], [ - "6uM1BTu9jkS6cMfFTtxzutmcNQYVpTome57XhxES6xKiiN7eM4v", - "1d7bee7a5f4be2bcd945a4bdce28a479bb1afcf4d925d29de0124325bb55277d", + "MQrxASS6brp3bASypWeKFqTCFbvJLcwQPE", + "a914ba0f3b5ba0efb58cda3e55f13b18462c971e6df987", { "chain": "main", "isPrivkey": false @@ -296,8 +296,8 @@ } ], [ - "91epwsbfDsLwAum2kYeibW9v3cyM9ALeHxFoR1wh7g8w58gihCj", - "08e0d6cf0999a1427830e034b5281c8112d707d463da05d993d8b2b66985d91f", + "QQo4rKLgyqkBLFsSEWFrgBwrH9eGhmcfbT", + "a9142df90970f496d9e6e165a69dacd1417f082c5cf587", { "chain": "test", "isPrivkey": false @@ -353,8 +353,8 @@ } ], [ - "T34vLND26MHR4j1L8qsmojWcHtwYcmDdibMrsgo41SRYDDDdJzQe", - "007c379af039e5472c784a1f41ccea5de8b8d6fde03139644f12294a5a4dc20d", + "MQS7zSkUt9PcbchboBEkg97g7ZojRxoXPW", + "a914b55d095bc6c28b86d87b313442aa3ee454e49cce87", { "chain": "main", "isCompressed": true, @@ -371,8 +371,8 @@ } ], [ - "cUNY2YHa2TZRNMKBjypnZ1kh7LnPzgBhapKQgqh8MXGGVQTqdqQS", - "ca9a6a553f353255f2d91fde1718bd1f86c40c0b16f2aaccf8efefe242f5a7b6", + "QV5Ti6jZKGQF7D7erT2dkpFXf3UgfKAw9h", + "a9145cf346cd43ff078ca1d8dc62e39207470e2a496b87", { "chain": "test", "isCompressed": true, @@ -425,8 +425,8 @@ } ], [ - "T7qqfYACj4bdqNMm9ZMMNtbaMXRzePBpL59msQiWw7i5JRuDLFVB", - "8ef16edbbc8996a1be1c8a8d7de566a489a84484912060471158c0d20fcd42ba", + "M7wQbFTJZextk1bjbWc1c2WgNmAj41meXv", + "a914006cd1745e13749236c7064614d93d4650a79e4887", { "chain": "main", "isPrivkey": false, @@ -443,8 +443,8 @@ } ], [ - "cVWTK7AxBVgndSKS6Xs54XonuEh4NUhaHVtyzrWhHfQ2rLWdVrNy", - "ec83a732c245dc6df111d6412aa1b2ed78072ae3ebaa499660ccb7f013adca8f", + "QeEUMazrWFAp7UTwHgxQ9aVtdER4e4E9aY", + "a914c160b11a8a042e801487f9f0c13be0246adff58687", { "chain": "main", "isPrivkey": false, @@ -497,8 +497,8 @@ } ], [ - "tb1qu4p26n0033720xm0rjgkds5ehdwf039k2fgv75um5krrvfhrrj7qckl9r2", - "0020e542ad4def8c7ca79b6f1c9166c299bb5c97c4b65250cf539ba5863626e31cbc", + "M825mF1bLC3hPL6ZmaEVqZ2pouU5iRE72D", + "a914014f2e7072e9907c7f636d937759b8ceb1053feb87", { "chain": "signet", "isPrivkey": false, diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index 360962b8d..6004db23a 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -82,7 +82,7 @@ def keyhash_to_p2pkh(hash, main=False): def scripthash_to_p2sh(hash, main=False): assert len(hash) == 20 - version = 5 if main else 196 + version = 5 if main else 58 return byte_to_base58(hash, version) def key_to_p2pkh(key, main=False): diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 22c44be0c..bd8d8a7bb 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -240,6 +240,7 @@ BASE_SCRIPTS = [ 'p2p_leak.py', 'wallet_encryption.py', 'wallet_encryption.py --descriptors', + 'wallet_scriptaddress2.py', 'feature_dersig.py', 'feature_cltv.py', 'rpc_uptime.py', diff --git a/test/functional/wallet_scriptaddress2.py b/test/functional/wallet_scriptaddress2.py new file mode 100755 index 000000000..586c08962 --- /dev/null +++ b/test/functional/wallet_scriptaddress2.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 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 new Litecoin multisig prefix functionality. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + connect_nodes, +) + +class ScriptAddress2Test(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 3 + self.setup_clean_chain = False + self.extra_args = [['-addresstype=legacy', '-deprecatedrpc=accounts'], [], []] + + def setup_network(self, split=False): + self.setup_nodes() + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + self.sync_all() + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + cnt = self.nodes[0].getblockcount() + + # Mine some blocks + self.nodes[1].generate(101) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 101): + raise AssertionError("Failed to mine 100 blocks") + + addr = self.nodes[0].getnewaddress() + addr2 = self.nodes[0].getnewaddress() + + multisig_addr = self.nodes[0].addmultisigaddress(2, [addr, addr2], "multisigaccount")['address'] + assert_equal(multisig_addr[0], 'Q') + + # Send to a new multisig address + txid = self.nodes[1].sendtoaddress(multisig_addr, 1) + self.nodes[1].generate(3) + self.sync_all() + tx = self.nodes[2].getrawtransaction(txid, 1) + dest_addrs = [tx["vout"][0]['scriptPubKey']['addresses'][0], + tx["vout"][1]['scriptPubKey']['addresses'][0]] + assert(multisig_addr in dest_addrs) + + # Spend from the new multisig address + addr3 = self.nodes[1].getnewaddress() + txid = self.nodes[0].sendfrom("multisigaccount", addr3, 0.8) + self.nodes[0].generate(2) + self.sync_all() + assert(self.nodes[0].getbalance("multisigaccount", 1) < 0.2) + assert(self.nodes[1].listtransactions()[-1]['address'] == addr3) + + # Send to an old multisig address. The api addmultisigaddress + # can only generate a new address so we manually compute + # multisig_addr_old beforehand using an old client. + priv_keys = ["cU7eeLPKzXeKMeZvnEJhvZZ3tLqVF3XGeo1BbM8dnbmV7pP3Qg89", + "cTw7mRhSvTfzqCt6MFgBoTBqwBpYu2rWugisXcwjv4cAASh3iqPt"] + + addrs = ["mj6gNGRXPXrD69R5ApjcsDerZGrYKSfb6v", + "mqET4JA3L7P7FoUjUP3F6m6YsLpCkyzzou"] + + self.nodes[0].importprivkey(priv_keys[0]) + self.nodes[0].importprivkey(priv_keys[1]) + + multisig_addr_new = self.nodes[0].addmultisigaddress(2, addrs, "multisigaccount2")['address'] + assert_equal(multisig_addr_new, 'QZ974ZrPrmqMmm1PSVp4m8YEgo3bCQZBbe') + multisig_addr_old = "2N5nLwYz9qfnGdaFLpPn3gS6oYQbmLTWPjq" + + # Let's send to the old address. We can then find it in the + # new address with the new client. So basically the old + # address and the new one are the same thing. + txid = self.nodes[1].sendtoaddress(multisig_addr_old, 1) + self.nodes[1].generate(1) + self.sync_all() + tx = self.nodes[2].getrawtransaction(txid, 1) + dest_addrs = [tx["vout"][0]['scriptPubKey']['addresses'][0], + tx["vout"][1]['scriptPubKey']['addresses'][0]] + + assert(multisig_addr_new in dest_addrs) + assert(multisig_addr_old not in dest_addrs) + + # Spend from the new multisig address + addr4 = self.nodes[1].getnewaddress() + txid = self.nodes[0].sendfrom("multisigaccount2", addr4, 0.8) + self.nodes[0].generate(2) + self.sync_all() + assert(self.nodes[0].getbalance("multisigaccount2", 1) < 0.2) + assert(self.nodes[1].listtransactions()[-1]['address'] == addr4) + +if __name__ == '__main__': + ScriptAddress2Test().main() diff --git a/test/util/data/txcreatemultisig5.json b/test/util/data/txcreatemultisig5.json index ea07822dd..e039c0671 100644 --- a/test/util/data/txcreatemultisig5.json +++ b/test/util/data/txcreatemultisig5.json @@ -18,7 +18,7 @@ "reqSigs": 1, "type": "scripthash", "addresses": [ - "3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos" + "MNrRAu4FS5FQt4FoMX8rDTn7wj5KUunnGr" ] } }