Beispiel #1
0
 async def asyncSetUp(self):
     self.ledger = Ledger({
         'db': Database(':memory:'),
         'headers': Headers(':memory:')
     })
     self.wallet = Wallet()
     await self.ledger.db.open()
Beispiel #2
0
 async def asyncSetUp(self):
     self.ledger = Ledger({
         'db': Database(':memory:'),
         'headers': Headers(':memory:')
     })
     self.account = Account.generate(self.ledger, Wallet(), "lbryum")
     await self.ledger.db.open()
Beispiel #3
0
 async def asyncSetUp(self):
     self.manager = WalletManager()
     config = {'data_path': '/tmp/wallet'}
     self.main_ledger = self.manager.get_or_create_ledger(
         Ledger.get_id(), config)
     self.test_ledger = self.manager.get_or_create_ledger(
         RegTestLedger.get_id(), config)
Beispiel #4
0
class TestTransactionSigning(AsyncioTestCase):
    async def asyncSetUp(self):
        self.ledger = Ledger({
            'db': Database(':memory:'),
            'headers': Headers(':memory:')
        })
        await self.ledger.db.open()

    async def asyncTearDown(self):
        await self.ledger.db.close()

    async def test_sign(self):
        account = Account.from_dict(
            self.ledger, Wallet(), {
                "seed":
                "carbon smart garage balance margin twelve chest sword toas"
                "t envelope bottom stomach absent"
            })

        await account.ensure_address_gap()
        address1, address2 = await account.receiving.get_addresses(limit=2)
        pubkey_hash1 = self.ledger.address_to_hash160(address1)
        pubkey_hash2 = self.ledger.address_to_hash160(address2)

        tx = Transaction() \
            .add_inputs([Input.spend(get_output(int(2*COIN), pubkey_hash1))]) \
            .add_outputs([Output.pay_pubkey_hash(int(1.9*COIN), pubkey_hash2)])

        await tx.sign([account])

        self.assertEqual(
            hexlify(tx.inputs[0].script.values['signature']),
            b'304402200dafa26ad7cf38c5a971c8a25ce7d85a076235f146126762296b1223c42ae21e022020ef9eeb8'
            b'398327891008c5c0be4357683f12cb22346691ff23914f457bf679601')
Beispiel #5
0
    def test_claim_signed_using_ecdsa_validates_with_coincurve(self):
        channel_tx = Transaction(
            unhexlify(
                "0100000001b91d829283c0d80cb8113d5f36b6da3dfe9df3e783f158bfb3fd1b2b178d7fc9010000006b48"
                "3045022100f4e2b4ee38388c3d3a62f4b12fdd413f6f140168e85884bbeb33a3f2d3159ef502201721200f"
                "4a4f3b87484d4f47c9054e31cd3ba451dd3886a7f9f854893e7c8cf90121023f9e906e0c120f3bf74feb40"
                "f01ddeafbeb1856d91938c3bef25bed06767247cffffffff0200e1f5050000000081b505406368616e4c5d"
                "00125a0a583056301006072a8648ce3d020106052b8104000a03420004d7fa13fd8e57f3a0b878eaaf3d17"
                "9144d25ddbe4a3e4440a661f51b4134c6a13c9c98678ff8411932e60fd97d7baf03ea67ebcc21097230cfb"
                "2241348aadb55e6d7576a9149c6d700f89c77f0e8c650ba05656f8f2392782d388acf47c95350000000019"
                "76a914d9502233e0e1fc76e13e36c546f704c3124d5eaa88ac00000000"))
        channel = channel_tx.outputs[0]

        stream_tx = Transaction(
            unhexlify(
                "010000000116a1d90763f2e3a2348c7fb438a23f232b15e3ffe3f058c3b2ab52c8bed8dcb5010000006b48"
                "30450221008f38561b3a16944c63b4f4f1562f1efe1b2060f31d249e234003ee5e3461756f02205773c99e"
                "83c968728e4f2433a13871c6ad23f6c10368ac52fa62a09f3f7ef5fd012102597f39845b98e2415b777aa0"
                "3849d346d287af7970deb05f11214b3418ae9d82ffffffff0200e1f50500000000fd0c01b505636c61696d"
                "4ce8012e6e40fa5fee1b915af3b55131dcbcebee34ab9148292b084ce3741f2e0db49783f3d854ac885f2b"
                "6304a76ef7048046e338dd414ba4c64e8468651768ffaaf550c8560637ac8c477ea481ac2a9264097240f4"
                "ab0a90010a8d010a3056bf5dbae43f77a63d075b0f2ae9c7c3e3098db93779c7f9840da0f4db9c2f8c8454"
                "f4edd1373e2b64ee2e68350d916e120b746d706c69647879363171180322186170706c69636174696f6e2f"
                "6f637465742d73747265616d3230f293f5acf4310562d4a41f6620167fe6d83761a98d36738908ce5c8776"
                "1642710e55352a396276a42eda92ff5856f46f6d7576a91434bd3dc4c45cc0635eb2ad5da658727e5442ca"
                "0f88ace82f902f000000001976a91427b27c89eaebf68d063c107241584c07e5a6ccc688ac00000000"
            ))
        stream = stream_tx.outputs[0]

        ledger = Ledger({
            'db': Database(':memory:'),
            'headers': Headers(':memory:')
        })
        self.assertTrue(stream.is_signed_by(channel, ledger))
