Ejemplo n.º 1
0
 def __init__(self,
              network,
              provider,
              base_url,
              denominator,
              api_key='',
              provider_coin_id='',
              network_overrides=None,
              timeout=TIMEOUT_REQUESTS,
              latest_block=None):
     try:
         self.network = network
         if not isinstance(network, Network):
             self.network = Network(network)
         self.provider = provider
         self.base_url = base_url
         self.resp = None
         self.units = denominator
         self.api_key = api_key
         self.provider_coin_id = provider_coin_id
         self.network_overrides = {}
         self.timeout = timeout
         self.latest_block = latest_block
         if network_overrides is not None:
             self.network_overrides = network_overrides
     except:
         raise ClientError("This Network is not supported by %s Client" %
                           provider)
Ejemplo n.º 2
0
    def __init__(self, network=DEFAULT_NETWORK, min_providers=1, max_providers=1, providers=None):
        """
        Open a service object for the specified network. By default the object connect to 1 service provider, but you
        can specify a list of providers or a minimum or maximum number of providers.

        :param network: Specify network used
        :type network: str, Network
        :param min_providers: Minimum number of providers to connect to. Default is 1. Use for instance to receive
        fee information from a number of providers and calculate the average fee.
        :type min_providers: int
        :param max_providers: Maximum number of providers to connect to. Default is 1.
        :type max_providers: int
        :param providers: List of providers to connect to. Default is all providers and select a provider at random.
        :type providers: list, str

        """
        self.network = network
        if not isinstance(network, Network):
            self.network = Network(network)
        if min_providers > max_providers:
            max_providers = min_providers
        try:
            fn = DEFAULT_SETTINGSDIR + "providers.json"
            f = open(fn, "r")
        except FileNotFoundError:
            fn = CURRENT_INSTALLDIR_DATA + "providers.json"
            f = open(fn, "r")

        try:
            self.providers_defined = json.loads(f.read())
        except json.decoder.JSONDecodeError as e:
            errstr = "Error reading provider definitions from %s: %s" % (fn, e)
            _logger.warning(errstr)
            raise ServiceError(errstr)
        f.close()

        provider_list = list([self.providers_defined[x]['provider'] for x in self.providers_defined])
        if providers is None:
            providers = []
        if not isinstance(providers, list):
            providers = [providers]
        for p in providers:
            if p not in provider_list:
                raise ServiceError("Provider '%s' not found in provider definitions" % p)

        self.providers = {}
        for p in self.providers_defined:
            if self.providers_defined[p]['network'] == network and \
                    (not providers or self.providers_defined[p]['provider'] in providers):
                self.providers.update({p: self.providers_defined[p]})

        if not self.providers:
            raise ServiceError("No providers found for network %s" % network)
        self.min_providers = min_providers
        self.max_providers = max_providers
        self.results = {}
        self.errors = {}
        self.resultcount = 0
Ejemplo n.º 3
0
    def network_change(self, new_network):
        """
        Change network for current key

        :param new_network: Name of new network
        :type new_network: str

        :return bool: True
        """
        self.network = Network(new_network)
        return True
Ejemplo n.º 4
0
    def _multisig_test(sigs_required, number_of_sigs, sort_keys, network):
        # Create Keys
        key_dict = {}
        for key_id in range(number_of_sigs):
            key_dict[key_id] = HDKey(network=network)
        random_output_address = HDKey(network=network).key.address()

        # Create wallets with 1 private key each
        wallet_dict = {}
        wallet_keys = {}
        for wallet_id in range(number_of_sigs):
            wallet_name = 'multisig-%d' % wallet_id
            key_list = []
            for key_id in key_dict:
                if key_id == wallet_id:
                    key_list.append(key_dict[key_id])
                else:
                    key_list.append(key_dict[key_id].subkey_for_path(
                        "m/45'/%d'/0'" %
                        Network(network).bip44_cointype).wif_public())
            wallet_dict[wallet_id] = HDWallet.create_multisig(
                wallet_name,
                key_list,
                sigs_required=sigs_required,
                network=network,
                sort_keys=sort_keys,
                databasefile=DATABASEFILE_UNITTESTS)
            wallet_keys[wallet_id] = wallet_dict[wallet_id].new_key()
            wallet_dict[wallet_id].utxos_update()

        # Create transaction in one random wallet
        wallet_ids = [i for i in range(0, number_of_sigs)]
        shuffle(wallet_ids)
        transaction_fee = 50000
        wallet_id = wallet_ids.pop()
        wlt = wallet_dict[wallet_id]
        utxos = wlt.utxos()
        output_arr = [(random_output_address,
                       utxos[0]['value'] - transaction_fee)]
        input_arr = [(utxos[0]['tx_hash'], utxos[0]['output_n'],
                      utxos[0]['key_id'], utxos[0]['value'])]
        t = wlt.transaction_create(output_arr,
                                   input_arr,
                                   transaction_fee=transaction_fee)
        t.sign()
        n_signs = 1

        # Sign transaction with other wallets until required number of signatures is reached
        while wallet_ids and n_signs < sigs_required:
            wallet_id = wallet_ids.pop()
            t = wallet_dict[wallet_id].transaction_import(t)
            t.sign()
            n_signs += 1
        return t
