email.message.Message: Representing an email message using the compat32 API

What is the most efficient way to concatenate many strings together?

Why does a_tuple[i] += [‘item’] raise an exception when the addition works?

PEP 3118: New memoryview implementation and buffer protocol documentation

PEP 476: Enabling certificate verification by default for stdlib http clients

PEP 471 - os.scandir() function – a better and faster directory iterator

Why must ‘self’ be used explicitly in method definitions and calls?

argparse — Parser for command-line options, arguments and sub-commands

functools — Higher-order functions and operations on callable objects

sysconfig — Provide access to Python’s configuration information

from .tools import *

class PrivateKey():
    """
    The class for creating private key object.

    :param key: (optional) private key in HEX,  bytes string or WIF format. In case no key specified
                new random private key will be created.
    :param compressed: (optional) if set to True private key corresponding compressed public key,
                       by default set to True. Recommended use only compressed public key.
    :param testnet: (optional) if set to True mean that this private key for testnet Bitcoin network.

    """
    def __init__(self, key=None, compressed=True, testnet=False):

        if key is None:

            #: flag for compressed type of corresponding public key (boolean)
            self.compressed = compressed
            #: flag for testnet network private key  (boolean)
            self.testnet = testnet

            #: private key in  bytes (bytes)
            self.key = create_private_key(wif=False)
            #: private key in HEX (string)
            self.hex = hexlify(self.key).decode()
            #: private key in WIF format (string)
            self.wif = private_key_to_wif(self.key, compressed, testnet)

        else:
            if isinstance(key, str):
                try:
                    key = unhexlify(key)
                except:
                    pass
            if isinstance(key, bytes):
                if len(key) != 32:
                    raise TypeError("private key invalid length")
                self.key = key
                self.compressed = compressed
                self.testnet = testnet
                self.hex = hexlify(self.key).decode()
                self.wif = private_key_to_wif(self.key, compressed, testnet)
                return
            if not isinstance(key, str) or not is_wif_valid(key):
                raise TypeError("private key invalid")

            self.key = wif_to_private_key(key, hex=False)
            if key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
                          TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
                self.compressed = False
            else:
                self.compressed = True
            if key[0] in (TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
                          TESTNET_PRIVATE_KEY_COMPRESSED_PREFIX):
                self.testnet = True
            else:
                self.testnet = False
            self.wif = private_key_to_wif(self.key, self.compressed, self.testnet)

    def __str__(self):
        return self.wif

class PublicKey():
    """
    The class for public key object.

    :param key:  one of this types allowed:
    
                - private key is instance of ``PrivateKey`` class
                - private key HEX encoded string
                - private key 32 bytes string
                - private key in WIF format
                - public key in HEX encoded string
                - public key [33/65] bytes string
                
                In case no key specified with HEX or bytes string you have to provide flag for testnet 
                and compressed key. WIF format and ``PrivateKey`` instance already contain this flags.
                For HEX or bytes public key only testnet flag has the meaning, comressed flag is determined 
                according to the length of key.
                
    """
    def __init__(self, key, compressed=True, testnet=False):
        if isinstance(key, str):
            try:
                key = unhexlify(key)
            except:
                if is_wif_valid(key):
                    key = PrivateKey(key)

        if isinstance(key, bytes):
            if len(key) == 32:
                key = PrivateKey(key, compressed=compressed, testnet=testnet)
            elif is_public_key_valid(key):
                public_key = key
                self.compressed = True if len(key) == 33 else False
            else:
                raise TypeError("key invalid")

        if isinstance(key, PrivateKey):
            self.testnet = key.testnet
            self.compressed = key.compressed
            public_key = private_to_public_key(key.key,
                                        compressed=key.compressed,
                                        hex=False)
        #: public key in  bytes (bytes)
        self.key = public_key
        #: public key in HEX (string)
        self.hex = hexlify(self.key).decode()

        return self.hex

class Address():
    """
    The class for Address object.

    :param key: (optional) one of this types allowed:
    
                - private key WIF format
                - instance of ``PrivateKey``
                - instance of ``PublicKey``
                
                In case no key specified new Address will be created with random keys.
    :param address_type: (optional) P2PKH, PUBKEY, P2WPKH, P2SH_P2WPKH, by default P2WPKH.

    In case instanse is created from WIF private key, ``PrivateKey`` or ``PublicKey`` compressed and testnet flags
    already contain in initial key parameter and will be ignored.
    """
    def __init__(self, key=None,
                 address_type="P2WPKH", testnet=False, compressed=True):
            #: instance of ``PrivateKey`` class
            self.private_key = PrivateKey(testnet=testnet,
                                          compressed=compressed)
            #: instance of ``PublicKey`` class
            self.public_key = PublicKey(self.private_key)
            #: flag for testnet network address  (boolean)
        if isinstance(key, str) or isinstance(key, bytes):
            key = PrivateKey(key, testnet=testnet, compressed=compressed)
            self.private_key = key
            compressed = key.compressed
        elif isinstance(key, PublicKey):
            self.public_key = key
        if address_type not in ("P2PKH", "PUBKEY", "P2WPKH", "P2SH_P2WPKH"):
            raise TypeError("address type invalid")
        if not compressed:
            if address_type not in ("P2PKH", "PUBKEY", "P2SH"):
                raise TypeError("compressed public key invalid")
        #: flag for testnet network address  (boolean)
        self.type = address_type

        if address_type in ("P2WPKH"):
            #: version of witness program for SEGWIT address (string)
            self.witness_version = 0
        else:
            self.witness_version = None
        self.compressed = compressed
        if address_type == "P2SH_P2WPKH":
            #: flag for script hash address (boolean)
            self.script_hash = True
            #: redeeem script, only for P2SH_P2WPKH (bytes)
            self.redeem_script = public_key_to_p2sh_p2wpkh_script(self.public_key.key)
            #: redeeem script HEX, only for P2SH_P2WPKH (string)
            self.redeem_script_hex = hexlify(self.redeem_script).decode()
            #: address hash
            self.hash = hash160(self.redeem_script)
        else:
            self.script_hash = False
            self.hash = hash160(self.public_key.key)
        #: address hash HEX (string)
        self.hash_hex = hexlify(self.hash).decode()
        #: address in base58 or bech32 encoding (string)
        self.address = hash_to_address(self.hash,
                                       script_hash=self.script_hash,
                                       witness_version=self.witness_version,
                                       testnet=self.testnet)

        return self.address

class ScriptAddress():
    def __init__(self, script, address_type="P2SH",
                 testnet=False, witness_version=None):
        self.witness_version = witness_version
        self.testnet = testnet
        if isinstance(script, str):
            script = unhexlify(script)
        self.script = script
        self.script_hex = hexlify(self.script).decode()
        self.hash = hash160(self.script)
        self.script_opcodes = decode_script(self.script)
        self.script_opcodes_asm = decode_script(self.script, 1)
                                       script_hash=True,

    @classmethod
    def multisig(cls, n, m, public_key_list, testnet = False):
        """
        The class method for creating a multisig address.

        :param n: count of required signatures (max 15).
        :param m: count of total addresses of participants (max 15).
        :param list address_list: addresses list, allowed types:
                       
                             - bytes or HEX encoded private key
                             - private key in WIF format
                             - PrivateKey instance,
                             - bytes or HEX encoded public key
                             - PublicKey instance
                             
        """
        if n > 15 or m > 15 or n > m or n < 1 or m < 1:
            raise TypeError("invalid n of m maximum 15 of 15 multisig allowed")
        if len(public_key_list) != m:
            raise TypeError("invalid address list count")
        script = bytes([0x50 + n])
        for a in list(public_key_list):
            if isinstance(a, str):
                try:
                    a = unhexlify(a)
                except:
                    if is_wif_valid(a):
                        a = private_to_public_key(a, hex=False)
                    pass
            if isinstance(a, Address):
                a = a.public_key.key
            elif isinstance(a, PublicKey):
                a = a.key
            elif isinstance(a, PrivateKey):
                a = private_to_public_key(a.key)
            if not isinstance(a, bytes):
                raise TypeError("invalid public key list element")
            if len(a) == 32:
                a = private_to_public_key(a)
            if len(a) != 33:
                raise TypeError("invalid public key list element size")
            script += int_to_var_int(len(a)) + a
        script += bytes([0x50 + m]) + OP_CHECKMULTISIG
        return cls(script, testnet=testnet)

from .transaction import Transaction
from struct import pack, unpack

class Block(dict):
    def __init__(self, block):
        s = get_stream(block)
        self["header"] = s.read(80)
        self["hash"] = double_sha256(self["header"])
        self["version"] = unpack("<L", s.read(4))
        self["previousBlockHash"] = s.read(32)
        self["merkleRoot"] = s.read(32)
        self["time"] = unpack("<L", s.read(4))
        self["bits"] = s.read(4),
        self["nonce"] = unpack("<L", s.read(4))
        s.seek(-80, 1)
        # self["tx"] = {i: Transaction(s)
        #               for i in range(var_int_to_int(read_var_int(s)))}
        self["weight"] = 0
        self["size"] = 0
        self["strippedSize"] = 0
        self["height"] = 0
        self["difficulty"] = 0
        self["targetDifficulty"] = 0
        self["target"] = 0

