예제 #1
0
def test_segwit_valid_txs(setup_segwit):
    with open("test/tx_segwit_valid.json", "r") as f:
        json_data = f.read()
    valid_txs = json.loads(json_data)
    for j in valid_txs:
        if len(j) < 2:
            continue
        deserialized_tx = btc.CMutableTransaction.deserialize(hextobin(j[1]))
        print(pformat(deserialized_tx))
        assert deserialized_tx.serialize() == hextobin(j[1])
예제 #2
0
    def render_POST(self, request):
        """ An individual proposal may be submitted in base64, with key
        appended after newline separator in hex.
        """
        log.debug("The server got this POST request: ")
        # unfortunately the twisted Request object is not
        # easily serialized:
        log.debug(request)
        log.debug(request.method)
        log.debug(request.uri)
        log.debug(request.args)
        sender_parameters = request.args
        log.debug(request.path)
        # defer logging of raw request content:
        proposals = request.content
        if not isinstance(proposals, BytesIO):
            return self.return_error(request, "Invalid request format",
                                     "invalid-request-format")
        proposals = proposals.read()
        # for now, only allowing proposals of form "base64ciphertext,hexkey",
        #newline separated:
        proposals = proposals.split(b"\n")
        log.debug("Client send proposal list of length: " +
                  str(len(proposals)))
        accepted_proposals = []
        for proposal in proposals:
            if len(proposal) == 0:
                continue
            try:
                encryptedtx, key, nonce = proposal.split(b",")
                bin_key = hextobin(key.decode('utf-8'))
                bin_nonce = hextobin(nonce.decode('utf-8'))
                base64.b64decode(encryptedtx)
            except:
                log.warn("This proposal was not accepted: " +
                         proposal.decode("utf-8"))
                # give up immediately in case of format error:
                return self.return_error(request, "Invalid request format",
                                         "invalid-request-format")
            if not verify_pow(proposal, nbits=self.nbits, truncate=32):
                return self.return_error(request, "Insufficient PoW",
                                         "insufficient proof of work")
            accepted_proposals.append((key, encryptedtx))

        # the proposals are valid format-wise; add them to the database
        for p in accepted_proposals:
            # note we will ignore errors here and continue;
            # warning will be shown in logs from called fn.
            self.add_proposal(p)
        content = "{} proposals accepted".format(len(accepted_proposals))
        request.setHeader(b"content-length",
                          ("%d" % len(content)).encode("ascii"))
        return content.encode("ascii")
예제 #3
0
 def deserialize_revelation(cls, ser_rev, separator='|'):
     """ Reads the over-the-wire format as used in
     Joinmarket communication protocol.
     """
     ser_list = ser_rev.split(separator)
     if len(ser_list) != 5:
         raise PoDLEError("Failed to deserialize, wrong format")
     utxostr, P, P2, s, e = ser_list
     success, utxo = utxostr_to_utxo(utxostr)
     assert success, "invalid utxo format in PoDLE."
     return {'utxo': utxo, 'P': hextobin(P),
             'P2': hextobin(P2), 'sig': hextobin(s), 'e': hextobin(e)}
예제 #4
0
 def _add_unspent_txo(self, utxo, height):
     """
     Add a UTXO as returned by rpc's listunspent call to the wallet.
     Note that these are returned as little endian outpoint txids, so
     are converted.
     params:
         utxo: single utxo dict as returned by listunspent
         current_blockheight: blockheight as integer, used to
         set the block in which a confirmed utxo is included.
     """
     txid = hextobin(utxo['txid'])
     script = hextobin(utxo['scriptPubKey'])
     value = int(Decimal(str(utxo['amount'])) * Decimal('1e8'))
     self.add_utxo(txid, int(utxo['vout']), script, value, height)