Ejemplo n.º 5
0
    def __init__(self,
                 inputs=None,
                 outputs=None,
                 locktime=0,
                 version=b'\x00\x00\x00\x01',
                 network=DEFAULT_NETWORK):
        """
        Create a new transaction class with provided inputs and outputs. 
        
        You can also create a empty transaction and add input and outputs later.
        
        To verify and sign transactions all inputs and outputs need to be included in transaction. Any modification 
        after signing makes the transaction invalid.
        
        :param inputs: Array of Input objects. Leave empty to add later
        :type inputs: Input, list
        :param outputs: Array of Output object. Leave empty to add later
        :type outputs: Output, list
        :param locktime: Unix timestamp or blocknumber. Default is 0
        :type locktime: int
        :param version: Version rules. Defaults to 1 in bytes 
        :type version: bytes
        :param network: Network, leave empty for default network
        :type network: str
        """
        if inputs is None:
            self.inputs = []
        else:
            self.inputs = inputs
        if outputs is None:
            self.outputs = []
        else:
            self.outputs = outputs

        self.version = version
        self.locktime = locktime
        self.network = Network(network)
        self.fee = None
        self.fee_per_kb = None
        self.size = None
        self.change = None
Ejemplo n.º 6
0
    def __init__(self,
                 import_key=None,
                 network=None,
                 compressed=True,
                 passphrase=''):
        """
        Initialize a Key object. Import key can be in WIF, bytes, hexstring, etc.
        If a private key is imported a public key will be derived. If a public is imported the private key data will
        be empty.
        
        Both compressed and uncompressed key version is available, the Key.compressed boolean attribute tells if the
        original imported key was compressed or not.

        :param import_key: If specified import given private or public key. If not specified a new private key is generated.
        :type import_key: str, int, bytes, bytearray
        :param network: Bitcoin, testnet, litecoin or other network
        :type network: str
        :param compressed: Is key compressed or not, default is True
        :type compressed: bool
        :param passphrase: Optional passphrase if imported key is password protected
        :type passphrase: str
        
        :return: Key object
        """
        self.public_hex = None
        self.public_uncompressed_hex = None
        self.public_compressed_hex = None
        self.public_byte = None
        self.public_uncompressed_byte = None
        self.public_compressed_byte = None
        self.private_byte = None
        self.private_hex = None
        self._x = None
        self._y = None
        self.secret = None
        self.compressed = compressed
        if not import_key:
            import_key = random.SystemRandom().randint(0, secp256k1_n)
        kf = get_key_format(import_key)
        self.key_format = kf["format"]
        network = check_network_and_key(import_key, network, kf["networks"])
        self.network = Network(network)
        if kf['isprivate']:
            self.isprivate = True
        elif kf['isprivate'] is None:
            raise KeyError("Could not determine if key is private or public")
        else:
            self.isprivate = False

        if self.key_format == "wif_protected":
            # TODO: return key as byte to make more efficient
            import_key, self.key_format = self._bip38_decrypt(
                import_key, passphrase)

        if not self.isprivate:
            self.secret = None
            pub_key = to_hexstring(import_key)
            if len(pub_key) == 130:
                self.public_uncompressed_hex = pub_key
                self._x = pub_key[2:66]
                self._y = pub_key[66:130]
                self.compressed = False
                if int(self._y, 16) % 2:
                    prefix = '03'
                else:
                    prefix = '02'
                self.public_hex = prefix + self._x
                self.public_compressed_hex = prefix + self._x
            else:
                self.public_hex = pub_key
                self._x = pub_key[2:66]
                self.compressed = True
                # Calculate y from x with y=x^3 + 7 function
                sign = pub_key[:2] == '03'
                x = int(self._x, 16)
                ys = (x**3 + 7) % secp256k1_p
                y = ecdsa.numbertheory.square_root_mod_prime(ys, secp256k1_p)
                if y & 1 != sign:
                    y = secp256k1_p - y
                self._y = change_base(y, 10, 16, 64)
                self.public_uncompressed_hex = '04' + self._x + self._y
                self.public_compressed_hex = pub_key
            self.public_compressed_byte = binascii.unhexlify(self.public_hex)
            self.public_uncompressed_byte = binascii.unhexlify(
                self.public_uncompressed_hex)
            if self.compressed:
                self.public_byte = self.public_compressed_byte
            else:
                self.public_byte = self.public_uncompressed_byte
        elif self.isprivate and self.key_format == 'decimal':
            self.secret = import_key
            self.private_hex = change_base(import_key, 10, 16, 64)
            self.private_byte = binascii.unhexlify(self.private_hex)
        elif self.isprivate:
            if self.key_format == 'hex':
                key_hex = import_key
                key_byte = binascii.unhexlify(key_hex)
            elif self.key_format == 'hex_compressed':
                key_hex = import_key[:-2]
                key_byte = binascii.unhexlify(key_hex)
                self.compressed = True
            elif self.key_format == 'bin':
                key_byte = import_key
                key_hex = to_hexstring(key_byte)
            elif self.key_format == 'bin_compressed':
                key_byte = import_key[:-1]
                key_hex = to_hexstring(key_byte)
                self.compressed = True
            elif self.isprivate and self.key_format in [
                    'wif', 'wif_compressed'
            ]:
                # Check and remove Checksum, prefix and postfix tags
                key = change_base(import_key, 58, 256)
                checksum = key[-4:]
                key = key[:-4]
                if checksum != hashlib.sha256(
                        hashlib.sha256(key).digest()).digest()[:4]:
                    raise BKeyError("Invalid checksum, not a valid WIF key")
                found_networks = network_by_value('prefix_wif', key[0:1])
                if not len(found_networks):
                    raise BKeyError(
                        "Unrecognised WIF private key, version byte unknown. Versionbyte: %s"
                        % key[0:1])
                if self.network.network_name not in found_networks:
                    if len(found_networks) > 1:
                        raise BKeyError(
                            "More then one network found with this versionbyte, please specify network. "
                            "Networks found: %s" % found_networks)
                    else:
                        _logger.warning(
                            "Current network %s is different then the one found in key: %s"
                            % (network, found_networks[0]))
                        self.network = Network(found_networks[0])
                if key[-1:] == b'\x01':
                    self.compressed = True
                    key = key[:-1]
                else:
                    self.compressed = False
                key_byte = key[1:]
                key_hex = to_hexstring(key_byte)
            else:
                raise KeyError("Unknown key format %s" % self.key_format)

            if not (key_byte or key_hex):
                raise KeyError("Cannot format key in hex or byte format")
            self.private_hex = key_hex
            self.private_byte = key_byte
            self.secret = int(key_hex, 16)
        else:
            raise KeyError("Cannot import key. Public key format unknown")

        if self.isprivate and not (self.public_byte or self.public_hex):
            if not self.isprivate:
                raise KeyError("Private key has no known secret number")
            point = ec_point(self.secret)
            self._x = change_base(point.x(), 10, 16, 64)
            self._y = change_base(point.y(), 10, 16, 64)
            if point.y() % 2:
                prefix = '03'
            else:
                prefix = '02'

            self.public_compressed_hex = prefix + self._x
            self.public_uncompressed_hex = '04' + self._x + self._y
            self.public_hex = self.public_compressed_hex if self.compressed else self.public_uncompressed_hex

            self.public_byte = binascii.unhexlify(self.public_hex)
            self.public_compressed_byte = binascii.unhexlify(
                self.public_compressed_hex)
            self.public_uncompressed_byte = binascii.unhexlify(
                self.public_uncompressed_hex)