Beispiel #6
0
 async def asyncSetUp(self):
     self.ledger = Ledger({
         'db': Database(':memory:'),
         'headers': Headers(':memory:')
     })
     await self.ledger.db.open()
     self.account = Account.generate(self.ledger, Wallet(), "torba", {'name': 'single-address'})
async def get_mock_wallet(sd_hash, storage, balance=10.0, fee=None):
    claim = Claim()
    if fee:
        if fee['currency'] == 'LBC':
            claim.stream.fee.lbc = Decimal(fee['amount'])
        elif fee['currency'] == 'USD':
            claim.stream.fee.usd = Decimal(fee['amount'])
    claim.stream.title = "33rpm"
    claim.stream.languages.append("en")
    claim.stream.source.sd_hash = sd_hash
    claim.stream.source.media_type = "image/png"

    tx = get_claim_transaction("33rpm", claim.to_bytes())
    tx.height = 514081
    txo = tx.outputs[0]
    txo.meta.update({
        "permanent_url": "33rpm#c49566d631226492317d06ad7fdbe1ed32925124",

    })

    class FakeHeaders:
        def estimated_timestamp(self, height):
            return 1984

        def __init__(self, height):
            self.height = height

        def __getitem__(self, item):
            return {'timestamp': 1984}

    wallet = Wallet()
    ledger = Ledger({
        'db': Database(':memory:'),
        'headers': FakeHeaders(514082)
    })
    await ledger.db.open()
    wallet.generate_account(ledger)
    manager = WalletManager()
    manager.config = Config()
    manager.wallets.append(wallet)
    manager.ledgers[Ledger] = ledger
    manager.ledger.network.client = ClientSession(
        network=manager.ledger.network, server=('fakespv.lbry.com', 50001)
    )

    async def mock_resolve(*args, **kwargs):
        result = {txo.meta['permanent_url']: txo}
        claims = [
            StreamManager._convert_to_old_resolve_output(manager, result)[txo.meta['permanent_url']]
        ]
        await storage.save_claims(claims)
        return result
    manager.ledger.resolve = mock_resolve

    async def get_balance(*_):
        return balance
    manager.get_balance = get_balance

    return manager, txo.meta['permanent_url']
Beispiel #8
0
    async def asyncSetUp(self):
        self.ledger = Ledger({
            'db': Database(':memory:'),
            'headers': Headers(':memory:')
        })
        await self.ledger.db.open()
        self.account = Account.from_dict(
            self.ledger, Wallet(), {
                "seed":
                "carbon smart garage balance margin twelve chest sword "
                "toast envelope bottom stomach absent"
            })

        addresses = await self.account.ensure_address_gap()
        self.pubkey_hash = [
            self.ledger.address_to_hash160(a) for a in addresses
        ]
        self.hash_cycler = cycle(self.pubkey_hash)
Beispiel #9
0
 async def create_tx_from_nothing(self, my_account, height):
     to_address = await my_account.receiving.get_or_create_usable_address()
     to_hash = Ledger.address_to_hash160(to_address)
     tx = Transaction(height=height, is_verified=True) \
         .add_inputs([self.txi(self.txo(1, sha256(str(height).encode())))]) \
         .add_outputs([self.txo(1, to_hash)])
     await self.ledger.db.insert_transaction(tx)
     await self.ledger.db.save_transaction_io(tx, to_address, to_hash, '')
     return tx
Beispiel #10
0
    async def test_reset_on_version_change(self):
        self.ledger = Ledger({
            'db': Database(self.path),
            'headers': Headers(':memory:')
        })

        # initial open, pre-version enabled db
        self.ledger.db.SCHEMA_VERSION = None
        self.assertListEqual(self.get_tables(), [])
        await self.ledger.db.open()
        self.assertEqual(
            self.get_tables(),
            ['account_address', 'pubkey_address', 'tx', 'txi', 'txo'])
        self.assertListEqual(self.get_addresses(), [])
        self.add_address('address1')
        await self.ledger.db.close()

        # initial open after version enabled
        self.ledger.db.SCHEMA_VERSION = '1.0'
        await self.ledger.db.open()
        self.assertEqual(self.get_version(), '1.0')
        self.assertListEqual(self.get_tables(), [
            'account_address', 'pubkey_address', 'tx', 'txi', 'txo', 'version'
        ])
        self.assertListEqual(self.get_addresses(),
                             [])  # address1 deleted during version upgrade
        self.add_address('address2')
        await self.ledger.db.close()

        # nothing changes
        self.assertEqual(self.get_version(), '1.0')
        self.assertListEqual(self.get_tables(), [
            'account_address', 'pubkey_address', 'tx', 'txi', 'txo', 'version'
        ])
        await self.ledger.db.open()
        self.assertEqual(self.get_version(), '1.0')
        self.assertListEqual(self.get_tables(), [
            'account_address', 'pubkey_address', 'tx', 'txi', 'txo', 'version'
        ])
        self.assertListEqual(self.get_addresses(), ['address2'])
        await self.ledger.db.close()

        # upgrade version, database reset
        self.ledger.db.SCHEMA_VERSION = '1.1'
        self.ledger.db.CREATE_TABLES_QUERY += """
        create table if not exists foo (bar text);
        """
        await self.ledger.db.open()
        self.assertEqual(self.get_version(), '1.1')
        self.assertListEqual(self.get_tables(), [
            'account_address', 'foo', 'pubkey_address', 'tx', 'txi', 'txo',
            'version'
        ])
        self.assertListEqual(self.get_addresses(), [])  # all tables got reset
        await self.ledger.db.close()