def test_ecdh():
    """Using private key test vectors from Bitcoin Core.
    1. Import a set of private keys from the json file.
    2. Calculate the corresponding public keys.
    3. Do ECDH on the cartesian product (x, Y), with x private
    and Y public keys, for all combinations.
    4. Compare the result from CoinCurve with the manual
    multiplication xY following by hash (sha256). Note that
    sha256(xY) is the default hashing function used for ECDH
    in libsecp256k1.

    Since there are about 20 private keys in the json file, this
    creates around 400 test cases (note xX is still valid).
    """
    with open(os.path.join(testdir, "base58_keys_valid.json"), "r") as f:
        json_data = f.read()
        valid_keys_list = json.loads(json_data)
        extracted_privkeys = []
        for a in valid_keys_list:
            key, hex_key, prop_dict = a
            if prop_dict["isPrivkey"]:
                c, k = btc.read_privkey(hextobin(hex_key))
                extracted_privkeys.append(k)
    extracted_pubkeys = [btc.privkey_to_pubkey(x) for x in extracted_privkeys]
    for p in extracted_privkeys:
        for P in extracted_pubkeys:
            c, k = btc.read_privkey(p)
            shared_secret = btc.ecdh(k, P)
            assert len(shared_secret) == 32
            # try recreating the shared secret manually:
            pre_secret = btc.multiply(p, P)
            derived_secret = hashlib.sha256(pre_secret).digest()
            assert derived_secret == shared_secret

    # test some important failure cases; null key, overflow case
    privkeys_invalid = [
        b'\x00' * 32,
        hextobin(
            'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141')
    ]
    for p in privkeys_invalid:
        with pytest.raises(Exception) as e_info:
            shared_secret = btc.ecdh(p, extracted_pubkeys[0])
    pubkeys_invalid = [b'0xff' + extracted_pubkeys[0][1:], b'0x00' * 12]
    for p in extracted_privkeys:
        with pytest.raises(Exception) as e_info:
            shared_secret = btc.ecdh(p, pubkeys_invalid[0])
        with pytest.raises(Exception) as e_info:
            shared_secret = btc.ecdh(p, pubkeys_invalid[1])
예제 #6
0
def test_ecies():
    """Using private key test vectors from Bitcoin Core.
    1. Import a set of private keys from the json file.
    2. Calculate the corresponding public keys.
    3. Do ECDH on the cartesian product (x, Y), with x private
    and Y public keys, for all combinations.
    4. Compare the result from CoinCurve with the manual
    multiplication xY following by hash (sha256). Note that
    sha256(xY) is the default hashing function used for ECDH
    in libsecp256k1.

    Since there are about 20 private keys in the json file, this
    creates around 400 test cases (note xX is still valid).
    """
    with open(os.path.join(testdir, "base58_keys_valid.json"), "r") as f:
        json_data = f.read()
        valid_keys_list = json.loads(json_data)
        print("got valid keys list")
        extracted_privkeys = []
        for a in valid_keys_list:
            key, hex_key, prop_dict = a
            if prop_dict["isPrivkey"]:
                c, k = btc.read_privkey(hextobin(hex_key))

                extracted_privkeys.append(k)
    extracted_pubkeys = [btc.privkey_to_pubkey(x) for x in extracted_privkeys]
    for (priv, pub) in zip(extracted_privkeys, extracted_pubkeys):
        test_message = base64.b64encode(os.urandom(15) * 20)
        assert btc.ecies_decrypt(priv, btc.ecies_encrypt(test_message,
                                                         pub)) == test_message
예제 #7
0
 def on_JM_REQUEST_MSGSIG_VERIFY(self, msg, fullmsg, sig, pubkey, nick,
                                 hashlen, max_encoded, hostid):
     pubkey_bin = hextobin(pubkey)
     verif_result = True
     if not btc.ecdsa_verify(str(msg), sig, pubkey_bin):
         # workaround for hostid, which sometimes is lowercase-only for some IRC connections
         if not btc.ecdsa_verify(str(msg[:-len(hostid)] + hostid.lower()),
                                 sig, pubkey_bin):
             jlog.debug("nick signature verification failed, ignoring: " +
                        str(nick))
             verif_result = False
     #check that nick matches hash of pubkey
     nick_pkh_raw = hashlib.sha256(
         pubkey.encode("ascii")).digest()[:hashlen]
     nick_stripped = nick[2:2 + max_encoded]
     #strip right padding
     nick_unpadded = ''.join([x for x in nick_stripped if x != 'O'])
     if not nick_unpadded == btc.base58.encode(nick_pkh_raw):
         jlog.debug("Nick hash check failed, expected: " +
                    str(nick_unpadded) + ", got: " +
                    str(btc.base58.encode(nick_pkh_raw)))
         verif_result = False
     d = self.callRemote(commands.JMMsgSignatureVerify,
                         verif_result=verif_result,
                         nick=nick,
                         fullmsg=fullmsg,
                         hostid=hostid)
     self.defaultCallbacks(d)
     return {'accepted': True}
