def create_wallet_for_sync(wallet_file, password, wallet_structure, a): #Prepare a testnet wallet file for this wallet password_key = bitcoin.bin_dbl_sha256(password) #We need a distinct seed for each run so as not to step over each other; #make it through a deterministic hash seedh = bitcoin.sha256("".join([str(x) for x in a]))[:32] encrypted_seed = encryptData(password_key, seedh.decode('hex')) timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") walletfilejson = { 'creator': 'joinmarket project', 'creation_time': timestamp, 'encrypted_seed': encrypted_seed.encode('hex'), 'network': get_network() } walletfile = json.dumps(walletfilejson) if not os.path.exists('wallets'): os.makedirs('wallets') with open(os.path.join('wallets', wallet_file), "wb") as f: f.write(walletfile) #The call to Wallet() in make_wallets should now find the file #and read from it: return make_wallets(1, [wallet_structure], fixed_seeds=[wallet_file], test_wallet=True, passwords=[password])[0]['wallet']
def generate_single_podle_sig(priv, i): """Make a podle entry for key priv at index i, using a dummy utxo value. This calls the underlying 'raw' code based on the class PoDLE, not the library 'generate_podle' which intelligently searches and updates commitments. """ dummy_utxo = bitcoin.sha256(priv) + ":3" podle = PoDLE(dummy_utxo, binascii.hexlify(priv).decode('ascii')) r = podle.generate_podle(i) return (r['P'], r['P2'], r['sig'], r['e'], r['commit'])
def test_imported_privkey(setup_wallets): for n in ["mainnet", "testnet"]: privkey = "7d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401" jm_single().config.set("BLOCKCHAIN", "network", n) password = "******" password_key = bitcoin.bin_dbl_sha256(password) wifprivkey = bitcoin.wif_compressed_privkey(privkey, get_p2pk_vbyte()) #mainnet is "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi" #to verify use from_wif_privkey and privkey_to_address if n == "mainnet": iaddr = "1LDsjB43N2NAQ1Vbc2xyHca4iBBciN8iwC" else: iaddr = "mzjq2E92B3oRB7yDKbwM7XnPaAnKfRERw2" privkey_bin = bitcoin.from_wif_privkey( wifprivkey, vbyte=get_p2pk_vbyte()).decode('hex')[:-1] encrypted_privkey = encryptData(password_key, privkey_bin) encrypted_privkey_bad = encryptData(password_key, privkey_bin[:6]) walletdir = "wallets" testwalletname = "test" + n pathtowallet = os.path.join(walletdir, testwalletname) seed = bitcoin.sha256("\xaa" * 64)[:32] encrypted_seed = encryptData(password_key, seed.decode('hex')) timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") for ep in [encrypted_privkey, encrypted_privkey_bad]: walletfilejson = { 'creator': 'joinmarket project', 'creation_time': timestamp, 'encrypted_seed': encrypted_seed.encode('hex'), 'network': n, 'index_cache': [[0, 0]] * 5, 'imported_keys': [{ 'encrypted_privkey': ep.encode('hex'), 'mixdepth': 0 }] } walletfile = json.dumps(walletfilejson) if not os.path.exists(walletdir): os.makedirs(walletdir) with open(pathtowallet, "wb") as f: f.write(walletfile) if ep == encrypted_privkey_bad: with pytest.raises(Exception) as e_info: Wallet(testwalletname, password, 5, 6, False, False) continue newwallet = Wallet(testwalletname, password, 5, 6, False, False) assert newwallet.seed == seed #test accessing the key from the addr assert newwallet.get_key_from_addr( iaddr) == bitcoin.from_wif_privkey(wifprivkey, vbyte=get_p2pk_vbyte()) if n == "testnet": jm_single().bc_interface.sync_wallet(newwallet) load_program_config()
def test_commitment_retries(setup_podle): """Assumes no external commitments available. Generate pretend priv/utxo pairs and check that they can be used taker_utxo_retries times. """ allowed = jm_single().config.getint("POLICY", "taker_utxo_retries") #make some pretend commitments dummy_priv_utxo_pairs = [(bitcoin.sha256(os.urandom(10)), bitcoin.sha256(os.urandom(10))+":0") for _ in range(10)] #test a single commitment request of all 10 for x in dummy_priv_utxo_pairs: p = generate_podle([x], allowed) assert p #At this point slot 0 has been taken by all 10. for i in range(allowed-1): p = generate_podle(dummy_priv_utxo_pairs[:1], allowed) assert p p = generate_podle(dummy_priv_utxo_pairs[:1], allowed) assert p is None
def donation_address(reusable_donation_pubkey=None): #pragma: no cover #Donation code currently disabled, so not tested. if not reusable_donation_pubkey: reusable_donation_pubkey = ('02be838257fbfddabaea03afbb9f16e852' '9dfe2de921260a5c46036d97b5eacf2a') sign_k = binascii.hexlify(os.urandom(32)).decode('ascii') c = btc.sha256(btc.multiply(sign_k, reusable_donation_pubkey, True)) sender_pubkey = btc.add_pubkeys( [reusable_donation_pubkey, btc.privtopub(c + '01', True)], True) sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) log.debug('sending coins to ' + sender_address) return sender_address, sign_k
def test_spend_p2sh_p2wpkh_multi(setup_segwit, wallet_structure, in_amt, amount, segwit_amt, segwit_ins, o_ins): """Creates a wallet from which non-segwit inputs/ outputs can be created, constructs one or more p2wpkh in p2sh spendable utxos (by paying into the corresponding address) and tests spending them in combination. wallet_structure is in accordance with commontest.make_wallets, see docs there in_amt is the amount to pay into each address into the wallet (non-segwit adds) amount (in satoshis) is how much we will pay to the output address segwit_amt in BTC is the amount we will fund each new segwit address with segwit_ins is a list of input indices (where to place the funding segwit utxos) other_ins is a list of input indices (where to place the funding non-sw utxos) """ wallet = make_wallets(1, wallet_structure, in_amt, walletclass=Wallet)[0]['wallet'] jm_single().bc_interface.sync_wallet(wallet) other_ins = {} ctr = 0 for k, v in wallet.unspent.iteritems(): #only extract as many non-segwit utxos as we need; #doesn't matter which they are if ctr == len(o_ins): break other_ins[k] = (v["value"], wallet.get_key_from_addr(v["address"]), o_ins[ctr]) ctr += 1 ins_sw = {} for i in range(len(segwit_ins)): #build segwit ins from "deterministic-random" keys; #intended to be the same for each run with the same parameters seed = json.dumps( [i, wallet_structure, in_amt, amount, segwit_ins, other_ins]) priv = btc.sha256(seed) + "01" pub = btc.privtopub(priv) #magicbyte is testnet p2sh addr1 = btc.pubkey_to_p2sh_p2wpkh_address(pub, magicbyte=196) print "got address for p2shp2wpkh: " + addr1 txid = jm_single().bc_interface.grab_coins(addr1, segwit_amt) #TODO - int cast, fix? ins_sw[get_utxo_from_txid(txid, addr1)] = (int(segwit_amt * 100000000), priv, segwit_ins[i]) #make_sign_and_push will sanity check the received amount is correct txid = make_sign_and_push(ins_sw, wallet, amount, other_ins) #will always be False if it didn't push. assert txid
def create_wallet_for_sync(wallet_structure, a, **kwargs): #We need a distinct seed for each run so as not to step over each other; #make it through a deterministic hash seedh = btc.sha256("".join([str(x) for x in a]))[:32] return make_wallets(1, [wallet_structure], fixed_seeds=[seedh], **kwargs)[0]['wallet']
def test_external_commitments(setup_podle): """Add this generated commitment to the external list {txid:N:{'P':pubkey, 'reveal':{1:{'P2':P2,'s':s,'e':e}, 2:{..},..}}} Note we do this *after* the sendpayment test so that the external commitments will not erroneously used (they are fake). """ #ensure the file exists even if empty update_commitments() ecs = {} tries = jm_single().config.getint("POLICY", "taker_utxo_retries") for i in range(10): priv = os.urandom(32) dummy_utxo = bitcoin.sha256(priv) + ":2" ecs[dummy_utxo] = {} ecs[dummy_utxo]['reveal'] = {} for j in range(tries): P, P2, s, e, commit = generate_single_podle_sig(priv, j) if 'P' not in ecs[dummy_utxo]: ecs[dummy_utxo]['P'] = P ecs[dummy_utxo]['reveal'][j] = {'P2': P2, 's': s, 'e': e} add_external_commitments(ecs) used, external = get_podle_commitments() for u in external: assert external[u]['P'] == ecs[u]['P'] for i in range(tries): for x in ['P2', 's', 'e']: assert external[u]['reveal'][str( i)][x] == ecs[u]['reveal'][i][x] #add a dummy used commitment, then try again update_commitments(commitment="ab" * 32) ecs = {} known_commits = [] known_utxos = [] tries = 3 for i in range(1, 6): u = binascii.hexlify(struct.pack(b'B', i) * 32).decode('ascii') known_utxos.append(u) priv = struct.pack(b'B', i) * 32 + b"\x01" ecs[u] = {} ecs[u]['reveal'] = {} for j in range(tries): P, P2, s, e, commit = generate_single_podle_sig(priv, j) known_commits.append(commit) if 'P' not in ecs[u]: ecs[u]['P'] = P ecs[u]['reveal'][j] = {'P2': P2, 's': s, 'e': e} add_external_commitments(ecs) #simulate most of those external being already used for c in known_commits[:-1]: update_commitments(commitment=c) #this should find the remaining one utxo and return from it assert generate_podle([], max_tries=tries, allow_external=known_utxos) #test commitment removal to_remove = ecs[binascii.hexlify(struct.pack(b'B', 3) * 32).decode('ascii')] update_commitments(external_to_remove={ binascii.hexlify(struct.pack(b'B', 3) * 32).decode('ascii'): to_remove }) #test that an incorrectly formatted file raises with open(get_commitment_file(), "rb") as f: validjson = json.loads(f.read().decode('utf-8')) corruptjson = copy.deepcopy(validjson) del corruptjson['used'] with open(get_commitment_file(), "wb") as f: f.write(json.dumps(corruptjson, indent=4).encode('utf-8')) with pytest.raises(PoDLEError) as e_info: get_podle_commitments() #clean up with open(get_commitment_file(), "wb") as f: f.write(json.dumps(validjson, indent=4).encode('utf-8'))
def test_wallet_create(setup_wallets, includecache, wrongnet, storepwd, extendmd, pwdnumtries): walletdir, pathtowallet, testwalletname, wallet = create_default_testnet_wallet( ) assert wallet.get_key( 4, 1, 17) == "1289ca322f96673acef83f396a9735840e3ab69f0459cf9bfa8d9985a876534401" assert wallet.get_addr(2, 0, 5) == "myWPu9QJWHGE79XAmuKkwKgNk8vsr5evpk" jm_single().bc_interface.wallet_synced = True assert wallet.get_new_addr(1, 0) == "mi88ZgDGPmarzcsU6S437h9CY9BLmgH5M6" assert wallet.get_external_addr(3) == "mvChQuChnXVhqvH67wfMxrodPQ7xccdVJU" addr3internal = wallet.get_internal_addr(3) assert addr3internal == "mv26o79Bauf2miJMoxoSu1vXmfXnk85YPQ" assert wallet.get_key_from_addr( addr3internal) == "2a283c9a2168a25509e2fb944939637228c50c8b4fecd9024650316c4584246501" dummyaddr = "mvw1NazKDRbeNufFANqpYNAANafsMC2zVU" assert not wallet.get_key_from_addr(dummyaddr) #Make a new Wallet(), and prepare a testnet wallet file for this wallet password = "******" password_key = bitcoin.bin_dbl_sha256(password) seed = bitcoin.sha256("\xaa" * 64)[:32] encrypted_seed = encryptData(password_key, seed.decode('hex')) timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") net = get_network() if not wrongnet else 'mainnnet' walletfilejson = {'creator': 'joinmarket project', 'creation_time': timestamp, 'encrypted_seed': encrypted_seed.encode('hex'), 'network': net} if includecache: mmd = wallet.max_mix_depth if not extendmd else wallet.max_mix_depth + 5 print("using mmd: " + str(mmd)) walletfilejson.update({'index_cache': [[0, 0]] * mmd}) walletfile = json.dumps(walletfilejson) if not os.path.exists(walletdir): os.makedirs(walletdir) with open(pathtowallet, "wb") as f: f.write(walletfile) if wrongnet: with pytest.raises(ValueError) as e_info: Wallet(testwalletname, password, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) return from string import ascii_letters for i in range( pwdnumtries): #multiple tries to ensure pkcs7 error is triggered with pytest.raises(WalletError) as e_info: wrongpwd = "".join([random.choice(ascii_letters) for _ in range(20) ]) Wallet(testwalletname, wrongpwd, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) with pytest.raises(WalletError) as e_info: Wallet(testwalletname, None, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) newwallet = Wallet(testwalletname, password, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) assert newwallet.seed == seed #now we have a functional wallet + file, update the cache; first try #with failed paths oldpath = newwallet.path newwallet.path = None newwallet.update_cache_index() newwallet.path = "fake-path-definitely-doesnt-exist" newwallet.update_cache_index() #with real path newwallet.path = oldpath newwallet.index = [[1, 1]] * 5 newwallet.update_cache_index() #ensure we cannot find a mainnet wallet from seed seed = "goodbye" jm_single().config.set("BLOCKCHAIN", "network", "mainnet") with pytest.raises(IOError) as e_info: Wallet(seed, 5, 6, False, False) load_program_config()
def test_wallet_create(setup_wallets, includecache, wrongnet, storepwd, extendmd, pwdnumtries): walletdir, pathtowallet, testwalletname, wallet = create_default_testnet_wallet( ) assert wallet.get_key( 4, 1, 17) == "96095d7542e4e832c476b9df7e49ca9e5be61ad3bb8c8a3bdd8e141e2f4caf9101" assert wallet.get_addr(2, 0, 5) == "2NBUxbEQrGPKrYCV6d4o7Y4AtJ34Uy6gZZg" jm_single().bc_interface.wallet_synced = True assert wallet.get_new_addr(1, 0) == "2Mz817RE6zqywgkG2h9cATUoiXwnFSxufk2" assert wallet.get_external_addr(3) == "2N3gn65WXEzbLnjk5FLDZPc1pL6ebvZAmoA" addr3internal = wallet.get_internal_addr(3) assert addr3internal == "2N5NMTYogAyrGhDtWBnVQUp1kgwwFzcf7UM" assert wallet.get_key_from_addr( addr3internal) == "089a7173314d29f99e02a37e36da517ce41537a317c83284db1f33dda0af0cc201" dummyaddr = "mvw1NazKDRbeNufFANqpYNAANafsMC2zVU" assert not wallet.get_key_from_addr(dummyaddr) #Make a new Wallet(), and prepare a testnet wallet file for this wallet password = "******" password_key = bitcoin.bin_dbl_sha256(password) seed = bitcoin.sha256("\xaa" * 64)[:32] encrypted_seed = encryptData(password_key, seed.decode('hex')) timestamp = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S") net = get_network() if not wrongnet else 'mainnnet' walletfilejson = {'creator': 'joinmarket project', 'creation_time': timestamp, 'encrypted_seed': encrypted_seed.encode('hex'), 'network': net} if includecache: mmd = wallet.max_mix_depth if not extendmd else wallet.max_mix_depth + 5 print("using mmd: " + str(mmd)) walletfilejson.update({'index_cache': [[0, 0]] * mmd}) walletfile = json.dumps(walletfilejson) if not os.path.exists(walletdir): os.makedirs(walletdir) with open(pathtowallet, "wb") as f: f.write(walletfile) if wrongnet: with pytest.raises(ValueError) as e_info: SegwitWallet(testwalletname, password, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) return from string import ascii_letters for i in range( pwdnumtries): #multiple tries to ensure pkcs7 error is triggered with pytest.raises(WalletError) as e_info: wrongpwd = "".join([random.choice(ascii_letters) for _ in range(20) ]) SegwitWallet(testwalletname, wrongpwd, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) with pytest.raises(WalletError) as e_info: SegwitWallet(testwalletname, None, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) newwallet = SegwitWallet(testwalletname, password, 5, 6, extend_mixdepth=extendmd, storepassword=storepwd) assert newwallet.seed == wallet.wallet_data_to_seed(seed) #now we have a functional wallet + file, update the cache; first try #with failed paths oldpath = newwallet.path newwallet.path = None newwallet.update_cache_index() newwallet.path = "fake-path-definitely-doesnt-exist" newwallet.update_cache_index() #with real path newwallet.path = oldpath newwallet.index = [[1, 1]] * 5 newwallet.update_cache_index() #ensure we cannot find a mainnet wallet from seed seed = "goodbye" jm_single().config.set("BLOCKCHAIN", "network", "mainnet") with pytest.raises(IOError) as e_info: Wallet(seed, 5, 6, False, False) load_program_config()
balance += addrvalue['value'] used = (' used' if balance > 0.0 else 'empty') balance_depth += balance if options.showprivkey: wip_privkey = btc.wif_compressed_privkey( privkey, get_p2pk_vbyte()) else: wip_privkey = '' cus_print(' ' * 13 + '%-35s%s %.8f btc %s' % ( addr, used, balance / 1e8, wip_privkey)) total_balance += balance_depth print('for mixdepth=%d balance=%.8fbtc' % (m, balance_depth / 1e8)) print('total balance = %.8fbtc' % (total_balance / 1e8)) elif method == 'generate' or method == 'recover': if method == 'generate': seed = btc.sha256(os.urandom(64))[:32] words = mn_encode(seed) print('Write down this wallet recovery seed\n\n' + ' '.join(words) + '\n') elif method == 'recover': words = raw_input('Input 12 word recovery seed: ') words = words.split() # default for split is 1 or more whitespace chars if len(words) != 12: print('ERROR: Recovery seed phrase must be exactly 12 words.') sys.exit(0) seed = mn_decode(words) print(seed) password = getpass.getpass('Enter wallet encryption passphrase: ') password2 = getpass.getpass('Reenter wallet encryption passphrase: ') if password != password2: print('ERROR. Passwords did not match')