def make_wallet(password, config_path=CONFIG_PATH, payment_privkey_info=None, owner_privkey_info=None, data_privkey_info=None, test_legacy=False, encrypt=True): """ Make a new, encrypted wallet structure. The owner and payment keys will be 2-of-3 multisig key bundles. The data keypair will be a single-key bundle. Return the new wallet on success. Return {'error': ...} on failure """ if test_legacy and not BLOCKSTACK_TEST: raise Exception("Not in testing but tried to make a legacy wallet") # default to 2-of-3 multisig key info if data isn't given payment_privkey_info = virtualchain.make_multisig_wallet(2, 3) if payment_privkey_info is None and not test_legacy else payment_privkey_info owner_privkey_info = virtualchain.make_multisig_wallet(2, 3) if owner_privkey_info is None and not test_legacy else owner_privkey_info data_privkey_info = ecdsa_private_key().to_hex() if data_privkey_info is None and not test_legacy else data_privkey_info decrypted_wallet = { 'owner_addresses': [virtualchain.get_privkey_address(owner_privkey_info)], 'owner_privkey': owner_privkey_info, 'payment_addresses': [virtualchain.get_privkey_address(payment_privkey_info)], 'payment_privkey': payment_privkey_info, 'data_pubkey': ecdsa_private_key(data_privkey_info).public_key().to_hex(), 'data_pubkeys': [ecdsa_private_key(data_privkey_info).public_key().to_hex()], 'data_privkey': data_privkey_info, 'version': SERIES_VERSION, } if not test_legacy: jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT) if encrypt: encrypted_wallet = encrypt_wallet(decrypted_wallet, password, test_legacy=test_legacy) if 'error' in encrypted_wallet: return encrypted_wallet # sanity check try: jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT) except ValidationError as ve: if test_legacy: # no data key is permitted assert BLOCKSTACK_TEST jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY) else: raise return encrypted_wallet else: return decrypted_wallet
def make_wallet(password, config_path=CONFIG_PATH, payment_privkey_info=None, owner_privkey_info=None, data_privkey_info=None, test_legacy=False, encrypt=True): """ Make a new, encrypted wallet structure. The owner and payment keys will be 2-of-3 multisig key bundles. The data keypair will be a single-key bundle. Return the new wallet on success. Return {'error': ...} on failure """ if test_legacy and not BLOCKSTACK_TEST: raise Exception("Not in testing but tried to make a legacy wallet") # default to 2-of-3 multisig key info if data isn't given payment_privkey_info = virtualchain.make_multisig_wallet( 2, 3 ) if payment_privkey_info is None and not test_legacy else payment_privkey_info owner_privkey_info = virtualchain.make_multisig_wallet( 2, 3 ) if owner_privkey_info is None and not test_legacy else owner_privkey_info data_privkey_info = ECPrivateKey().to_wif( ) if data_privkey_info is None and not test_legacy else data_privkey_info new_wallet = _make_encrypted_wallet_data(password, payment_privkey_info, owner_privkey_info, data_privkey_info, test_legacy=test_legacy) if 'error' in new_wallet: return new_wallet # sanity check if not test_legacy: jsonschema.validate(new_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT) if encrypt: return new_wallet # decrypt and return wallet_info = decrypt_wallet(new_wallet, password, config_path=config_path) assert 'error' not in wallet_info, "Failed to decrypt new wallet: {}".format( wallet_info['error']) return wallet_info['wallet']
def make_wallet(password, hex_privkey=None, payment_privkey_info=None, owner_privkey_info=None, data_privkey_info=None, config_path=CONFIG_PATH): """ Make a wallet structure. By default, the owner and payment keys will be key bundles set up to require 2-of-3 signatures. @payment_privkey_info, @owner_privkey_info, and @data_privkey_info can either be individual private keys, or dicts with {'redeem_script': ..., 'private_keys': ...} defined. Return the new wallet on success. Return {'error': ...} on failure """ hex_password = hexlify(password) wallet = HDWallet(hex_privkey) if hex_privkey is None: hex_privkey = wallet.get_master_privkey() child = wallet.get_child_keypairs(count=3, include_privkey=True) data = {} encrypted_key = aes_encrypt(hex_privkey, hex_password) data['encrypted_master_private_key'] = encrypted_key multisig = False curr_height = get_block_height(config_path=config_path) if curr_height >= config.EPOCH_HEIGHT_MINIMUM: # safe to use multisig multisig = True # default to 2-of-3 multisig key info if data isn't given if payment_privkey_info is None: if multisig: payment_privkey_info = virtualchain.make_multisig_wallet(2, 3) else: payment_privkey_info = virtualchain.BitcoinPrivateKey().to_wif() if not is_singlesig(payment_privkey_info) and not is_multisig( payment_privkey_info): return { 'error': 'Payment private key info must be either a single private key or a multisig bundle' } if not multisig and is_multisig(payment_privkey_info): return {'error': 'Multisig payment private key info is not supported'} if owner_privkey_info is None: if multisig: owner_privkey_info = virtualchain.make_multisig_wallet(2, 3) else: owner_privkey_info = virtualchain.BitcoinPrivateKey().to_wif() if not is_singlesig(owner_privkey_info) and not is_multisig( owner_privkey_info): return { 'error': 'Owner private key info must be either a single private key or a multisig bundle' } if not multisig and is_multisig(owner_privkey_info): return {'error': 'Multisig owner private key info is not supported'} if data_privkey_info is None: # TODO: for now, this must be a single private key data_privkey_info = child[2][1] elif not is_singlesig(data_privkey_info): return {'error': 'Data private key info must be a single private key'} enc_payment_info = encrypt_private_key_info(payment_privkey_info, password) if 'error' in enc_payment_info: return {'error': enc_payment_info['error']} enc_owner_info = encrypt_private_key_info(owner_privkey_info, password) if 'error' in enc_owner_info: return {'error': enc_owner_info['error']} enc_data_info = encrypt_private_key_info(data_privkey_info, password) if 'error' in enc_data_info: return {'error': enc_data_info['error']} payment_addr = enc_payment_info['encrypted_private_key_info']['address'] owner_addr = enc_owner_info['encrypted_private_key_info']['address'] enc_payment_info = enc_payment_info['encrypted_private_key_info'][ 'private_key_info'] enc_owner_info = enc_owner_info['encrypted_private_key_info'][ 'private_key_info'] enc_data_info = enc_data_info['encrypted_private_key_info'][ 'private_key_info'] data['encrypted_payment_privkey'] = enc_payment_info data['payment_addresses'] = [payment_addr] data['encrypted_owner_privkey'] = enc_owner_info data['owner_addresses'] = [owner_addr] data['encrypted_data_privkey'] = enc_data_info data['data_pubkeys'] = [ virtualchain.BitcoinPrivateKey( data_privkey_info).public_key().to_hex() ] data['data_pubkey'] = data['data_pubkeys'][0] return data
def make_wallet(password, payment_privkey_info=None, owner_privkey_info=None, data_privkey_info=None, test_legacy=False, encrypt=True, segwit=None): """ Make a new, encrypted wallet structure. The owner and payment keys will be 2-of-3 multisig key bundles. The data keypair will be a single-key bundle. Return the new wallet on success. Return {'error': ...} on failure """ if test_legacy and not BLOCKSTACK_TEST: raise Exception("Not in testing but tried to make a legacy wallet") if segwit is None: # no preference given. # safe to use by default post-F-day 2017 (Dec 1 2017) ''' if time.time() >= 1512086400: segwit = True else: # defer to virtualchain segwit = virtualchain.get_features('segwit') ''' # disable for now segwit = False # default to 2-of-3 multisig key info if data isn't given if segwit: payment_privkey_info = virtualchain.make_multisig_segwit_wallet(2,3) if payment_privkey_info is None and not test_legacy else payment_privkey_info owner_privkey_info = virtualchain.make_multisig_segwit_wallet(2,3) if owner_privkey_info is None and not test_legacy else owner_privkey_info else: payment_privkey_info = virtualchain.make_multisig_wallet(2,3) if payment_privkey_info is None and not test_legacy else payment_privkey_info owner_privkey_info = virtualchain.make_multisig_wallet(2,3) if owner_privkey_info is None and not test_legacy else owner_privkey_info data_privkey_info = ecdsa_private_key().to_hex() if data_privkey_info is None and not test_legacy else data_privkey_info decrypted_wallet = { 'owner_addresses': [virtualchain.get_privkey_address(owner_privkey_info)], 'owner_privkey': owner_privkey_info, 'payment_addresses': [virtualchain.get_privkey_address(payment_privkey_info)], 'payment_privkey': payment_privkey_info, 'data_pubkey': ecdsa_private_key(data_privkey_info).public_key().to_hex(), 'data_pubkeys': [ecdsa_private_key(data_privkey_info).public_key().to_hex()], 'data_privkey': data_privkey_info, 'version': SERIES_VERSION, } if not test_legacy: jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT) if encrypt: encrypted_wallet = encrypt_wallet(decrypted_wallet, password, test_legacy=test_legacy) if 'error' in encrypted_wallet: return encrypted_wallet # sanity check try: jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT) except ValidationError as ve: if test_legacy: # no data key is permitted assert BLOCKSTACK_TEST jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY) else: raise return encrypted_wallet else: return decrypted_wallet