예제 #8
0
    def on_JM_TX_RECEIVED(self, nick, txhex, offer):
        offer = json.loads(offer)
        retval = self.client.on_tx_received(nick, txhex, offer)
        if not retval[0]:
            jlog.info("Maker refuses to continue on receipt of tx")
        else:
            sigs = retval[1]
            self.finalized_offers[nick] = offer
            tx = btc.CMutableTransaction.deserialize(hextobin(txhex))
            self.finalized_offers[nick]["txd"] = tx
            txid = tx.GetTxid()[::-1]
            # we index the callback by the out-set of the transaction,
            # because the txid is not known until all scriptSigs collected
            # (hence this is required for Makers, but not Takers).
            # For more info see WalletService.transaction_monitor():
            txinfo = tuple((x.scriptPubKey, x.nValue) for x in tx.vout)
            self.client.wallet_service.register_callbacks(
                [self.unconfirm_callback], txinfo, "unconfirmed")
            self.client.wallet_service.register_callbacks(
                [self.confirm_callback], txinfo, "confirmed")

            task.deferLater(
                reactor,
                float(jm_single().config.getint("TIMEOUT",
                                                "unconfirm_timeout_sec")),
                self.client.wallet_service.check_callback_called, txinfo,
                self.unconfirm_callback, "unconfirmed",
                "transaction with outputs: " + str(txinfo) + " not broadcast.")

            d = self.callRemote(commands.JMTXSigs,
                                nick=nick,
                                sigs=json.dumps(sigs))
            self.defaultCallbacks(d)
        return {"accepted": True}
예제 #9
0
 def setUp(self):
     self.wss_url = "ws://127.0.0.1:" + str(self.wss_port)
     self.wss_factory = JmwalletdWebSocketServerFactory(self.wss_url)
     self.wss_factory.protocol = JmwalletdWebSocketServerProtocol
     self.wss_factory.valid_token = encoded_token
     self.listeningport = listenWS(self.wss_factory, contextFactory=None)
     self.test_tx = CTransaction.deserialize(hextobin(test_tx_hex_1))
 def setUp(self):
     load_test_config()
     self.clean_out_wallet_files()
     jm_single().bc_interface.tick_forward_chain_interval = 5
     jm_single().bc_interface.simulate_blocks()
     # a client connnection object which is often but not always
     # instantiated:
     self.client_connector = None
     # start the daemon; note we are using tcp connections
     # to avoid storing certs in the test env.
     # TODO change that.
     self.daemon = JMWalletDaemonT(self.dport, self.wss_port, tls=False)
     self.daemon.auth_disabled = False
     # because we sync and start the wallet service manually here
     # (and don't use wallet files yet), we won't have set a wallet name,
     # so we set it here:
     self.daemon.wallet_name = self.get_wallet_file_name(1)
     r, s = self.daemon.startService()
     self.listener_rpc = r
     self.listener_ws = s
     wallet_structures = [self.wallet_structure] * 2
     # note: to test fidelity bond wallets we should add the argument
     # `wallet_cls=SegwitWalletFidelityBonds` here, but it slows the
     # test down from 9 seconds to 1 minute 40s, which is too slow
     # to be acceptable. TODO: add a test with FB by speeding up
     # the sync for test, by some means or other.
     self.daemon.services["wallet"] = make_wallets_to_list(
         make_wallets(1,
                      wallet_structures=[wallet_structures[0]],
                      mean_amt=self.mean_amt,
                      wallet_cls=SegwitWalletFidelityBonds))[0]
     jm_single().bc_interface.tickchain()
     sync_wallets([self.daemon.services["wallet"]])
     # dummy tx example to force a notification event:
     self.test_tx = CTransaction.deserialize(hextobin(test_tx_hex_1))
예제 #11
0
def get_transactions_in_block(block):
    """ `block` is hex output from RPC `getblock`.
    Return:
    yields the block's transactions, type CBitcoinTransaction
    """
    block = hextobin(block)

    # Skipping the header
    transaction_data = block[80:]

    # Decoding the number of transactions, offset is the size of
    # the varint (1 to 9 bytes)
    n_transactions, offset = decode_varint(transaction_data)

    for i in range(n_transactions):
        # This 'strat' of reading in small chunks optimistically is taken from:
        # https://github.com/alecalve/python-bitcoin-blockchain-parser/blob/7a9e15c236b10d2a6dff5e696801c0641af72628/blockchain_parser/utils.py
        # Try from 1024 (1KiB) -> 1073741824 (1GiB) slice widths
        for j in range(0, 20):
            try:
                offset_e = offset + (1024 * 2 ** j)
                transaction = CBitcoinTransaction.deserialize(
                    transaction_data[offset:offset_e], allow_padding=True)
                yield transaction
                break
            except:
                continue

        # Skipping to the next transaction
        offset += len(transaction.serialize())
