示例#1
0
    def create_menu(self, position: QPoint) -> None:
        self.selectedIndexes()
        item = self.currentItem()
        if not item:
            return
        column = self.currentColumn()
        account_id = item.data(Columns.STATUS, self.ACCOUNT_ROLE)
        tx_hash = item.data(Columns.STATUS, self.TX_ROLE)
        if account_id is None or tx_hash is None:
            return
        if column == 0:
            column_title = "ID"
            column_data = hash_to_hex_str(tx_hash)
        else:
            column_title = self.headerItem().text(column)
            column_data = item.text(column).strip()

        account = self._wallet.get_account(account_id)

        tx_id = hash_to_hex_str(tx_hash)
        tx_URL = web.BE_URL(self.config, 'tx', tx_id)
        height, _conf, _timestamp = self._wallet.get_tx_height(tx_hash)
        tx = account.get_transaction(tx_hash)
        if not tx:
            return  # this happens sometimes on account synch when first starting up.
        is_unconfirmed = height <= 0

        menu = QMenu()
        menu.addAction(
            _("Copy {}").format(column_title),
            lambda: self._main_window.app.clipboard().setText(column_data))
        if column in self.editable_columns:
            # We grab a fresh reference to the current item, as it has been deleted in a
            # reported issue.
            menu.addAction(
                _("Edit {}").format(column_title),
                lambda: self.currentItem() and self.editItem(
                    self.currentItem(), column))
        menu.addAction(_("Details"),
                       lambda: self._main_window.show_transaction(account, tx))
        if is_unconfirmed and tx:
            child_tx = account.cpfp(tx, 0)
            if child_tx:
                menu.addAction(
                    _("Child pays for parent"),
                    lambda: self._main_window.cpfp(account, tx, child_tx))
        entry = self._account.get_transaction_entry(tx_hash)
        if entry.flags & TxFlags.PaysInvoice:
            invoice_row = self._account.invoices.get_invoice_for_tx_hash(
                tx_hash)
            invoice_id = invoice_row.invoice_id if invoice_row is not None else None
            action = menu.addAction(
                read_QIcon(ICON_NAME_INVOICE_PAYMENT), _("View invoice"),
                partial(self._show_invoice_window, invoice_id))
            action.setEnabled(invoice_id is not None)

        if tx_URL:
            menu.addAction(_("View on block explorer"),
                           lambda: webbrowser.open(tx_URL))
        menu.exec_(self.viewport().mapToGlobal(position))
示例#2
0
    def create_menu(self, position):
        self.selectedIndexes()
        item = self.currentItem()
        if not item:
            return
        column = self.currentColumn()
        edit_data = item.data(0, Qt.UserRole)
        if not edit_data:
            return
        account_id, tx_hash = edit_data
        if column == 0:
            column_title = "ID"
            column_data = hash_to_hex_str(tx_hash)
        else:
            column_title = self.headerItem().text(column)
            column_data = item.text(column).strip()

        account = self._wallet.get_account(account_id)

        tx_id = hash_to_hex_str(tx_hash)
        tx_URL = web.BE_URL(self.config, 'tx', tx_id)
        height, _conf, _timestamp = account.get_tx_height(tx_hash)
        tx = account.get_transaction(tx_hash)
        if not tx:
            return  # this happens sometimes on account synch when first starting up.
        is_unconfirmed = height <= 0
        pr_key = account.invoices.paid.get(tx_hash)

        menu = QMenu()
        menu.addAction(
            _("Copy {}").format(column_title),
            lambda: self._main_window.app.clipboard().setText(column_data))
        if column in self.editable_columns:
            # We grab a fresh reference to the current item, as it has been deleted in a
            # reported issue.
            menu.addAction(
                _("Edit {}").format(column_title),
                lambda: self.currentItem() and self.editItem(
                    self.currentItem(), column))
        label = account.get_transaction_label(tx_hash) or None
        menu.addAction(
            _("Details"),
            lambda: self._main_window.show_transaction(account, tx, label))
        if is_unconfirmed and tx:
            child_tx = account.cpfp(tx, 0)
            if child_tx:
                menu.addAction(
                    _("Child pays for parent"),
                    lambda: self._main_window.cpfp(account, tx, child_tx))
        if pr_key:
            menu.addAction(read_QIcon("seal"), _("View invoice"),
                           lambda: self._main_window.show_invoice(pr_key))
        if tx_URL:
            menu.addAction(_("View on block explorer"),
                           lambda: webbrowser.open(tx_URL))
        menu.exec_(self.viewport().mapToGlobal(position))
