Ejemplo n.º 1
0
    def get_addresses(self, testnet=False):
        """ Returns all addresses found in this script

        For output scripts, P2PKH scripts will return a single
        address the funds are being sent to. P2SH scripts will
        return a single address of the script the funds are being
        sent to.

        For input scripts, only standard signature and
        multi-signature scripts will return results: the
        address(es) used to sign. For standard signature scripts,
        a single address is returned while for multi-sig scripts,
        all n addresses in the redeem script are returned.

        Args:
            testnet (bool): True if the addresses are being used on testnet,
                False if used on mainnet.

        Returns:
            list: A list of Base58Check encoded bitcoin addresses.
        """
        rv = []
        # Determine script type
        if self.is_p2pkh():
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            rv.append(key_hash_to_address(self.get_hash160(), version))
        elif self.is_p2sh():
            version = self.P2SH_TESTNET_VERSION if testnet else self.P2SH_MAINNET_VERSION
            rv.append(key_hash_to_address(self.get_hash160(), version))
        elif self.is_multisig_sig():
            # Extract out the info
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            sig_info = self.extract_multisig_sig_info()
            redeem_info = sig_info[
                'redeem_script'].extract_multisig_redeem_info()
            for p in redeem_info['public_keys']:
                rv.append(key_hash_to_address(hash160(p), version))
            # Also include the address of the redeem script itself.
            redeem_version = self.P2SH_TESTNET_VERSION if testnet else self.P2SH_MAINNET_VERSION
            rv.append(
                key_hash_to_address(sig_info['redeem_script'].hash160(),
                                    redeem_version))
        elif self.is_p2pkh_sig():
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            # Normal signature script...
            sig_info = self.extract_sig_info()
            rv.append(
                key_hash_to_address(hash160(sig_info['public_key']), version))
        elif Script.validate_template(self, [bytes, 'OP_CHECKSIG']):
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            rv.append(key_hash_to_address(hash160(self[0]), version))

        return rv
Ejemplo n.º 2
0
    def get_addresses(self, testnet=False):
        """ Returns all addresses found in this script

        For output scripts, P2PKH scripts will return a single
        address the funds are being sent to. P2SH scripts will
        return a single address of the script the funds are being
        sent to.

        For input scripts, only standard signature and
        multi-signature scripts will return results: the
        address(es) used to sign. For standard signature scripts,
        a single address is returned while for multi-sig scripts,
        all n addresses in the redeem script are returned.

        Args:
            testnet (bool): True if the addresses are being used on testnet,
                False if used on mainnet.

        Returns:
            list: A list of Base58Check encoded bitcoin addresses.
        """
        rv = []
        # Determine script type
        if self.is_p2pkh():
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            rv.append(key_hash_to_address(self.get_hash160(), version))
        elif self.is_p2sh():
            version = self.P2SH_TESTNET_VERSION if testnet else self.P2SH_MAINNET_VERSION
            rv.append(key_hash_to_address(self.get_hash160(), version))
        elif self.is_multisig_sig():
            # Extract out the info
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            sig_info = self.extract_multisig_sig_info()
            redeem_info = sig_info['redeem_script'].extract_multisig_redeem_info()
            for p in redeem_info['public_keys']:
                rv.append(key_hash_to_address(hash160(p), version))
            # Also include the address of the redeem script itself.
            redeem_version = self.P2SH_TESTNET_VERSION if testnet else self.P2SH_MAINNET_VERSION
            rv.append(key_hash_to_address(sig_info['redeem_script'].hash160(), redeem_version))
        elif self.is_p2pkh_sig():
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            # Normal signature script...
            sig_info = self.extract_sig_info()
            rv.append(key_hash_to_address(hash160(sig_info['public_key']),
                                          version))
        elif Script.validate_template(self, [bytes, 'OP_CHECKSIG']):
            version = self.P2PKH_TESTNET_VERSION if testnet else self.P2PKH_MAINNET_VERSION
            rv.append(key_hash_to_address(hash160(self[0]), version))

        return rv