Beispiel #11
0
 async def create_tx_from_txo(self, txo, to_account, height):
     from_hash = txo.script.values['pubkey_hash']
     from_address = self.ledger.hash160_to_address(from_hash)
     to_address = await to_account.receiving.get_or_create_usable_address()
     to_hash = Ledger.address_to_hash160(to_address)
     tx = Transaction(height=height, is_verified=True) \
         .add_inputs([self.txi(txo)]) \
         .add_outputs([self.txo(1, to_hash)])
     await self.ledger.db.insert_transaction(tx)
     await self.ledger.db.save_transaction_io(tx, from_address, from_hash, '')
     await self.ledger.db.save_transaction_io(tx, to_address, to_hash, '')
     return tx
Beispiel #12
0
    async def asyncSetUp(self):
        wallet_dir = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, wallet_dir)
        self.ledger = Ledger({
            'db':
            Database(os.path.join(wallet_dir, 'blockchain.db')),
            'headers':
            Headers(':memory:'),
        })
        await self.ledger.db.open()
        self.account = Account.from_dict(
            self.ledger, Wallet(), {
                "seed":
                "carbon smart garage balance margin twelve chest sword "
                "toast envelope bottom stomach absent"
            })

        addresses = await self.account.ensure_address_gap()
        self.pubkey_hash = [
            self.ledger.address_to_hash160(a) for a in addresses
        ]
        self.hash_cycler = cycle(self.pubkey_hash)
Beispiel #13
0
    def test_signed_claim_made_by_ytsync(self):
        stream_tx = Transaction(
            unhexlify(
                b'0100000001eb2a756e15bde95db3d2ae4a6e9b2796a699087890644607b5b04a5f15b67062010000006a4'
                b'7304402206444b920bd318a07d9b982e30eb66245fdaaa6c9866e1f6e5900161d9b0ffd70022036464714'
                b'4f1830898a2042aa0d6cef95a243799cc6e36630a58d411e2f9111f00121029b15f9a00a7c3f21b10bd4b'
                b'98ab23a9e895bd9160e21f71317862bf55fbbc89effffffff0240420f0000000000fd1503b52268657265'
                b'2d6172652d352d726561736f6e732d692d6e657874636c6f75642d746c674dd302080110011aee0408011'
                b'2a604080410011a2b4865726520617265203520526561736f6e73204920e29da4efb88f204e657874636c'
                b'6f7564207c20544c4722920346696e64206f7574206d6f72652061626f7574204e657874636c6f75643a2'
                b'068747470733a2f2f6e657874636c6f75642e636f6d2f0a0a596f752063616e2066696e64206d65206f6e'
                b'20746865736520736f6369616c733a0a202a20466f72756d733a2068747470733a2f2f666f72756d2e686'
                b'5617679656c656d656e742e696f2f0a202a20506f64636173743a2068747470733a2f2f6f6666746f7069'
                b'63616c2e6e65740a202a2050617472656f6e3a2068747470733a2f2f70617472656f6e2e636f6d2f74686'
                b'56c696e757867616d65720a202a204d657263683a2068747470733a2f2f746565737072696e672e636f6d'
                b'2f73746f7265732f6f6666696369616c2d6c696e75782d67616d65720a202a205477697463683a2068747'
                b'470733a2f2f7477697463682e74762f786f6e64616b0a202a20547769747465723a2068747470733a2f2f'
                b'747769747465722e636f6d2f7468656c696e757867616d65720a0a2e2e2e0a68747470733a2f2f7777772'
                b'e796f75747562652e636f6d2f77617463683f763d4672546442434f535f66632a0f546865204c696e7578'
                b'2047616d6572321c436f7079726967687465642028636f6e7461637420617574686f722938004a2968747'
                b'470733a2f2f6265726b2e6e696e6a612f7468756d626e61696c732f4672546442434f535f666352005a00'
                b'1a41080110011a30040e8ac6e89c061f982528c23ad33829fd7146435bf7a4cc22f0bff70c4fe0b91fd36'
                b'da9a375e3e1c171db825bf5d1f32209766964656f2f6d70342a5c080110031a4062b2dd4c45e364030fbf'
                b'ad1a6fefff695ebf20ea33a5381b947753e2a0ca359989a5cc7d15e5392a0d354c0b68498382b2701b22c'
                b'03beb8dcb91089031b871e72214feb61536c007cdf4faeeaab4876cb397feaf6b516d7576a914f4f43f6f'
                b'7a472bbf27fa3630329f771135fc445788ac86ff0600000000001976a914cef0fe3eeaf04416f0c3ff3e7'
                b'8a598a081e70ee788ac00000000'))
        stream = stream_tx.outputs[0]

        channel_tx = Transaction(
            unhexlify(
                b'010000000192a1e1e3f66b8ca05a021cfa5fb6645ebc066b46639ccc9b3781fa588a88da65010000006a4'
                b'7304402206be09a355f6abea8a10b5512180cd258460b42d516b5149431ffa3230a02533a0220325e83c6'
                b'176b295d633b18aad67adb4ad766d13152536ac04583f86d14645c9901210269c63bc8bac8143ef02f972'
                b'4a4ab35b12bdfa65ee1ad8c0db3d6511407a4cc2effffffff0240420f000000000091b50e405468654c69'
                b'6e757847616d65724c6408011002225e0801100322583056301006072a8648ce3d020106052b8104000a0'
                b'34200043878b1edd4a1373149909ef03f4339f6da9c2bd2214c040fd2e530463ffe66098eca14fc70b50f'
                b'f3aefd106049a815f595ed5a13eda7419ad78d9ed7ae473f176d7576a914994dad5f21c384ff526749b87'
                b'6d9d017d257b69888ac00dd6d00000000001976a914979202508a44f0e8290cea80787c76f98728845388'
                b'ac00000000'))
        channel = channel_tx.outputs[0]

        ledger = Ledger({
            'db': Database(':memory:'),
            'headers': Headers(':memory:')
        })

        self.assertTrue(stream.is_signed_by(channel, ledger))
