コード例 #1
0
ファイル: address.py プロジェクト: mickeystone/cryptotools
    def utxos(self):
        if self._outputs is None:
            import urllib.request
            import json
            url = network('utxo_url').format(address=self.address)

            req = urllib.request.Request(url)
            outputs = []
            try:
                with urllib.request.urlopen(req) as resp:
                    data = json.loads(resp.read().decode())
            except HTTPError as e:
                resp = e.read().decode()
                if resp == 'No free outputs to spend':
                    self._outputs = []
                else:
                    raise UpstreamError(resp)
            else:
                for item in data['unspent_outputs']:
                    out = Output(value=item['value'],
                                 script=hex_to_bytes(item['script']))
                    out.parent_id = hex_to_bytes(item['tx_hash_big_endian'])
                    out.tx_index = item['tx_output_n']
                    outputs.append(out)
                self._outputs = outputs
        return self._outputs
コード例 #2
0
 def wif(self, compressed=False) -> str:
     from btctools import base58, sha256
     from btctools.network import network
     extended = network('wif') + self.bytes() + (b'\x01' if compressed else b'')
     hashed = sha256(sha256(extended))
     checksum = hashed[:4]
     return base58.encode(extended + checksum)
コード例 #3
0
ファイル: bip32.py プロジェクト: Starry9/cryptotools
 def serialize(self):
     version = network('extended_pub')[self.type]
     depth = int_to_bytes(self.depth)
     child = bytes(4) if self.is_master() else int_to_bytes(self.i).rjust(
         4, b'\x00')
     return version + depth + self.parent + child + self.code + self.keydata(
     )
コード例 #4
0
 def serialize(self):
     version = network('xprv')
     depth = int_to_bytes(self.depth)
     fingerprint = bytes(4) if self.depth == 0 else self.fingerprint()
     child = bytes(4) if self.i is None else int_to_bytes(self.i).rjust(
         4, b'\x00')
     return version + depth + fingerprint + child + self.code + self.keydata(
     )
コード例 #5
0
def get_address(script):
    """Extracts the address from a scriptPubkey"""
    script = hex_to_bytes(script) if isinstance(script, str) else script
    stype = get_type(script)
    if stype == TX.P2SH:
        data = script[2:22]
        version = network('scripthash')
        return hashed_payload_to_address(version + data)
    elif stype == TX.P2PKH:
        data = script[3:23]
        version = network('keyhash')
        return hashed_payload_to_address(version + data)
    elif stype in (TX.P2WSH, TX.P2WPKH):
        witver = version_byte(script)
        witprog = witness_program(script)
        return bech32.encode(network('hrp'), witver, witprog)
    elif stype == TX.P2PK:
        return "N/A"
    raise ValidationError(f"Unknown script type: {bytes_to_hex(script)}")
コード例 #6
0
ファイル: bip32.py プロジェクト: Starry9/cryptotools
    def deserialize(cls, bts: bytes) -> 'ExtendedKey':
        def read(n):
            nonlocal bts
            data, bts = bts[:n], bts[n:]
            return data

        net = read(4)
        is_private = net in network('extended_prv').values()
        is_public = net in network('extended_pub').values()
        assert is_public ^ is_private, f'Invalid network bytes : {bytes_to_hex(net)}'
        address_lookup = {
            val: key
            for key, val in (network('extended_prv') if is_private else
                             network('extended_pub')).items()
        }
        constructor = Xprv if is_private else Xpub
        depth = bytes_to_int(read(1))
        assert depth in range(256), f'Invalid depth : {depth}'
        fingerprint = read(4)
        i = bytes_to_int(read(4))
        if depth == 0:
            i = None
            path = None
        else:
            ih = f'{i}' if i < 2**31 else f"{i - 2**31}h"
            path = '/'.join([constructor.root_path] +
                            ['x' for _ in range(depth - 1)] + [ih])

        code = read(32)
        key = read(33)
        key = PrivateKey(key) if is_private else PublicKey.decode(key)
        assert not bts, 'Leftover bytes'
        return constructor(key,
                           code,
                           depth=depth,
                           i=i,
                           parent=fingerprint,
                           path=path,
                           addresstype=address_lookup[net])
コード例 #7
0
 def from_wif(cls, wif: str) -> 'PrivateKey':
     from btctools import base58, sha256
     from btctools.network import network
     bts = base58.decode(wif)
     network_byte, key, checksum = bts[0:1], bts[1:-4], bts[-4:]
     assert sha256(sha256(network_byte + key))[:4] == checksum, 'Invalid Checksum'
     assert network_byte == network('wif'), 'Invalid Network byte'
     if key.endswith(b'\x01'):
         key = key[:-1]
         compressed = True  # TODO
     else:
         compressed = False  # TODO
     return cls(key)
