Exemplo n.º 1
0
def multisig_script(public_keys: Sequence[str], m: int) -> str:
    n = len(public_keys)
    assert 1 <= m <= n <= 15, f'm {m}, n {n}'
    op_m = bh2u(add_number_to_script(m))
    op_n = bh2u(add_number_to_script(n))
    keylist = [push_script(k) for k in public_keys]
    return op_m + ''.join(keylist) + op_n + opcodes.OP_CHECKMULTISIG.hex()
Exemplo n.º 2
0
def get_address_from_output_script(_bytes: bytes,
                                   *,
                                   net=None) -> Tuple[int, str]:
    try:
        decoded = [x for x in script_GetOp(_bytes)]
    except MalformedBitcoinScript:
        decoded = None

    # p2pk
    match = [OPPushDataPubkey, opcodes.OP_CHECKSIG]
    if match_decoded(decoded, match) and ecc.ECPubkey.is_pubkey_bytes(
            decoded[0][1]):
        return TYPE_PUBKEY, bh2u(decoded[0][1])

    # p2pkh
    match = [
        opcodes.OP_DUP, opcodes.OP_HASH160,
        OPPushDataGeneric(lambda x: x == 20), opcodes.OP_EQUALVERIFY,
        opcodes.OP_CHECKSIG
    ]
    if match_decoded(decoded, match):
        return TYPE_ADDRESS, hash160_to_p2pkh(decoded[2][1], net=net)

    # p2sh
    match = [
        opcodes.OP_HASH160,
        OPPushDataGeneric(lambda x: x == 20), opcodes.OP_EQUAL
    ]
    if match_decoded(decoded, match):
        return TYPE_ADDRESS, hash160_to_p2sh(decoded[1][1], net=net)

    # segwit address (version 0)
    match = [opcodes.OP_0, OPPushDataGeneric(lambda x: x in (20, 32))]
    if match_decoded(decoded, match):
        return TYPE_ADDRESS, hash_to_segwit_addr(decoded[1][1],
                                                 witver=0,
                                                 net=net)

    # segwit address (version 1-16)
    future_witness_versions = list(range(opcodes.OP_1, opcodes.OP_16 + 1))
    for witver, opcode in enumerate(future_witness_versions, start=1):
        match = [opcode, OPPushDataGeneric(lambda x: 2 <= x <= 40)]
        if match_decoded(decoded, match):
            return TYPE_ADDRESS, hash_to_segwit_addr(decoded[1][1],
                                                     witver=witver,
                                                     net=net)

    return TYPE_SCRIPT, bh2u(_bytes)
Exemplo n.º 3
0
 def txid(self):
     self.deserialize()
     all_segwit = all(self.is_segwit_input(x) for x in self.inputs())
     if not all_segwit and not self.is_complete():
         return None
     ser = self.serialize_to_network(witness=False)
     return bh2u(sha256d(bfh(ser))[::-1])
Exemplo n.º 4
0
 def _calc_bip143_shared_txdigest_fields(
         self) -> BIP143SharedTxDigestFields:
     inputs = self.inputs()
     outputs = self.outputs()
     hashPrevouts = bh2u(
         sha256d(
             bfh(''.join(self.serialize_outpoint(txin)
                         for txin in inputs))))
     hashSequence = bh2u(
         sha256d(
             bfh(''.join(
                 int_to_hex(txin.get('sequence', 0xffffffff - 1), 4)
                 for txin in inputs))))
     hashOutputs = bh2u(
         sha256d(bfh(''.join(self.serialize_output(o) for o in outputs))))
     return BIP143SharedTxDigestFields(hashPrevouts=hashPrevouts,
                                       hashSequence=hashSequence,
                                       hashOutputs=hashOutputs)