示例#3
0
    def deserialize_getheaders(cls, f):
        """for checking my own getheaders request"""
        version = bitcoinx.read_le_uint32(f.read)
        hash_count = bitcoinx.read_varint(f.read)
        block_locator_hashes = []
        for i in range(hash_count):
            block_locator_hashes.append(bitcoinx.hash_to_hex_str(f.read(32)))
        hash_stop = bitcoinx.hash_to_hex_str(f.read(32))

        message = {'version': version,
                   'hash_count': hash_count,
                   'block_locator_hashes': block_locator_hashes,
                   'hash_stop': hash_stop}
        return message
示例#4
0
    def delete(self, tx_hash: bytes,
            completion_callback: Optional[CompletionCallbackType]=None) -> None:
        with self._lock:
            self._logger.debug("cache_deletion: %s", hash_to_hex_str(tx_hash))
            del self._cache[tx_hash]

            self._store.delete([ tx_hash ], completion_callback=completion_callback)
示例#5
0
    def _on_transaction_deleted(self, account_id: int, tx_hash: bytes) -> None:
        if not self._validate_account_event({account_id}):
            return

        self._logger.debug("_on_transaction_deleted %s",
                           hash_to_hex_str(tx_hash))
        self._mark_transactions_removed([tx_hash])
示例#6
0
    def validate_block_header(header):
        """ Takes in a single block header; returns True if valid block; False if invalid
            Validation checks to be performed
            (1) checks that calculated block hash is < target (difficulty)
            (2) checks that this hashed block contains a "prev_block_hash" field equal to
                the prior block calculated hash
            (3) check than target is set as per the consensus difficulty adjustment algorithm (NOT DONE HERE)
            see 'validate_header_difficulty()' --> this phase 2 check is done on the whole database in one go """

        # extract nbits as int direct from byte position 72:76 in header
        target = Validate.bits_to_target(bitcoinx.unpack_le_int32(header[72:72 + 4])[0])

        # get block hash
        block_hash = get_block_hash(header)

        prev_hash_que.append(block_hash)

        # check if hash of current block is less than nbits "target"
        is_less_than_target = int(block_hash, 16) < target
        if is_less_than_target:
            pass
        else:
            raise ValueError("hash of current block is not less than nbits target!")

        # check if prev_block_hash matches the last block on record in db
        # genesis block (#0) is not sent with "headers" message so first block is the block after genesis (#1)
        prev_block_hash = bitcoinx.hash_to_hex_str(header[4:36])
        if prev_block_hash == prev_hash_que.pop(0):
            return True
        else:
            return False
示例#7
0
    def test_update_flags(self):
        cache = TxCache(self.store)

        tx_bytes_1 = bytes.fromhex(tx_hex_1)
        tx_hash_bytes_1 = bitcoinx.double_sha256(tx_bytes_1)
        tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1)
        data = TxData(position=11)
        cache.add([(tx_id_1, data, tx_bytes_1, TxFlags.StateDispatched)])
        self.assertTrue(cache.is_cached(tx_id_1))
        entry = cache.get_entry(tx_id_1)
        self.assertEqual(
            TxFlags.HasByteData | TxFlags.HasPosition
            | TxFlags.StateDispatched, entry.flags)
        self.assertIsNotNone(entry.bytedata)

        cache.update_flags(tx_id_1, TxFlags.StateCleared,
                           TxFlags.HasByteData | TxFlags.HasProofData)
        entry = cache.get_entry(tx_id_1)
        store_flags = self.store.get_flags(tx_id_1)
        expected_flags = TxFlags.HasByteData | TxFlags.HasPosition | TxFlags.StateCleared
        self.assertEqual(
            expected_flags, store_flags,
            f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(store_flags)}"
        )
        self.assertEqual(
            expected_flags, entry.flags,
            f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(entry.flags)}"
        )
        self.assertIsNotNone(entry.bytedata)
