ttests: sends between wallets - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 68d891941667f707474198b024d7d723ac0de405
 (DIR) parent e13183ea7a4d43c861a973f4792980d637005074
 (HTM) Author: SomberNight <somber.night@protonmail.com>
       Date:   Fri, 27 Apr 2018 21:43:46 +0200
       
       ttests: sends between wallets
       
       Diffstat:
         M lib/tests/test_wallet_vertical.py   |     225 +++++++++++++++++++++++++++++--
       
       1 file changed, 214 insertions(+), 11 deletions(-)
       ---
 (DIR) diff --git a/lib/tests/test_wallet_vertical.py b/lib/tests/test_wallet_vertical.py
       t@@ -1,11 +1,11 @@
        import unittest
        from unittest import mock
        
       -import lib.bitcoin as bitcoin
       -import lib.keystore as keystore
       -import lib.storage as storage
       -import lib.wallet as wallet
       -from lib import constants
       +import lib
       +from lib import storage, bitcoin, keystore, constants
       +from lib.transaction import Transaction
       +from lib.simple_config import SimpleConfig
       +from lib.wallet import TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_UNCONF_PARENT
        
        from plugins.trustedcoin import trustedcoin
        
       t@@ -31,16 +31,16 @@ class WalletIntegrityHelper:
                test_obj.assertFalse(ks.has_seed())
        
            @classmethod
       -    def create_standard_wallet(cls, ks):
       +    def create_standard_wallet(cls, ks, gap_limit=None):
                store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
                store.put('keystore', ks.dump())
       -        store.put('gap_limit', cls.gap_limit)
       -        w = wallet.Standard_Wallet(store)
       +        store.put('gap_limit', gap_limit or cls.gap_limit)
       +        w = lib.wallet.Standard_Wallet(store)
                w.synchronize()
                return w
        
            @classmethod
       -    def create_multisig_wallet(cls, ks1, ks2, ks3=None):
       +    def create_multisig_wallet(cls, ks1, ks2, ks3=None, gap_limit=None):
                """Creates a 2-of-2 or 2-of-3 multisig wallet."""
                store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
                store.put('x%d/' % 1, ks1.dump())
       t@@ -51,8 +51,8 @@ class WalletIntegrityHelper:
                    multisig_type = "%dof%d" % (2, 3)
                    store.put('x%d/' % 3, ks3.dump())
                store.put('wallet_type', multisig_type)
       -        store.put('gap_limit', cls.gap_limit)
       -        w = wallet.Multisig_Wallet(store)
       +        store.put('gap_limit', gap_limit or cls.gap_limit)
       +        w = lib.wallet.Multisig_Wallet(store)
                w.synchronize()
                return w
        
       t@@ -314,3 +314,206 @@ class TestWalletKeystoreAddressIntegrityForTestnet(TestCaseForTestnet):
        
                self.assertEqual(w.get_receiving_addresses()[0], '2MzsfTfTGomPRne6TkctMmoDj6LwmVkDrMt')
                self.assertEqual(w.get_change_addresses()[0], '2NFp9w8tbYYP9Ze2xQpeYBJQjx3gbXymHX7')
       +
       +
       +class TestWalletSending(TestCaseForTestnet):
       +
       +    config = SimpleConfig()
       +
       +    def create_standard_wallet_from_seed(self, seed_words):
       +        ks = keystore.from_seed(seed_words, '', False)
       +        return WalletIntegrityHelper.create_standard_wallet(ks, gap_limit=2)
       +
       +    @mock.patch.object(storage.WalletStorage, '_write')
       +    def test_sending_between_p2wpkh_and_compressed_p2pkh(self, mock_write):
       +        wallet1 = self.create_standard_wallet_from_seed('bitter grass shiver impose acquire brush forget axis eager alone wine silver')
       +        wallet2 = self.create_standard_wallet_from_seed('cycle rocket west magnet parrot shuffle foot correct salt library feed song')
       +
       +        # bootstrap wallet1
       +        funding_tx = Transaction('01000000014576dacce264c24d81887642b726f5d64aa7825b21b350c7b75a57f337da6845010000006b483045022100a3f8b6155c71a98ad9986edd6161b20d24fad99b6463c23b463856c0ee54826d02200f606017fd987696ebbe5200daedde922eee264325a184d5bbda965ba5160821012102e5c473c051dae31043c335266d0ef89c1daab2f34d885cc7706b267f3269c609ffffffff0240420f00000000001600148a28bddb7f61864bdcf58b2ad13d5aeb3abc3c42a2ddb90e000000001976a914c384950342cb6f8df55175b48586838b03130fad88ac00000000')
       +        funding_txid = funding_tx.txid()
       +        funding_output_value = 1000000
       +        self.assertEqual('add2535aedcbb5ba79cc2260868bb9e57f328738ca192937f2c92e0e94c19203', funding_txid)
       +        wallet1.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet1 -> wallet2
       +        outputs = [(bitcoin.TYPE_ADDRESS, wallet2.get_receiving_address(), 250000)]
       +        tx = wallet1.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
       +
       +        self.assertTrue(tx.is_complete())
       +        self.assertTrue(tx.is_segwit())
       +        self.assertEqual(1, len(tx.inputs()))
       +        tx_copy = Transaction(tx.serialize())
       +        self.assertEqual(wallet1.is_mine(tx.inputs()[0]['address']), wallet1.is_mine(tx_copy.inputs()[0]['address']))
       +        self.assertTrue(wallet1.is_mine(tx.inputs()[0]['address']))
       +        self.assertEqual(wallet1.txin_type, tx_copy.inputs()[0]['type'])
       +        self.assertEqual(tx.wtxid(), tx_copy.wtxid())
       +        self.assertEqual('3c06ae4d9be8226a472b3e7f7c127c7e3016f525d658d26106b80b4c7e3228e2', tx_copy.txid())
       +
       +        wallet1.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)  # TX_HEIGHT_UNCONF_PARENT but nvm
       +        wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet2 -> wallet1
       +        outputs = [(bitcoin.TYPE_ADDRESS, wallet1.get_receiving_address(), 100000)]
       +        tx = wallet2.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
       +
       +        self.assertTrue(tx.is_complete())
       +        self.assertFalse(tx.is_segwit())
       +        self.assertEqual(1, len(tx.inputs()))
       +        tx_copy = Transaction(tx.serialize())
       +        self.assertEqual(wallet2.is_mine(tx.inputs()[0]['address']), wallet2.is_mine(tx_copy.inputs()[0]['address']))
       +        self.assertTrue(wallet2.is_mine(tx.inputs()[0]['address']))
       +        self.assertEqual(wallet2.txin_type, tx_copy.inputs()[0]['type'])
       +        self.assertEqual(tx.wtxid(), tx_copy.wtxid())
       +        self.assertEqual('5f25707571eb776bdf14142f9966bf2a681906e0a79501edbb99a972c2ceb972', tx_copy.txid())
       +
       +        wallet1.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +        wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet level checks
       +        self.assertEqual((0, funding_output_value - 250000 - 5000 + 100000, 0), wallet1.get_balance())
       +        self.assertEqual((0, 250000 - 5000 - 100000, 0), wallet2.get_balance())
       +
       +    @mock.patch.object(storage.WalletStorage, '_write')
       +    def test_sending_between_p2sh_2of3_and_uncompressed_p2pkh(self, mock_write):
       +        wallet1a = WalletIntegrityHelper.create_multisig_wallet(
       +            keystore.from_seed('blast uniform dragon fiscal ensure vast young utility dinosaur abandon rookie sure', '', True),
       +            keystore.from_xpub('tpubD6NzVbkrYhZ4YTPEgwk4zzr8wyo7pXGmbbVUnfYNtx6SgAMF5q3LN3Kch58P9hxGNsTmP7Dn49nnrmpE6upoRb1Xojg12FGLuLHkVpVtS44'),
       +            keystore.from_xpub('tpubD6NzVbkrYhZ4XJzYkhsCbDCcZRmDAKSD7bXi9mdCni7acVt45fxbTVZyU6jRGh29ULKTjoapkfFsSJvQHitcVKbQgzgkkYsAmaovcro7Mhf'),
       +            gap_limit=2
       +        )
       +        wallet1b = WalletIntegrityHelper.create_multisig_wallet(
       +            keystore.from_seed('cycle rocket west magnet parrot shuffle foot correct salt library feed song', '', True),
       +            keystore.from_xpub('tpubD6NzVbkrYhZ4YTPEgwk4zzr8wyo7pXGmbbVUnfYNtx6SgAMF5q3LN3Kch58P9hxGNsTmP7Dn49nnrmpE6upoRb1Xojg12FGLuLHkVpVtS44'),
       +            keystore.from_xpub('tpubD6NzVbkrYhZ4YARFMEZPckrqJkw59GZD1PXtQnw14ukvWDofR7Z1HMeSCxfYEZVvg4VdZ8zGok5VxHwdrLqew5cMdQntWc5mT7mh1CSgrnX'),
       +            gap_limit=2
       +        )
       +        # ^ third seed: ghost into match ivory badge robot record tackle radar elbow traffic loud
       +        wallet2 = self.create_standard_wallet_from_seed('powerful random nobody notice nothing important anyway look away hidden message over')
       +
       +        # bootstrap wallet1
       +        funding_tx = Transaction('010000000001014121f99dc02f0364d2dab3d08905ff4c36fc76c55437fd90b769c35cc18618280100000000fdffffff02d4c22d00000000001600143fd1bc5d32245850c8cb5be5b09c73ccbb9a0f75001bb7000000000017a91480c2353f6a7bc3c71e99e062655b19adb3dd2e4887024830450221008781c78df0c9d4b5ea057333195d5d76bc29494d773f14fa80e27d2f288b2c360220762531614799b6f0fb8d539b18cb5232ab4253dd4385435157b28a44ff63810d0121033de77d21926e09efd04047ae2d39dbd3fb9db446e8b7ed53e0f70f9c9478f735dac11300')
       +        funding_txid = funding_tx.txid()
       +        funding_output_value = 12000000
       +        self.assertEqual('b25cd55687c9e528c2cfd546054f35fb6741f7cf32d600f07dfecdf2e1d42071', funding_txid)
       +        wallet1a.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet1 -> wallet2
       +        outputs = [(bitcoin.TYPE_ADDRESS, wallet2.get_receiving_address(), 370000)]
       +        tx = wallet1a.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
       +        tx = Transaction(tx.serialize())  # simulates moving partial txn between cosigners
       +        self.assertFalse(tx.is_complete())
       +        wallet1b.sign_transaction(tx, password=None)
       +
       +        self.assertTrue(tx.is_complete())
       +        self.assertFalse(tx.is_segwit())
       +        self.assertEqual(1, len(tx.inputs()))
       +        tx_copy = Transaction(tx.serialize())
       +        self.assertEqual(wallet1a.is_mine(tx.inputs()[0]['address']), wallet1a.is_mine(tx_copy.inputs()[0]['address']))
       +        self.assertTrue(wallet1a.is_mine(tx.inputs()[0]['address']))
       +        self.assertEqual(wallet1a.txin_type, tx_copy.inputs()[0]['type'])
       +        self.assertEqual(tx.wtxid(), tx_copy.wtxid())
       +        self.assertEqual('26f3bdd0402e1cff19126244ebe3d32722cef0db507c7229ca8754f5e06ef25d', tx_copy.txid())
       +
       +        wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +        wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet2 -> wallet1
       +        outputs = [(bitcoin.TYPE_ADDRESS, wallet1a.get_receiving_address(), 100000)]
       +        tx = wallet2.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
       +
       +        self.assertTrue(tx.is_complete())
       +        self.assertFalse(tx.is_segwit())
       +        self.assertEqual(1, len(tx.inputs()))
       +        tx_copy = Transaction(tx.serialize())
       +        self.assertEqual(wallet2.is_mine(tx.inputs()[0]['address']), wallet2.is_mine(tx_copy.inputs()[0]['address']))
       +        self.assertTrue(wallet2.is_mine(tx.inputs()[0]['address']))
       +        self.assertEqual(wallet2.txin_type, tx_copy.inputs()[0]['type'])
       +        self.assertEqual(tx.wtxid(), tx_copy.wtxid())
       +        self.assertEqual('c573b3f8464a4ed40dfc79d0889a780f44e917beef7a75883b2427c2987f3e95', tx_copy.txid())
       +
       +        wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +        wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet level checks
       +        self.assertEqual((0, funding_output_value - 370000 - 5000 + 100000, 0), wallet1a.get_balance())
       +        self.assertEqual((0, 370000 - 5000 - 100000, 0), wallet2.get_balance())
       +
       +    @mock.patch.object(storage.WalletStorage, '_write')
       +    def test_sending_between_p2wsh_2of3_and_p2wsh_p2sh_2of2(self, mock_write):
       +        wallet1a = WalletIntegrityHelper.create_multisig_wallet(
       +            keystore.from_seed('bitter grass shiver impose acquire brush forget axis eager alone wine silver', '', True),
       +            keystore.from_xpub('Vpub5fcdcgEwTJmbmqAktuK8Kyq92fMf7sWkcP6oqAii2tG47dNbfkGEGUbfS9NuZaRywLkHE6EmUksrqo32ZL3ouLN1HTar6oRiHpDzKMAF1tf'),
       +            keystore.from_xpub('Vpub5fjkKyYnvSS4wBuakWTkNvZDaBM2vQ1MeXWq368VJHNr2eT8efqhpmZ6UUkb7s2dwCXv2Vuggjdhk4vZVyiAQTwUftvff73XcUGq2NQmWra'),
       +            gap_limit=2
       +        )
       +        wallet1b = WalletIntegrityHelper.create_multisig_wallet(
       +            keystore.from_seed('snow nest raise royal more walk demise rotate smooth spirit canyon gun', '', True),
       +            keystore.from_xpub('Vpub5fjkKyYnvSS4wBuakWTkNvZDaBM2vQ1MeXWq368VJHNr2eT8efqhpmZ6UUkb7s2dwCXv2Vuggjdhk4vZVyiAQTwUftvff73XcUGq2NQmWra'),
       +            keystore.from_xpub('Vpub5gSKXzxK7FeKQedu2q1z9oJWxqvX72AArW3HSWpEhc8othDH8xMDu28gr7gf17sp492BuJod8Tn7anjvJrKpETwqnQqX7CS8fcYyUtedEMk'),
       +            gap_limit=2
       +        )
       +        # ^ third seed: hedgehog sunset update estate number jungle amount piano friend donate upper wool
       +        wallet2a = WalletIntegrityHelper.create_multisig_wallet(
       +            # bip39: finish seminar arrange erosion sunny coil insane together pretty lunch lunch rose, der: m/1234'/1'/0', p2wsh-p2sh multisig
       +            keystore.from_xprv('Uprv9CvELvByqm8k2dpecJVjgLMX1z5DufEjY4fBC5YvdGF5WjGCa7GVJJ2fYni1tyuF7Hw83E6W2ZBjAhaFLZv2ri3rEsubkCd5avg4EHKoDBN'),
       +            keystore.from_xpub('Upub5Qb8ik4Cnu8g97KLXKgVXHqY6tH8emQvqtBncjSKsyfTZuorPtTZgX7ovKKZHuuVGBVd1MTTBkWez1XXt2weN1sWBz6SfgRPQYEkNgz81QF'),
       +            gap_limit=2
       +        )
       +        wallet2b = WalletIntegrityHelper.create_multisig_wallet(
       +            # bip39: square page wood spy oil story rebel give milk screen slide shuffle, der: m/1234'/1'/0', p2wsh-p2sh multisig
       +            keystore.from_xprv('Uprv9BbnKEXJxXaNvdEsRJ9VA9toYrSeFJh5UfGBpM2iKe8Uh7UhrM9K8ioL53s8gvCoGfirHHaqpABDAE7VUNw8LNU1DMJKVoWyeNKu9XcDC19'),
       +            keystore.from_xpub('Upub5RuakRisg8h3F7u7iL2k3UJFa1uiK7xauHamzTxYBbn4PXbM7eajr6M9Q2VCr6cVGhfhqWQqxnABvtSATuVM1xzxk4nA189jJwzaMn1QX7V'),
       +            gap_limit=2
       +        )
       +
       +        # bootstrap wallet1
       +        funding_tx = Transaction('01000000000101a41aae475d026c9255200082c7fad26dc47771275b0afba238dccda98a597bd20000000000fdffffff02400d0300000000002200203c43ac80d6e3015cf378bf6bac0c22456723d6050bef324ec641e7762440c63c9dcd410000000000160014824626055515f3ed1d2cfc9152d2e70685c71e8f02483045022100b9f39fad57d07ce1e18251424034f21f10f20e59931041b5167ae343ce973cf602200fefb727fa0ffd25b353f1bcdae2395898fe407b692c62f5885afbf52fa06f5701210301a28f68511ace43114b674371257bb599fd2c686c4b19544870b1799c954b40e9c11300')
       +        funding_txid = funding_tx.txid()
       +        funding_output_value = 200000
       +        self.assertEqual('d2bd6c9d332db8e2c50aa521cd50f963fba214645aab2f7556e061a412103e21', funding_txid)
       +        wallet1a.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet1 -> wallet2
       +        outputs = [(bitcoin.TYPE_ADDRESS, wallet2a.get_receiving_address(), 165000)]
       +        tx = wallet1a.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
       +        tx = Transaction(tx.serialize())  # simulates moving partial txn between cosigners
       +        self.assertFalse(tx.is_complete())
       +        wallet1b.sign_transaction(tx, password=None)
       +
       +        self.assertTrue(tx.is_complete())
       +        self.assertTrue(tx.is_segwit())
       +        self.assertEqual(1, len(tx.inputs()))
       +        tx_copy = Transaction(tx.serialize())
       +        self.assertEqual(wallet1a.is_mine(tx.inputs()[0]['address']), wallet1a.is_mine(tx_copy.inputs()[0]['address']))
       +        self.assertTrue(wallet1a.is_mine(tx.inputs()[0]['address']))
       +        self.assertEqual(wallet1a.txin_type, tx_copy.inputs()[0]['type'])
       +        self.assertEqual(tx.wtxid(), tx_copy.wtxid())
       +        self.assertEqual('6e9c3cd8788bdb970a124ea06136d52bc01cec4f9b1e217627d5e90ebe77d049', tx_copy.txid())
       +
       +        wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +        wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet2 -> wallet1
       +        outputs = [(bitcoin.TYPE_ADDRESS, wallet1a.get_receiving_address(), 100000)]
       +        tx = wallet2a.mktx(outputs=outputs, password=None, config=self.config, fee=5000)
       +        tx = Transaction(tx.serialize())  # simulates moving partial txn between cosigners
       +        self.assertFalse(tx.is_complete())
       +        wallet2b.sign_transaction(tx, password=None)
       +
       +        self.assertTrue(tx.is_complete())
       +        self.assertTrue(tx.is_segwit())
       +        self.assertEqual(1, len(tx.inputs()))
       +        tx_copy = Transaction(tx.serialize())
       +        self.assertEqual(wallet2a.is_mine(tx.inputs()[0]['address']), wallet2a.is_mine(tx_copy.inputs()[0]['address']))
       +        self.assertTrue(wallet2a.is_mine(tx.inputs()[0]['address']))
       +        self.assertEqual(wallet2a.txin_type, tx_copy.inputs()[0]['type'])
       +        self.assertEqual(tx.wtxid(), tx_copy.wtxid())
       +        self.assertEqual('84b0dcb43022385f7a10e2710e5625a2be3cd6e390387b6100b55500d5eea8f6', tx_copy.txid())
       +
       +        wallet1a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +        wallet2a.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
       +
       +        # wallet level checks
       +        self.assertEqual((0, funding_output_value - 165000 - 5000 + 100000, 0), wallet1a.get_balance())
       +        self.assertEqual((0, 165000 - 5000 - 100000, 0), wallet2a.get_balance())