Exemplo n.º 5
0
def construct_witness(items: Sequence[Union[str, int, bytes]]) -> str:
    """Constructs a witness from the given stack items."""
    witness = var_int(len(items))
    for item in items:
        if type(item) is int:
            item = bitcoin.script_num_to_hex(item)
        elif type(item) is bytes:
            item = bh2u(item)
        witness += bitcoin.witness_push(item)
    return witness
Exemplo n.º 6
0
 def serialize(self, estimate_size=False, witness=True):
     network_ser = self.serialize_to_network(estimate_size, witness)
     if estimate_size:
         return network_ser
     if self.is_partial_originally and not self.is_complete():
         partial_format_version = '00'
         return bh2u(PARTIAL_TXN_HEADER_MAGIC
                     ) + partial_format_version + network_ser
     else:
         return network_ser
Exemplo n.º 7
0
def parse_witness(vds, txin, full_parse: bool):
    n = vds.read_compact_size()
    if n == 0:
        txin['witness'] = '00'
        return
    if n == 0xffffffff:
        txin['value'] = vds.read_uint64()
        txin['witness_version'] = vds.read_uint16()
        n = vds.read_compact_size()
    # now 'n' is the number of items in the witness
    w = list(bh2u(vds.read_bytes(vds.read_compact_size())) for i in range(n))
    txin['witness'] = construct_witness(w)
    if not full_parse:
        return

    try:
        if txin.get('witness_version', 0) != 0:
            raise UnknownTxinType()
        if txin['type'] == 'coinbase':
            pass
        elif txin['type'] == 'address':
            pass
        elif txin['type'] == 'p2wsh-p2sh' or n > 2:
            witness_script_unsanitized = w[
                -1]  # for partial multisig txn, this has x_pubkeys
            try:
                m, n, x_pubkeys, pubkeys, witness_script = parse_redeemScript_multisig(
                    bfh(witness_script_unsanitized))
            except NotRecognizedRedeemScript:
                raise UnknownTxinType()
            txin['signatures'] = parse_sig(w[1:-1])
            txin['num_sig'] = m
            txin['x_pubkeys'] = x_pubkeys
            txin['pubkeys'] = pubkeys
            txin['witness_script'] = witness_script
            if not txin.get('scriptSig'):  # native segwit script
                txin['type'] = 'p2wsh'
                txin['address'] = bitcoin.script_to_p2wsh(witness_script)
        elif txin['type'] == 'p2wpkh-p2sh' or n == 2:
            txin['num_sig'] = 1
            txin['x_pubkeys'] = [w[1]]
            txin['pubkeys'] = [safe_parse_pubkey(w[1])]
            txin['signatures'] = parse_sig([w[0]])
            if not txin.get('scriptSig'):  # native segwit script
                txin['type'] = 'p2wpkh'
                txin['address'] = bitcoin.public_key_to_p2wpkh(
                    bfh(txin['pubkeys'][0]))
        else:
            raise UnknownTxinType()
    except UnknownTxinType:
        txin['type'] = 'unknown'
    except BaseException:
        txin['type'] = 'unknown'
        _logger.exception(f"failed to parse witness {txin.get('witness')}")
Exemplo n.º 8
0
def parse_output(vds, i):
    d = {}
    d['value'] = vds.read_int64()
    if d['value'] > TOTAL_COIN_SUPPLY_LIMIT_IN_BTC * COIN:
        raise SerializationError('invalid output amount (too large)')
    if d['value'] < 0:
        raise SerializationError('invalid output amount (negative)')
    scriptPubKey = vds.read_bytes(vds.read_compact_size())
    d['type'], d['address'] = get_address_from_output_script(scriptPubKey)
    d['scriptPubKey'] = bh2u(scriptPubKey)
    d['prevout_n'] = i
    return d
Exemplo n.º 9
0
 def sign_txin(self,
               txin_index,
               privkey_bytes,
               *,
               bip143_shared_txdigest_fields=None) -> str:
     pre_hash = sha256d(
         bfh(
             self.serialize_preimage(
                 txin_index,
                 bip143_shared_txdigest_fields=bip143_shared_txdigest_fields
             )))
     privkey = ecc.ECPrivkey(privkey_bytes)
     sig = privkey.sign_transaction(pre_hash)
     sig = bh2u(sig) + '01'
     return sig
