Ejemplo n.º 1
0
    def test_mempool_observer(self):
        connection = Mock()
        from pycoin.tx.Tx import Tx
        tx = Tx.from_hex(
            '01000000000101112a649fd72656cf572259cb7cb61bd31ccdbdf0944070e73401565affbe629d0100000000ffffffff02608'
            'de2110000000017a914d52b516c1a094462959ed6facebb94429d2cebf487d3135b0b00000000220020701a8d401c84fb13e6'
            'baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d0400473044022006b149e0cf031f57fd443bd1210b381e9b1b15094'
            '57ba1f49e48b803696f56e802203d66bd974ad3ac5b7591cc84e706b78d139c61e2bf1995a89c4dc0758984a2b70148304502'
            '2100fe7275d601080e1870517774a3ad6accaa7f8ad144addec3251e98685d4fefad02207792c2b0ed6ab42ed2ba6d12e6bd3'
            '4db8c6f4ac6f15e604f70ea85a735c450b1016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd'
            '92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e'
            '046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000')
        self.loop.run_until_complete(
            self.sut.on_transaction(connection, {'tx': tx}))
        self.assertEqual(tx.w_id(),
                         [x for x in self.mempool_repository.get_txids()][0])
        self.repository.blockchain.get_transactions_by_block_hash.return_value = [], None

        block = Block(1,
                      b'0' * 32,
                      merkle_root=merkle([tx.hash()]),
                      timestamp=123456789,
                      difficulty=3000000,
                      nonce=1 * 137)
        block.txs.append(tx)
        as_bin = block.as_bin()
        Block.from_bin(as_bin)
        block_header = {'block_hash': block.id()}
        self.batcher_factory.add_peer.return_value = async_coro(True)
        self.batcher_factory.inv_item_to_future.return_value = block.as_bin()
        mempool_response = self.mempool_repository.get_raw_mempool(True)

        self.assertEqual(
            {
                '41867301a6cff5c47951aa1a4eef0be910db0cb5f154eaeb469732e1f9b54548':
                {
                    'size': 381,
                    'fee': 0,
                    'modifiedfee': 0,
                    'time': ANY,
                    'height': 0,
                    'descendantcount': 0,
                    'descendantsize': 0,
                    'descendantfees': 0,
                    'ancestorcount': 0,
                    'ancestorsize': 0,
                    'ancestorfees': 0,
                    'depends': []
                }
            }, mempool_response)
        self.repository.blockchain.save_block.side_effect = lambda a: {
            'block_object': Block.from_bin(a['block_bytes'])
        }
        self.repository.blockchain.get_transactions_by_block_hash.return_value = [], None
        self.loop.run_until_complete(self.sut.on_block_header(block_header))
        self.assertEqual(self.mempool_repository.get_raw_mempool(True), {})
        self.assertEqual([x for x in self.mempool_repository.get_txids()], [])
    async def on_block_header(self, blockheader: dict, i=0):
        try:
            Logger.mempool.debug('New block request: %s',
                                 blockheader['block_hash'])
            block_transactions, size = self.repository.blockchain.get_transactions_by_block_hash(
                blockheader['block_hash'])
            block_raw_data = (tx['transaction_bytes']
                              for tx in block_transactions)
            cached_block = block_transactions and (
                blockheader['header_bytes'] + b''.join(block_raw_data)) or None
            try:
                block_object = Block.from_bin(cached_block)
            except:
                block_object = None
            if block_object:
                Logger.mempool.debug('Block %s in cache',
                                     blockheader['block_hash'])
                block = {
                    'block_object': block_object,
                }
            else:
                Logger.mempool.debug('Block %s not in cache, fetching',
                                     blockheader['block_hash'])
                block = await self.p2p.get_block(blockheader['block_hash'],
                                                 timeout=15)
                if not block:
                    raise exceptions.MissingResponseException
                Logger.mempool.debug('Block %s not cached, saving',
                                     blockheader['block_hash'])
                block = self.repository.blockchain.save_block(block)

            Logger.mempool.debug('Block %s, fetch done',
                                 blockheader['block_hash'])
            block_txids, removed_txids = self.repository.mempool.on_new_block(
                block['block_object'])
            Logger.mempool.debug(
                'Block %s parsed by mempool repository, removed %s transactions'
                % (blockheader['block_hash'], len(removed_txids)))
            blockheader.update({"txs": block_txids})
            block.update({"verbose": blockheader})

            for callback in self.on_new_block_callbacks:
                self.loop.create_task(callback(block['block_object']))
        except (exceptions.NoPeersException,
                exceptions.MissingResponseException) as e:
            if i > 10:
                Logger.mempool.debug(
                    'Block fetch for %s failed (will NOT retry)',
                    blockheader['block_hash'])
                raise
            Logger.mempool.debug('Block fetch for %s failed (will retry)',
                                 blockheader['block_hash'])
            self.loop.create_task(
                self.delayer(self.on_block_header(blockheader, i=i + 1), 10))
 async def get(self, block_bytes: bytes):
     if not self.min_size or len(block_bytes) <= self.min_size:
         return Block.from_bin(block_bytes)
     else:
         q = queue.Queue()
         thread = threading.Thread(target=self.getblock, args=(block_bytes, q))
         thread.start()
         try:
             while 1:
                 try:
                     data = q.get(block=False)
                     return data
                 except:
                     pass
                 await asyncio.sleep(0.1)
         finally:
             del thread
    def save_block(self, block: Dict, tracker=None) -> Dict:
        block['size'] = len(block['block_bytes'])
        block['block_object'] = block.get(
            'block_object', Block.from_bin(block.get('block_bytes')))

        blockhash = binascii.unhexlify(block['block_hash'].encode())
        txids = list()
        for transaction in block['block_object'].txs:
            self.save_transaction({
                'txid': transaction.id(),
                'transaction_bytes': transaction.as_bin(),
                'block_hash': blockhash
            })
            txids.append(binascii.unhexlify(transaction.id()))
        self._save_block_index(blockhash, block['size'], txids)
        tracker and tracker.track(
            self.get_key(block['block_hash'], prefix=BLOCK_INDEX_PREFIX),
            len(block['block_bytes']))
        return block