Beispiel #14
0
 async def test_private_key_derivation(self):
     private_key = PrivateKey(
         Ledger({
             'db': Database(':memory:'),
             'headers': Headers(':memory:'),
         }),
         unhexlify('2423f3dc6087d9683f73a684935abc0ccd8bc26370588f56653128c6a6f0bf7c'),
         b'abcd'*8, 0, 1
     )
     for i in range(20):
         new_privkey = private_key.child(i)
         self.assertIsInstance(new_privkey, PrivateKey)
         self.assertEqual(hexlify(new_privkey.private_key_bytes), expected_privkeys[i])
     for i in range(PrivateKey.HARDENED + 1, private_key.HARDENED + 20):
         new_privkey = private_key.child(i)
         self.assertIsInstance(new_privkey, PrivateKey)
         self.assertEqual(hexlify(new_privkey.private_key_bytes), expected_hardened_privkeys[i - 1 - PrivateKey.HARDENED])
Beispiel #15
0
 async def test_from_extended_keys(self):
     ledger = Ledger({
         'db': Database(':memory:'),
         'headers': Headers(':memory:'),
     })
     self.assertIsInstance(
         from_extended_key_string(
             ledger,
             'xprv9s21ZrQH143K2dyhK7SevfRG72bYDRNv25yKPWWm6dqApNxm1Zb1m5gGcBWYfbsPjTr2v5joit8Af2Zp5P'
             '6yz3jMbycrLrRMpeAJxR8qDg8',
         ), PrivateKey
     )
     self.assertIsInstance(
         from_extended_key_string(
             ledger,
             'xpub661MyMwAqRbcF84AR8yfHoMzf4S2ct6mPJtvBtvNeyN9hBHuZ6uGJszkTSn5fQUCdz3XU17eBzFeAUwV6f'
             'iW44g14WF52fYC5J483wqQ5ZP',
         ), PubKey
     )
Beispiel #16
0
    def test_read_write(self):
        manager = WalletManager()
        config = {'data_path': '/tmp/wallet'}
        ledger = manager.get_or_create_ledger(Ledger.get_id(), config)

        with tempfile.NamedTemporaryFile(suffix='.json') as wallet_file:
            wallet_file.write(b'{"version": 1}')
            wallet_file.seek(0)

            # create and write wallet to a file
            wallet = manager.import_wallet(wallet_file.name)
            account = wallet.generate_account(ledger)
            wallet.save()

            # read wallet from file
            wallet_storage = WalletStorage(wallet_file.name)
            wallet = Wallet.from_storage(wallet_storage, manager)

            self.assertEqual(account.public_key.address,
                             wallet.default_account.public_key.address)
Beispiel #17
0
 async def test_private_key_validation(self):
     with self.assertRaisesRegex(TypeError, 'private key must be raw bytes'):
         PrivateKey(None, None, b'abcd'*8, 0, 255)
     with self.assertRaisesRegex(ValueError, 'private key must be 32 bytes'):
         PrivateKey(None, b'abcd', b'abcd'*8, 0, 255)
     private_key = PrivateKey(
         Ledger({
             'db': Database(':memory:'),
             'headers': Headers(':memory:'),
         }),
         unhexlify('2423f3dc6087d9683f73a684935abc0ccd8bc26370588f56653128c6a6f0bf7c'),
         b'abcd'*8, 0, 1
     )
     ec_point = private_key.ec_point()
     self.assertEqual(
         ec_point[0], 30487144161998778625547553412379759661411261804838752332906558028921886299019
     )
     self.assertEqual(
         ec_point[1], 86198965946979720220333266272536217633917099472454294641561154971209433250106
     )
     self.assertEqual('bUDcmraBp2zCV3QWmVVeQaEgepbs1b2gC9', private_key.address())
     with self.assertRaisesRegex(ValueError, 'invalid BIP32 private key child number'):
         private_key.child(-1)
     self.assertIsInstance(private_key.child(PrivateKey.HARDENED), PrivateKey)
Beispiel #18
0
 async def asyncSetUp(self):
     self.ledger = Ledger({
         'db': Database(':memory:'),
         'headers': Headers(':memory:')
     })