def test_auth_pub_not_found(setup_taker):
    taker = get_taker([(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw",
                        0, NO_ROUNDING)])
    orderbook = copy.deepcopy(t_orderbook)
    res = taker.initialize(orderbook, [])
    taker.orderbook = copy.deepcopy(
        t_chosen_orders)  #total_cjfee unaffected, all same
    maker_response = copy.deepcopy(t_maker_response)
    utxos = [
        utxostr_to_utxo(x)[1] for x in [
            "03243f4a659e278a1333f8308f6aaf32db4692ee7df0340202750fd6c09150f6:1",
            "498faa8b22534f3b443c6b0ce202f31e12f21668b4f0c7a005146808f250d4c3:0",
            "3f3ea820d706e08ad8dc1d2c392c98facb1b067ae4c671043ae9461057bd2a3c:1"
        ]
    ]
    fake_query_results = [{
        'value':
        200000000,
        'address':
        "mrKTGvFfYUEqk52qPKUroumZJcpjHLQ6pn",
        'script':
        hextobin('76a914767c956efe6092a775fea39a06d1cac9aae956d788ac'),
        'utxo':
        utxos[i],
        'confirms':
        20
    } for i in range(3)]
    jm_single().bc_interface.insert_fake_query_results(fake_query_results)
    res = taker.receive_utxos(maker_response)
    assert not res[0]
    assert res[1] == "Not enough counterparties responded to fill, giving up"
    jm_single().bc_interface.insert_fake_query_results(None)
def test_hr_psbt(setup_psbt_wallet):
    bitcoin.select_chain_params("bitcoin")
    for k, v in hr_test_vectors.items():
        print(
            PSBTWalletMixin.human_readable_psbt(
                bitcoin.PartiallySignedTransaction.from_binary(hextobin(v))))
    bitcoin.select_chain_params("bitcoin/regtest")
def test_coinjoin_mixdepth_wrap_taker(monkeypatch, tmpdir, setup_cj):
    def raise_exit(i):
        raise Exception("sys.exit called")

    monkeypatch.setattr(sys, 'exit', raise_exit)
    set_commitment_file(str(tmpdir.join('commitments.json')))

    MAKER_NUM = 3
    wallet_services = make_wallets_to_list(
        make_wallets(MAKER_NUM + 1,
                     wallet_structures=[[4, 0, 0, 0, 0]] * MAKER_NUM +
                     [[0, 0, 0, 0, 3]],
                     mean_amt=1))

    for wallet_service in wallet_services:
        assert wallet_service.max_mixdepth == 4

    jm_single().bc_interface.tickchain()
    jm_single().bc_interface.tickchain()

    sync_wallets(wallet_services)

    cj_fee = 2000
    makers = [
        YieldGeneratorBasic(
            wallet_services[i],
            [0, cj_fee, 0, absoffer_type_map[SegwitWallet], 10**7])
        for i in range(MAKER_NUM)
    ]
    create_orders(makers)

    orderbook = create_orderbook(makers)
    assert len(orderbook) == MAKER_NUM

    cj_amount = int(1.1 * 10**8)
    # mixdepth, amount, counterparties, dest_addr, waittime, rounding
    schedule = [(4, cj_amount, MAKER_NUM, 'INTERNAL', 0, NO_ROUNDING)]
    taker = create_taker(wallet_services[-1], schedule, monkeypatch)

    active_orders, maker_data = init_coinjoin(taker, makers, orderbook,
                                              cj_amount)

    txdata = taker.receive_utxos(maker_data)
    assert txdata[0], "taker.receive_utxos error"

    taker_final_result = do_tx_signing(taker, makers, active_orders, txdata)
    assert taker_final_result is not False

    tx = btc.CMutableTransaction.deserialize(hextobin(txdata[2]))

    wallet_service = wallet_services[-1]
    # TODO change for new tx monitoring:
    wallet_service.remove_old_utxos(tx)
    wallet_service.add_new_utxos(tx)

    balances = wallet_service.get_balance_by_mixdepth()
    assert balances[0] == cj_amount
    # <= because of tx fee
    assert balances[4] <= 3 * 10**8 - cj_amount - (cj_fee * MAKER_NUM)