import time
import struct
from secp256k1 import ffi
from .constants import *
from .opcodes import *
from .hash import *
from .encode import *
import math
import io

# Key management

def create_private_key(compressed=True, testnet=False, wif=True, hex=False):
    """
    Create private key
    
    :param compressed: (optional) Type of public key, by default set to compressed. 
                                 Using uncompressed public keys is deprecated in new SEGWIT addresses, 
                                 use this option only for backward compatibility.  
    :param testnet: (optional) flag for testnet network, by default is False.
    :param wif:  (optional) If set to True return key in WIF format, by default is True.
    :param hex:  (optional) If set to True return key in HEX format, by default is False.
    :return: Private key in wif format (default), hex encoded byte string in case of hex flag or
             raw bytes string in case wif and hex flags set to False.

    """
    a = random.SystemRandom().randint(0, MAX_INT_PRIVATE_KEY)
    i = int((time.time() % 0.01)*100000)
    h = a.to_bytes(32, byteorder="big")
    # more entropy from system timer and sha256 derivation
    while i:
        h = hashlib.sha256(h).digest()
        i -= 1
        if not i and int.from_bytes(h, byteorder="big") > MAX_INT_PRIVATE_KEY:
            i += 1
    if wif:
        return private_key_to_wif(h, compressed=compressed, testnet=testnet)
    elif hex:
        return hexlify(h).decode()
    return h

def private_key_to_wif(h, compressed=True, testnet=False):
    """
    Encode private key in HEX or RAW bytes format to WIF format.
    
    :param h: private key 32 byte string or HEX encoded string.
    :param compressed: (optional) flag of public key compressed format, by default set to True.  
    :return: Private key in WIF format.
    """
    # uncompressed: 0x80 + [32-byte secret] + [4 bytes of Hash() of previous 33 bytes], base58 encoded.
    # compressed: 0x80 + [32-byte secret] + 0x01 + [4 bytes of Hash() previous 34 bytes], base58 encoded.
    if isinstance(h, str):
        h = unhexlify(h)
    if len(h) != 32 and isinstance(h, bytes):
        raise TypeError("private key must be a 32 bytes or hex encoded string")
    if testnet:
        h = TESTNET_PRIVATE_KEY_BYTE_PREFIX + h
    else:
        h = MAINNET_PRIVATE_KEY_BYTE_PREFIX + h
    if compressed:
        h += b'\x01'
    h += double_sha256(h)[:4]
    return encode_base58(h)

def wif_to_private_key(h, hex=True):
    """
    Decode WIF private key to bytes string or HEX encoded string
    
    :param hex:  (optional) if set to True return key in HEX format, by default is True.
    :return: Private key HEX encoded string or raw bytes string.
    """
    if not is_wif_valid(h):
        raise TypeError("invalid wif key")
    h = decode_base58(h)
    if hex:
        return hexlify(h[1:33]).decode()
    return h[1:33]

def is_wif_valid(wif):
    """
    Check is private key in WIF format string is valid.
        
    :param wif: private key in WIF format string.
    :return: boolean.
    """
    if not isinstance(wif, str):
    if wif[0] not in PRIVATE_KEY_PREFIX_LIST:
        return False
    try:
        h = decode_base58(wif)
    except:
    checksum = h[-4:]
    if wif[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
                  TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
        if len(h) != 37:
            return False
    elif len(h) != 38:
    if double_sha256(h[:-4])[:4] != checksum:
    return True

def private_to_public_key(private_key, compressed=True, hex=True):
    """
    Get public key from private key using ECDSA secp256k1
    
    :param private_key: private key in WIF, HEX or bytes.
    :param compressed: (optional) flag of public key compressed format, by default set to True.
                       In case private_key in WIF format, this flag is set in accordance with 
                       the key format specified in WIF string.
    :return: 33/65 bytes public key in HEX or bytes string.
    """
    if not isinstance(private_key, bytes):
        if isinstance(private_key, bytearray):
            private_key = bytes(private_key)
        elif isinstance(private_key, str):
            if not is_wif_valid(private_key):
                private_key = unhexlify(private_key)
            else:
                if private_key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
                                      TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
                    compressed = False
                private_key = wif_to_private_key(private_key, hex=0)
        else:
            raise TypeError("private key must be a bytes or WIF or hex encoded string")
    pubkey_ptr = ffi.new('secp256k1_pubkey *')
    r = secp256k1.secp256k1_ec_pubkey_create(ECDSA_CONTEXT_ALL, pubkey_ptr, private_key)
    if not r:
        raise RuntimeError("secp256k1 error")
    len_key = 33 if compressed else 65
    pubkey = ffi.new('char [%d]' % len_key)
    outlen = ffi.new('size_t *', len_key)
    compflag = EC_COMPRESSED if compressed else EC_UNCOMPRESSED
    r = secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, compflag)
    pub = bytes(ffi.buffer(pubkey, len_key))
    if not r:
    return hexlify(pub).decode() if hex else pub

def is_public_key_valid(key):
    """
    Check public key is valid.

    :param key: public key in HEX or bytes string format.
    """
    if isinstance(key, str):
        key = unhexlify(key)
    if len(key) < 33:
    if key[0] == 0x04 and len(key) != 65:
    elif key[0] == 0x02 or key[0] == 0x03:
        if len(key) != 33:

# Addresses

def hash_to_address(address_hash, testnet=False, script_hash=False, witness_version=0):
    """
    Get address from public key/script hash. In case PUBKEY, P2PKH, P2PKH public key/script hash is SHA256+RIPEMD160,
    P2WSH script hash is SHA256.
    
    :param address_hash: public key hash or script hash in HEX or bytes string format.
    :param script_hash: (optional) flag for script hash (P2SH address), by default is False.
    :param witness_version: (optional) witness program version, by default is 0, for legacy
                            address format use None.
    :return: address in base58 or bech32 format.
    """
    if isinstance(address_hash, str):
        address_hash = unhexlify(address_hash)
    if not isinstance(address_hash, bytes):
        raise TypeError("address hash must be HEX encoded string or bytes")

    if not script_hash:
        if witness_version is None:
            if len(address_hash) != 20:
                raise TypeError("address hash length incorrect")
            if testnet:
                prefix = TESTNET_ADDRESS_BYTE_PREFIX
            else:
                prefix = MAINNET_ADDRESS_BYTE_PREFIX
            address_hash = prefix + address_hash
            address_hash += double_sha256(address_hash)[:4]
            return encode_base58(address_hash)
        else:
            if len(address_hash) not in (20, 32):

    if witness_version is None:
        if testnet:
            prefix = TESTNET_SCRIPT_ADDRESS_BYTE_PREFIX
        else:
            prefix = MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX
        address_hash = prefix + address_hash
        address_hash += double_sha256(address_hash)[:4]
        return encode_base58(address_hash)

        prefix = TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX
        hrp = TESTNET_SEGWIT_ADDRESS_PREFIX
    else:
        prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX
        hrp = MAINNET_SEGWIT_ADDRESS_PREFIX

    address_hash = witness_version.to_bytes(1, "big") + rebase_8_to_5(address_hash)
    checksum = bech32_polymod(prefix + address_hash + b"\x00" * 6)
    checksum = rebase_8_to_5(checksum.to_bytes(5, "big"))[2:]
    return "%s1%s" % (hrp, rebase_5_to_32(address_hash + checksum).decode())

def public_key_to_address(pubkey, testnet=False, p2sh_p2wpkh=False, witness_version=0):
    """

    :param pubkey: public key HEX or bytes string format.
    :param p2sh_p2wpkh: (optional) flag for P2WPKH inside P2SH address, by default is False.
    """
    if isinstance(pubkey, str):
        pubkey = unhexlify(pubkey)
    if not isinstance(pubkey, bytes):
        raise TypeError("public key invalid")
    if p2sh_p2wpkh:
        if len(pubkey) != 33:
            raise TypeError("public key invalid")
        h = hash160(b'\x00\x14' + hash160(pubkey))
        witness_version = None
    else:
        if witness_version is not None:
            if len(pubkey) != 33:
                raise TypeError("public key invalid")
        h = hash160(pubkey)
    return hash_to_address(h, testnet=testnet,
                           script_hash=p2sh_p2wpkh,
                           witness_version=witness_version)

def address_to_hash(address, hex=True):
    """
    Get address hash from base58 or bech32 address format.

    :param address: address in base58 or bech32 format.
    :param hex:  (optional) If set to True return key in HEX format, by default is True.
    :return: script in HEX or bytes string.
    """
    if address[0] in ADDRESS_PREFIX_LIST:
        h = decode_base58(address)[1:-4]
    elif address[:2] in (MAINNET_SEGWIT_ADDRESS_PREFIX,
                         TESTNET_SEGWIT_ADDRESS_PREFIX):
        address = address.split("1")[1]
        h = rebase_5_to_8(rebase_32_to_5(address)[1:-6], False)
    else:
        return None
    return h.hex() if hex else h