Beispiel #19
0
class TransactionIOBalancing(AsyncioTestCase):
    async def asyncSetUp(self):
        self.ledger = Ledger({
            'db': Database(':memory:'),
            'headers': Headers(':memory:')
        })
        await self.ledger.db.open()
        self.account = Account.from_dict(
            self.ledger, Wallet(), {
                "seed":
                "carbon smart garage balance margin twelve chest sword "
                "toast envelope bottom stomach absent"
            })

        addresses = await self.account.ensure_address_gap()
        self.pubkey_hash = [
            self.ledger.address_to_hash160(a) for a in addresses
        ]
        self.hash_cycler = cycle(self.pubkey_hash)

    async def asyncTearDown(self):
        await self.ledger.db.close()

    def txo(self, amount, address=None):
        return get_output(int(amount * COIN), address
                          or next(self.hash_cycler))

    def txi(self, txo):
        return Input.spend(txo)

    def tx(self, inputs, outputs):
        return Transaction.create(inputs, outputs, [self.account],
                                  self.account)

    async def create_utxos(self, amounts):
        utxos = [self.txo(amount) for amount in amounts]

        self.funding_tx = Transaction(is_verified=True) \
            .add_inputs([self.txi(self.txo(sum(amounts)+0.1))]) \
            .add_outputs(utxos)

        await self.ledger.db.insert_transaction(self.funding_tx)

        for utxo in utxos:
            await self.ledger.db.save_transaction_io(
                self.funding_tx,
                self.ledger.hash160_to_address(
                    utxo.script.values['pubkey_hash']),
                utxo.script.values['pubkey_hash'], '')

        return utxos

    @staticmethod
    def inputs(tx):
        return [round(i.amount / COIN, 2) for i in tx.inputs]

    @staticmethod
    def outputs(tx):
        return [round(o.amount / COIN, 2) for o in tx.outputs]

    async def test_basic_use_cases(self):
        self.ledger.fee_per_byte = int(.01 * CENT)

        # available UTXOs for filling missing inputs
        utxos = await self.create_utxos([1, 1, 3, 5, 10])

        # pay 3 coins (3.02 w/ fees)
        tx = await self.tx(
            [],  # inputs
            [self.txo(3)]  # outputs
        )
        # best UTXO match is 5 (as UTXO 3 will be short 0.02 to cover fees)
        self.assertListEqual(self.inputs(tx), [5])
        # a change of 1.98 is added to reach balance
        self.assertListEqual(self.outputs(tx), [3, 1.98])

        await self.ledger.release_outputs(utxos)

        # pay 2.98 coins (3.00 w/ fees)
        tx = await self.tx(
            [],  # inputs
            [self.txo(2.98)]  # outputs
        )
        # best UTXO match is 3 and no change is needed
        self.assertListEqual(self.inputs(tx), [3])
        self.assertListEqual(self.outputs(tx), [2.98])

        await self.ledger.release_outputs(utxos)

        # supplied input and output, but input is not enough to cover output
        tx = await self.tx(
            [self.txi(self.txo(10))],  # inputs
            [self.txo(11)]  # outputs
        )
        # additional input is chosen (UTXO 3)
        self.assertListEqual([10, 3], self.inputs(tx))
        # change is now needed to consume extra input
        self.assertListEqual([11, 1.96], self.outputs(tx))

        await self.ledger.release_outputs(utxos)

        # liquidating a UTXO
        tx = await self.tx(
            [self.txi(self.txo(10))],  # inputs
            []  # outputs
        )
        self.assertListEqual([10], self.inputs(tx))
        # missing change added to consume the amount
        self.assertListEqual([9.98], self.outputs(tx))

        await self.ledger.release_outputs(utxos)

        # liquidating at a loss, requires adding extra inputs
        tx = await self.tx(
            [self.txi(self.txo(0.01))],  # inputs
            []  # outputs
        )
        # UTXO 1 is added to cover some of the fee
        self.assertListEqual([0.01, 1], self.inputs(tx))
        # change is now needed to consume extra input
        self.assertListEqual([0.97], self.outputs(tx))
Beispiel #20
0
 def test_valid_address(self):
     self.assertTrue(
         Ledger.is_script_address("rCz6yb1p33oYHToGZDzTjX7nFKaU3kNgBd"))