示例#8
0
def _parse_input(vds):
    d = {}
    prevout_hash = hash_to_hex_str(vds.read_bytes(32))
    prevout_n = vds.read_uint32()
    scriptSig = vds.read_bytes(vds.read_compact_size())
    sequence = vds.read_uint32()
    d['prevout_hash'] = prevout_hash
    d['prevout_n'] = prevout_n
    d['sequence'] = sequence
    d['address'] = UnknownAddress()
    if prevout_hash == '00' * 32:
        d['type'] = 'coinbase'
        d['scriptSig'] = bh2u(scriptSig)
    else:
        d['x_pubkeys'] = []
        d['pubkeys'] = []
        d['signatures'] = {}
        d['address'] = None
        d['type'] = 'unknown'
        d['num_sig'] = 0
        d['scriptSig'] = bh2u(scriptSig)
        _parse_scriptSig(d, scriptSig)

        if not Transaction.is_txin_complete(d):
            d['value'] = vds.read_uint64()
    return d
示例#9
0
    def test_add_then_update(self):
        cache = TxCache(self.store)

        bytedata_1 = bytes.fromhex(tx_hex_1)
        tx_id_1 = bitcoinx.hash_to_hex_str(bitcoinx.double_sha256(bytedata_1))
        metadata_1 = TxData(position=11)
        cache.add([(tx_id_1, metadata_1, bytedata_1, TxFlags.StateDispatched)])
        self.assertTrue(cache.is_cached(tx_id_1))
        entry = cache.get_entry(tx_id_1)
        self.assertEqual(
            TxFlags.HasByteData | TxFlags.HasPosition
            | TxFlags.StateDispatched, entry.flags)
        self.assertIsNotNone(entry.bytedata)

        metadata_2 = TxData(fee=10, height=88)
        propagate_flags = TxFlags.HasFee | TxFlags.HasHeight
        cache.update([(tx_id_1, metadata_2, None,
                       propagate_flags | TxFlags.HasPosition)])
        entry = cache.get_entry(tx_id_1)
        expected_flags = propagate_flags | TxFlags.StateDispatched | TxFlags.HasByteData
        self.assertEqual(
            expected_flags, entry.flags,
            f"{TxFlags.to_repr(expected_flags)} !=  {TxFlags.to_repr(entry.flags)}"
        )
        self.assertIsNotNone(entry.bytedata)
示例#10
0
    def _create_menu(self, position) -> None:
        item = self.currentItem()
        if not item:
            return

        column = self.currentColumn()
        column_title = self.headerItem().text(column)
        column_data = item.text(column).strip()

        tx_hash = item.data(InputColumns.INDEX, Roles.TX_HASH)
        have_tx = self.parent()._account.have_transaction_data(tx_hash)

        tx_id = hash_to_hex_str(tx_hash)
        tx_URL = web.BE_URL(self._main_window.config, 'tx', tx_id)

        menu = QMenu()
        menu.addAction(
            _("Copy {}").format(column_title),
            lambda: self._main_window.app.clipboard().setText(column_data))
        details_menu = menu.addAction(
            _("Transaction details"),
            partial(self._show_other_transaction, tx_hash))
        details_menu.setEnabled(have_tx)
        if tx_URL:
            menu.addAction(_("View on block explorer"),
                           lambda: webbrowser.open(tx_URL))
        menu.exec_(self.viewport().mapToGlobal(position))