예제 #15
0
def fund_wallet_addr(wallet, addr, value_btc=1):
    # special case, grab_coins returns hex from rpc:
    txin_id = hextobin(jm_single().bc_interface.grab_coins(addr, value_btc))
    txinfo = jm_single().bc_interface.get_transaction(txin_id)
    txin = btc.CMutableTransaction.deserialize(btc.x(txinfo["hex"]))
    utxo_in = wallet.add_new_utxos(txin, 1)
    assert len(utxo_in) == 1
    return list(utxo_in.keys())[0]
 def get_deser_from_gettransaction(self, rpcretval):
     """Get full transaction deserialization from a call
     to `gettransaction`
     """
     if not "hex" in rpcretval:
         log.info("Malformed gettransaction output")
         return None
     return btc.CMutableTransaction.deserialize(hextobin(rpcretval["hex"]))
def test_get_utxo_info():
    load_test_config()
    # this test tests mainnet keys, so temporarily switch network
    select_chain_params("bitcoin")
    jm_single().config.set("BLOCKCHAIN", "network", "mainnet")

    dbci = DummyBlockchainInterface()
    privkey = "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi"
    #to verify use from_wif_privkey and privkey_to_address
    iaddr = "bc1q6tvmnmetj8vfz98vuetpvtuplqtj4uvvwjgxxc"
    fakeutxo = "aa" * 32 + ":08"
    success, fakeutxo_bin = utxostr_to_utxo(fakeutxo)
    assert success
    fake_query_results = [{
        'value': 200000000,
        'script': BTC_P2WPKH.address_to_script(iaddr),
        'utxo': fakeutxo_bin,
        'confirms': 20
    }]
    dbci.insert_fake_query_results(fake_query_results)
    jm_single().bc_interface = dbci
    u, priv = get_utxo_info(fakeutxo + "," + privkey)
    assert u == fakeutxo
    assert priv == privkey
    #invalid format
    with pytest.raises(Exception):
        u, priv = get_utxo_info(fakeutxo + privkey)
    #invalid index
    fu2 = "ab" * 32 + ":-1"
    with pytest.raises(Exception):
        u, priv = get_utxo_info(fu2 + "," + privkey)
    #invalid privkey
    p2 = privkey[:-1] + 'j'
    with pytest.raises(Exception):
        u, priv = get_utxo_info(fakeutxo + "," + p2)

    utxodatas = [(fakeutxo_bin, privkey)]
    retval = validate_utxo_data(utxodatas, False)
    assert retval
    #try to retrieve
    retval = validate_utxo_data(utxodatas, True)
    assert retval[0] == (fakeutxo_bin, 200000000)
    fake_query_results[0]['script'] = hextobin(
        "76a91479b000887626b294a914501a4cd226b58b23598388ac")
    dbci.insert_fake_query_results(fake_query_results)
    #validate should fail for wrong address
    retval = validate_utxo_data(utxodatas, False)
    assert not retval
    #remove fake query result and trigger not found
    dbci.fake_query_results = None
    dbci.setQUSFail(True)
    retval = validate_utxo_data(utxodatas, False)
    assert not retval
    dbci.setQUSFail(False)
    select_chain_params("bitcoin/regtest")
    jm_single().config.set("BLOCKCHAIN", "network", "regtest")
예제 #18
0
def test_pushtx_errors(setup_wallets):
    """Ensure pushtx fails return False
    """
    badtx = b"\xaa\xaa"
    assert not jm_single().bc_interface.pushtx(badtx)
    #Break the authenticated jsonrpc and try again
    jm_single().bc_interface.jsonRpc.port = 18333
    assert not jm_single().bc_interface.pushtx(hextobin(t_raw_signed_tx))
    #rebuild a valid jsonrpc inside the bci
    load_test_config()
예제 #19
0
    def on_push_tx(self, nick, txhex):
        """Broadcast unquestioningly, except checking
        hex format.
	"""
        try:
            dummy = hextobin(txhex)
        except:
            return
        d = self.callRemote(JMTXBroadcast, txhex=txhex)
        self.defaultCallbacks(d)