Beispiel #21
0
class TestQueries(AsyncioTestCase):
    async def asyncSetUp(self):
        self.ledger = Ledger({
            'db': Database(':memory:'),
            'headers': Headers(':memory:')
        })
        self.wallet = Wallet()
        await self.ledger.db.open()

    async def asyncTearDown(self):
        await self.ledger.db.close()

    async def create_account(self, wallet=None):
        account = Account.generate(self.ledger, wallet or self.wallet)
        await account.ensure_address_gap()
        return account

    async def create_tx_from_nothing(self, my_account, height):
        to_address = await my_account.receiving.get_or_create_usable_address()
        to_hash = Ledger.address_to_hash160(to_address)
        tx = Transaction(height=height, is_verified=True) \
            .add_inputs([self.txi(self.txo(1, sha256(str(height).encode())))]) \
            .add_outputs([self.txo(1, to_hash)])
        await self.ledger.db.insert_transaction(tx)
        await self.ledger.db.save_transaction_io(tx, to_address, to_hash, '')
        return tx

    async def create_tx_from_txo(self, txo, to_account, height):
        from_hash = txo.script.values['pubkey_hash']
        from_address = self.ledger.hash160_to_address(from_hash)
        to_address = await to_account.receiving.get_or_create_usable_address()
        to_hash = Ledger.address_to_hash160(to_address)
        tx = Transaction(height=height, is_verified=True) \
            .add_inputs([self.txi(txo)]) \
            .add_outputs([self.txo(1, to_hash)])
        await self.ledger.db.insert_transaction(tx)
        await self.ledger.db.save_transaction_io(tx, from_address, from_hash,
                                                 '')
        await self.ledger.db.save_transaction_io(tx, to_address, to_hash, '')
        return tx

    async def create_tx_to_nowhere(self, txo, height):
        from_hash = txo.script.values['pubkey_hash']
        from_address = self.ledger.hash160_to_address(from_hash)
        to_hash = NULL_HASH
        tx = Transaction(height=height, is_verified=True) \
            .add_inputs([self.txi(txo)]) \
            .add_outputs([self.txo(1, to_hash)])
        await self.ledger.db.insert_transaction(tx)
        await self.ledger.db.save_transaction_io(tx, from_address, from_hash,
                                                 '')
        return tx

    def txo(self, amount, address):
        return get_output(int(amount * COIN), address)

    def txi(self, txo):
        return Input.spend(txo)

    async def test_large_tx_doesnt_hit_variable_limits(self):
        # SQLite is usually compiled with 999 variables limit: https://www.sqlite.org/limits.html
        # This can be removed when there is a better way. See: https://github.com/lbryio/lbry-sdk/issues/2281
        fetchall = self.ledger.db.db.execute_fetchall

        def check_parameters_length(sql, parameters):
            self.assertLess(len(parameters or []), 999)
            return fetchall(sql, parameters)

        self.ledger.db.db.execute_fetchall = check_parameters_length
        account = await self.create_account()
        tx = await self.create_tx_from_nothing(account, 0)
        for height in range(1, 1200):
            tx = await self.create_tx_from_txo(tx.outputs[0],
                                               account,
                                               height=height)
        variable_limit = self.ledger.db.MAX_QUERY_VARIABLES
        for limit in range(variable_limit - 2, variable_limit + 2):
            txs = await self.ledger.get_transactions(
                accounts=self.wallet.accounts,
                limit=limit,
                order_by='height asc')
            self.assertEqual(len(txs), limit)
            inputs, outputs, last_tx = set(), set(), txs[0]
            for tx in txs[1:]:
                self.assertEqual(len(tx.inputs), 1)
                self.assertEqual(tx.inputs[0].txo_ref.tx_ref.id, last_tx.id)
                self.assertEqual(len(tx.outputs), 1)
                last_tx = tx

    async def test_queries(self):
        wallet1 = Wallet()
        account1 = await self.create_account(wallet1)
        self.assertEqual(
            26, await self.ledger.db.get_address_count(accounts=[account1]))
        wallet2 = Wallet()
        account2 = await self.create_account(wallet2)
        account3 = await self.create_account(wallet2)
        self.assertEqual(
            26, await self.ledger.db.get_address_count(accounts=[account2]))

        self.assertEqual(
            0, await self.ledger.db.get_transaction_count(
                accounts=[account1, account2, account3]))
        self.assertEqual(0, await self.ledger.db.get_utxo_count())
        self.assertListEqual([], await self.ledger.db.get_utxos())
        self.assertEqual(0, await self.ledger.db.get_txo_count())
        self.assertEqual(0, await self.ledger.db.get_balance(wallet=wallet1))
        self.assertEqual(0, await self.ledger.db.get_balance(wallet=wallet2))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account1]))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account2]))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account3]))

        tx1 = await self.create_tx_from_nothing(account1, 1)
        self.assertEqual(
            1, await self.ledger.db.get_transaction_count(accounts=[account1]))
        self.assertEqual(
            0, await self.ledger.db.get_transaction_count(accounts=[account2]))
        self.assertEqual(
            1, await self.ledger.db.get_utxo_count(accounts=[account1]))
        self.assertEqual(
            1, await self.ledger.db.get_txo_count(accounts=[account1]))
        self.assertEqual(
            0, await self.ledger.db.get_txo_count(accounts=[account2]))
        self.assertEqual(10**8, await
                         self.ledger.db.get_balance(wallet=wallet1))
        self.assertEqual(0, await self.ledger.db.get_balance(wallet=wallet2))
        self.assertEqual(10**8, await
                         self.ledger.db.get_balance(accounts=[account1]))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account2]))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account3]))

        tx2 = await self.create_tx_from_txo(tx1.outputs[0], account2, 2)
        tx2b = await self.create_tx_from_nothing(account3, 2)
        self.assertEqual(
            2, await self.ledger.db.get_transaction_count(accounts=[account1]))
        self.assertEqual(
            1, await self.ledger.db.get_transaction_count(accounts=[account2]))
        self.assertEqual(
            1, await self.ledger.db.get_transaction_count(accounts=[account3]))
        self.assertEqual(
            0, await self.ledger.db.get_utxo_count(accounts=[account1]))
        self.assertEqual(
            1, await self.ledger.db.get_txo_count(accounts=[account1]))
        self.assertEqual(
            1, await self.ledger.db.get_utxo_count(accounts=[account2]))
        self.assertEqual(
            1, await self.ledger.db.get_txo_count(accounts=[account2]))
        self.assertEqual(
            1, await self.ledger.db.get_utxo_count(accounts=[account3]))
        self.assertEqual(
            1, await self.ledger.db.get_txo_count(accounts=[account3]))
        self.assertEqual(0, await self.ledger.db.get_balance(wallet=wallet1))
        self.assertEqual(10**8 + 10**8, await
                         self.ledger.db.get_balance(wallet=wallet2))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account1]))
        self.assertEqual(10**8, await
                         self.ledger.db.get_balance(accounts=[account2]))
        self.assertEqual(10**8, await
                         self.ledger.db.get_balance(accounts=[account3]))

        tx3 = await self.create_tx_to_nowhere(tx2.outputs[0], 3)
        self.assertEqual(
            2, await self.ledger.db.get_transaction_count(accounts=[account1]))
        self.assertEqual(
            2, await self.ledger.db.get_transaction_count(accounts=[account2]))
        self.assertEqual(
            0, await self.ledger.db.get_utxo_count(accounts=[account1]))
        self.assertEqual(
            1, await self.ledger.db.get_txo_count(accounts=[account1]))
        self.assertEqual(
            0, await self.ledger.db.get_utxo_count(accounts=[account2]))
        self.assertEqual(
            1, await self.ledger.db.get_txo_count(accounts=[account2]))
        self.assertEqual(0, await self.ledger.db.get_balance(wallet=wallet1))
        self.assertEqual(10**8, await
                         self.ledger.db.get_balance(wallet=wallet2))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account1]))
        self.assertEqual(0, await
                         self.ledger.db.get_balance(accounts=[account2]))
        self.assertEqual(10**8, await
                         self.ledger.db.get_balance(accounts=[account3]))

        txs = await self.ledger.db.get_transactions(
            accounts=[account1, account2])
        self.assertListEqual([tx3.id, tx2.id, tx1.id], [tx.id for tx in txs])
        self.assertListEqual([3, 2, 1], [tx.height for tx in txs])

        txs = await self.ledger.db.get_transactions(wallet=wallet1,
                                                    accounts=wallet1.accounts)
        self.assertListEqual([tx2.id, tx1.id], [tx.id for tx in txs])
        self.assertEqual(txs[0].inputs[0].is_my_account, True)
        self.assertEqual(txs[0].outputs[0].is_my_account, False)
        self.assertEqual(txs[1].inputs[0].is_my_account, False)
        self.assertEqual(txs[1].outputs[0].is_my_account, True)

        txs = await self.ledger.db.get_transactions(wallet=wallet2,
                                                    accounts=[account2])
        self.assertListEqual([tx3.id, tx2.id], [tx.id for tx in txs])
        self.assertEqual(txs[0].inputs[0].is_my_account, True)
        self.assertEqual(txs[0].outputs[0].is_my_account, False)
        self.assertEqual(txs[1].inputs[0].is_my_account, False)
        self.assertEqual(txs[1].outputs[0].is_my_account, True)
        self.assertEqual(
            2, await self.ledger.db.get_transaction_count(accounts=[account2]))

        tx = await self.ledger.db.get_transaction(txid=tx2.id)
        self.assertEqual(tx.id, tx2.id)
        self.assertFalse(tx.inputs[0].is_my_account)
        self.assertFalse(tx.outputs[0].is_my_account)
        tx = await self.ledger.db.get_transaction(wallet=wallet1, txid=tx2.id)
        self.assertTrue(tx.inputs[0].is_my_account)
        self.assertFalse(tx.outputs[0].is_my_account)
        tx = await self.ledger.db.get_transaction(wallet=wallet2, txid=tx2.id)
        self.assertFalse(tx.inputs[0].is_my_account)
        self.assertTrue(tx.outputs[0].is_my_account)

        # height 0 sorted to the top with the rest in descending order
        tx4 = await self.create_tx_from_nothing(account1, 0)
        txos = await self.ledger.db.get_txos()
        self.assertListEqual([0, 2, 2, 1], [txo.tx_ref.height for txo in txos])
        self.assertListEqual([tx4.id, tx2.id, tx2b.id, tx1.id],
                             [txo.tx_ref.id for txo in txos])
        txs = await self.ledger.db.get_transactions(
            accounts=[account1, account2])
        self.assertListEqual([0, 3, 2, 1], [tx.height for tx in txs])
        self.assertListEqual([tx4.id, tx3.id, tx2.id, tx1.id],
                             [tx.id for tx in txs])

    async def test_empty_history(self):
        self.assertEqual((None, []), await
                         self.ledger.get_local_status_and_history(''))