Exemplo n.º 10
0
    def get_preimage_script(self, txin):
        preimage_script = txin.get('preimage_script', None)
        if preimage_script is not None:
            return preimage_script

        pubkeys, x_pubkeys = self.get_sorted_pubkeys(txin)
        if txin['type'] == 'p2pkh':
            return bitcoin.address_to_script(txin['address'])
        elif txin['type'] in ['p2sh', 'p2wsh', 'p2wsh-p2sh']:
            return multisig_script(pubkeys, txin['num_sig'])
        elif txin['type'] in ['p2wpkh', 'p2wpkh-p2sh']:
            pubkey = pubkeys[0]
            pkh = bh2u(hash_160(bfh(pubkey)))
            return '76a9' + push_script(pkh) + '88ac'
        elif txin['type'] == 'p2pk':
            pubkey = pubkeys[0]
            return bitcoin.public_key_to_p2pk_script(pubkey)
        else:
            raise TypeError('Unknown txin type', txin['type'])
Exemplo n.º 11
0
def parse_input(vds, full_parse: bool):
    d = {}
    prevout_hash = hash_encode(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['scriptSig'] = bh2u(scriptSig)
    d['sequence'] = sequence
    d['type'] = 'unknown' if prevout_hash != '00' * 32 else 'coinbase'
    d['address'] = None
    d['num_sig'] = 0
    if not full_parse:
        return d
    d['x_pubkeys'] = []
    d['pubkeys'] = []
    d['signatures'] = {}
    if d['type'] != 'coinbase' and scriptSig:
        try:
            parse_scriptSig(d, scriptSig)
        except BaseException:
            _logger.exception(f'failed to parse scriptSig {bh2u(scriptSig)}')
    return d
Exemplo n.º 12
0
def parse_redeemScript_multisig(redeem_script: bytes):
    try:
        dec2 = [x for x in script_GetOp(redeem_script)]
    except MalformedBitcoinScript:
        raise NotRecognizedRedeemScript()
    try:
        m = dec2[0][0] - opcodes.OP_1 + 1
        n = dec2[-2][0] - opcodes.OP_1 + 1
    except IndexError:
        raise NotRecognizedRedeemScript()
    op_m = opcodes.OP_1 + m - 1
    op_n = opcodes.OP_1 + n - 1
    match_multisig = [op_m] + [OPPushDataGeneric] * n + [
        op_n, opcodes.OP_CHECKMULTISIG
    ]
    if not match_decoded(dec2, match_multisig):
        raise NotRecognizedRedeemScript()
    x_pubkeys = [bh2u(x[1]) for x in dec2[1:-2]]
    pubkeys = [safe_parse_pubkey(x) for x in x_pubkeys]
    redeem_script2 = bfh(multisig_script(x_pubkeys, m))
    if redeem_script2 != redeem_script:
        raise NotRecognizedRedeemScript()
    redeem_script_sanitized = multisig_script(pubkeys, m)
    return m, n, x_pubkeys, pubkeys, redeem_script_sanitized
Exemplo n.º 13
0
def parse_scriptSig(d, _bytes):
    try:
        decoded = [x for x in script_GetOp(_bytes)]
    except Exception as e:
        # coinbase transactions raise an exception
        _logger.info(
            f"parse_scriptSig: cannot find address in input script (coinbase?) {bh2u(_bytes)}"
        )
        return

    match = [OPPushDataGeneric]
    if match_decoded(decoded, match):
        item = decoded[0][1]
        if item[0] == 0:
            # segwit embedded into p2sh
            # witness version 0
            d['address'] = bitcoin.hash160_to_p2sh(hash_160(item))
            if len(item) == 22:
                d['type'] = 'p2wpkh-p2sh'
            elif len(item) == 34:
                d['type'] = 'p2wsh-p2sh'
            else:
                _logger.info(f"unrecognized txin type {bh2u(item)}")
        elif opcodes.OP_1 <= item[0] <= opcodes.OP_16:
            # segwit embedded into p2sh
            # witness version 1-16
            pass
        else:
            # assert item[0] == 0x30
            # pay-to-pubkey
            d['type'] = 'p2pk'
            d['address'] = "(pubkey)"
            d['signatures'] = [bh2u(item)]
            d['num_sig'] = 1
            d['x_pubkeys'] = ["(pubkey)"]
            d['pubkeys'] = ["(pubkey)"]
        return

    # p2pkh TxIn transactions push a signature
    # (71-73 bytes) and then their public key
    # (33 or 65 bytes) onto the stack:
    match = [OPPushDataGeneric, OPPushDataGeneric]
    if match_decoded(decoded, match):
        sig = bh2u(decoded[0][1])
        x_pubkey = bh2u(decoded[1][1])
        try:
            signatures = parse_sig([sig])
            pubkey, address = xpubkey_to_address(x_pubkey)
        except:
            _logger.info(
                f"parse_scriptSig: cannot find address in input script (p2pkh?) {bh2u(_bytes)}"
            )
            return
        d['type'] = 'p2pkh'
        d['signatures'] = signatures
        d['x_pubkeys'] = [x_pubkey]
        d['num_sig'] = 1
        d['pubkeys'] = [pubkey]
        d['address'] = address
        return

    # p2sh transaction, m of n
    match = [opcodes.OP_0] + [OPPushDataGeneric] * (len(decoded) - 1)
    if match_decoded(decoded, match):
        x_sig = [bh2u(x[1]) for x in decoded[1:-1]]
        redeem_script_unsanitized = decoded[-1][
            1]  # for partial multisig txn, this has x_pubkeys
        try:
            m, n, x_pubkeys, pubkeys, redeem_script = parse_redeemScript_multisig(
                redeem_script_unsanitized)
        except NotRecognizedRedeemScript:
            _logger.info(
                f"parse_scriptSig: cannot find address in input script (p2sh?) {bh2u(_bytes)}"
            )

            # we could still guess:
            # d['address'] = hash160_to_p2sh(hash_160(decoded[-1][1]))
            return
        # write result in d
        d['type'] = 'p2sh'
        d['num_sig'] = m
        d['signatures'] = parse_sig(x_sig)
        d['x_pubkeys'] = x_pubkeys
        d['pubkeys'] = pubkeys
        d['redeem_script'] = redeem_script
        d['address'] = hash160_to_p2sh(hash_160(bfh(redeem_script)))
        return

    # custom partial format for imported addresses
    match = [opcodes.OP_INVALIDOPCODE, opcodes.OP_0, OPPushDataGeneric]
    if match_decoded(decoded, match):
        x_pubkey = bh2u(decoded[2][1])
        pubkey, address = xpubkey_to_address(x_pubkey)
        d['type'] = 'address'
        d['address'] = address
        d['num_sig'] = 1
        d['x_pubkeys'] = [x_pubkey]
        d['pubkeys'] = None  # get_sorted_pubkeys will populate this
        d['signatures'] = [None]
        return

    _logger.info(
        f"parse_scriptSig: cannot find address in input script (unknown) {bh2u(_bytes)}"
    )
Exemplo n.º 14
0
 def wtxid(self):
     self.deserialize()
     if not self.is_complete():
         return None
     ser = self.serialize_to_network(witness=True)
     return bh2u(sha256d(bfh(ser))[::-1])
Exemplo n.º 15
0
 def serialize_outpoint(self, txin):
     return bh2u(bfh(txin['prevout_hash'])[::-1]) + int_to_hex(
         txin['prevout_n'], 4)