示例#11
0
    def test_update_many(self):
        to_add = []
        for i in range(10):
            tx_bytes = os.urandom(10)
            tx_hash_bytes = bitcoinx.double_sha256(tx_bytes)
            tx_id = bitcoinx.hash_to_hex_str(tx_hash_bytes)
            tx_data = TxData(height=None, fee=2, position=None, timestamp=None)
            to_add.append((tx_id, tx_data, tx_bytes, TxFlags.Unset))
        self.store.add_many(to_add)

        to_update = []
        for tx_id, metadata, tx_bytes, flags in to_add:
            tx_metadata = TxData(height=1,
                                 fee=2,
                                 position=None,
                                 timestamp=None)
            to_update.append((tx_id, tx_metadata, tx_bytes, flags))
        self.store.update_many(to_update)

        for tx_id_get, metadata_get, bytedata_get, flags_get in self.store.get_many(
        ):
            for update_tx_id, update_metadata, update_tx_bytes, update_flags in to_update:
                if update_tx_id == tx_id_get:
                    self.assertEqual(metadata_get, update_metadata)
                    self.assertEqual(bytedata_get, update_tx_bytes)
                    continue
示例#12
0
    def test_update_flags(self):
        bytedata = os.urandom(10)
        tx_hash_bytes = bitcoinx.double_sha256(bytedata)
        tx_id = bitcoinx.hash_to_hex_str(tx_hash_bytes)
        metadata = TxData(height=1, fee=2, position=None, timestamp=None)
        self.store.add(tx_id, metadata, bytedata)

        # Verify the field flags are assigned correctly on the add.
        expected_flags = TxFlags.HasFee | TxFlags.HasHeight | TxFlags.HasByteData
        flags = self.store.get_flags(tx_id)
        self.assertEqual(expected_flags, flags)

        flags = TxFlags.StateReceived
        mask = TxFlags.METADATA_FIELD_MASK | TxFlags.HasByteData | TxFlags.HasProofData
        self.store.update_flags(tx_id, flags, mask)

        # Verify the state flag is correctly added via the mask.
        flags_get = self.store.get_flags(tx_id)
        expected_flags |= TxFlags.StateReceived
        self.assertEqual(
            expected_flags, flags_get,
            f"{TxFlags.to_repr(expected_flags)} != {TxFlags.to_repr(flags_get)}"
        )

        flags = TxFlags.StateReceived
        mask = TxFlags.Unset
        self.store.update_flags(tx_id, flags, mask)

        # Verify the state flag is correctly set via the mask.
        flags = self.store.get_flags(tx_id)
        self.assertEqual(TxFlags.StateReceived, flags)
示例#13
0
def test_Bitcoin(raw_header, header_hash, version, prev_hash, merkle_root,
                 timestamp, bits, nonce):
    header_hash = hex_str_to_hash(header_hash)
    prev_hash = hex_str_to_hash(prev_hash)
    merkle_root = hex_str_to_hash(merkle_root)

    assert Bitcoin.header_hash(raw_header) == header_hash
    assert Bitcoin.header_prev_hash(raw_header) == prev_hash
    assert Bitcoin.header_work(raw_header) == bits_to_work(bits)
    assert Bitcoin.header_timestamp(raw_header) == timestamp

    header = Bitcoin.deserialized_header(raw_header, 0)
    assert header.version == version
    assert header.prev_hash == prev_hash
    assert header.merkle_root == merkle_root
    assert header.timestamp == timestamp
    assert header.bits == bits
    assert header.nonce == nonce
    assert header.raw == raw_header
    assert header.hash == header_hash
    assert header.height == 0
    assert header.work() == Bitcoin.header_work(raw_header)
    assert header.target() == bits_to_target(bits)
    assert header.hash_value() == hash_to_value(header_hash)
    assert header.hex_str() == hash_to_hex_str(header_hash)
    assert 'height=0' in str(header)
