Пример #1
0
    def createrawtransaction(self, addscript=True, withmark=True):
        """
			:addscript bool: For witness input, you can choose dont add input script(i.e. 0014dc72fd7bf4ef5bfd8dfe021f41f1ad7d37166dca)
		"""

        if not (self.check_inputs() and self.check_outputs()):
            # check input and output, if failed, over.
            return

        hex_input = ""
        witness_blank = ""
        vin_count = tolittle_endian(len(self.inputs), 2)
        hex_input += vin_count

        for _, input_ in enumerate(self.inputs):
            prev_txid = input_.get("prev_txid")
            prev_vout = input_.get("prev_vout")

            # script_length, signature, sighash_type, pubkey
            script = self.createscript(input_)

            if script and addscript:
                for _ in range(2):
                    # double length for witness input script
                    script = _hex(len(script) / 2) + script
            else:
                script = "00"

            sequence = self.seq

            if input_.get("address_type") in [P2SH, P2PKH]:
                script_blank = "{%s_%s}" % (input_.get("address"), prev_txid)
                hex_input += prev_txid + prev_vout + script_blank + sequence
                witness_blank += "00"

            else:
                witness_blank += "{%s_%s}" % (input_.get("address"), prev_txid)
                hex_input += prev_txid + prev_vout + script + sequence

        hex_output = ""

        vout_count = tolittle_endian(len(self.outputs), 2)
        hex_output += vout_count

        for output_ in self.outputs:
            amount = tolittle_endian(output_.get("amount"), 16)
            scriptpubkey = output_.get("scriptpubkey")

            hex_output += amount + _hex(len(scriptpubkey) / 2) + scriptpubkey

        txhex = self.ver + self.maker + self.flag + hex_input + hex_output + witness_blank + self.locktime

        if withmark:
            return txhex

        return re.sub(r"{.*?}", "{}", txhex).format(*(["00"] * int(vin_count)))
Пример #2
0
    def scriptlength(self, value):
        value = int(len(value) / 2)
        if 0 < value <= int("fc", 16):
            return _hex(value)

        else:
            return "fd" + tolittle_endian(
                _hex(value + 1)) + "00"  # 1bytes for OP_0(00)
Пример #3
0
    def createrawtransaction(self, withmark=True):

        # raise RuntimeError("can not handle multisig yet")

        if not (self.check_inputs() and self.check_outputs()):
            # check input and output, if failed, over.
            return

        hex_input = ""

        vin_count = tolittle_endian(len(self.inputs), 2)
        hex_input += vin_count

        for num, input_ in enumerate(self.inputs):
            prev_txid = input_.get("prev_txid")
            prev_vout = input_.get("prev_vout")

            # script_length, signature, sighash_type, pubkey
            script_blank = "{%s_%s}" % (input_.get("address"), prev_txid)
            sequence = self.seq

            hex_input += prev_txid + prev_vout + script_blank + sequence

        hex_output = ""

        vout_count = tolittle_endian(len(self.outputs), 2)
        hex_output += vout_count

        for output_ in self.outputs:
            amount = tolittle_endian(output_.get("amount"), 16)
            scriptpubkey = output_.get("scriptpubkey")

            hex_output += amount + _hex(len(scriptpubkey) / 2) + scriptpubkey

        txhex = self.ver + hex_input + hex_output + self.locktime

        if withmark:
            return txhex

        return re.sub(r"{.*?}", "{}", txhex).format(*(["00"] * int(vin_count)))
Пример #4
0
def txid(txhex):
    """
		return txid, wtxid
	"""
    # https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id
    if txhex.find("0001") == 8:
        # witness
        wtxid = hexlify(dsha256(txhex))

        _dict = loads(witness_tx.decoderawtransaction(txhex),
                      object_pairs_hook=OrderedDict)
        _dict["maker"] = ""
        _dict["flag"] = ""

        for v in _dict.get("vin"):
            if v.get("txwitness"):
                v["txwitness"] = ""

        txid = hexlify(dsha256(tohex(_dict)))

    else:
        txid = wtxid = hexlify(dsha256(txhex))

    return tolittle_endian(txid), tolittle_endian(wtxid)