예제 #20
0
 def _add_unspent_txo(self, utxo, height):
     """
     Add a UTXO as returned by rpc's listunspent call to the wallet.
     Note that these are returned as little endian outpoint txids, so
     are converted.
     params:
         utxo: single utxo dict as returned by listunspent
         current_blockheight: blockheight as integer, used to
         set the block in which a confirmed utxo is included.
     """
     txid = hextobin(utxo['txid'])
     script = hextobin(utxo['scriptPubKey'])
     value = int(Decimal(str(utxo['amount'])) * Decimal('1e8'))
     self.add_utxo(txid, int(utxo['vout']), script, value, height)
     # if we start up with unconfirmed outputs, they must be
     # put into the transaction monitor state, so we can recognize
     # when they transition to confirmed.
     if height is None:
         txd = self.bci.get_deser_from_gettransaction(
             self.bci.get_transaction(txid))
         self.active_txs[utxo['txid']] = txd
         self.processed_txids.add(utxo['txid'])
예제 #21
0
 def get_all_transactions(self):
     """ Get all transactions (spending or receiving) that
     are currently recorded by our blockchain interface as relating
     to this wallet, as a list.
     """
     res = []
     processed_txids = set()
     for r in self.bci._yield_transactions():
         txid = r["txid"]
         if txid not in processed_txids:
             tx = self.bci.get_transaction(hextobin(txid))
             res.append(self.bci.get_deser_from_gettransaction(tx))
             processed_txids.add(txid)
     return res
예제 #22
0
 def on_JM_TX_BROADCAST(self, txhex):
     """ Makers have no issue broadcasting anything,
     so only need to prevent crashes.
     Note in particular we don't check the return value,
     since the transaction being accepted or not is not
     our (maker)'s concern.
     """
     try:
         txbin = hextobin(txhex)
         jm_single().bc_interface.pushtx(txbin)
     except:
         jlog.info("We received an invalid transaction broadcast "
                   "request: " + txhex)
     return {"accepted": True}
예제 #23
0
 def query_utxo_set(self, txouts, includeconf=False):
     if self.qusfail:
         #simulate failure to find the utxo
         return [None]
     if self.fake_query_results:
         result = []
         for x in self.fake_query_results:
             for y in txouts:
                 if y == x['utxo']:
                     result.append(x)
         return result
     result = []
     #external maker utxos
     known_outs = {"03243f4a659e278a1333f8308f6aaf32db4692ee7df0340202750fd6c09150f6:1": "03a2d1cbe977b1feaf8d0d5cc28c686859563d1520b28018be0c2661cf1ebe4857",
                   "498faa8b22534f3b443c6b0ce202f31e12f21668b4f0c7a005146808f250d4c3:0": "02b4b749d54e96b04066b0803e372a43d6ffa16e75a001ae0ed4b235674ab286be",
                   "3f3ea820d706e08ad8dc1d2c392c98facb1b067ae4c671043ae9461057bd2a3c:1": "023bcbafb4f68455e0d1d117c178b0e82a84e66414f0987453d78da034b299c3a9"}
     known_outs = dictchanger(known_outs)
     #our wallet utxos, faked, for podle tests: utxos are doctored (leading 'f'),
     #and the lists are (amt, age)
     wallet_outs = {'f34b635ed8891f16c4ec5b8236ae86164783903e8e8bb47fa9ef2ca31f3c2d7a:0': [10000000, 2],
                    'f780d6e5e381bff01a3519997bb4fcba002493103a198fde334fd264f9835d75:1': [20000000, 6],
                    'fe574db96a4d43a99786b3ea653cda9e4388f377848f489332577e018380cff1:0': [50000000, 3],
                    'fd9711a2ef340750db21efb761f5f7d665d94b312332dc354e252c77e9c48349:0': [50000000, 6]}
     wallet_outs = dictchanger(wallet_outs)
     
     if includeconf and set(txouts).issubset(set(wallet_outs)):
         #includeconf used as a trigger for a podle check;
         #here we simulate a variety of amount/age returns
         results = []
         for to in txouts:
             results.append({'value': wallet_outs[to][0],
                             'confirms': wallet_outs[to][1]})
         return results
     if txouts[0] in known_outs:
         scr = BTC_P2SH_P2WPKH.pubkey_to_script(known_outs[txouts[0]])
         addr = btc.CCoinAddress.from_scriptPubKey(scr)
         return [{'value': 200000000,
                  'address': addr,
                  'script': scr,
                  'confirms': 20}]
     for t in txouts:
         result_dict = {'value': 10000000000,
                        'address': "mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ",
                        'script': hextobin('76a91479b000887626b294a914501a4cd226b58b23598388ac')}
         if includeconf:
             result_dict['confirms'] = 20
         result.append(result_dict)        
     return result