示例#14
0
 def _write(db: sqlite3.Connection):
     self._logger.debug("deleting transactions %s",
                        [hash_to_hex_str(b[0]) for b in datas])
     db.executemany(TransactionDeltaTable.DELETE_TRANSACTION_SQL, datas)
     db.executemany(TransactionOutputTable.DELETE_TRANSACTION_SQL,
                    datas)
     db.executemany(self.DELETE_SQL, datas)
    def _update_transactions(self, tx_hashes: List[bytes], state: Dict[bytes, EventFlags]) -> None:
        self._logger.debug("_update_transactions %d", len(tx_hashes))
        if not len(tx_hashes):
            return

        matches = self._match_transactions(tx_hashes)
        if len(matches) != len(tx_hashes):
            matched_tx_hashes = [ line.hash for (row, line) in matches ]
            # The add database write has not completed yet.
            self._logger.debug("_update_transactions missing entries %s",
                [ hash_to_hex_str(a) for a in tx_hashes if a not in matched_tx_hashes ])

        if not len(matches):
            return

        matches_by_hash = dict((t[1].hash, t) for t in matches)
        matched_tx_hashes = list(matches_by_hash.keys())
        for tx_hash, tx_flags, tx_data in self._wallet.read_transaction_metadatas(
                tx_hashes=matched_tx_hashes, account_id=self._account_id):
            row, line = matches_by_hash[tx_hash]
            new_line = self._create_transaction_entry(tx_hash, tx_data)
            self._data[row] = new_line
            self._base_model.invalidate_row(row)

        self.changed_signal.emit(self._account_id)
示例#16
0
    def test_update_or_add(self):
        cache = TxCache(self.store)

        # Add.
        bytedata_1 = bytes.fromhex(tx_hex_1)
        tx_hash_bytes_1 = bitcoinx.double_sha256(bytedata_1)
        tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1)
        metadata_1 = TxData()
        cache.update_or_add([(tx_id_1, metadata_1, bytedata_1,
                              TxFlags.StateCleared)])
        self.assertTrue(cache.is_cached(tx_id_1))
        entry = cache.get_entry(tx_id_1)
        self.assertEqual(TxFlags.HasByteData | TxFlags.StateCleared,
                         entry.flags)
        self.assertIsNotNone(entry.bytedata)

        # Update.
        metadata_2 = TxData(position=22)
        cache.update_or_add([(tx_id_1, metadata_2, None,
                              TxFlags.HasPosition | TxFlags.StateDispatched)])
        entry = cache.get_entry(tx_id_1)
        store_flags = self.store.get_flags(tx_id_1)
        # State flags if present get set in an update otherwise they remain the same.
        expected_flags = TxFlags.HasPosition | TxFlags.HasByteData | TxFlags.StateDispatched
        self.assertEqual(
            expected_flags, store_flags,
            f"{TxFlags.to_repr(expected_flags)} !=  {TxFlags.to_repr(store_flags)}"
        )
        self.assertEqual(
            expected_flags, entry.flags,
            f"{TxFlags.to_repr(expected_flags)} !=  {TxFlags.to_repr(entry.flags)}"
        )
        self.assertEqual(bytedata_1, entry.bytedata)
        self.assertEqual(metadata_2.position, entry.metadata.position)
    def update_row(self, row: int, values: Dict[int, Any]) -> bool:
        old_line = self._data[row]
        tx_id = hash_to_hex_str(old_line.hash)
        self._logger.debug("update_line tx=%s idx=%d", tx_id, row)

        if len(values):
            l = list(old_line)
            for value_index, value in values.items():
                l[value_index] = value
            new_line = self._data[row] = TxLine(*l)

            old_key = get_sort_key(old_line)
            new_key = get_sort_key(new_line)

            if old_key != new_key:
                # We need to move the line, so it is more than a simple row update.
                self.remove_row(row)
                insert_row = self._add_line(new_line)
                return True

        start_index = self.createIndex(row, 0)
        column_count = self.columnCount(start_index)
        end_index = self.createIndex(row, column_count-1)
        self.dataChanged.emit(start_index, end_index)

        return True
