From 837ee5b597eae126235c02462cfc2939fad1df2d Mon Sep 17 00:00:00 2001 From: Xinxi Wang Date: Sat, 14 Jan 2017 13:17:42 +0000 Subject: [PATCH] Litecoin: M prefix added for script addresses --- src/base58.cpp | 29 +++++--- src/base58.h | 4 +- src/test/base58_tests.cpp | 2 +- test/functional/test_runner.py | 1 + test/functional/test_script_address2.py | 97 +++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 test/functional/test_script_address2.py diff --git a/src/base58.cpp b/src/base58.cpp index c70e358eb..220a95420 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -216,12 +216,18 @@ class CBitcoinAddressVisitor : public boost::static_visitor { private: CBitcoinAddress* addr; + CChainParams::Base58Type script_type_; public: - CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {} + CBitcoinAddressVisitor(CBitcoinAddress* addrIn, CChainParams::Base58Type script_type) + : addr(addrIn), script_type_(script_type) + { + assert(script_type == CChainParams::SCRIPT_ADDRESS || + script_type == CChainParams::SCRIPT_ADDRESS2); + } bool operator()(const CKeyID& id) const { return addr->Set(id); } - bool operator()(const CScriptID& id) const { return addr->Set(id); } + bool operator()(const CScriptID& id) const { return addr->Set(id, script_type_); } bool operator()(const CNoDestination& no) const { return false; } }; @@ -233,15 +239,17 @@ bool CBitcoinAddress::Set(const CKeyID& id) return true; } -bool CBitcoinAddress::Set(const CScriptID& id) +bool CBitcoinAddress::Set(const CScriptID& id, CChainParams::Base58Type type) { - SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); + assert(type == CChainParams::SCRIPT_ADDRESS || type == CChainParams::SCRIPT_ADDRESS2); + SetData(Params().Base58Prefix(type), &id, 20); return true; } -bool CBitcoinAddress::Set(const CTxDestination& dest) +bool CBitcoinAddress::Set(const CTxDestination& dest, CChainParams::Base58Type type) { - return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); + assert(type == CChainParams::SCRIPT_ADDRESS || type == CChainParams::SCRIPT_ADDRESS2); + return boost::apply_visitor(CBitcoinAddressVisitor(this, type), dest); } bool CBitcoinAddress::IsValid() const @@ -253,7 +261,8 @@ bool CBitcoinAddress::IsValid(const CChainParams& params) const { bool fCorrectSize = vchData.size() == 20; bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) || - vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); + vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS) || + vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS2); return fCorrectSize && fKnownVersion; } @@ -265,7 +274,8 @@ CTxDestination CBitcoinAddress::Get() const memcpy(&id, vchData.data(), 20); if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) return CKeyID(id); - else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) + else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS) || + vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS2)) return CScriptID(id); else return CNoDestination(); @@ -283,7 +293,8 @@ bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const bool CBitcoinAddress::IsScript() const { - return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); + return IsValid() && (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS) || + vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS2)); } void CBitcoinSecret::SetKey(const CKey& vchSecret) diff --git a/src/base58.h b/src/base58.h index db12208f7..12572277e 100644 --- a/src/base58.h +++ b/src/base58.h @@ -104,8 +104,8 @@ public: class CBitcoinAddress : public CBase58Data { public: bool Set(const CKeyID &id); - bool Set(const CScriptID &id); - bool Set(const CTxDestination &dest); + bool Set(const CScriptID &id, CChainParams::Base58Type type=CChainParams::SCRIPT_ADDRESS2); + bool Set(const CTxDestination &dest, CChainParams::Base58Type type=CChainParams::SCRIPT_ADDRESS2); bool IsValid() const; bool IsValid(const CChainParams ¶ms) const; diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index b33cdb9fe..8c2a61d2d 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) continue; } CBitcoinAddress addrOut; - BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest); + BOOST_CHECK_MESSAGE(addrOut.Set(dest, CChainParams::SCRIPT_ADDRESS), "encode dest: " + strTest); BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest); } } diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index ca74bb68d..337fbc823 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -107,6 +107,7 @@ BASE_SCRIPTS= [ 'invalidtxrequest.py', 'p2p-versionbits-warning.py', 'preciousblock.py', + 'test_script_address2.py', 'importprunedfunds.py', 'signmessages.py', 'nulldummy.py', diff --git a/test/functional/test_script_address2.py b/test/functional/test_script_address2.py new file mode 100644 index 000000000..57f63ed67 --- /dev/null +++ b/test/functional/test_script_address2.py @@ -0,0 +1,97 @@ +#!/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 * +import decimal + +class ScriptAddress2Test(BitcoinTestFramework): + def __init__(self): + super().__init__() + self.num_nodes = 3 + self.setup_clean_chain = False + + def setup_network(self): + self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + self.is_network_split = False + self.sync_all() + + def run_test(self): + cnt = self.nodes[0].getblockcount() + + # Mine some blocks + self.nodes[1].generate(100) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 100): + 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") + assert_equal(multisig_addr[0], 'Q') + + # Send to a new multisig address + txid = self.nodes[1].sendtoaddress(multisig_addr, 1) + block = 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) + block = 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") + 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) + block = 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) + block = 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()