Ejemplo n.º 7
0
    def __init__(self, network=DEFAULT_NETWORK, min_providers=1, max_providers=1, providers=None,
                 timeout=TIMEOUT_REQUESTS):
        """
        Open a service object for the specified network. By default the object connect to 1 service provider, but you
        can specify a list of providers or a minimum or maximum number of providers.

        :param network: Specify network used
        :type network: str, Network
        :param min_providers: Minimum number of providers to connect to. Default is 1. Use for instance to receive
        fee information from a number of providers and calculate the average fee.
        :type min_providers: int
        :param max_providers: Maximum number of providers to connect to. Default is 1.
        :type max_providers: int
        :param providers: List of providers to connect to. Default is all providers and select a provider at random.
        :type providers: list, str
        :param timeout: Timeout for web requests. Leave empty to use default from config settings
        :type timeout: int

        """
        self.network = network
        if not isinstance(network, Network):
            self.network = Network(network)
        if min_providers > max_providers:
            max_providers = min_providers
        fn = os.path.join(BCL_CONFIG_DIR, "providers.json")
        if not os.path.isfile(fn):
            fn = os.path.join(BCL_DATA_DIR, "providers.json")
        f = open(fn, "r")

        try:
            self.providers_defined = json.loads(f.read())
        except json.decoder.JSONDecodeError as e:  # pragma: no cover
            errstr = "Error reading provider definitions from %s: %s" % (fn, e)
            _logger.warning(errstr)
            raise ServiceError(errstr)
        f.close()

        provider_list = list([self.providers_defined[x]['provider'] for x in self.providers_defined])
        if providers is None:
            providers = []
        if not isinstance(providers, list):
            providers = [providers]
        for p in providers:
            if p not in provider_list:
                raise ServiceError("Provider '%s' not found in provider definitions" % p)

        self.providers = {}
        for p in self.providers_defined:
            if self.providers_defined[p]['network'] == network and \
                    (not providers or self.providers_defined[p]['provider'] in providers):
                self.providers.update({p: self.providers_defined[p]})

        if not self.providers:
            raise ServiceError("No providers found for network %s" % network)
        self.min_providers = min_providers
        self.max_providers = max_providers
        self.results = {}
        self.errors = {}
        self.resultcount = 0
        self.complete = None
        self.timeout = timeout
        self._blockcount = None
        self._blockcount_update = 0