def address_type(address, num=False):
    """
    Get address type.   
    
    :param num: (optional) If set to True return type in numeric format, by default is False.
    :return: address type in string or numeric format. 
    """
    if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
                      MAINNET_SCRIPT_ADDRESS_PREFIX):
        t = 'P2SH'
    elif address[0] in (MAINNET_ADDRESS_PREFIX,
                        TESTNET_ADDRESS_PREFIX,
                        TESTNET_ADDRESS_PREFIX_2):
        t = 'P2PKH'
        if len(address) == 42:
            t = 'P2WPKH'
        elif len(address) == 62:
            t = 'P2WSH'
        else:
            return SCRIPT_TYPES['NON_STANDARD'] if num else 'UNKNOWN'
    else:
        return SCRIPT_TYPES['NON_STANDARD'] if num else 'UNKNOWN'
    return SCRIPT_TYPES[t] if num else t

def address_net_type(address):
    """
    Get address network type.   

    :return: address network type in string format or None. 
    """
    if address[0] in (MAINNET_SCRIPT_ADDRESS_PREFIX,
                      MAINNET_ADDRESS_PREFIX):
        return "mainnet"
    elif address[:2] == MAINNET_SEGWIT_ADDRESS_PREFIX:
    elif address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
        return "testnet"
    elif address[:2] == TESTNET_SEGWIT_ADDRESS_PREFIX:
    return None

def address_to_script(address, hex=False):
    """
    Get public key script from address.

    :return: public key script in HEX or bytes string.
    """
        s = [BYTE_OPCODE["OP_HASH160"],
             b'\x14',
             address_to_hash(address, hex=False),
             BYTE_OPCODE["OP_EQUAL"]]
        s = [BYTE_OPCODE["OP_DUP"],
             BYTE_OPCODE["OP_HASH160"],
             b'\x14',
             BYTE_OPCODE["OP_EQUALVERIFY"],
             BYTE_OPCODE["OP_CHECKSIG"]]
    elif address[:2] in (TESTNET_SEGWIT_ADDRESS_PREFIX,
                         MAINNET_SEGWIT_ADDRESS_PREFIX):
        h = address_to_hash(address, hex=False)
        s = [BYTE_OPCODE["OP_0"],
             bytes([len(h)]),
             h]
    else:
        raise TypeError("address invalid")
    s = b''.join(s)
    return hexlify(s).decode() if hex else s

def public_key_to_p2sh_p2wpkh_script(pubkey):
    if len(pubkey) != 33:
        raise TypeError("public key len invalid")
    return b'\x00\x14%s' % hash160(pubkey)

def is_address_valid(address, testnet=False):
    """
    Check is address valid.

    """
    if not address or type(address) != str:
    if address[0] in (MAINNET_ADDRESS_PREFIX,
                      MAINNET_SCRIPT_ADDRESS_PREFIX,
                      TESTNET_ADDRESS_PREFIX,
                      TESTNET_ADDRESS_PREFIX_2,
                      TESTNET_SCRIPT_ADDRESS_PREFIX):
            if address[0] not in (TESTNET_ADDRESS_PREFIX,
                                  TESTNET_ADDRESS_PREFIX_2,
                                  TESTNET_SCRIPT_ADDRESS_PREFIX):
                return False
        else:
            if address[0] not in (MAINNET_ADDRESS_PREFIX,
                                  MAINNET_SCRIPT_ADDRESS_PREFIX):
        h = decode_base58(address)
        if len(h) != 25:
        checksum = h[-4:]
        if double_sha256(h[:-4])[:4] != checksum:
        return True
    elif address[:2].lower() in (TESTNET_SEGWIT_ADDRESS_PREFIX,
                                 MAINNET_SEGWIT_ADDRESS_PREFIX):
        if len(address) not in (42, 62):
        try:
            prefix, payload = address.split('1')
        except:
        upp = True if prefix[0].isupper() else False
        for i in payload[1:]:
            if upp:
                if not i.isupper() or i not in base32charset_upcase:
                    return False
            else:
                if i.isupper() or i not in base32charset:
        payload = payload.lower()
        prefix = prefix.lower()
            if prefix != TESTNET_SEGWIT_ADDRESS_PREFIX:
            stripped_prefix = TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX
        else:
            if prefix != MAINNET_SEGWIT_ADDRESS_PREFIX:
            stripped_prefix = MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX
        d = rebase_32_to_5(payload)
        address_hash = d[:-6]
        checksum = d[-6:]
        checksum2 = bech32_polymod(stripped_prefix + address_hash + b"\x00" * 6)
        checksum2 = rebase_8_to_5(checksum2.to_bytes(5, "big"))[2:]
        if checksum != checksum2:

def get_witness_version(address):
    address = address.split("1")[1]
    h = rebase_32_to_5(address)
    return h[0]

#  Script

def parse_script(script, segwit=True):
    """
    Parse script and return script type, script address and required signatures count.

    :param script: script in bytes string or HEX encoded string format.
    :param segwit:  (optional) If set to True recognize P2WPKH and P2WSH sripts, by default set to True.
    
    :return: dictionary:
    
            - nType - numeric script type
            - type  - script type
            - addressHash - address hash in case address recognized
            - script - script if no address recognized
            - reqSigs - required signatures count
    """
    if not script:
        return {"nType": 7, "type": "NON_STANDARD", "reqSigs": 0, "script": b""}
    if type(script) == str:
        try:
        except:
            pass
        assert type(script) == bytes
    l = len(script)
    if segwit:
        if l == 22 and script[0] == 0:
            return {"nType": 5, "type": "P2WPKH", "reqSigs": 1, "addressHash": script[2:]}
        if l == 34 and script[0] == 0:
            return {"nType": 6, "type": "P2WSH", "reqSigs": None, "addressHash": script[2:]}
    if l == 25 and \
                    script[:2] == b"\x76\xa9" and \
                    script[-2:] == b"\x88\xac":
        return {"nType": 0, "type": "P2PKH", "reqSigs": 1, "addressHash": script[3:-2]}
    if l == 23 and \
                    script[0] == 169 and \
                    script[-1] == 135:
        return {"nType": 1, "type": "P2SH", "reqSigs": None, "addressHash": script[2:-1]}
    if l == 67 and script[-1] == 172:
        return {"nType": 2, "type": "PUBKEY", "reqSigs": 1, "addressHash": hash160(script[1:-1])}
    if l == 35 and script[-1] == 172:
    if script[0] == 106 and l > 1 and l <= 82:
        if script[1] == l - 2:
            return {"nType": 3, "type": "NULL_DATA", "reqSigs": 0, "data": script[2:]}
    if script[0] >= 81 and script[0] <= 96:
        if script[-1] == 174:
            if script[-2] >= 81 and script[-2] <= 96:
                if script[-2] >= script[0]:
                    c, s = 0, 1
                    while l - 2 - s > 0:
                        if script[s] < 0x4c:
                            s += script[s]
                            c += 1
                        else:
                            c = 0
                            break
                        s += 1
                    if c == script[-2] - 80:
                        return {"nType": 4, "type": "MULTISIG", "reqSigs": script[0] - 80, "script": script}

    s, m, n, last, req_sigs = 0, 0, 0, 0, 0
    while l - s > 0:
        if script[s] >= 81 and script[s] <= 96:
            if not n:
                n = script[s] - 80
            else:
                if m == 0:
                    n, m = script[s] - 80, 0
                elif n > m:
                elif m == script[s] - 80:
                    last = 0 if last else 2
        elif script[s] < 0x4c:
            s += script[s]
            m += 1
            if m > 16:
                n, m = 0, 0
        elif script[s] == OPCODE["OP_PUSHDATA1"]:
            try:
                s += 1 + script[s + 1]
            except:
                break
        elif script[s] == OPCODE["OP_PUSHDATA2"]:
            try:
                s += 2 + struct.unpack('<H', script[s: s + 2])[0]
            except:
                break
        elif script[s] == OPCODE["OP_PUSHDATA4"]:
            try:
                s += 4 + struct.unpack('<L', script[s: s + 4])[0]
            except:
                break
        else:
            if script[s] == OPCODE["OP_CHECKSIG"]:
                req_sigs += 1
            elif script[s] == OPCODE["OP_CHECKSIGVERIFY"]:
            elif script[s] in (OPCODE["OP_CHECKMULTISIG"], OPCODE["OP_CHECKMULTISIGVERIFY"]):
                if last:
                    req_sigs += n
                else:
                    req_sigs += 20
            n, m = 0, 0
        if last:
            last -= 1
        s += 1
    return {"nType": 7, "type": "NON_STANDARD", "reqSigs": req_sigs, "script": script}