Beispiel #22
0
    def test_another_signed_claim_made_by_ytsync(self):
        stream_tx = Transaction(
            unhexlify(
                b'010000000185870fabdd6bd2d57749afebc0b239e8d0ebeb6f3647d6cfcabd5ea2200ac632010000006b4'
                b'83045022100877c86de154e39f21959bc2157865071924adb7930a7a8910714f27398cd2689022074270f'
                b'074ae260fff319d5e0c030691821bc75b82ff0179898ac3eaeda4123eb01210200328f7f001f22ea25d72'
                b'ba37379e3065020c4d8371d9199dc4e3770084e26b9ffffffff0240420f0000000000fdcc05b527746865'
                b'2d637269746963616c2d6e6565642d666f722d696e646570656e64656e742d6d656469614d85050191bba'
                b'd064bdc455b9ebddeeb559686b13f027615384ec7c9d981c3c21a6e3d723a654e86bd707d21174c4f697f'
                b'5080cf367a3b2dfc059e6cc14a962631df69b9886f4d8b97cb339b14633966fd5ac7d75edacdf30ac5010'
                b'a90010a304af34d1c1467ebfc8785e2a49c7d5bec3cc6db94db858f1dcf95e4256564fba586d6e01f496d'
                b'f2a34344e021d2725ffd12197468652d637269746963616c2d6e6565642d666f722e6d703418ee97eac10'
                b'22209766964656f2f6d70343230ba13e6b667a9acef7e1b1caa88b9eb1d4680dea84b1d3e838266595805'
                b'ab3343855c20af35012f942ce0d5111ce080331a1f436f7079726967687465642028636f6e74616374207'
                b'075626c69736865722928e2e3c98d065a0908800f10b80818f314423954686520437269746963616c204e'
                b'65656420666f7220496e646570656e64656e74204d65646961207c20476c656e6e20477265656e77616c6'
                b'44af006496e636c7564657320616e20696e74726f64756374696f6e20627920546f6d20576f6f64732e20'
                b'5265636f7264656420696e204c616b65204a61636b736f6e2c2054657861732c206f6e20446563656d626'
                b'57220342c20323032312e0a0a526f6e205061756c27732074776f2063616d706169676e7320666f722070'
                b'7265736964656e7420283230303820616e64203230313229207765726520776174657273686564206d6f6'
                b'd656e747320666f72206c6962657274792d6d696e6465642070656f706c652061726f756e642074686520'
                b'776f726c642e205468652022526f6e205061756c205265766f6c7574696f6e22e2809463656e746572656'
                b'42061726f756e642068697320756e64696c75746564206d657373616765206f662070656163652c207072'
                b'6f70657274792c20616e64206d61726b657473e280946368616e6765642074686520776179206d696c6c6'
                b'96f6e732074686f756768742061626f75742074686520416d65726963616e20656d7069726520616e6420'
                b'74686520416d65726963616e2066696e616e6369616c2073797374656d2e2044722e205061756c2773206'
                b'66f637573206f6e2063656e7472616c2062616e6b696e6720616e6420666f726569676e20706f6c696379'
                b'2063617567687420706f6c6974696369616e7320616e642070756e64697473206f66662067756172642c2'
                b'0666f7263696e67207468656d20746f20736372616d626c6520666f72206578706c616e6174696f6e7320'
                b'6f66206f7572204d6964646c65204561737420706f6c69637920616e6420536f766965742d7374796c652'
                b'063656e7472616c20706c616e6e696e6720617420746865204665642e20506f6c697469637320696e2041'
                b'6d657269636120686173206e6f74206265656e207468652073616d652073696e636520746865202247697'
                b'56c69616e69206d6f6d656e742220616e642022456e6420746865204665642e222054686520526f6e2050'
                b'61756c205265766f6c7574696f6e2077617320626f7468206120706f6c69746963616c20616e642063756'
                b'c747572616c207068656e6f6d656e6f6e2e0a0a303a303020496e74726f64756374696f6e20627920546f'
                b'6d20576f6f64730a343a323720476c656e6e20477265656e77616c640a2e2e2e0a68747470733a2f2f777'
                b'7772e796f75747562652e636f6d2f77617463683f763d4e4b70706d52467673453052292a276874747073'
                b'3a2f2f7468756d626e61696c732e6c6272792e636f6d2f4e4b70706d5246767345305a046e6577735a096'
                b'3617468656472616c5a0f636f72706f72617465206d656469615a08637269746963616c5a0f676c656e6e'
                b'20677265656e77616c645a0b696e646570656e64656e745a0a6a6f75726e616c69736d5a056d656469615'
                b'a056d697365735a08706f6c69746963735a0a70726f706167616e64615a08726f6e207061756c5a057472'
                b'757468620208016d7576a9140969964db5b5744e2d2d0de797f5904efc80d02188acc8814200000000001'
                b'976a91439086597f9cfc066f4749b8bb245bf561714fda888ac00000000')
        )
        stream = stream_tx.outputs[0]

        channel_tx = Transaction(
            unhexlify(
                b'01000000011d47b91b409b317e427adb87ec4b0bfc9fad2abf6ec3296f41918e4b3cb9d4e7010000006a4'
                b'7304402205e53ef7fc643ed00f0240dd1c3302b82141f481ed071cbcdd6b6ec6166ffd4e002203eb28ce6'
                b'39f80253f66ff3bf45288a60133d7f5625217d1ecf3b57da440b559f012103b852d61074eb995b702a800'
                b'f284e937ece4fea7f023beb70e6b0d1bff36d64b9ffffffff0240420f0000000000fdde01b506406d6973'
                b'65734db801001299010a583056301006072a8648ce3d020106052b8104000a034200047ddb1d639d7bdd0'
                b'953d9ab0bf9e971a632f85f9823c1d85780aa3e0a702b503c2962d00f67360e803514bf5864710925aacb'
                b'effd9597532c7e60eb21b4e3fd03223d2a3b68747470733a2f2f7468756d626e61696c732e6c6272792e6'
                b'36f6d2f62616e6e65722d55436d54362d43684b7061694956753266684549734e7451420a6d697365736d'
                b'656469614ad401466561747572656420766964656f732066726f6d20746865204d6973657320496e73746'
                b'9747574652e20546865204d6973657320496e737469747574652070726f6d6f7465732041757374726961'
                b'6e2065636f6e6f6d6963732c2066726565646f6d2c20616e6420706561636520696e20746865206c69626'
                b'572616c20696e74656c6c65637475616c20747261646974696f6e206f66204c756477696720766f6e204d'
                b'69736573207468726f7567682072657365617263682c207075626c697368696e672c20616e64206564756'
                b'36174696f6e2e52362a3468747470733a2f2f7468756d626e61696c732e6c6272792e636f6d2f55436d54'
                b'362d43684b7061694956753266684549734e74516d7576a914cd77ded2400e6569f03a2580244bb395f95'
                b'f91fc88ac344ab701000000001976a914cabdbfce726d2fda92ffe0041a4303f6c6c34cda88ac00000000'
            ))
        channel = channel_tx.outputs[0]

        ledger = Ledger({
            'db': Database(':memory:'),
            'headers': Headers(':memory:')
        })

        self.assertTrue(stream.is_signed_by(channel, ledger))