示例#18
0
    def test_get_many(self):
        to_add = []
        for i in range(10):
            tx_bytes = os.urandom(10)
            tx_hash_bytes = bitcoinx.double_sha256(tx_bytes)
            tx_id = bitcoinx.hash_to_hex_str(tx_hash_bytes)
            tx_data = TxData(height=None, fee=2, position=None, timestamp=None)
            to_add.append((tx_id, tx_data, tx_bytes, TxFlags.HasFee))
        self.store.add_many(to_add)

        # Test the first "add" id is matched.
        matches = self.store.get_many(tx_ids=[to_add[0][0]])
        self.assertEqual(to_add[0][0], matches[0][0])

        # Test no id is matched.
        matches = self.store.get_many(tx_ids=["aaaa"])
        self.assertEqual(0, len(matches))

        # Test flag and mask combinations.
        matches = self.store.get_many(flags=TxFlags.HasFee)
        self.assertEqual(10, len(matches))

        matches = self.store.get_many(flags=TxFlags.Unset,
                                      mask=TxFlags.HasHeight)
        self.assertEqual(10, len(matches))

        matches = self.store.get_many(flags=TxFlags.HasFee,
                                      mask=TxFlags.HasFee)
        self.assertEqual(10, len(matches))

        matches = self.store.get_many(flags=TxFlags.Unset, mask=TxFlags.HasFee)
        self.assertEqual(0, len(matches))
示例#19
0
 def _validate_new_flags(tx_hash: bytes, flags: TxFlags) -> None:
     # All current states are expected to have bytedata.
     if (flags & TxFlags.STATE_MASK) == 0 or (flags
                                              & TxFlags.HasByteData) != 0:
         return
     tx_id = hash_to_hex_str(tx_hash)
     raise InvalidDataError("setting uncleared state without bytedata "
                            f"{tx_id} {TxFlags.to_repr(flags)}")
示例#20
0
 def get_name(self, other_chain):
     if other_chain is self:
         return f'our_chain'
     else:
         fork_height = self.common_height(other_chain) + 1
         header = self.header_at_height(fork_height)
         prefix = hash_to_hex_str(header.hash).lstrip('00')[0:10]
         return f'{prefix}@{fork_height}'
    def _on_transaction_added(self, tx_hash: bytes, tx: Transaction, account_ids: Set[int]) \
            -> None:
        if not self._validate_account_event(account_ids):
            return

        self._logger.debug("_on_transaction_added %s", hash_to_hex_str(tx_hash))
        with self._update_lock:
            self._pending_state[tx_hash] = EventFlags.TX_ADDED
示例#22
0
    def _on_transaction_deleted(self, wallet_path: str, account_id: int,
                                tx_hash: bytes) -> None:
        if not self._validate_event(wallet_path, account_id):
            return

        self._logger.debug("_on_transaction_deleted %s",
                           hash_to_hex_str(tx_hash))
        self.remove_transactions([tx_hash])
示例#23
0
 def chain_name(self, chain, our_chain):
     if chain is our_chain:
         return f'our_chain'
     _chain, common_height = our_chain.common_chain_and_height(chain)
     fork_height = common_height + 1
     header = self.header_at_height(fork_height)
     prefix = hash_to_hex_str(header.hash).lstrip('00')[0:10]
     return f'{prefix}@{fork_height}'
示例#24
0
 def get_and_set_frozen_utxos_for_tx(self, tx: Transaction, child_wallet: AbstractAccount,
                                     freeze: bool=True) -> List[UTXO]:
     spendable_coins = child_wallet.get_utxos(exclude_frozen=False)
     input_keys = set(
         [(bitcoinx.hash_to_hex_str(input.prev_hash), input.prev_idx) for input in tx.inputs])
     frozen_utxos = [utxo for utxo in spendable_coins if utxo.key() in input_keys]
     child_wallet.set_frozen_coin_state(frozen_utxos, freeze)
     return frozen_utxos
示例#25
0
 def test_delete(self):
     tx_bytes = os.urandom(10)
     tx_hash_bytes = bitcoinx.double_sha256(tx_bytes)
     tx_id = bitcoinx.hash_to_hex_str(tx_hash_bytes)
     data = TxData(height=1, fee=2, position=None, timestamp=None)
     self.store.add(tx_id, data, tx_bytes)
     self.assertTrue(self.store.has(tx_id))
     self.store.delete(tx_id)
     self.assertFalse(self.store.has(tx_id))