def restart_wait(txid):
    """ Returns true only if the transaction txid is seen in the wallet,
    and confirmed (it must be an in-wallet transaction since it always
    spends coins from the wallet).
    """
    res = jm_single().bc_interface.get_transaction(hextobin(txid))
    if not res:
        return False
    if res["confirmations"] == 0:
        return False
    if res["confirmations"] < 0:
        log.warn("Tx: " + txid + " has a conflict, abandoning.")
        sys.exit(EXIT_SUCCESS)
    else:
        log.debug("Tx: " + str(txid) + " has " + str(res["confirmations"]) +
                  " confirmations.")
        return True
예제 #25
0
def test_valid_bip341_scriptpubkeys_addresses():
    with ChainParams("bitcoin"):
        with open(os.path.join(testdir, "bip341_wallet_test_vectors.json"),
                  "r") as f:
            json_data = json.loads(f.read())
        for x in json_data["scriptPubKey"]:
            sPK = hextobin(x["expected"]["scriptPubKey"])
            addr = x["expected"]["bip350Address"]
            res, message = validate_address(addr)
            assert res, message
            print("address {} was valid bech32m".format(addr))
            # test this specific conversion because this is how
            # our human readable outputs work:
            assert str(CCoinAddress.from_scriptPubKey(
                btc.CScript(sPK))) == addr
            print("and it converts correctly from scriptPubKey: {}".format(
                btc.CScript(sPK)))
 def query_utxo_set(self, txout, includeconf=False, includeunconf=False):
     """If txout is either (a) a single utxo in (txidbin, n) form,
     or a list of the same, returns, as a list for each txout item,
     the result of gettxout from the bitcoind rpc for those utxos;
     if any utxo is invalid, None is returned.
     includeconf: if this is True, the current number of confirmations
     of the prescribed utxo is included in the returned result dict.
     includeunconf: if True, utxos which currently have zero confirmations
     are included in the result set.
     If the utxo is of a non-standard type such that there is no address,
     the address field in the dict is None.
     """
     if not isinstance(txout, list):
         txout = [txout]
     result = []
     for txo in txout:
         txo_hex = bintohex(txo[0])
         if len(txo_hex) != 64:
             log.warn("Invalid utxo format, ignoring: {}".format(txo))
             result.append(None)
             continue
         try:
             txo_idx = int(txo[1])
         except ValueError:
             log.warn("Invalid utxo format, ignoring: {}".format(txo))
             result.append(None)
             continue
         ret = self.rpc('gettxout', [txo_hex, txo_idx, includeunconf])
         if ret is None:
             result.append(None)
         else:
             if ret['scriptPubKey'].get('addresses'):
                 address = ret['scriptPubKey']['addresses'][0]
             else:
                 address = None
             result_dict = {
                 'value': int(Decimal(str(ret['value'])) * Decimal('1e8')),
                 'address': address,
                 'script': hextobin(ret['scriptPubKey']['hex'])
             }
             if includeconf:
                 result_dict['confirms'] = int(ret['confirmations'])
             result.append(result_dict)
     return result
 def on_privmsg(self, nick, message):
     """handles the case when a private message is received"""
     #Aberrant short messages should be handled by subclasses
     #in _privmsg, but this constitutes a sanity check. Note that
     #messages which use an encrypted_command but present no
     #ciphertext will be rejected with the ValueError on decryption.
     #Other ill formatted messages will be caught in the try block.
     if len(message) < 2:
         return
     if message[0] != COMMAND_PREFIX:
         log.debug('message not a cmd')
         return
     cmd_string = message[1:].split(' ')[0]
     if cmd_string not in plaintext_commands + encrypted_commands:
         log.debug('cmd not in cmd_list, line="' + message + '"')
         return
     badsigmsg = "Sig not properly appended to privmsg, ignoring"
     #Verify nick ownership
     try:
         pub, sig = message[1:].split(' ')[-2:]
     except Exception:
         log.debug(badsigmsg)
         return
     #reconstruct original message without cmd
     rawmessage = ' '.join(message[1:].split(' ')[1:-2])
     # can happen if not enough fields for command, (stuff), pub, sig:
     if len(rawmessage) == 0:
         log.debug(badsigmsg)
         return
     # Sanitising signature before attempting to verify:
     # Note that the sig itself can be any garbage, because `ecdsa_verify`
     # swallows any fail and returns False; but the pubkey is assumed
     # to be hex-encoded, and the signature base64 encoded, so check early:
     try:
         dummypub = hextobin(pub)
         dummysig = base64.b64decode(sig)
     except Exception:
         log.debug(badsigmsg)
         return
     self.daemon.request_signature_verify(rawmessage + str(self.hostid),
                                          message, sig, pub, nick,
                                          NICK_HASH_LENGTH,
                                          NICK_MAX_ENCODED,
                                          str(self.hostid))