Ejemplo n.º 5
0
 def getblock(data, q):
     q.put(Block.from_bin(data))
Ejemplo n.º 6
0
    def test_validate_block_data(self):
        # block 80971
        block_80971_id = '00000000001126456C67A1F5F0FF0268F53B4F22E0531DC70C7B69746AF69DAC'.lower(
        )
        block_80971_data = h2b(
            "01000000950A1631FB9FAC411DFB173487B9E18018B7C6F7147E78C062584100000000"
            "00A881352F97F14BF191B54915AE124E051B8FE6C3922C5082B34EAD503000FC34D891"
            "974CED66471B4016850A04010000000100000000000000000000000000000000000000"
            "00000000000000000000000000FFFFFFFF0804ED66471B02C301FFFFFFFF0100F2052A"
            "01000000434104CB6B6B4EADC96C7D08B21B29D0ADA5F29F9378978CABDB602B8B65DA"
            "08C8A93CAAB46F5ABD59889BAC704925942DD77A2116D10E0274CAD944C71D3D1A6705"
            "70AC0000000001000000018C55ED829F16A4E43902940D3D33005264606D5F7D555B5F"
            "67EE4C033390C2EB010000008A47304402202D1BF606648EDCDB124C1254930852D991"
            "88E1231715031CBEAEA80CCFD2B39A02201FA9D6EE7A1763580E342474FC1AEF59B046"
            "8F98479953437F525063E25675DE014104A01F763CFBF5E518C628939158AF3DC0CAAC"
            "35C4BA7BC1CE8B7E634E8CDC44E15F0296B250282BD649BAA8398D199F2424FCDCD88D"
            "3A9ED186E4FD3CB9BF57CFFFFFFFFF02404B4C00000000001976A9148156FF75BEF24B"
            "35ACCE3C05289A2411E1B0E57988AC00AA38DF010000001976A914BC7E692A5FFE95A5"
            "96712F5ED83393B3002E452E88AC0000000001000000019C97AFDF6C9A31FFA86D71EA"
            "79A079001E2B59EE408FD418498219400639AC0A010000008B4830450220363CFFAE09"
            "599397B21E6D8A8073FB1DFBE06B6ACDD0F2F7D3FEA86CA9C3F605022100FA255A6ED2"
            "3FD825C759EF1A885A31CAD0989606CA8A3A16657D50FE3CEF5828014104FF444BAC08"
            "308B9EC97F56A652AD8866E0BA804DA97868909999566CB377F4A2C8F1000E83B49686"
            "8F3A282E1A34DF78565B65C15C3FA21A0763FD81A3DFBBB6FFFFFFFF02C05EECDE0100"
            "00001976A914588554E6CC64E7343D77117DA7E01357A6111B7988AC404B4C00000000"
            "001976A914CA6EB218592F289999F13916EE32829AD587DBC588AC0000000001000000"
            "01BEF5C9225CB9FE3DEF929423FA36AAD9980B9D6F8F3070001ACF3A5FB389A69F0000"
            "00004A493046022100FB23B1E2F2FB8B96E04D220D385346290A9349F89BBBC5C225D5"
            "A56D931F8A8E022100F298EB28294B90C1BAF319DAB713E7CA721AAADD8FCC15F849DE"
            "7B0A6CF5412101FFFFFFFF0100F2052A010000001976A9146DDEA8071439951115469D"
            "0D2E2B80ECBCDD48DB88AC00000000")

        # block 80974
        block_80974_id = '0000000000089F7910F6755C10EA2795EC368A29B435D80770AD78493A6FECF1'.lower(
        )
        block_80974_data = h2b(
            "010000007480150B299A16BBCE5CCDB1D1BBC65CFC5893B01E6619107C552000000000"
            "007900A2B203D24C69710AB6A94BEB937E1B1ADD64C2327E268D8C3E5F8B41DBED8796"
            "974CED66471B204C324703010000000100000000000000000000000000000000000000"
            "00000000000000000000000000FFFFFFFF0804ED66471B024001FFFFFFFF0100F2052A"
            "010000004341045FEE68BAB9915C4EDCA4C680420ED28BBC369ED84D48AC178E1F5F7E"
            "EAC455BBE270DABA06802145854B5E29F0A7F816E2DF906E0FE4F6D5B4C9B92940E4F0"
            "EDAC000000000100000001F7B30415D1A7BF6DB91CB2A272767C6799D721A4178AA328"
            "E0D77C199CB3B57F010000008A4730440220556F61B84F16E637836D2E74B8CB784DE4"
            "0C28FE3EF93CCB7406504EE9C7CAA5022043BD4749D4F3F7F831AC696748AD8D8E79AE"
            "B4A1C539E742AA3256910FC88E170141049A414D94345712893A828DE57B4C2054E2F5"
            "96CDCA9D0B4451BA1CA5F8847830B9BE6E196450E6ABB21C540EA31BE310271AA00A49"
            "ED0BA930743D1ED465BAD0FFFFFFFF0200E1F505000000001976A914529A63393D63E9"
            "80ACE6FA885C5A89E4F27AA08988ACC0ADA41A000000001976A9145D17976537F30886"
            "5ED533CCCFDD76558CA3C8F088AC00000000010000000165148D894D3922EF5FFDA962"
            "BE26016635C933D470C8B0AB7618E869E3F70E3C000000008B48304502207F5779EBF4"
            "834FEAEFF4D250898324EB5C0833B16D7AF4C1CB0F66F50FCF6E85022100B78A65377F"
            "D018281E77285EFC31E5B9BA7CB7E20E015CF6B7FA3E4A466DD195014104072AD79E0A"
            "A38C05FA33DD185F84C17F611E58A8658CE996D8B04395B99C7BE36529CAB7606900A0"
            "CD5A7AEBC6B233EA8E0FE60943054C63620E05E5B85F0426FFFFFFFF02404B4C000000"
            "00001976A914D4CAA8447532CA8EE4C80A1AE1D230A01E22BFDB88AC8013A0DE010000"
            "001976A9149661A79AE1F6D487AF3420C13E649D6DF3747FC288AC00000000")

        block_80971 = Block.from_bin(block_80971_data)
        self.assertEqual(block_80971.id(), block_80971_id)
        block_80974 = Block.from_bin(block_80974_data)
        self.assertEqual(block_80974.id(), block_80974_id)

        tx_db = {tx.hash(): tx for tx in block_80971.txs}

        tx_to_validate = block_80974.txs[2]
        self.assertEqual(
            "OP_DUP OP_HASH160 [d4caa8447532ca8ee4c80a1ae1d230a01e22bfdb] OP_EQUALVERIFY OP_CHECKSIG",
            BitcoinScriptTools.disassemble(tx_to_validate.txs_out[0].script))
        self.assertEqual(
            tx_to_validate.id(),
            "7c4f5385050c18aa8df2ba50da566bbab68635999cc99b75124863da1594195b")

        tx_to_validate.unspents_from_db(tx_db)
        self.assertEqual(tx_to_validate.bad_signature_count(), 0)

        # now, let's corrupt the Tx and see what happens
        tx_out = tx_to_validate.txs_out[1]

        disassembly = BitcoinScriptTools.disassemble(tx_out.script)
        tx_out.script = BitcoinScriptTools.compile(disassembly)

        self.assertEqual(tx_to_validate.bad_signature_count(), 0)

        disassembly = disassembly.replace(
            "9661a79ae1f6d487af3420c13e649d6df3747fc2",
            "9661a79ae1f6d487af3420c13e649d6df3747fc3")

        tx_out.script = BitcoinScriptTools.compile(disassembly)

        self.assertEqual(tx_to_validate.bad_signature_count(), 1)
        self.assertFalse(tx_to_validate.is_signature_ok(0))