def decode_script(script, asm=False):
    """
    Decode script to ASM format or to human readable OPCODES string.

    :param asm:  (optional) If set to True decode to ASM fromat, by default set to False.
    :return: script in ASM format string or OPCODES string.
    """
    if isinstance(script, str):
        try:
        except:
            pass
    if not isinstance(script, bytes):
        raise TypeError("script invalid")
    s = 0
    result = []
        if script[s] < 0x4c and script[s]:
            if asm:
                result.append(hexlify(script[s + 1:s + 1 + script[s]]).decode())
            else:
                result.append('[%s]' % script[s])
            s += script[s] + 1
            continue
            s += 1 + script[s + 1]
            s += 2 + struct.unpack('<H', script[s: s + 2])
            s += 4 + struct.unpack('<L', script[s: s + 4])
        result.append(RAW_OPCODE[script[s]])
        s += 1
    return ' '.join(result)

def delete_from_script(script, sub_script):
    """
    Decode OPCODE or subscript from script.

    :param script: traget script in bytes or HEX encoded string.
    :param sub_script:  sub_script which is necessary to remove from target script in bytes or HEX encoded string.
    :return: script in bytes or HEX encoded string corresponding to the format of target script.
    """
    if not sub_script:
        return script
    s_hex = False
        try:
            s_hex = True
        except:
            pass
    if isinstance(sub_script, str):
        try:
            sub_script = unhexlify(sub_script)
        except:
            pass

    if not isinstance(sub_script, bytes):
        raise TypeError("sub_script invalid")

    ls = len(sub_script)
    s = 0
    k = 0
    stack = []
    result = []
            stack.append(script[s] + 1)
            stack.append(1 + script[s + 1])
            stack.append(2 + struct.unpack('<H', script[s: s + 2]))
            stack.append(4 + struct.unpack('<L', script[s: s + 4]))
        else:
            stack.append(1)
            s += 1
        if s - k >= ls:
            if script[k:s][:ls] == sub_script:
                if s - k > ls:
                    result.append(script[k + ls:s])
                t = 0
                while t != s - k:
                    t += stack.pop(0)
                k = s
            else:
                t = stack.pop(0)
                result.append(script[k:k + t])
                k += t
    if script[k:s][:ls] == sub_script:
        if s - k > ls:
            result.append(script[k + ls:s])
    else:
        result.append(script[k:k + ls])

    return b''.join(result) if not s_hex else hexlify(b''.join(result)).decode()

def script_to_hash(script, witness=False, hex=True):
    """
    Encode script to hash HASH160 or SHA256 in dependency of the witness.

    :param script: script in bytes or HEX encoded string.
    :param witness:  (optional) If set to True return SHA256 hash for P2WSH, by default is False.
    """
        s = unhexlify(script)
    if witness:
        return sha256(script, hex)
    else:
        return hash160(script, hex)

#  Signatures

def verify_signature(sig, pub_key, msg):
    """
    Verify signature for message and given public key

    :param sig: signature in bytes or HEX encoded string.
    :param pub_key:  public key in bytes or HEX encoded string.
    :param msg:  message in bytes or HEX encoded string.
    """
    if not isinstance(sig, bytes):
        if isinstance(sig, bytearray):
            sig = bytes(sig)
        elif isinstance(sig, str):
            sig = unhexlify(sig)
        else:
            raise TypeError("signature must be a bytes or hex encoded string")
    if not isinstance(pub_key, bytes):
        if isinstance(pub_key, bytearray):
            pub_key = bytes(pub_key)
        elif isinstance(pub_key, str):
            pub_key = unhexlify(pub_key)
        else:
            raise TypeError("public key must be a bytes or hex encoded string")
    if not isinstance(msg, bytes):
        if isinstance(msg, bytearray):
            msg = bytes(msg)
        elif isinstance(msg, str):
            msg = unhexlify(msg)
        else:
            raise TypeError("message must be a bytes or hex encoded string")

    raw_sig = ffi.new('secp256k1_ecdsa_signature *')
    raw_pubkey = ffi.new('secp256k1_pubkey *')
    if not secp256k1.secp256k1_ecdsa_signature_parse_der(ECDSA_CONTEXT_VERIFY, raw_sig, sig, len(sig)):
        raise TypeError("signature must be DER encoded")
    if not secp256k1.secp256k1_ec_pubkey_parse(ECDSA_CONTEXT_VERIFY, raw_pubkey, pub_key, len(pub_key)):
        raise TypeError("public key format error")
    result = secp256k1.secp256k1_ecdsa_verify(ECDSA_CONTEXT_VERIFY, raw_sig, msg, raw_pubkey)
    return True if result else False

def sign_message(msg, private_key, hex=True):
    """
    Sign message
    
    :param msg:  message to sign  bytes or HEX encoded string.
    :param private_key:  private key (bytes, hex encoded string or WIF format)
    :return:  DER encoded signature in bytes or HEX encoded string.  
    """
    if isinstance(msg, bytearray):
        msg = bytes(msg)
    if isinstance(msg, str):
        try:
        except:
            pass

    if isinstance(private_key, bytearray):
        private_key = bytes(private_key)
    if isinstance(private_key, str):
        try:
            private_key = unhexlify(private_key)
        except:
            if is_wif_valid(private_key):
                private_key = wif_to_private_key(private_key, hex=False)
            raise TypeError("private key must be a bytes, hex encoded string or in WIF format")

    signed = secp256k1.secp256k1_ecdsa_sign(ECDSA_CONTEXT_SIGN, raw_sig, msg,
                                            private_key, ffi.NULL, ffi.NULL)
    if not signed:
    len_sig = 74
    output = ffi.new('unsigned char[%d]' % len_sig)
    outputlen = ffi.new('size_t *', len_sig)
    res = secp256k1.secp256k1_ecdsa_signature_serialize_der(ECDSA_CONTEXT_SIGN,
                                                            output, outputlen, raw_sig)
    if not res:
    signature = bytes(ffi.buffer(output, outputlen[0]))
    return hexlify(signature).decode() if hex else signature

def is_valid_signature_encoding(sig):
    """
    Check is valid signature encoded in DER format

    :param sig:  signature in bytes or HEX encoded string.
    :return:  boolean.  
    """
    # Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
    # * total-length: 1-byte length descriptor of everything that follows,
    #   excluding the sighash byte.
    # * R-length: 1-byte length descriptor of the R value that follows.
    # * R: arbitrary-length big-endian encoded R value. It must use the shortest
    #   possible encoding for a positive integers (which means no null bytes at
    #   the start, except a single one when the next byte has its highest bit set).
    # * S-length: 1-byte length descriptor of the S value that follows.
    # * S: arbitrary-length big-endian encoded S value. The same rules apply.
    # * sighash: 1-byte value indicating what data is hashed (not part of the DER
    #   signature)
    length = len(sig)
    # Minimum and maximum size constraints.
    if (length < 9) or (length > 73):
    # A signature is of type 0x30 (compound).
    if sig[0] != 0x30:
    # Make sure the length covers the entire signature.
    if sig[1] != (length - 3):
    # Extract the length of the R element.
    len_r = sig[3]
    # Make sure the length of the S element is still inside the signature.
    if (5 + len_r) >= length:
    # Extract the length of the S element.
    len_s = sig[5 + len_r]
    # Verify that the length of the signature matches the sum of the length
    # of the elements.
    if (len_r + len_s + 7) != length:
    # Check whether the R element is an integer.
    if sig[2] != 0x02:
    # Zero-length integers are not allowed for R.
    if len_r == 0:
    # Negative numbers are not allowed for R.
    if sig[4] & 0x80:
    # Null bytes at the start of R are not allowed, unless R would
    # otherwise be interpreted as a negative number.
    if (len_r > 1) and (sig[4] == 0x00) and (not sig[5] & 0x80):
    # Check whether the S element is an integer.
    if sig[len_r + 4] != 0x02:
    # Zero-length integers are not allowed for S.
    if len_s == 0:
    # Negative numbers are not allowed for S.
    if sig[len_r + 6] & 0x80:
    # Null bytes at the start of S are not allowed, unless S would otherwise be
    # interpreted as a negative number.
    if (len_s > 1) and (sig[len_r + 6] == 0x00) and (not sig[len_r + 7] & 0x80):

# Hash encoding

def rh2s(raw_hash):
    """
    Encode raw transaction hash to HEX string with bytes order change

    :param raw_hash: transaction hash in bytes string.
    :return:  HEX encoded string.
    """
    return hexlify(raw_hash[::-1]).decode()

def s2rh(hash_string):
    """
    Decode HEX  transaction hash to bytes with byte order change

    :return:  bytes string.
    """
    return unhexlify(hash_string)[::-1]

def s2rh_step4(hash_string):
    h = unhexlify(hash_string)
    return reverse_hash(h)

def reverse_hash(raw_hash):
    """
    Reverse hash order

    :param raw_hash: bytes string.
    """
    return struct.pack('>IIIIIIII', *struct.unpack('>IIIIIIII', raw_hash)[::-1])[::-1]

# Merkle root