Ejemplo n.º 8
0
    def __init__(self,
                 amount,
                 address='',
                 public_key_hash=b'',
                 public_key=b'',
                 lock_script=b'',
                 network=DEFAULT_NETWORK):
        """
        Create a new transaction output
        
        An transaction outputs locks the specified amount to a public key. Anyone with the private key can unlock
        this output.
        
        The transaction output class contains an amount and the destination which can be provided either as address, 
        public key, public key hash or a locking script. Only one needs to be provided as the they all can be derived 
        from each other, but you can provide as much attributes as you know to improve speed.
        
        :param amount: Amount of output in smallest denominator of currency, for example satoshi's for bitcoins
        :type amount: int
        :param address: Destination address of output. Leave empty to derive from other attributes you provide.
        :type address: str
        :param public_key_hash: Hash of public key
        :type public_key_hash: bytes, str
        :param public_key: Destination public key
        :type public_key: bytes, str
        :param lock_script: Locking script of output. If not provided a default unlocking script will be provided with a public key hash.
        :type lock_script: bytes, str
        :param network: Network, leave empty for default
        :type network: str
        """
        if not (address or public_key_hash or public_key or lock_script):
            raise TransactionError(
                "Please specify address, lock_script, public key or public key hash when "
                "creating output")

        self.amount = amount
        self.lock_script = to_bytes(lock_script)
        self.public_key_hash = to_bytes(public_key_hash)
        self.address = address
        self.public_key = to_bytes(public_key)
        self.network = Network(network)
        self.compressed = True
        self.k = None
        self.versionbyte = self.network.prefix_address
        self.script_type = 'p2pkh'

        if self.public_key:
            self.k = Key(binascii.hexlify(self.public_key).decode('utf-8'),
                         network=network)
            self.address = self.k.address()
            self.compressed = self.k.compressed
        if self.public_key_hash and not self.address:
            self.address = pubkeyhash_to_addr(public_key_hash,
                                              versionbyte=self.versionbyte)
        if self.address:
            address_dict = deserialize_address(self.address)
            if address_dict['script_type']:
                self.script_type = address_dict['script_type']
            else:
                raise TransactionError(
                    "Could not determine script type of address %s" %
                    self.address)
            self.public_key_hash = address_dict['public_key_hash_bytes']
            if address_dict[
                    'network'] and self.network.network_name != address_dict[
                        'network']:
                raise TransactionError(
                    "Address (%s) is from different network then defined %s" %
                    (address_dict['network'], self.network.network_name))
        if not self.public_key_hash and self.k:
            self.public_key_hash = self.k.hash160()

        if self.lock_script and not self.public_key_hash:
            ss = script_deserialize(self.lock_script)
            self.script_type = ss['script_type']
            if self.script_type == 'p2sh':
                self.versionbyte = self.network.prefix_address_p2sh
            if self.script_type in ['p2pkh', 'p2sh']:
                self.public_key_hash = ss['signatures'][0]
                self.address = pubkeyhash_to_addr(self.public_key_hash,
                                                  versionbyte=self.versionbyte)
            else:
                _logger.warning("Script type %s not supported" %
                                self.script_type)

        if self.lock_script == b'':
            if self.script_type == 'p2pkh':
                self.lock_script = b'\x76\xa9\x14' + self.public_key_hash + b'\x88\xac'
            elif self.script_type == 'p2sh':
                self.lock_script = b'\xa9\x14' + self.public_key_hash + b'\x87'
            else:
                raise TransactionError(
                    "Unknown output script type %s, please provide own locking script"
                    % self.script_type)
Ejemplo n.º 9
0
    if pa.outputs_repeat and pa.outputs is None:
        parser.error("--output_repeat requires --outputs")
    if not pa.wallet_remove and not pa.list_wallets and not pa.wallet_info and not pa.recover_wallet_passphrase \
            and not pa.test_pdf and not (pa.outputs or pa.outputs_import):
        parser.error(
            "Either --outputs or --outputs-import should be specified")
    return pa


if __name__ == '__main__':
    # --- Parse commandline arguments ---
    args = parse_args()

    wallet_name = args.wallet_name
    network = args.network
    network_obj = Network(network)
    style_file = args.style
    template_file = args.template

    # List wallets, then exit
    if args.list_wallets:
        print("\nBitcoinlib wallets:")
        for w in wallets_list():
            print(w['name'])
        print("\n")
        sys.exit()

    if args.wallet_info:
        print("Wallet info for %s" % args.wallet_name)
        if wallet_exists(args.wallet_name):
            wallet = BulkPaperWallet(args.wallet_name)