Пример #5
0
def decodewtx(txhex):

    if not txhex[8:12] == "0001":
        raise RuntimeError("This is not witness transaction")

    version = txhex[:8]
    maker = txhex[8:10]
    flag = txhex[10:12]
    locktime = txhex[-8:]
    txhex = txhex[12:-8]

    vin_count = txhex[:2]
    txhex = txhex[2:]

    inputs = []
    for _ in range(int(vin_count)):
        __input = OrderedDict()
        __input["prev_txid"] = tolittle_endian(txhex[:64])
        __input["prev_vout"] = tolittle_endian(txhex[64:72])
        txhex = txhex[72:]

        # fd + 2bytes length if length > fc. fdfd00 -> length = fd
        # sl -> script length
        if re.findall(r"^fd\w+", txhex):
            __input["script_length"] = txhex[:6]
            sl = int(tolittle_endian(__input["script_length"][2:]), 16) * 2

        else:
            __input["script_length"] = txhex[:2]
            sl = int(__input["script_length"], 16) * 2

        # the length of script_length
        sll = len(__input["script_length"])

        if sl >= 20000:
            print(__input["script_length"])
            raise RuntimeError("script length is too long")

        __input["script"] = txhex[sll:sll + sl]

        if 0 <= sl < 134:
            # just scriptpubkey or empty, only witness can do that
            __input["txwitness"] = 1

        l = sll + sl

        __input["sequence"] = txhex[l:l + 8]
        inputs.append(__input)
        txhex = txhex[l + 8:]

    vout_count = txhex[:2]
    txhex = txhex[2:]
    outputs = []
    for _ in range(int(vout_count, 16)):
        __output = OrderedDict()
        __output["amount"] = txhex[:16]
        __output["script_length"] = txhex[16:18]
        l = 18 + int(__output["script_length"], 16) * 2
        __output["scriptpubkey"] = txhex[18:l]
        outputs.append(__output)
        txhex = txhex[l:]

    txwitness = []
    for _ in range(int(vin_count)):
        witness_list = []
        witness_count = txhex[:2]

        if not txhex:
            # vin count <= witness count
            break

        witness_count_int = int(witness_count, 16)

        if witness_count_int > 2:
            # multisig
            OP_0 = txhex[2:4]  # necessary
            txhex = txhex[4:]

            witness_list.append(OP_0)
            witness_count_int -= 1

        elif witness_count_int == 0:
            # Placeholder, watch dfb40fbf72c8fa9b11c67ba24f12bc48ba2a26f08bd709a3a11ca9ae30323a3f.test_tx
            txhex = txhex[2:]
            continue

        elif witness_count_int == 2:
            # one sig
            txhex = txhex[2:]

        for _ in range(witness_count_int):
            length_int = int(txhex[:2], 16) * 2
            witness_list.append(txhex[2:length_int + 2])
            txhex = txhex[length_int + 2:]

        txwitness.append(witness_list)

    txwitness = txwitness[::-1]

    for inp in inputs:
        if inp.get("txwitness"):
            inp["txwitness"] = txwitness[-1]
            txwitness.pop()

    tx_json = OrderedDict(version=version,
                          maker=maker,
                          flag=flag,
                          vin_count=vin_count,
                          vin=inputs,
                          vout_count=vout_count,
                          vout=outputs,
                          locktime=locktime)

    return dumps(tx_json, indent=4)
Пример #6
0
def decodetx(txhex):

    if txhex[8:12] == "0001":
        raise RuntimeError("Don't support witness transaction for now.")

    version = txhex[:8]
    locktime = txhex[-8:]
    txhex = txhex[8:-8]

    vin_count = txhex[:2]
    txhex = txhex[2:]

    inputs = []
    for _ in range(int(vin_count)):
        __input = OrderedDict()
        __input["prev_txid"] = txhex[:64]
        __input["prev_vout"] = txhex[64:72]
        txhex = txhex[72:]

        # fd + 2bytes length if length > fc. fdfd00 -> length = fd
        # sl -> script length
        if re.findall(r"^fd\w+", txhex):
            __input["script_length"] = txhex[:6]
            sl = int(tolittle_endian(__input["script_length"][2:]), 16) * 2

        else:
            __input["script_length"] = txhex[:2]
            sl = int(__input["script_length"], 16) * 2

        # the length of script_length
        sll = len(__input["script_length"])

        if sl >= 20000:
            print(__input["script_length"])
            raise RuntimeError("script length is too long")

        __input["script"] = txhex[sll:sll + sl]

        l = sll + sl

        __input["sequence"] = txhex[l:l + 8]
        inputs.append(__input)
        txhex = txhex[l + 8:]

    vout_count = txhex[:2]
    txhex = txhex[2:]
    outputs = []
    for _ in range(int(vout_count, 16)):
        __output = OrderedDict()
        __output["amount"] = txhex[:16]
        __output["script_length"] = txhex[16:18]
        l = 18 + int(__output["script_length"], 16) * 2
        __output["scriptpubkey"] = txhex[18:l]
        outputs.append(__output)
        txhex = txhex[l:]

    tx_json = OrderedDict(version=version,
                          vin_count=vin_count,
                          vin=inputs,
                          vout_count=vout_count,
                          vout=outputs,
                          locktime=locktime)

    return dumps(tx_json, indent=4)