Ejemplo n.º 3
0
    def insert_txn(self, wallet_txn, mark_provisional=False, expiration=0):
        """ Inserts a transaction into the cache and updates the
            relevant dicts based on the addresses found in the
            transaction.

        Args:
            wallet_txn (WalletTransaction): A wallet transaction object.
            mark_provisional (bool): Marks the transaction as
                provisional (i.e. the transaction may have been built
                but not yet broadcast to the blockchain). Transactions
                marked as provisional are automatically pruned if they
                are not also seen by normal transaction
                updates/insertions within a certain time period.
            expiration (int): Time, in seconds from epoch, when a provisional
                transaction should be automatically pruned. This is invalid
                unless mark_provisional=True. If expiration == 0, it is set
                to time.time() + PROVISIONAL_MAX_DURATION. This cannot be
                greater than PROVISIONAL_MAX_DURATION seconds in the future.
        """
        txid = str(wallet_txn.hash)

        # Check if it's already in with no change in status
        if txid in self._txn_cache and \
           wallet_txn._serialize() == self._txn_cache[txid]._serialize():
            return

        if mark_provisional and not wallet_txn.provisional:
            now = time.time()
            if expiration < 0:
                raise ValueError("expiration cannot be negative.")

            if expiration == 0 or \
               expiration > now + self.PROVISIONAL_MAX_DURATION:
                expiration = now + self.PROVISIONAL_MAX_DURATION
            wallet_txn.provisional = expiration

        if not mark_provisional and wallet_txn.provisional:
            wallet_txn.provisional = False

        self._txn_cache[txid] = wallet_txn

        conf = wallet_txn.confirmations > 0
        status = self.SPENT
        out_status = self.UNSPENT
        if not conf:
            status |= self.UNCONFIRMED
            out_status |= self.UNCONFIRMED
        if mark_provisional:
            status |= self.PROVISIONAL
            out_status |= self.PROVISIONAL

        # Get all the addresses for the transaction
        addrs = wallet_txn.get_addresses(self.testnet)

        if txid not in self._inputs_cache:
            self._inputs_cache[txid] = dict()

        if txid not in self._outputs_cache:
            self._outputs_cache[txid] = dict()

        for i, inp in enumerate(wallet_txn.inputs):
            self._inputs_cache[txid][i] = inp

            if not isinstance(inp,
                              CoinbaseInput) and inp.script.is_multisig_sig():
                # Only keep the P2SH address
                sig_info = inp.script.extract_multisig_sig_info()
                redeem_version = Script.P2SH_TESTNET_VERSION if self.testnet \
                    else Script.P2SH_MAINNET_VERSION
                a = key_hash_to_address(sig_info['redeem_script'].hash160(),
                                        redeem_version)

                addrs['inputs'][i] = [a]

            # Update the status of any outputs
            out_txid = str(inp.outpoint)
            if out_txid not in self._outputs_cache:
                self._outputs_cache[out_txid] = {}

            if inp.outpoint_index not in self._outputs_cache[out_txid]:
                d = dict(output=None,
                         status=status,
                         spend_txid=txid,
                         spend_index=i)
                self._outputs_cache[out_txid][inp.outpoint_index] = d
            else:
                x = self._outputs_cache[out_txid][inp.outpoint_index]
                x['status'] = status
                x['spend_txid'] = txid
                x['spend_index'] = i

        for i, out in enumerate(wallet_txn.outputs):
            if i in self._outputs_cache[txid]:
                o = self._outputs_cache[txid][i]
                o['output'] = out
                # Only update the status if it is unconfirmed unspent going
                # to confirmed unspent as it is possible that an input has
                # already marked it as spent.
                if not (o['status'] & self.SPENT):
                    o['status'] = out_status
            else:
                self._outputs_cache[txid][i] = dict(output=out,
                                                    status=out_status,
                                                    spend_txid=None,
                                                    spend_index=None)

        self._insert_txid(txid, addrs['inputs'], 'input')
        self._insert_txid(txid, addrs['outputs'], 'output')

        self._dirty = True