Ejemplo n.º 10
0
    def __init__(self,
                 network=DEFAULT_NETWORK,
                 min_providers=1,
                 max_providers=1,
                 providers=None,
                 timeout=TIMEOUT_REQUESTS,
                 cache_uri=None,
                 ignore_priority=False,
                 exclude_providers=None):
        """
        Open a service object for the specified network. By default the object connect to 1 service provider, but you
        can specify a list of providers or a minimum or maximum number of providers.

        :param network: Specify network used
        :type network: str, Network
        :param min_providers: Minimum number of providers to connect to. Default is 1. Use for instance to receive fee information from a number of providers and calculate the average fee.
        :type min_providers: int
        :param max_providers: Maximum number of providers to connect to. Default is 1.
        :type max_providers: int
        :param providers: List of providers to connect to. Default is all providers and select a provider at random.
        :type providers: list of str
        :param timeout: Timeout for web requests. Leave empty to use default from config settings
        :type timeout: int
        :param cache_uri: Database to use for caching
        :type cache_uri: str
        :param ignore_priority: Ignores provider priority if set to True. Could be used for unit testing, so no providers are missed when testing. Default is False
        :type ignore_priority: bool
        :param exclude_providers: Exclude providers in this list, can be used when problems with certain providers arise.
        :type exclude_providers: list of str

        """

        self.network = network
        if not isinstance(network, Network):
            self.network = Network(network)
        if min_providers > max_providers:
            max_providers = min_providers
        fn = Path(BCL_DATA_DIR, 'providers.json')
        f = fn.open("r")

        try:
            self.providers_defined = json.loads(f.read())
        except json.decoder.JSONDecodeError as e:  # pragma: no cover
            errstr = "Error reading provider definitions from %s: %s" % (fn, e)
            _logger.warning(errstr)
            raise ServiceError(errstr)
        f.close()

        provider_list = list([
            self.providers_defined[x]['provider']
            for x in self.providers_defined
        ])
        if providers is None:
            providers = []
        if exclude_providers is None:
            exclude_providers = []
        if not isinstance(providers, list):
            providers = [providers]
        for p in providers:
            if p not in provider_list:
                raise ServiceError(
                    "Provider '%s' not found in provider definitions" % p)

        self.providers = {}
        for p in self.providers_defined:
            if (self.providers_defined[p]['network'] == network or self.providers_defined[p]['network'] == '') and \
                    (not providers or self.providers_defined[p]['provider'] in providers):
                self.providers.update({p: self.providers_defined[p]})
        for nop in exclude_providers:
            if nop in self.providers:
                del (self.providers[nop])

        if not self.providers:
            raise ServiceError("No providers found for network %s" % network)
        self.min_providers = min_providers
        self.max_providers = max_providers
        self.results = {}
        self.errors = {}
        self.resultcount = 0
        self.complete = None
        self.timeout = timeout
        self._blockcount_update = 0
        self._blockcount = None
        self.cache = None
        self.cache_uri = cache_uri
        try:
            self.cache = Cache(self.network, db_uri=cache_uri)
        except Exception as e:
            self.cache = Cache(self.network, db_uri='')
            _logger.warning("Could not connect to cache database. Error: %s" %
                            e)
        self.results_cache_n = 0
        self.ignore_priority = ignore_priority
        if self.min_providers > 1:
            self._blockcount = Service(network=network,
                                       cache_uri=cache_uri).blockcount()
        else:
            self._blockcount = self.blockcount()
Ejemplo n.º 11
0
    pa = parser.parse_args()
    if pa.outputs_repeat and pa.outputs is None:
        parser.error("--output_repeat requires --outputs")
    if not pa.wallet_remove and not pa.list_wallets and not pa.wallet_info and not pa.recover_wallet_passphrase \
            and not pa.test_pdf and not (pa.outputs or pa.outputs_import):
        parser.error("Either --outputs or --outputs-import should be specified")
    return pa


if __name__ == '__main__':
    # --- Parse commandline arguments ---
    args = parse_args()

    wallet_name = args.wallet_name
    network = args.network
    network_obj = Network(network)
    style_file = args.style
    template_file = args.template

    # List wallets, then exit
    if args.list_wallets:
        print("\nBitcoinlib wallets:")
        for w in wallets_list():
            print(w['name'])
        print("\n")
        sys.exit()

    if args.wallet_info:
        print("Wallet info for %s" % args.wallet_name)
        if wallet_exists(args.wallet_name):
            wallet = BulkPaperWallet(args.wallet_name)
Ejemplo n.º 12
0
 def test_networks_print_value(self):
     network = Network('dash')
     self.assertEqual(network.print_value(10000), '0.00010000 DASH')
Ejemplo n.º 13
0
 def test_networks_prefix_hdkey_wif(self):
     network = Network('bitcoin')
     self.assertEqual(network.wif_prefix(is_private=True),
                      b'\x04\x88\xad\xe4')
