示例#1
0
    def get_public_key(self, change, n=-1):
        """ Returns a public key in the chain
        Args:
            change (bool): If True, returns an address for change purposes,
               otherwise returns an address for payment.
            n (int): index of address in chain. If n == -1, a new key
               is created with index = self.last_[change|payout]_index + 1
        Returns:
            HDPublicKey: a public key in this account's chain.
        """
        # We only use public key derivation per BIP44
        c = int(change)
        k = self._chain_pub_keys[c]
        if n < 0:
            self.last_indices[c] += 1
            i = self.last_indices[c]
            pub_key = HDPublicKey.from_parent(k, i)
            addr = pub_key.address(True, self.testnet)
            self._cache_manager.insert_address(self.index, change, i, addr)
        else:
            pub_key = HDPublicKey.from_parent(k, n)

        return pub_key
示例#2
0
    def from_bytes(b):
        """ Generates either a HDPrivateKey or HDPublicKey from the underlying
            bytes.
            The serialization must conform to the description in:
            https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format
        Args:
            b (bytes): A byte stream conforming to the above.
        Returns:
            HDPrivateKey or HDPublicKey: Either an HD private or
                public key object, depending on what was serialized.
        """
        if len(b) < 78:
            raise ValueError("b must be at least 78 bytes long.")

        version = int.from_bytes(b[:4], 'big')
        depth = b[4]
        parent_fingerprint = b[5:9]
        index = int.from_bytes(b[9:13], 'big')
        chain_code = b[13:45]
        key_bytes = b[45:78]

        rv = None
        if version == HDPrivateKey.MAINNET_VERSION or version == HDPrivateKey.TESTNET_VERSION:
            if key_bytes[0] != 0:
                raise ValueError("First byte of private key must be 0x00!")

            private_key = int.from_bytes(key_bytes[1:], 'big')
            rv = HDPrivateKey(key=private_key,
                              chain_code=chain_code,
                              index=index,
                              depth=depth,
                              parent_fingerprint=parent_fingerprint)
        elif version == HDPublicKey.MAINNET_VERSION or version == HDPublicKey.TESTNET_VERSION:
            if key_bytes[0] != 0x02 and key_bytes[0] != 0x03:
                raise ValueError("First byte of public key must be 0x02 or 0x03!")

            public_key = PublicKey.from_bytes(key_bytes)
            rv = HDPublicKey(x=public_key.point.x,
                             y=public_key.point.y,
                             chain_code=chain_code,
                             index=index,
                             depth=depth,
                             parent_fingerprint=parent_fingerprint)
        else:
            raise ValueError("incorrect encoding.")

        return (rv, b[78:])
示例#3
0
    def __init__(self, hd_key, name, index, data_provider, cache_manager,
                 testnet=False, last_state=None, skip_discovery=False):
        # Take in either public or private key for this account as we
        # can derive everything from it.
        if not isinstance(hd_key, HDKey):
            raise TypeError("hd_key must be a HDKey object")

        self.key = hd_key
        self.name = name
        self.index = index
        self.data_provider = data_provider
        self.testnet = testnet

        self.last_indices = [-1, -1]
        self._cache_manager = cache_manager
        self._last_update = 0
        self._last_full_update = 0

        if last_state is not None and isinstance(last_state, dict):
            if "last_payout_index" in last_state:
                self.last_indices[self.PAYOUT_CHAIN] = last_state["last_payout_index"]
            if "last_change_index" in last_state:
                self.last_indices[self.CHANGE_CHAIN] = last_state["last_change_index"]

        # Check to see that the address cache has up to last_indices
        for change in [self.PAYOUT_CHAIN, self.CHANGE_CHAIN]:
            k = self._cache_manager.get_chain_indices(self.index, change)
            for i in range(self.last_indices[change] + 1):
                if i not in k or k[i] != i:
                    self.last_indices[change] = -1
                    break

        self._chain_priv_keys = [None, None]
        self._chain_pub_keys = [None, None]

        for change in [0, 1]:
            if isinstance(self.key, HDPrivateKey):
                self._chain_priv_keys[change] = HDPrivateKey.from_parent(self.key, change)
                self._chain_pub_keys[change] = self._chain_priv_keys[change].public_key
            else:
                self._chain_pub_keys[change] = HDPublicKey.from_parent(self.key, change)

        if not skip_discovery:
            self._sync_txns(check_all=True)
            self._update_balance()