def merkle_root(tx_hash_list, hex=True):
    """
    Calculate merkle root from transaction hash list

    :param tx_hash_list: list of transaction hashes in bytes or HEX encoded string.
    :param hex:  (optional) If set to True return result in HEX format, by default is True.
    :return: merkle root in bytes or HEX encoded string corresponding hex flag.
    """
    tx_hash_list = [h if isinstance(h, bytes) else s2rh(h) for h in tx_hash_list]
    if len(tx_hash_list) == 1:
        return tx_hash_list[0]
    while True:
        new_hash_list = list()
        while tx_hash_list:
            h1 = tx_hash_list.pop(0)
            try:
                h2 = tx_hash_list.pop(0)
            except:
                h2 = h1
            new_hash_list.append(double_sha256(h1 + h2))
        if len(new_hash_list) > 1:
            tx_hash_list = new_hash_list
        else:
            return new_hash_list[0] if not hex else hexlify(new_hash_list[0]).decode()

def merkle_branches(tx_hash_list, hex=True):
    """
    Calculate merkle branches for coinbase transacton

    :return: list of merkle branches in bytes or HEX encoded string corresponding hex flag.
    """
    branches = []
        return []
    tx_hash_list.pop(0)
        branches.append(tx_hash_list.pop(0))
            try:
            except:
                h2 = h1
        else:
            if new_hash_list:
                branches.append(new_hash_list.pop(0))
            return branches if not hex else [hexlify(h).decode() for h in branches]

def merkleroot_from_branches(merkle_branches, coinbase_hash, hex=True):
    """
    Calculate merkle root from merkle branches and coinbase transacton hash

    :param merkle_branches: list merkle branches in bytes or HEX encoded string.
    :param coinbase_hash: list coinbase transaction hash in bytes or HEX encoded string.
    """
    merkle_root = coinbase_hash if not isinstance(coinbase_hash, str) else unhexlify(coinbase_hash)
    for h in merkle_branches:
        if type(h) == str:
            h = unhexlify(h)
        merkle_root = double_sha256(merkle_root + h)
    return merkle_root if not hex else hexlify(merkle_root).decode()

#  Difficulty

def bits_to_target(bits):
    """
    Calculate target from bits

    :param bits: HEX string, bytes string or integer representation of bits.
    :return: integer.
    """
    if type(bits) == str:
        bits = unhexlify(bits)
    if type(bits) == bytes:
        return int.from_bytes(bits[1:], 'big') * (2 ** (8 * (bits[0] - 3)))
    else:
        shift = bits >> 24
        target = (bits & 0xffffff) * (1 << (8 * (shift - 3)))
        return target

def target_to_difficulty(target):
    """
    Calculate difficulty from target

    :param target: integer.
    :return: float.
    """
    return 0x00000000FFFF0000000000000000000000000000000000000000000000000000 / target

def bits_to_difficulty(bits):
    """
    Calculate difficulty from bits

    """
    return target_to_difficulty(bits_to_target(bits))

def difficulty_to_target(difficulty):
    """
    Calculate target from difficulty

    """
    return int(0x00000000FFFF0000000000000000000000000000000000000000000000000000 / difficulty)

# Tools

def bytes_needed(n):
    """
    Calculate bytes needed to convert integer to bytes.

    :param n: integer.
    """
    if n == 0:
        return 1
    return math.ceil(n.bit_length()/8)

def int_to_bytes(i, byteorder='big'):
    """
    Convert integer to bytes.

    :param byteorder: (optional) byte order 'big' or 'little', by default 'big'.
    :return: bytes.
    """
    return i.to_bytes(bytes_needed(i), byteorder=byteorder, signed=False)

def bytes_to_int(i, byteorder='big'):
    """
    Convert bytes to integer.

    :param i: bytes.
    """
    return int.from_bytes(i, byteorder=byteorder, signed=False)

# variable integer

def int_to_var_int(i):
    """
    Convert integer to variable integer

    :param i: integer.
    """
    if i < 0xfd:
        return struct.pack('<B', i)
    if i <= 0xffff:
        return b'\xfd' + struct.pack('<H', i)
    if i <= 0xffffffff:
        return b'\xfe' + struct.pack('<L', i)
    return b'\xff' + struct.pack('<Q', i)

def var_int_to_int(data):
    """
    Convert variable integer to integer

    :param data: bytes vriable integer.
    """
    if data[0] == 0xfd:
        return struct.unpack('<H', data[1:3])[0]
    elif data[0] == 0xfe:
        return struct.unpack('<L', data[1:5])[0]
    elif data[0] == 0xff:
        return struct.unpack('<Q', data[1:9])[0]
    return data[0]

def var_int_len(n):
    """
    Get variable integer length in bytes from integer value

    """
    if n <= 0xfc:
        return 1
    if n <= 0xffff:
        return 3
    elif n <= 0xffffffff:
        return 5
    return 9

def get_var_int_len(bytes):
    """
    Get variable integer length in bytes from bytes

    :param bytes: bytes.
    """
    if bytes[0] == 253:
        return 3
    elif bytes[0] == 254:
        return 5
    elif bytes[0] == 255:
        return 9
    return 1

def read_var_int(stream):
    """
    Read variable integer from io.BytesIO stream to bytes

    :param stream: io.BytesIO stream.
    """
    l = stream.read(1)
    bytes_length = get_var_int_len(l)
    return l + stream.read(bytes_length - 1)

def read_var_list(stream, data_type):
    """
    Read variable integer list from io.BytesIO stream to bytes

    :param data_type: list data type.
    :return: list of data_type.
    """
    count = var_int_to_int(read_var_int(stream))
    return [data_type.deserialize(stream) for i in range(count)]

# compressed integer

def int_to_c_int(n, base_bytes=1):
    """
    Convert integer to compresed integer

    :param base_bytes: len of bytes base from which start compression.
    """
    if n == 0:
        return b'\x00'
    else:
        l = n.bit_length() + 1
    min_bits = base_bytes * 8 - 1
    if l <= min_bits + 1:
        return n.to_bytes(base_bytes, byteorder="big")
    prefix = 0
    payload_bytes = math.ceil((l)/8) - base_bytes
    extra_bytes = int(math.ceil((l+payload_bytes)/8) - base_bytes)
    for i in range(extra_bytes):
        prefix += 2 ** i
    if l < base_bytes * 8:
        l = base_bytes * 8
    prefix = prefix << l
    if prefix.bit_length() % 8:
        prefix = prefix << 8 - prefix.bit_length() % 8
    n ^= prefix
    return n.to_bytes(math.ceil(n.bit_length()/8), byteorder="big")

def c_int_to_int(b, base_bytes=1):
    """
    Convert compressed integer bytes to integer

    :param b: compressed integer bytes.
    """
    byte_length = 0
    f = 0
        v = b[f]
        if v == 0xff:
            byte_length += 8
            f += 1
            continue
        while v & 0b10000000:
            byte_length += 1
            v = v << 1
        break
    n = int.from_bytes(b[:byte_length+base_bytes], byteorder="big")
    if byte_length:
        return n & ((1 << (byte_length+base_bytes) * 8 - byte_length) - 1)
    return n

def c_int_len(n, base_bytes=1):
    """
    Get length of compressed integer from integer value

    :param n: bytes.
    """
    if n == 0:
        return 1
    l = n.bit_length() + 1
        return 1
    return int(math.ceil((l+payload_bytes)/8))