Ejemplo n.º 14
0
    def __init__(self,
                 import_key=None,
                 key=None,
                 chain=None,
                 depth=0,
                 parent_fingerprint=b'\0\0\0\0',
                 child_index=0,
                 isprivate=True,
                 network=None,
                 key_type='bip32',
                 passphrase='',
                 compressed=True):
        """
        Hierarchical Deterministic Key class init function.
        If no import_key is specified a key will be generated with systems cryptographically random function.
        Import key can be any format normal or HD key (extended key) accepted by get_key_format. 
        If a normal key with no chain part is provided, an chain with only 32 0-bytes will be used.

        :param import_key: HD Key to import in WIF format or as byte with key (32 bytes) and chain (32 bytes)
        :type import_key: str, bytes, int, bytearray
        :param key: Private or public key (length 32)
        :type key: bytes
        :param chain: A chain code (length 32)
        :type chain: bytes
        :param depth: Level of depth in BIP32 key path
        :type depth: int
        :param parent_fingerprint: 4-byte fingerprint of parent
        :type parent_fingerprint: bytes
        :param child_index: Index number of child as integer
        :type child_index: int
        :param isprivate: True for private, False for public key. Default is True
        :type isprivate: bool
        :param network: Network name. Derived from import_key if possible
        :type network: str
        :param key_type: HD BIP32 or normal Private Key. Default is 'bip32'
        :type key_type: str
        
        :return HDKey: 
        """

        self.key_format = None
        if (key and not chain) or (not key and chain):
            raise KeyError(
                "Please specify both key and chain, use import_key attribute "
                "or use simple Key class instead")
        self.compressed = compressed
        self.key = None
        if not (key and chain):
            if not import_key:
                # Generate new Master Key
                seedbits = random.SystemRandom().getrandbits(512)
                seed = change_base(str(seedbits), 10, 256, 64)
                key, chain = self._key_derivation(seed)
            elif isinstance(import_key,
                            (bytearray, bytes if sys.version > '3' else
                             bytearray)) and len(import_key) == 64:
                key = import_key[:32]
                chain = import_key[32:]
            elif isinstance(import_key, Key):
                self.key = import_key
                if not import_key.compressed:
                    _logger.warning(
                        "Uncompressed private keys are not standard for BIP32 keys, use at your own risk!"
                    )
                    self.compressed = False
                chain = b'\0' * 32
                key = self.key.private_byte
                key_type = 'private'
            else:
                kf = get_key_format(import_key)
                self.key_format = kf["format"]
                network = check_network_and_key(import_key, network,
                                                kf["networks"])
                self.network = Network(network)
                if self.key_format in ['hdkey_private', 'hdkey_public']:
                    bkey = change_base(import_key, 58, 256)
                    # Derive key, chain, depth, child_index and fingerprint part from extended key WIF
                    if ord(bkey[45:46]):
                        isprivate = False
                        key = bkey[45:78]
                    else:
                        key = bkey[46:78]
                    depth = ord(bkey[4:5])
                    parent_fingerprint = bkey[5:9]
                    child_index = int(change_base(bkey[9:13], 256, 10))
                    chain = bkey[13:45]
                    # chk = bkey[78:82]
                else:
                    try:
                        self.key = Key(import_key,
                                       passphrase=passphrase,
                                       network=network)
                        if not self.key.compressed:
                            _logger.warning(
                                "Uncompressed private keys are not standard for BIP32 keys, use at your own risk!"
                            )
                            self.compressed = False
                        # FIXME: Maybe its better to create a random chain?
                        chain = b'\0' * 32
                        key = self.key.private_byte
                        key_type = 'private'
                    except BKeyError as e:
                        raise BKeyError("[BKeyError] %s" % e)

        if not isinstance(key, (bytes, bytearray)) or not (len(key) == 32
                                                           or len(key) == 33):
            raise KeyError(
                "Invalid key specified must be in bytes with length 32. You can use "
                "'import_key' attribute to import keys in other formats")
        self.chain = chain
        if self.key is None:
            self.key = Key(key,
                           passphrase=passphrase,
                           network=network,
                           compressed=compressed)
        self.depth = depth
        self.parent_fingerprint = parent_fingerprint
        self.child_index = child_index
        self.isprivate = isprivate
        if not network:
            network = DEFAULT_NETWORK
        self.network = Network(network)
        self.public_byte = self.key.public_byte
        self.public_hex = self.key.public_hex
        self.secret = None
        self.private_hex = None
        self.private_byte = None
        if isprivate:
            self.secret = self.key.secret
            self.private_hex = self.key.private_hex
            self.private_byte = self.key.private_byte
            self.key_hex = self.private_hex
        else:
            self.key_hex = self.public_hex
        self.key_type = key_type
Ejemplo n.º 15
0
# -*- coding: utf-8 -*-
#
#    BitcoinLib - Python Cryptocurrency Library
#
#    EXAMPLES - Network class
#
#    © 2017 - 2019 February - 1200 Web Development <http://1200wd.com/>
#

from bitcoinlib.networks import Network, network_by_value, network_values_for, wif_prefix_search

#
# Network examples
#