def test_ecies():
    """Tests encryption and decryption of random messages using
    the ECIES module.
    TODO these tests are very minimal.
    """
    with open(os.path.join(testdir,"base58_keys_valid.json"), "r") as f:
        json_data = f.read()
        valid_keys_list = json.loads(json_data)
        print("got valid keys list")
        extracted_privkeys = []
        for a in valid_keys_list:
            key, hex_key, prop_dict = a
            if prop_dict["isPrivkey"]:
                c, k = btc.read_privkey(hextobin(hex_key))

                extracted_privkeys.append(k)
    extracted_pubkeys = [btc.privkey_to_pubkey(x) for x in extracted_privkeys]
    for (priv, pub) in zip(extracted_privkeys, extracted_pubkeys):
        test_message = base64.b64encode(os.urandom(15)*20)
        assert btc.ecies_decrypt(priv, btc.ecies_encrypt(test_message, pub)) == test_message
예제 #29
0
def read_from_podle_file():
    """ Returns used commitment list and external commitments dict
    struct currently stored in PODLE_COMMIT_FILE.
    """
    if os.path.isfile(PODLE_COMMIT_FILE):
        with open(PODLE_COMMIT_FILE, "rb") as f:
            try:
                c = json.loads(f.read().decode('utf-8'))
            except ValueError: #pragma: no cover
                #Exit conditions cannot be included in tests.
                jmprint("the file: " + PODLE_COMMIT_FILE + " is not valid json.",
                        "error")
                sys.exit(EXIT_FAILURE)
            if 'used' not in c.keys() or 'external' not in c.keys():
                raise PoDLEError("Incorrectly formatted file: " + PODLE_COMMIT_FILE)

        used = [hextobin(x) for x in c["used"]]
        external = external_dict_from_file(c["external"])
        return (used, external)
    return ([], {})
예제 #30
0
 def query_utxo_set(self, txout, includeconfs=False, include_mempool=True):
     """If txout is either (a) a single utxo in (txidbin, n) form,
     or a list of the same, returns, as a list for each txout item,
     the result of gettxout from the bitcoind rpc for those utxos;
     if any utxo is invalid, None is returned.
     includeconfs: if this is True, the current number of confirmations
     of the prescribed utxo is included in the returned result dict.
     include_mempool: if True, the contents of the mempool are included;
     this *both* means that utxos that are spent in in-mempool transactions
     are *not* returned, *and* means that utxos that are created in the
     mempool but have zero confirmations *are* returned.
     If the utxo is of a non-standard type such that there is no address,
     the address field in the dict is None.
     """
     if not isinstance(txout, list):
         txout = [txout]
     result = []
     for txo in txout:
         txo_hex = bintohex(txo[0])
         if len(txo_hex) != 64:
             log.warn("Invalid utxo format, ignoring: {}".format(txo))
             result.append(None)
             continue
         try:
             txo_idx = int(txo[1])
         except ValueError:
             log.warn("Invalid utxo format, ignoring: {}".format(txo))
             result.append(None)
             continue
         ret = self._rpc('gettxout', [txo_hex, txo_idx, include_mempool])
         if ret is None:
             result.append(None)
         else:
             result_dict = {
                 'value': int(Decimal(str(ret['value'])) * Decimal('1e8')),
                 'script': hextobin(ret['scriptPubKey']['hex'])
             }
             if includeconfs:
                 result_dict['confirms'] = int(ret['confirmations'])
             result.append(result_dict)
     return result