Пример #7
0
 def __init__(self, inputs, ouputs, witness=None, maker=0, flag=1, **kw):
     super(witness_tx, self).__init__(inputs, ouputs, **kw)
     self.maker = tolittle_endian(maker, 2)
     self.flag = tolittle_endian(flag, 2)
     self.witness = witness
Пример #8
0
    def check_inputs(self):
        """
			address
			address_type(option) P2SH P2SH(P2WSH) P2SH(P2WPKH) P2PKH P2WSH P2WPKH
			redeemscript(option, multisig, redeemscript and mon must have one)
			mon(option, for multisig, tuple)
			:pubkey list:
			:prikey(option):
			locktime(option)
			sequence(option)
			prev_txid
			prev_vout
		"""
        for _input in self.inputs:
            locktime = _input.get("locktime")
            self.locktime = tolittle_endian(
                locktime) if locktime and locktime > 0 and isinstance(
                    locktime, int) else self.locktime

            sequence = _input.get("sequence")
            self.seq = tolittle_endian(
                sequence) if sequence and sequence > 0 and isinstance(
                    sequence, int) else self.seq

            prev_txid, prev_vout = _input.get("prev_txid"), _input.get(
                "prev_vout")
            if prev_txid != None and prev_vout != None and isinstance(
                    prev_vout, int) and len(prev_txid) == 64:
                _input["prev_txid"] = tolittle_endian(prev_txid)
                _input["prev_vout"] = tolittle_endian(prev_vout, 8)
            else:
                print(prev_txid, prev_vout, len(prev_txid) == 64)
                raise RuntimeError(
                    ":prev_txid string 32bytes: :prev_vout int:")

            pubkey = _input.get("pubkey")
            redeemscript = _input.get("redeemscript")
            mon = _input.get("mon")

            if not pubkey or not isinstance(pubkey, list):
                raise RuntimeError(
                    "pubkey is necessary. And it must be in a list")

            elif len(pubkey) > 1 and not redeemscript:

                if not isinstance(mon, tuple):
                    raise RuntimeError(
                        "redeemscript is necessary when using multisig")

                elif mon[0] <= mon[1] and mon[1] > 2:
                    _input["redeemscript"] = self.MoNscript(
                        mon[0], mon[1], pubkey)

            elif len(pubkey) == 1 and redeemscript:
                warnings.warn(
                    "redeemscript should not exit when using single signature",
                    RuntimeError)

            elif len(pubkey) == 1 and mon:
                warnings.warn(
                    "mon should not exit when using single signature",
                    RuntimeError)

            address = _input.get("address")
            if not address or not isinstance(address, str):
                raise RuntimeError(
                    "address is necessary. And it must be a string")

            elif not _input.get("address_type"):
                # analysis what kind of address it is.

                if re.findall(r"^[3,2]", address) and len(pubkey) > 1:
                    # P2SH or P2SH(P2WSH)
                    if not redeemscript:

                        check_redeemscript_again = _input.get("redeemscript")

                        if check_redeemscript_again and P2WSHoP2SHAddress(
                                bytes.fromhex(check_redeemscript_again)
                        ) == _input["address"]:
                            _input["address_type"] = P2WSHoP2SH

                        elif check_redeemscript_again:
                            _input["address_type"] = P2SH

                        else:
                            _input["address_type"] = P2WSHoP2SH
                            warnings.warn(
                                "P2SH or P2SH(P2WSH), not sure, but has set to P2SH(P2WSH)[default]"
                            )

                    elif re.findall(r"^(0020)", redeemscript):
                        _input["address_type"] = P2WSHoP2SH

                    else:
                        _input["address_type"] = P2SH

                elif re.findall(r"^[3,2]", address) and len(pubkey) == 1:
                    # P2SH(P2WPKH)
                    _input["address_type"] = P2WPKHoP2SH

                elif re.findall(r"^[1,m]", address):
                    # P2PKH
                    _input["address_type"] = P2PKH

                elif re.findall(r"^(bc|tb)", address) and len(pubkey) > 1:
                    # P2WSH
                    _input["address_type"] = P2WSH

                elif re.findall(r"^(bc|tb)", address) and len(pubkey) == 1:
                    # P2WPKH
                    _input["address_type"] = P2WPKH

        return True