network = Network('bitcoin')
print("\n=== Get all WIF prefixes ===")
print("WIF Prefixes: %s" % network_values_for('prefix_wif'))

print("\n=== Get all HDkey private prefixes ===")
print("HDkey private prefixes: %s" % network_values_for('prefix_wif'))

print("\n=== Get network(s) for WIF prefix B0 ===")
print("WIF Prefixes: %s" % network_by_value('prefix_wif', 'B0'))

print("\n=== Get HD key private prefix for current network ===")
print("self.prefix_hdkey_private: %s" % network.wif_prefix())

print("\n=== Network parameters ===")
for k in network.__dir__():
    if k[:1] != '_':
Ejemplo n.º 16
0
    def __init__(self,
                 block_hash,
                 version,
                 prev_block,
                 merkle_root,
                 time,
                 bits,
                 nonce,
                 transactions=None,
                 height=None,
                 confirmations=None,
                 network=DEFAULT_NETWORK):
        """
        Create a new Block object with provided parameters.

        >>> b = Block('0000000000000000000154ba9d02ddd6cee0d71d1ea232753e02c9ac6affd709', version=0x20000000, prev_block='0000000000000000000f9578cda278ae7a2002e50d8e6079d11e2ea1f672b483', merkle_root='20e86f03c24c53c12014264d0e405e014e15a02ad02c174f017ee040750f8d9d', time=1592848036, bits=387044594, nonce=791719079)
        >>> b
        <Block(0000000000000000000154ba9d02ddd6cee0d71d1ea232753e02c9ac6affd709, None, transactions: None)>

        :param block_hash: Hash value of serialized block
        :type block_hash: bytes, str
        :param version: Block version to indicate which software / BIPs are used to create block
        :type version: bytes, str, in
        :param prev_block: Hash of previous block in blockchain
        :type prev_block: bytes, str
        :param merkle_root: Merkle root. Top item merkle chain tree to validate transactions.
        :type merkle_root: bytes, str
        :param time: Timestamp of time when block was included in blockchain
        :type time: int, bytes
        :param bits: Bits are used to indicate target / difficulty
        :type bits: bytes, str, int
        :param nonce: Number used once, n-once is used to create randomness for miners to find a suitable block hash
        :type nonce: bytes, str, int
        :param transactions: List of transaction included in this block. As list of transaction objects or list of transaction IDs strings
        :type transactions: list of Transaction, list of str
        :param height: Height of this block in the Blockchain
        :type height: int
        :param confirmations: Number of confirmations for this block, or depth. Increased when new blocks are found
        :type confirmations: int
        :param network: Network, leave empty for default network
        :type network: str, Network
        """

        self.block_hash = to_bytes(block_hash)
        if isinstance(version, int):
            self.version = struct.pack('>L', version)
            self.version_int = version
        else:
            self.version = to_bytes(version)
            self.version_int = 0 if not self.version else struct.unpack(
                '>L', self.version)[0]
        self.prev_block = to_bytes(prev_block)
        self.merkle_root = to_bytes(merkle_root)
        self.time = time
        if not isinstance(time, int):
            self.time = struct.unpack('>L', time)[0]
        if isinstance(bits, int):
            self.bits = struct.pack('>L', bits)
            self.bits_int = bits
        else:
            self.bits = to_bytes(bits)
            self.bits_int = 0 if not self.bits else struct.unpack(
                '>L', self.bits)[0]
        if isinstance(nonce, int):
            self.nonce = struct.pack('>L', nonce)
            self.nonce_int = nonce
        else:
            self.nonce = to_bytes(nonce)
            self.nonce_int = 0 if not self.nonce else struct.unpack(
                '>L', self.nonce)[0]
        self.transactions = transactions
        self.txs_data = None
        self.confirmations = confirmations
        self.network = network
        if not isinstance(network, Network):
            self.network = Network(network)
        self.tx_count = None
        self.page = 1
        self.limit = 0
        self.height = height
        if self.transactions and len(self.transactions) and isinstance(self.transactions[0], Transaction) \
                and self.version_int > 1:
            # first bytes of unlocking script of coinbase transaction contains block height (BIP0034)
            if self.transactions[0].coinbase and self.transactions[0].inputs[
                    0].unlocking_script:
                calc_height = struct.unpack(
                    '<L',
                    self.transactions[0].inputs[0].unlocking_script[1:4] +
                    b'\x00')[0]
                if height and calc_height != height:
                    raise ValueError(
                        "Specified block height is different than calculated block height according to "
                        "BIP0034")
                self.height = calc_height