コード例 #8
0
ファイル: address.py プロジェクト: mickeystone/cryptotools
def address_type(addr):
    if addr.startswith(('1', '2', '3', 'm', 'n')):
        try:
            address = base58.decode(addr).rjust(25, b'\x00')
        except Base58DecodeError as e:
            raise InvalidAddress(f"{addr} : {e}") from None
        payload, checksum = address[:-4], address[-4:]
        version_byte, digest = payload[0:1], payload[1:].rjust(20, b'\x00')
        if len(digest) != 20:
            raise InvalidAddress(f"{addr} : Bad Payload") from None
        if sha256(sha256(payload))[:4] != checksum:
            raise InvalidAddress(f"{addr} : Invalid checksum") from None
        try:
            return {
                network('keyhash'): ADDRESS.P2PKH,
                network('scripthash'): ADDRESS.P2SH
            }[version_byte]
        except KeyError:
            raise InvalidAddress(f"{addr} : Invalid version byte") from None
    elif addr.startswith(network('hrp')):
        try:
            witness_version, witness_program = bech32.decode(
                network('hrp'), addr)
        except Bech32DecodeError as e:
            raise InvalidAddress(f"{addr} : {e}") from None

        if not witness_version == 0x00:
            raise InvalidAddress(f"{addr} : Invalid witness version") from None
        if len(witness_program) == 20:
            return ADDRESS.P2WPKH
        elif len(witness_program) == 32:
            return ADDRESS.P2WSH
        else:
            raise InvalidAddress(f"{addr} : Invalid witness program") from None
    else:
        raise InvalidAddress(f"{addr} : Invalid leading character") from None
コード例 #9
0
    def broadcast(self):
        import urllib.request
        import urllib.parse

        url = network('broadcast_url')
        payload = {'tx': self.hex()}
        data = urllib.parse.urlencode(payload).encode('ascii')
        req = urllib.request.Request(url, data)

        try:
            with urllib.request.urlopen(req) as response:
                resp = response.read()
        except HTTPError as e:
            resp = e.read()
        return resp.decode().strip('\n')
コード例 #10
0
    def get(cls, txhash):
        """Construct a transaction from it's tx id by getting the raw data from blockchain.info"""
        import urllib.request
        from urllib.error import HTTPError
        if isinstance(txhash, bytes):
            txhash = bytes_to_hex(txhash)

        url = network('rawtx_url').format(txid=txhash)
        req = urllib.request.Request(url)
        sleep(0.1)
        try:
            with urllib.request.urlopen(req) as resp:
                try:
                    return cls.from_hex(resp.read().decode())
                except SerializationError as e:
                    e.txhash = txhash
                    raise e
        except HTTPError as e:
            resp = e.read().decode()
            raise UpstreamError(resp)
コード例 #11
0
ファイル: address.py プロジェクト: mickeystone/cryptotools
 def _receive(self, value: int):
     """Creates an output that sends to this address"""
     addr_type = self.type()
     output = Output(value=value, script=b'')
     if addr_type == ADDRESS.P2PKH:
         address = base58.decode(self.address).rjust(25, b'\x00')
         keyhash = address[1:-4]
         output.script = OP.DUP.byte + OP.HASH160.byte + push(
             keyhash) + OP.EQUALVERIFY.byte + OP.CHECKSIG.byte
     elif addr_type == ADDRESS.P2SH:
         address = base58.decode(self.address).rjust(25, b'\x00')
         scripthash = address[1:-4]
         output.script = OP.HASH160.byte + push(scripthash) + OP.EQUAL.byte
     elif addr_type in (ADDRESS.P2WPKH, ADDRESS.P2WSH):
         witness_version, witness_program = bech32.decode(
             network('hrp'), self.address)
         output.script = OP(bytes_to_int(
             witness_byte(witness_version))).byte + push(
                 bytes(witness_program))
     else:
         raise ValidationError(f"Cannot create output of type {addr_type}")
     return output
コード例 #12
0
ファイル: address.py プロジェクト: mickeystone/cryptotools
def pubkey_to_bech32(pub: PublicKey, witver: int) -> str:
    """https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program"""
    witprog = hash160(pub.encode(compressed=True))
    return bech32.encode(network('hrp'), witver, witprog)
コード例 #13
0
ファイル: address.py プロジェクト: mickeystone/cryptotools
def script_to_bech32(script: bytes, witver: int) -> str:
    """https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program"""
    witprog = sha256(script)
    return bech32.encode(network('hrp'), witver, witprog)
コード例 #14
0
ファイル: address.py プロジェクト: mickeystone/cryptotools
def script_to_bech32(script: bytes, witver: int) -> str:
    """https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program"""
    witprog = sha256(script)
    return bech32.encode(network('hrp'), witver, witprog)


def pubkey_to_bech32(pub: PublicKey, witver: int) -> str:
    """https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program"""
    witprog = hash160(pub.encode(compressed=True))
    return bech32.encode(network('hrp'), witver, witprog)


key_to_addr_versions = {
    ADDRESS.P2PKH:
    lambda pub: legacy_address(pub, version_byte=network('keyhash')),
    # 'P2WPKH': partial(pubkey_to_p2wpkh, version_byte=0x06, witver=0x00),  # WAS REPLACED BY BIP 173
    ADDRESS.P2WPKH_P2SH:
    lambda pub: legacy_address(witness_byte(witver=0) + push(
        hash160(pub.encode(compressed=True))),
                               version_byte=network('scripthash')),
    ADDRESS.P2WPKH:
    partial(pubkey_to_bech32, witver=0x00),
}

script_to_addr_versions = {
    ADDRESS.P2SH:
    lambda script: legacy_address(script, version_byte=network('scripthash')),
    # 'P2WSH': partial(script_to_p2wsh, version_byte=0x0A, witver=0x00),  # WAS REPLACED BY BIP 173
    ADDRESS.P2WSH_P2SH:
    lambda script: legacy_address(witness_byte(witver=0) + push(sha256(script)