Ejemplo n.º 4
0
    def insert_txn(self, wallet_txn, mark_provisional=False, expiration=0):
        """ Inserts a transaction into the cache and updates the
            relevant dicts based on the addresses found in the
            transaction.

        Args:
            wallet_txn (WalletTransaction): A wallet transaction object.
            mark_provisional (bool): Marks the transaction as
                provisional (i.e. the transaction may have been built
                but not yet broadcast to the blockchain). Transactions
                marked as provisional are automatically pruned if they
                are not also seen by normal transaction
                updates/insertions within a certain time period.
            expiration (int): Time, in seconds from epoch, when a provisional
                transaction should be automatically pruned. This is invalid
                unless mark_provisional=True. If expiration == 0, it is set
                to time.time() + PROVISIONAL_MAX_DURATION. This cannot be
                greater than PROVISIONAL_MAX_DURATION seconds in the future.
        """
        txid = str(wallet_txn.hash)

        # Check if it's already in with no change in status
        if txid in self._txn_cache and \
           wallet_txn._serialize() == self._txn_cache[txid]._serialize():
            return

        if mark_provisional and not wallet_txn.provisional:
            now = time.time()
            if expiration < 0:
                raise ValueError("expiration cannot be negative.")

            if expiration == 0 or \
               expiration > now + self.PROVISIONAL_MAX_DURATION:
                expiration = now + self.PROVISIONAL_MAX_DURATION
            wallet_txn.provisional = expiration

        if not mark_provisional and wallet_txn.provisional:
            wallet_txn.provisional = False

        self._txn_cache[txid] = wallet_txn

        conf = wallet_txn.confirmations > 0
        status = self.SPENT
        out_status = self.UNSPENT
        if not conf:
            status |= self.UNCONFIRMED
            out_status |= self.UNCONFIRMED
        if mark_provisional:
            status |= self.PROVISIONAL
            out_status |= self.PROVISIONAL

        # Get all the addresses for the transaction
        addrs = wallet_txn.get_addresses(self.testnet)

        if txid not in self._inputs_cache:
            self._inputs_cache[txid] = dict()

        if txid not in self._outputs_cache:
            self._outputs_cache[txid] = dict()

        for i, inp in enumerate(wallet_txn.inputs):
            self._inputs_cache[txid][i] = inp

            if not isinstance(inp, CoinbaseInput) and inp.script.is_multisig_sig():
                # Only keep the P2SH address
                sig_info = inp.script.extract_multisig_sig_info()
                redeem_version = Script.P2SH_TESTNET_VERSION if self.testnet \
                    else Script.P2SH_MAINNET_VERSION
                a = key_hash_to_address(
                    sig_info['redeem_script'].hash160(), redeem_version)

                addrs['inputs'][i] = [a]

            # Update the status of any outputs
            out_txid = str(inp.outpoint)
            if out_txid not in self._outputs_cache:
                self._outputs_cache[out_txid] = {}

            if inp.outpoint_index not in self._outputs_cache[out_txid]:
                d = dict(output=None,
                         status=status,
                         spend_txid=txid,
                         spend_index=i)
                self._outputs_cache[out_txid][inp.outpoint_index] = d
            else:
                x = self._outputs_cache[out_txid][inp.outpoint_index]
                x['status'] = status
                x['spend_txid'] = txid
                x['spend_index'] = i

        for i, out in enumerate(wallet_txn.outputs):
            if i in self._outputs_cache[txid]:
                o = self._outputs_cache[txid][i]
                o['output'] = out
                # Only update the status if it is unconfirmed unspent going
                # to confirmed unspent as it is possible that an input has
                # already marked it as spent.
                if not (o['status'] & self.SPENT):
                    o['status'] = out_status
            else:
                self._outputs_cache[txid][i] = dict(output=out,
                                                    status=out_status,
                                                    spend_txid=None,
                                                    spend_index=None)

        self._insert_txid(txid, addrs['inputs'], 'input')
        self._insert_txid(txid, addrs['outputs'], 'output')

        self._dirty = True