Пример #9
0
 def __init__(self, inputs, ouputs, locktime=0, seq=4294967295, version=2):
     self.ver = tolittle_endian(version)
     self.inputs = inputs
     self.outputs = ouputs
     self.locktime = tolittle_endian(locktime)
     self.seq = tolittle_endian(seq)
Пример #10
0
    def deserialize(self, txhex, amounts, sighashtype="ALL"):

        json = self.decodetransaction(txhex)

        nVersion = json.get("version")

        vin = json.get("vin")

        Preimages = []
        count = 0

        for pos, v in enumerate(vin):

            st = self.check_scripttype(v)

            the_txwitness = v.get("txwitness")

            if the_txwitness and len(the_txwitness) == 2 and st in [3, 5]:
                # P2WPKH / P2SH(P2WPKH)
                outpoint = v.get("prev_txid") + v.get("prev_vout")
                nSequence = v.get("sequence")
                hashPrevouts = hexlify(
                    dsha256("".join([
                        vx.get("prev_txid") + vx.get("prev_vout") for vx in vin
                    ])))
                hashSequence = hexlify(
                    dsha256("".join([vx.get("sequence") for vx in vin])))

                scriptCode = P2PKH(the_txwitness[-1])  # used P2PKH
                scriptCode = hex(int(len(scriptCode) / 2))[2:] + scriptCode

                amount = amounts[count]
                count += 1

                output = "".join([
                    vout.get("amount") + vout.get("script_length") +
                    vout.get("scriptpubkey") for vout in json.get("vout")
                ])
                hashOutputs = hexlify(dsha256(output))

                nLockTime = json.get("locktime")
                nHashType = tolittle_endian(SIGHASH.get(sighashtype), 8)

                if sighashtype == "SINGLE":
                    hashSequence = "0" * 64

                Preimages.append(nVersion + hashPrevouts + hashSequence +
                                 outpoint + scriptCode + amount + nSequence +
                                 hashOutputs + nLockTime + nHashType)

            if the_txwitness and len(the_txwitness) >= 2 and st in [4, 6]:
                # P2WSH / P2SH(P2WSH)
                outpoint = v.get("prev_txid") + v.get("prev_vout")
                nSequence = v.get("sequence")
                hashPrevouts = hexlify(
                    dsha256("".join([
                        vx.get("prev_txid") + vx.get("prev_vout") for vx in vin
                    ])))
                hashSequence = hexlify(
                    dsha256("".join([vx.get("sequence") for vx in vin])))

                if sighashtype.find("SINGLE") >= 0:

                    scriptCode = self.getlastpart(
                        the_txwitness[-1])  # get last part

                    if not scriptCode:
                        scriptCode = the_txwitness[-1]

                elif sighashtype.find("ALL") >= 0 or sighashtype.find(
                        "None") >= 0:
                    scriptCode = the_txwitness[-1]

                scriptCode = hex(int(len(scriptCode) / 2))[2:] + scriptCode

                amount = amounts[count]
                count += 1

                if sighashtype.find("SINGLE") >= 0:
                    output = "".join(
                        [
                            vout.get("amount") + vout.get("script_length") +
                            vout.get("scriptpubkey")
                            for _, vout in enumerate(json.get("vout"))
                            if _ == pos
                        ]
                    )  # _ == pos means second inputs to second ouput/ 1-input to 1-output

                elif sighashtype.find("ALL") >= 0:
                    output = "".join([
                        vout.get("amount") + vout.get("script_length") +
                        vout.get("scriptpubkey")
                        for _, vout in enumerate(json.get("vout"))
                    ])

                elif sighashtype.find("None") >= 0:
                    output = ""

                hashOutputs = hexlify(dsha256(output)) if output else "0" * 64

                nLockTime = json.get("locktime")
                nHashType = tolittle_endian(SIGHASH.get(sighashtype), 8)

                if sighashtype == "SINGLE" or sighashtype == "None":
                    hashSequence = "0" * 64

                elif sighashtype.find("ANYONECANPAY") > 0:
                    hashSequence = hashPrevouts = "0" * 64

                Preimages.append(nVersion + hashPrevouts + hashSequence +
                                 outpoint + scriptCode + amount + nSequence +
                                 hashOutputs + nLockTime + nHashType)

        return [hexlify(dsha256(p)) for p in Preimages]