示例#26
0
 def _write(db: sqlite3.Connection) -> None:
     if len(entries) < 20:
         self._logger.debug(
             "update %d transactions: %s", len(entries),
             [(hash_to_hex_str(a), b, byte_repr(c), TxFlags.to_repr(d))
              for (a, b, c, d) in entries])
     else:
         self._logger.debug("update %d transactions (too many to show)",
                            len(entries))
     db.executemany(self.UPDATE_MANY_SQL, datas)
示例#27
0
 def utxo_as_dict(self, utxo):
     return {"value": utxo.value,
             "script_pubkey": utxo.script_pubkey.to_hex(),
             "script_type": utxo.script_type,
             "tx_hash": hash_to_hex_str(utxo.tx_hash),
             "out_index": utxo.out_index,
             "keyinstance_id": utxo.keyinstance_id,
             "address": utxo.address.to_string(),
             "is_coinbase": utxo.is_coinbase,
             "flags": utxo.flags}  # TransactionOutputFlag(s) only
示例#28
0
    def deserialize_headers(cls, f):
        """deserialize block headers into a list of dicts"""
        lst_headers = []
        global headers_stream
        global hashes_stream
        # Store headers temporarily to memory as binary stream
        headers_stream.seek(0)
        headers_stream.write(f.read())

        # make a list of block hashes for validating
        headers_stream.seek(0)
        count = bitcoinx.read_varint(headers_stream.read)  # count of headers
        for i in range(count):
            header = headers_stream.read(80)  # minus final txn count (1 byte)
            headers_stream.read(1)  # discard txn count
            _hash = simple_spv.tools.get_block_hash(header)  # calculates hash as part of validation
            hashes_stream.write(_hash + '\n')

        f.seek(0)

        number_headers = bitcoinx.read_varint(f.read)
        for i in range(number_headers):
            # TODO make into single function call for readability and reuse
            version = bitcoinx.read_le_int32(f.read)
            prev_block = bitcoinx.hash_to_hex_str(f.read(32))
            merkle_root = bitcoinx.hash_to_hex_str(f.read(32))
            timestamp = bitcoinx.read_le_uint32(f.read)
            bits = ut.int_to_hex(bitcoinx.read_le_uint32(f.read))
            nonce = bitcoinx.read_le_uint32(f.read)
            txn_count = bitcoinx.read_varint(f.read)

            block_header = {'version': version,
                            'prev_block_hash': prev_block,
                            'merkle_root': merkle_root,
                            'timestamp': timestamp,
                            'bits': bits,
                            'nonce': nonce,
                            'txn_count': txn_count}

            lst_headers.append(block_header)

        return lst_headers
示例#29
0
    def test_get_unverified_entries_too_high(self):
        cache = TxCache(self.store)

        tx_bytes_1 = bytes.fromhex(tx_hex_1)
        tx_hash_bytes_1 = bitcoinx.double_sha256(tx_bytes_1)
        tx_id_1 = bitcoinx.hash_to_hex_str(tx_hash_bytes_1)
        data = TxData(height=11, position=22)
        cache.add([(tx_id_1, data, tx_bytes_1, TxFlags.StateCleared)])

        results = cache.get_unverified_entries(100)
        self.assertEqual(0, len(results))
示例#30
0
    def test_get_transaction(self):
        bytedata = bytes.fromhex(tx_hex_1)
        tx_hash_bytes = bitcoinx.double_sha256(bytedata)
        tx_id = bitcoinx.hash_to_hex_str(tx_hash_bytes)
        metadata = TxData(height=1, fee=2, position=None, timestamp=None)
        self.store.add(tx_id, metadata, bytedata)

        cache = TxCache(self.store)
        tx = cache.get_transaction(tx_id)
        self.assertIsNotNone(tx)
        self.assertEqual(tx_id, tx.txid())