# generic big endian MPI format
def bn_bytes(v, have_ext=False):
    ext = 0
    if have_ext:
        ext = 1
    return ((v.bit_length() + 7) // 8) + ext

def bn2bin(v):
    s = bytearray()
    i = bn_bytes(v)
    while i > 0:
        s.append((v >> ((i - 1) * 8)) & 0xff)
        i -= 1
    return s

def bin2bn(s):
    l = 0
    for ch in s:
        l = (l << 8) | ch
    return l

def bn2mpi(v):
    have_ext = False
    if v.bit_length() > 0:
        have_ext = (v.bit_length() & 0x07) == 0
    neg = False
    if v < 0:
        neg = True
        v = -v
    s = struct.pack(b">I", bn_bytes(v, have_ext))
    ext = bytearray()
        ext.append(0)
    v_bin = bn2bin(v)
    if neg:
        if have_ext:
            ext[0] |= 0x80
        else:
            v_bin[0] |= 0x80
    return s + ext + v_bin

def mpi2bn(s):
    if len(s) < 4:
    s_size = bytes(s[:4])
    v_len = struct.unpack(b">I", s_size)[0]
    if len(s) != (v_len + 4):
    if v_len == 0:
        return 0
    v_str = bytearray(s[4:])
    neg = False
    i = v_str[0]
    if i & 0x80:
        neg = True
        i &= ~0x80
        v_str[0] = i
    v = bin2bn(v_str)

    if neg:
        return -v
    return v

# bitcoin-specific little endian format, with implicit size

def mpi2vch(s):
    r = s[4:]           # strip size
    # if r:
    r = r[::-1]         # reverse string, converting BE->LE
    # else: r=b'\x00'
    return r

def bn2vch(v):
    return bytes(mpi2vch(bn2mpi(v)))

def vch2mpi(s):
    r = struct.pack(b">I", len(s))   # size
    r += s[::-1]            # reverse string, converting LE->BE
    return r

def vch2bn(s):
    return mpi2bn(vch2mpi(s))

def i2b(i): return bn2vch(i)

def b2i(b): return vch2bn(b)

def get_stream(stream):
    if type(stream) != io.BytesIO:
        if type(stream) == str:
            stream = unhexlify(stream)
        if type(stream) == bytes:
            stream = io.BytesIO(stream)
        else:
            raise TypeError
    return stream

from struct import unpack
import json
from .address import PrivateKey, Address, PublicKey, ScriptAddress
from binascii import hexlify, unhexlify

class Transaction(dict):
    """
    The class for Transaction object

    :param raw_tx: (optional) raw transaction in bytes or HEX encoded string, if no raw transaction provided
                well be created new empty transaction template.
    :param tx_format: "raw" or "decoded" format. Raw format is mean that all transaction represented in bytes
                      for best performance.
                      Decoded transaction is represented in human readable format using base68, hex, bech32, 
                      asm and opcodes. By default "decoded" format using.
    :param int version: transaction version for new template, by default 1.
    :param int lock_time: transaction lock time for new template, by default 0.
    :param boolean testnet: address type for "decoded" transaction representation.

    """
    def __init__(self, raw_tx=None, tx_format="decoded", version=1, lock_time=0, testnet=False):
        if tx_format not in ("decoded", "raw"):
            raise TypeError("tx_format error, raw or decoded allowed")
        self["format"] = tx_format
        self["testnet"] = testnet
        self["segwit"] = False
        self["txId"] = None
        self["hash"] = None
        self["version"] = version
        self["vSize"] = 0
        self["bSize"] = 0
        self["lockTime"] = lock_time
        self["vIn"] = dict()
        self["vOut"] = dict()
        self["rawTx"] = None
        self["blockHash"] = None
        self["confirmations"] = None
        self["time"] = None
        self["blockTime"] = None
        self["blockIndex"] = None
        self["coinbase"] = False
        self["fee"] = None
        self["data"] = None
        self["amount"] = None
        if raw_tx is None:
            return

        self["amount"] = 0
        sw = sw_len = 0
        stream = self.get_stream(raw_tx)
        start = stream.tell()

        # start deserialization
        self["version"] = unpack('<L', stream.read(4))[0]
        n = read_var_int(stream)
        if n == b'\x00':
            # segwit format
            sw = 1
            self["flag"] = stream.read(1)
            n = read_var_int(stream)

        # inputs
        ic = var_int_to_int(n)
        for k in range(ic):
            self["vIn"][k] = dict()
            self["vIn"][k]["txId"] = stream.read(32)
            self["vIn"][k]["vOut"] = unpack('<L', stream.read(4))[0]
            self["vIn"][k]["scriptSig"] = stream.read(var_int_to_int(read_var_int(stream)))
            (self["vIn"][k]["sequence"],) = unpack('<L', stream.read(4))

        # outputs
        for k in range(var_int_to_int(read_var_int(stream))):
            self["vOut"][k] = dict()
            self["vOut"][k]["value"] = unpack('<Q', stream.read(8))[0]
            self["amount"] += self["vOut"][k]["value"]
            self["vOut"][k]["scriptPubKey"] = stream.read(var_int_to_int(read_var_int(stream)))
            s = parse_script(self["vOut"][k]["scriptPubKey"], sw)
            self["vOut"][k]["nType"] = s["nType"]
            self["vOut"][k]["type"] = s["type"]
            if self["data"] is None:
                if s["nType"] == 3:
                    self["data"] = s["data"]
            if s["nType"] not in (3, 4, 7):
                self["vOut"][k]["addressHash"] = s["addressHash"]
                self["vOut"][k]["reqSigs"] = s["reqSigs"]

        # witness
        if sw:
            sw = stream.tell() - start
            for k in range(ic):
                self["vIn"][k]["txInWitness"] = [stream.read(var_int_to_int(read_var_int(stream))) \
                                                 for c in range(var_int_to_int(read_var_int(stream)))]
            sw_len = stream.tell() - sw + 2

        self["lockTime"] = unpack('<L', stream.read(4))[0]

        end = stream.tell()
        stream.seek(start)
        b = stream.read(end - start)
        self["rawTx"] = b
        self["size"] = end - start
        self["bSize"] = end - start - sw_len
        self["weight"] = self["bSize"] * 3 + self["size"]
        self["vSize"] = math.ceil(self["weight"] / 4)
        if ic == 1 and \
                        self["vIn"][0]["txId"] == b'\x00' * 32 and \
                        self["vIn"][0]["vOut"] == 0xffffffff:
            self["coinbase"] = True
        else:
            self["coinbase"] = False
        if sw:
            self["segwit"] = True
            self["hash"] = double_sha256(b)
            self["txId"] = double_sha256(b[:4] + b[6:sw] + b[-4:])
        else:
            self["segwit"] = False
            self["txId"] = double_sha256(b)
            self["hash"] = self["txId"]

    def decode(self, testnet=None):
        """
        change Transacion object representation to "decoded" human readable format

        :param bool testnet: (optional) address type for "decoded" transaction representation, by default None.
                            if None used type from transaction property "format".
        """
        if self["format"] == "decoded":
            self.encode()
        self["format"] = "decoded"
        if testnet is not None:
            self["testnet"] = testnet
        if type(self["txId"]) == bytes:
            self["txId"] = rh2s(self["txId"])
        if "flag" in self:
            if type(self["flag"]) == bytes:
                self["flag"] = rh2s(self["flag"])
        if type(self["hash"]) == bytes:
            self["hash"] = rh2s(self["hash"])
        if type(self["rawTx"]) == bytes:
            self["rawTx"] = hexlify(self["rawTx"]).decode()
        for i in self["vIn"]:
            if type(self["vIn"][i]["txId"]) == bytes:
                self["vIn"][i]["txId"] = rh2s(self["vIn"][i]["txId"])
            if type(self["vIn"][i]["scriptSig"]) == bytes:
                self["vIn"][i]["scriptSig"] = hexlify(self["vIn"][i]["scriptSig"]).decode()
            try:
                t = list()
                for w in self["vIn"][i]["txInWitness"]:
                    if type(w) == bytes:
                        w = hexlify(w).decode()
                    t.append(w)
                self["vIn"][i]["txInWitness"] = t
                self["vIn"][i]["txInWitnessAsm"] = [decode_script(ws, 1) for ws in
                                                    self["vIn"][i]["txInWitness"]]
                self["vIn"][i]["txInWitnessOpcodes"] = [decode_script(ws) for ws in
                                                        self["vIn"][i]["txInWitness"]]
            except:
                pass
            try:
                if type(self["vIn"][i]["addressHash"]) == bytes:
                    self["vIn"][i]["addressHash"] = hexlify(self["vIn"][i]["addressHash"]).decode()
                sh = True if self["vIn"][i]["nType"] in (1, 5) else False
                witness_version = None if self["vIn"][i]["nType"] < 5 else 0
                self["vIn"][i]["address"] = hash_to_address(self["vIn"][i]["addressHash"],
                                                            self["testnet"],
                                                            sh,
                                                            witness_version)
            except:
                pass
            if "scriptPubKey" in self["vIn"][i]:
                if type(self["vIn"][i]["scriptPubKey"]) == bytes:
                    self["vIn"][i]["scriptPubKey"] = hexlify(self["vIn"][i]["scriptPubKey"]).decode()
                self["vIn"][i]["scriptPubKeyOpcodes"] = decode_script(self["vIn"][i]["scriptPubKey"])
                self["vIn"][i]["scriptPubKeyAsm"] = decode_script(self["vIn"][i]["scriptPubKey"], 1)
            if "redeemScript" in self["vIn"][i]:
                if type(self["vIn"][i]["redeemScript"]) == bytes:
                    self["vIn"][i]["redeemScript"] = hexlify(self["vIn"][i]["redeemScript"]).decode()
                self["vIn"][i]["redeemScriptOpcodes"] = decode_script(self["vIn"][i]["redeemScript"])
                self["vIn"][i]["redeemScriptAsm"] = decode_script(self["vIn"][i]["redeemScript"], 1)
            if not self["coinbase"]:
                if type(self["vIn"][i]["scriptSig"]) == bytes:
                    self["vIn"][i]["scriptSig"] = hexlify(self["vIn"][i]["scriptSig"]).decode()
                self["vIn"][i]["scriptSigOpcodes"] = decode_script(self["vIn"][i]["scriptSig"])
                self["vIn"][i]["scriptSigAsm"] = decode_script(self["vIn"][i]["scriptSig"], 1)

        for i in self["vOut"]:
            if type(self["vOut"][i]["scriptPubKey"]) == bytes:
                self["vOut"][i]["scriptPubKey"] = hexlify(self["vOut"][i]["scriptPubKey"]).decode()
            try:
                if type(self["vOut"][i]["addressHash"]) == bytes:
                    self["vOut"][i]["addressHash"] = hexlify(self["vOut"][i]["addressHash"]).decode()
                sh = True if self["vOut"][i]["nType"] in (1, 5) else False
                witness_version = None if self["vOut"][i]["nType"] < 5 else 0
                self["vOut"][i]["address"] = hash_to_address(self["vOut"][i]["addressHash"],
                                                             self["testnet"],
                                                             sh,
                                                             witness_version)
            except:
                pass
            self["vOut"][i]["scriptPubKeyOpcodes"] = decode_script(self["vOut"][i]["scriptPubKey"])
            self["vOut"][i]["scriptPubKeyAsm"] = decode_script(self["vOut"][i]["scriptPubKey"], 1)
        if "data" in self:
            if type(self["data"]) == bytes:
                self["data"] = hexlify(self["data"]).decode()
        return self

    def encode(self):
        """
        change Transaction object representation to "raw" bytes format, 
        all human readable part will be stripped.

        """
        if type(self["txId"]) == str:
            self["txId"] = s2rh(self["txId"])
            if type(self["flag"]) == str:
                self["flag"] = s2rh(self["flag"])
        if type(self["hash"]) == str:
            self["hash"] = s2rh(self["hash"])
        if type(self["rawTx"]) == str:
            self["rawTx"] = unhexlify(self["rawTx"])

            if type(self["vIn"][i]["txId"]) == str:
                self["vIn"][i]["txId"] = s2rh(self["vIn"][i]["txId"])
            if type(self["vIn"][i]["scriptSig"]) == str:
                self["vIn"][i]["scriptSig"] = unhexlify(self["vIn"][i]["scriptSig"])
            try:
                t = list()
                    if type(w) == str:
                        w = unhexlify(w)
                if "txInWitnessAsm" in self["vIn"][i]:
                    del self["vIn"][i]["txInWitnessAsm"]
                if "txInWitnessOpcodes" in self["vIn"][i]:
                    del self["vIn"][i]["txInWitnessOpcodes"]
            except:
                pass
            try:
                if type(self["vIn"][i]["addressHash"]) == str:
                    self["vIn"][i]["addressHash"] = unhexlify(self["vIn"][i]["addressHash"])
                if "address" in self["vIn"][i]:
                    del self["vIn"][i]["address"]
            except:
                pass
            if "scriptSigAsm" in self["vIn"][i]:
                del self["vIn"][i]["scriptSigAsm"]
            if "scriptSigOpcodes" in self["vIn"][i]:
                del self["vIn"][i]["scriptSigOpcodes"]

            if type(self["vOut"][i]["scriptPubKey"]) == str:
                self["vOut"][i]["scriptPubKey"] = unhexlify(self["vOut"][i]["scriptPubKey"])
            try:
                if type(self["vOut"][i]["addressHash"]) == str:
                    self["vOut"][i]["addressHash"] = unhexlify(self["vOut"][i]["addressHash"])
                if "address" in self["vOut"][i]:
                    del self["vOut"][i]["address"]
            except:
                pass
            if "scriptPubKeyOpcodes" in self["vOut"][i]:
                del self["vOut"][i]["scriptPubKeyOpcodes"]
            if "scriptPubKeyAsm" in self["vOut"][i]:
                del self["vOut"][i]["scriptPubKeyAsm"]

            if type(self["data"]) == str:
                self["data"] = unhexlify(self["data"])
        self["format"] = "raw"

    def get_stream(self, stream):
        if type(stream) != io.BytesIO:
            if type(stream) == str:
                stream = unhexlify(stream)
            if type(stream) == bytes:
                stream = io.BytesIO(stream)
            else:
                raise TypeError
        return stream

    def serialize(self, segwit=True, hex=True):
        """
        Get serialized transaction 
        
        :param bool segwit: (optional) flag for segwit representation of serialized transaction, by 
                            default True.
        :param bool hex: (optional) if set to True return HEX encoded string, by default True.
        :return str,bytes: serialized transaction in HEX or bytes.
         """
        chunks = []
        chunks.append(struct.pack('<L', self["version"]))
        if segwit and self["segwit"]:
            chunks.append(b"\x00\x01")
        chunks.append(int_to_var_int(len(self["vIn"])))
            if isinstance(self["vIn"][i]['txId'], bytes):
                chunks.append(self["vIn"][i]['txId'])
            else:
                chunks.append(s2rh(self["vIn"][i]['txId']))
            chunks.append(struct.pack('<L', self["vIn"][i]['vOut']))
            if isinstance(self["vIn"][i]['scriptSig'], bytes):
                chunks.append(int_to_var_int(len(self["vIn"][i]['scriptSig'])))
                chunks.append(self["vIn"][i]['scriptSig'])
            else:
                chunks.append(int_to_var_int(int(len(self["vIn"][i]['scriptSig']) / 2)))
                chunks.append(unhexlify(self["vIn"][i]['scriptSig']))
            chunks.append(struct.pack('<L', self["vIn"][i]['sequence']))
        chunks.append(int_to_var_int(len(self["vOut"])))
            chunks.append(struct.pack('<Q', self["vOut"][i]['value']))
            if isinstance(self["vOut"][i]['scriptPubKey'], bytes):
                chunks.append(int_to_var_int(len(self["vOut"][i]['scriptPubKey'])))
                chunks.append(self["vOut"][i]['scriptPubKey'])
            else:
                chunks.append(int_to_var_int(int(len(self["vOut"][i]['scriptPubKey']) / 2)))
                chunks.append(unhexlify(self["vOut"][i]['scriptPubKey']))
            for i in self["vIn"]:
                chunks.append(int_to_var_int(len(self["vIn"][i]['txInWitness'])))
                for w in self["vIn"][i]['txInWitness']:
                    if isinstance(w, bytes):
                        chunks.append(int_to_var_int(len(w)))
                        chunks.append(w)
                    else:
                        chunks.append(int_to_var_int(int(len(w) / 2)))
                        chunks.append(unhexlify(w))
        chunks.append(struct.pack('<L', self['lockTime']))
        tx = b''.join(chunks)
        return tx if not hex else hexlify(tx).decode()

    def json(self):
        """
        Get json transaction representation

        """
        try:
            return json.dumps(self)
        except:
            pass
        return json.dumps(self.decode())

    def add_input(self, tx_id=None, v_out=0, sequence=0xffffffff,
                  script_sig=b"", tx_in_witness=None, amount=None,
                  script_pub_key=None, address=None, private_key=None):
        if tx_id is None:
            tx_id = b"\x00" * 32
            v_out = 0xffffffff
            assert v_out == 0xffffffff and sequence == 0xffffffff
            assert not self["vIn"]
        if type(tx_id) == str:
            tx_id = s2rh(tx_id)
        if type(script_sig) == str:
            script_sig = unhexlify(script_sig)
        assert type(tx_id) == bytes
        assert len(tx_id) == 32
        assert type(v_out) == int
        assert v_out <= 0xffffffff and v_out >= 0
        assert type(sequence) == int
        assert sequence <= 0xffffffff and sequence >= 0
        assert type(script_sig) == bytes
        assert len(script_sig) <= 520
        if private_key:
            if type(private_key) != PrivateKey:
                private_key = PrivateKey(private_key)
        if amount:
            assert type(amount) == int
            assert amount >= 0 and amount <= MAX_AMOUNT
        if tx_in_witness:
            assert type(tx_in_witness) == list
            l = 0
            witness = []
            for w in tx_in_witness:
                if type(w) == str:
                    witness.append(unhexlify(w) if self["format"] == "raw" else w)
                else:
                    witness.append(w if self["format"] == "raw" else unhexlify(w))
                l += 1 + len(w)
                if len(w) >= 0x4c:
                    l += 1
                if len(w) > 0xff:
                    l += 1
            # witness script limit
            assert l <= 10000
        if tx_id == b"\x00" * 32:
            assert v_out == 0xffffffff and sequence == 0xffffffff and len(script_sig) <= 100

        # script_pub_key
        if script_pub_key:
            if type(script_pub_key) == str:
                script_pub_key = unhexlify(script_pub_key)
            type(script_pub_key) == bytes
        if address is not None:
            if type(address) == str:
                net = True if address_net_type(address) == 'mainnet' else False
                assert not net == self["testnet"]
                script = address_to_script(address)
            elif type(address) in (Address, ScriptAddress):
                assert type(address) == Address
                script = address_to_script(address.address)
            if script_pub_key:
                assert script_pub_key == script
            else:
                script_pub_key = script

        k = len(self["vIn"])
        self["vIn"][k] = dict()
        self["vIn"][k]["vOut"] = v_out
        self["vIn"][k]["sequence"] = sequence
        if self["format"] == "raw":
            self["vIn"][k]["txId"] = tx_id
            self["vIn"][k]["scriptSig"] = script_sig
                self["vIn"][k]["scriptPubKey"] = script_pub_key
        else:
            self["vIn"][k]["txId"] = rh2s(tx_id)
            self["vIn"][k]["scriptSig"] = hexlify(script_sig).decode()
            self["vIn"][k]["scriptSigOpcodes"] = decode_script(script_sig)
            self["vIn"][k]["scriptSigAsm"] = decode_script(script_sig, 1)
                self["vIn"][k]["scriptPubKey"] = hexlify(script_pub_key).decode()
            self["vIn"][k]["txInWitness"] = witness
        if amount:
            self["vIn"][k]["value"] = amount
            self["vIn"][k].private_key = private_key
        self.__refresh__()

    def add_output(self, amount, address=None, script_pub_key=None):
        assert address is not None or script_pub_key is not None
        assert not (address is None and script_pub_key is None)
        assert type(amount) == int
        assert amount >= 0 and amount <= MAX_AMOUNT
            assert type(script_pub_key) == bytes
        else:
            if type(address) == Address:
                address = address.address
            script_pub_key = address_to_script(address)

        k = len(self["vOut"])
        self["vOut"][k] = dict()
        self["vOut"][k]["value"] = amount
        segwit = True if "segwit" in self else False
        s = parse_script(script_pub_key, segwit)
        self["vOut"][k]["nType"] = s["nType"]
        self["vOut"][k]["type"] = s["type"]

            self["vOut"][k]["scriptPubKey"] = script_pub_key
        else:
            self["vOut"][k]["scriptPubKey"] = hexlify(script_pub_key).decode()
                    self["data"] = hexlify(s["data"]).decode()
                self["vOut"][k]["addressHash"] = hexlify(s["addressHash"]).decode()
            self["vOut"][k]["scriptPubKeyOpcodes"] = decode_script(script_pub_key)
            self["vOut"][k]["scriptPubKeyAsm"] = decode_script(script_pub_key, 1)
            sh = True if self["vOut"][k]["nType"] in (1, 5) else False
            witness_version = None if self["vOut"][k]["nType"] < 5 else 0
            if "addressHash" in self["vOut"][k]:
                self["vOut"][k]["address"] = hash_to_address(self["vOut"][k]["addressHash"],
                                                             sh,

    def del_output(self, n=None):
        if not self["vOut"]:
            return self
        if n is None:
            n = len(self["vOut"]) - 1
        new_out = dict()
        c = 0
        for i in range(len(self["vOut"])):
            if i != n:
                new_out[c] = self["vOut"][i]
                c += 1
        self["vOut"] = new_out

    def del_input(self, n):
        if not self["vIn"]:
            n = len(self["vIn"]) - 1
        new_in = dict()
        c = 0
        for i in range(len(self["vIn"])):
            if i != n:
                new_in[c] = self["vIn"][i]
                c += 1
        self["vIn"] = new_in

    def sign_input(self, n, private_key=None, script_pub_key=None, redeem_script=None, sighash_type=SIGHASH_ALL):
        if private_key is not None:
            if private_key:
                if type(private_key) != PrivateKey:
                    private_key_obj = PrivateKey(private_key)
                    public_key = PublicKey(private_key_obj).key
                    private_key = private_key_obj.key
        else:
            if "privateKey" not in self["vIn"][n]:
                return self
            private_key = self["vIn"][n].private_key.key
            public_key = PublicKey(self["vIn"][n].private_key).key

        if redeem_script:
            if type(redeem_script) == str:
                redeem_script = unhexlify(redeem_script).decode()
            assert type(redeem_script) == bytes
            script = redeem_script
        else:
            script = script_pub_key

        sighash = self.sig_hash_input(n, script_pub_key=script, sighash_type=sighash_type)
        if type(sighash) == str:
            sighash = s2rh(sighash)
        signature = sign_message(sighash, private_key, 0) + bytes([sighash_type])
            if self["vIn"][n]["scriptSig"]:
                sig_script = self["vIn"][n]["scriptSig"]
                if type(sig_script) == str:
                    sig_script = unhexlify(sig_script).decode()
                sig_script = bytes([len(public_key)]) + public_key + sig_script
                sig_script = bytes([len(signature)]) + signature + sig_script
            else:
                sig_script = bytes([len(signature)]) + signature
                sig_script += bytes([len(public_key)]) + public_key
                if len(redeem_script) <= 0x4b:
                    sig_script += bytes([len(redeem_script)]) + redeem_script
                elif len(redeem_script) <= 0xff:
                    sig_script = BYTE_OPCODE["OP_PUSHDATA1"] + bytes([len(redeem_script)]) + redeem_script
                elif len(redeem_script) <= 0xffff:
                    sig_script = BYTE_OPCODE["OP_PUSHDATA2"] + bytes([len(redeem_script)]) + redeem_script
                else:
                    sig_script = BYTE_OPCODE["OP_PUSHDATA4"] + bytes([len(redeem_script)]) + redeem_script
        else:
            sig_script = bytes([len(signature)]) + signature
            sig_script += bytes([len(public_key)]) + public_key
            self["vIn"][n]["scriptSig"] = sig_script
        else:
            self["vIn"][n]["scriptSig"] = hexlify(sig_script).decode()
            self["vIn"][n]["scriptSigOpcodes"] = decode_script(sig_script)
            self["vIn"][n]["scriptSigAsm"] = decode_script(sig_script, 1)

    def sig_hash_input(self, n, script_pub_key=None, sighash_type=SIGHASH_ALL):
        # check n
        assert n >= 0
        tx_in_count = len(self["vIn"])

        if n >= tx_in_count:
            if self["format"] == "raw":
                return b'\x01' + b'\x00' * 31
            else:
                return rh2s(b'\x01' + b'\x00' * 31)

        # check script_pub_key for input
        if script_pub_key is not None:
            script_code = script_pub_key
        else:
            assert "scriptPubKey" in self["vIn"][n]
            script_code = self["vIn"][n]["scriptPubKey"]
        if type(script_code) == str:
            script_code = unhexlify(script_code)
        assert type(script_code) == bytes

        # remove opcode separators
        script_code = delete_from_script(script_code, BYTE_OPCODE["OP_CODESEPARATOR"])
        preimage = bytearray()

        if ((sighash_type & 31) == SIGHASH_SINGLE) and (n >= (len(self["vOut"]))):
            else:

        preimage += struct.pack('<L', self["version"])
        preimage += b'\x01' if sighash_type & SIGHASH_ANYONECANPAY else int_to_var_int(tx_in_count)

            # skip all other inputs for SIGHASH_ANYONECANPAY case
            if (sighash_type & SIGHASH_ANYONECANPAY) and (n != i):
                continue
            sequence = self["vIn"][i]["sequence"]
            if (sighash_type & 31) == SIGHASH_SINGLE and (n != i):
                sequence = 0
            if (sighash_type & 31) == SIGHASH_NONE and (n != i):
            tx_id = self["vIn"][i]["txId"]
            if type(tx_id) == str:
                tx_id = s2rh(tx_id)
            input = tx_id + struct.pack('<L', self["vIn"][i]["vOut"])
            if n == i:
                input += int_to_var_int(len(script_code)) + script_code
                input += struct.pack('<L', sequence)
            else:
                input += b'\x00' + struct.pack('<L', sequence)
            preimage += input

        if (sighash_type & 31) == SIGHASH_NONE:
            preimage += b'\x00'
        else:
            if (sighash_type & 31) == SIGHASH_SINGLE:
                preimage += int_to_var_int(n + 1)
            else:
                preimage += int_to_var_int(len(self["vOut"]))

        if (sighash_type & 31) != SIGHASH_NONE:
            for i in self["vOut"]:
                script_pub_key = self["vOut"][i]["scriptPubKey"]
                if type(self["vOut"][i]["scriptPubKey"]) == str:
                    script_pub_key = unhexlify(script_pub_key)
                if i > n and (sighash_type & 31) == SIGHASH_SINGLE:
                    continue
                if (sighash_type & 31) == SIGHASH_SINGLE and (n != i):
                    preimage += b'\xff' * 8 + b'\x00'
                else:
                    preimage += self["vOut"][i]["value"].to_bytes(8, 'little')
                    preimage += int_to_var_int(len(script_pub_key)) + script_pub_key

        preimage += self["lockTime"].to_bytes(4, 'little')
        preimage += struct.pack(b"<i", sighash_type)
        return double_sha256(preimage) if self["format"] == "raw" else rh2s(double_sha256(preimage))

    def __refresh__(self):
        if not self["vOut"] or not self["vIn"]:
            return
        no_segwit_view = self.serialize(segwit=False, hex=False)
        self["txId"] = double_sha256(no_segwit_view)
        self["rawTx"] = self.serialize(segwit=True, hex=False)
        self["hash"] = double_sha256(self["rawTx"])

        self["size"] = len(self["rawTx"])
        self["bSize"] = len(no_segwit_view)

        if self["format"] != "raw":

        input_sum = 0
            if "value" in self["vIn"][i]:
                input_sum += self["vIn"][i]["value"]
            else:
                input_sum = None
                break

        output_sum = 0
            if "value" in self["vOut"][i]:
                output_sum += self["vOut"][i]["value"]
            else:
                output_sum = None
                break
        self["amount"] = output_sum
        if output_sum and input_sum:
            self["fee"] = input_sum - output_sum
        else:
            self["fee"] = None