Ejemplo n.º 17
0
    def __init__(self,
                 prev_hash,
                 output_index,
                 keys=None,
                 signatures=None,
                 unlocking_script=b'',
                 script_type='p2pkh',
                 sequence=b'\xff\xff\xff\xff',
                 compressed=True,
                 sigs_required=None,
                 sort=False,
                 network=DEFAULT_NETWORK,
                 tid=0):
        """
        Create a new transaction input
        
        :param prev_hash: Transaction hash of the UTXO (previous output) which will be spent.
        :type prev_hash: bytes, hexstring
        :param output_index: Output number in previous transaction.
        :type output_index: bytes, int
        :param keys: A list of Key objects or public / private key string in various formats. If no list is provided but a bytes or string variable, a list with one item will be created. Optional
        :type keys: list (bytes, str)
        :param signatures: Specify optional signatures
        :type signatures: bytes, str
        :param unlocking_script: Unlocking script (scriptSig) to prove ownership. Optional
        :type unlocking_script: bytes, hexstring
        :param script_type: Type of unlocking script used, i.e. p2pkh or p2sh_multisig. Default is p2pkh
        :type script_type: str
        :param sequence: Sequence part of input, you normally do not have to touch this
        :type sequence: bytes
        :param compressed: Use compressed or uncompressed public keys. Default is compressed
        :type compressed: bool
        :param sigs_required: Number of signatures required for a p2sh_multisig unlocking script
        :param sigs_required: int
        :param sort: Sort public keys according to BIP0045 standard. Default is False to avoid unexpected change of key order.
        :type sort: boolean
        :param network: Network, leave empty for default
        :type network: str
        :param tid: Index of input in transaction. Used by Transaction class.
        :type tid: int
        """
        self.prev_hash = to_bytes(prev_hash)
        self.output_index = output_index
        if isinstance(output_index, numbers.Number):
            self.output_index_int = output_index
            self.output_index = struct.pack('>I', output_index)
        else:
            self.output_index_int = struct.unpack('I', output_index)[0]
            self.output_index = output_index
        if isinstance(keys, (bytes, str)):
            keys = [keys]
        self.unlocking_script = to_bytes(unlocking_script)
        self.unlocking_script_unsigned = b''
        self.script_type = script_type
        self.sequence = to_bytes(sequence)
        self.compressed = compressed
        self.network = Network(network)
        self.tid = tid
        if keys is None:
            keys = []
        self.keys = []
        if not isinstance(keys, list):
            keys = [keys]
        if not signatures:
            signatures = []
        if not isinstance(signatures, list):
            signatures = [signatures]
        # Sort according to BIP45 standard
        self.sort = sort
        if sort:
            self.keys.sort(key=lambda k: k.public_byte)
        self.address = ''
        self.signatures = []
        self.redeemscript = b''
        if not sigs_required:
            if script_type == 'p2sh_multisig':
                raise TransactionError(
                    "Please specify number of signatures required (sigs_required) parameter"
                )
            else:
                sigs_required = 1
        self.sigs_required = sigs_required
        self.script_type = script_type

        if prev_hash == b'\0' * 32:
            self.script_type = 'coinbase'

        # If unlocking script is specified extract keys, signatures, type from script
        if unlocking_script:
            us_dict = script_deserialize(unlocking_script)
            if not us_dict or us_dict['script_type'] in ['unknown', 'empty']:
                raise TransactionError(
                    "Could not parse unlocking script (%s)" %
                    binascii.hexlify(unlocking_script))
            self.script_type = us_dict['script_type']
            self.sigs_required = us_dict['number_of_sigs_n']
            self.redeemscript = us_dict['redeemscript']
            signatures += us_dict['signatures']
            keys += us_dict['keys']

        for key in keys:
            if not isinstance(key, Key):
                kobj = Key(key, network=network)
            else:
                kobj = key
            if kobj not in self.keys:
                self.keys.append(kobj)

        for sig in signatures:
            sig_der = ''
            if sig.startswith(b'\x30'):
                # If signature ends with Hashtype, remove hashtype and continue
                # TODO: support for other hashtypes
                if sig.endswith(b'\x01'):
                    _, junk = ecdsa.der.remove_sequence(sig)
                    if junk == b'\x01':
                        sig_der = sig[:-1]
                else:
                    sig_der = sig
                try:
                    sig = convert_der_sig(sig[:-1], as_hex=False)
                except:
                    pass
            self.signatures.append({
                'sig_der': sig_der,
                'signature': to_bytes(sig),
                'priv_key': '',
                'pub_key': ''
            })

        if self.script_type == 'sig_pubkey':
            self.script_type = 'p2pkh'
        if self.script_type == 'p2pkh':
            if self.keys:
                self.unlocking_script_unsigned = b'\x76\xa9\x14' + to_bytes(
                    self.keys[0].hash160()) + b'\x88\xac'
                self.address = self.keys[0].address()
        elif self.script_type == 'p2sh_multisig':
            if not self.keys:
                raise TransactionError(
                    "Please provide keys to append multisig transaction input")
            if not self.redeemscript:
                self.redeemscript = serialize_multisig_redeemscript(
                    self.keys,
                    n_required=self.sigs_required,
                    compressed=self.compressed)

            self.address = pubkeyhash_to_addr(
                script_to_pubkeyhash(self.redeemscript),
                versionbyte=self.network.prefix_address_p2sh)
            self.unlocking_script_unsigned = self.redeemscript