Пример #11
0
    print("tx2:", state2)

    # My transaction 4dc48bc2dff60410c77bf3674cdc22954db99e4b2841c0ef8cfd5ff4a0df34fa testnet
    txhex3 = "0200000000010341e241eb1e14125ac93a43bd1561a839de3aad1fce8b49ab7a44e31b903a5e100100000000fdffffff6b626907ad9ebe7dab31e18337aa42408757312fa239a98fa0afc68fe8dcce9e0000000000fdffffffb87c4c430ad2d1d3575e55824bfbbb394016760d6a0b987d10759ccbeef5ab4a0000000000fdffffff01f2a2210600000000160014dc72fd7bf4ef5bfd8dfe021f41f1ad7d37166dca0247304402200ed9eb7189da61da05c9ed35ffdb589e5b98a9135b9d74db1edfb8e00177e2b90220229bd12925be2aff620b6ae2f72d832eb27468c0dac6165ffab590eacdad273d012102b497bfc891cc3b85df8b1ab4cbe4d6dce76d037c3d3a13712073960d54d6dcf7024730440220716345f34607a9a8b4acd434f8318937ad7164bd92dbe602fae458afe7b83a9102201217c1357df8fc3be1bf28283ef3fd16f5269daef9a00f45368b0770090b3e45012102b497bfc891cc3b85df8b1ab4cbe4d6dce76d037c3d3a13712073960d54d6dcf70247304402205300b916b6ce48a945098585e61197783ef98ddb61af385d432c2ea0ad1fedef0220279e3afc47e77f8503880efaeebc3a72f6f65dd0989933c38a256144b2ec6637012102b0573d73a59544b9f5e6f50f992738970a5521d74b94c4dd2d7ecf393fb1da7a2ffa1700"
    signature3 = "304402200ed9eb7189da61da05c9ed35ffdb589e5b98a9135b9d74db1edfb8e00177e2b90220229bd12925be2aff620b6ae2f72d832eb27468c0dac6165ffab590eacdad273d"
    pubkeyhash3 = "02b497bfc891cc3b85df8b1ab4cbe4d6dce76d037c3d3a13712073960d54d6dcf7"

    signature4 = "30440220716345f34607a9a8b4acd434f8318937ad7164bd92dbe602fae458afe7b83a9102201217c1357df8fc3be1bf28283ef3fd16f5269daef9a00f45368b0770090b3e45"
    pubkeyhash4 = "02b497bfc891cc3b85df8b1ab4cbe4d6dce76d037c3d3a13712073960d54d6dcf7"

    signature5 = "304402205300b916b6ce48a945098585e61197783ef98ddb61af385d432c2ea0ad1fedef0220279e3afc47e77f8503880efaeebc3a72f6f65dd0989933c38a256144b2ec6637"
    pubkeyhash5 = "02b0573d73a59544b9f5e6f50f992738970a5521d74b94c4dd2d7ecf393fb1da7a"

    ffff3 = inspector.deserialize(
        txhex3,
        amounts=[tolittle_endian(i, 16) for i in [4178886, 96115369, 2573688]])
    ffff3, ffff4, ffff5 = ffff3

    state3 = inspector.verify(signature=signature3,
                              pubkeyhash=pubkeyhash3,
                              msg=ffff3)
    state4 = inspector.verify(signature=signature4,
                              pubkeyhash=pubkeyhash4,
                              msg=ffff4)
    state5 = inspector.verify(signature=signature5,
                              pubkeyhash=pubkeyhash5,
                              msg=ffff5)
    print("tx3:", state3)
    print("tx4:", state4)
    print("tx5:", state5)