Exemple #1
0
def get_coinbase_info(blockheight):
    '''Gets coinbase tag and addresses of a block with specified height.

    Returns:
        addresses - A list of p2sh/p2pkh addresses corresponding to the
                    outputs. Returns None in place of an unrecognizable
                    scriptPubKey.
        tag - the UTF-8 decoded scriptSig.
    Raises:
        Exceptions originating from bitcoin.rpc.Proxy, if there is a problem
        with JSON-RPC.
    '''
    block = proxy.getblock(proxy.getblockhash(blockheight))
    coinbase_tx = block.vtx[0]
    assert coinbase_tx.is_coinbase()
    addresses = []
    for output in coinbase_tx.vout:
        try:
            addr = str(CBitcoinAddress.from_scriptPubKey(output.scriptPubKey))
        except (CBitcoinAddressError, ValueError):
            addr = None
        else:
            addr = addr.decode('ascii')
        addresses.append(addr)

    tag = str(coinbase_tx.vin[0].scriptSig).decode('utf-8', 'ignore')

    return addresses, tag
def _check_output_address(mytx):
    print
    for vout in mytx.vout:
        pubkey = vout.scriptPubKey
        address = b2lx(CBitcoinAddress.from_scriptPubKey(pubkey))
        address = "".join(map(str.__add__, address[-2::-2], address[-1::-2]))
        #print address
        address = int(address, 16)
        for bl in blacklist:
            if hex(bl.start) <= hex(address) <= hex(bl.end):
                print "This address use by: " + bl.name
                return False
    return True
def payment_ack(serialized_Payment_message):
    """Generates a PaymentACK object, captures client refund address and returns a message"""

    pao = o.PaymentACK()
    pao.payment.ParseFromString(serialized_Payment_message)
    pao.memo = "String shown to user after payment confirmation"

    refund_address = CBitcoinAddress.from_scriptPubKey(CScript(pao.payment.refund_to[0].script))

    sds_pa = pao.SerializeToString()

    open("sds_pa_blob", "wb").write(sds_pa)
    headers = {"Content-Type": "application/bitcoin-payment", "Accept": "application/bitcoin-paymentack"}
    http_response_object = urllib2.Request("file:sds_pa_blob", None, headers)

    return http_response_object
Exemple #4
0
 def get(cls, address):
     """Get a Channel with the specified address."""
     row = g.dat.execute(
         "SELECT * from CHANNELS WHERE address = ?", (address,)).fetchone()
     if row is None:
         raise Exception("Unknown address", address)
     address, commitment = row
     commitment = CMutableTransaction.deserialize(commitment)
     commitment = CMutableTransaction.from_tx(commitment)
     assert len(commitment.vin) == 1
     assert len(commitment.vout) == 2
     commitment.vin[0].scriptSig = AnchorScriptSig.from_script(
         commitment.vin[0].scriptSig)
     for tx_out in commitment.vout:
         tx_out.scriptPubKey = CBitcoinAddress.from_scriptPubKey(tx_out.scriptPubKey)
     return cls(address,
                commitment.vin[0],
                commitment.vout[0],
                commitment.vout[1])
Exemple #5
0
    def setup_preimage(self, payer_pubkey, redeemer_pubkey, hashes, amount,
                       lock_time):
        '''
            Setups a P2SH that can only be redeemed
            if the redeemer is able to provide
            the hash preimages.
            Also, sends a tx funding the escrow
            (Assumes payer calls the setup)
        '''

        # Set locktime relative to current block
        if not self.test:
            lock = self.proxy.getblockcount() + lock_time
        else:
            lock = lock_time

        script = self.create_hash_script(redeemer_pubkey, hashes)
        redeem_script = CScript([OP_IF] + script + [
            OP_ELSE, lock, OP_CHECKLOCKTIMEVERIFY, OP_DROP, payer_pubkey,
            OP_CHECKSIG, OP_ENDIF
        ])

        redeem = b2x(redeem_script)
        self.logger.info("setup_preimage: Redeem script is %s", redeem)

        # Get P2SH address
        # 1. Get public key
        script_pub_key = redeem_script.to_p2sh_scriptPubKey()

        # 2. Get bitcoin address
        p2sh_address = CBitcoinAddress.from_scriptPubKey(script_pub_key)
        self.logger.info("setup_preimage: P2SH is %s", str(p2sh_address))

        # 3. Fund address
        if not self.test:
            # funding_tx = self.proxy.call("sendtoaddress", str(p2sh_address),
            #                              amount)
            funding_tx = FUNDING_TX
            self.logger.info("setup_preimage: P2SH Fund TX is %s", funding_tx)
        else:
            funding_tx = FUNDING_TX

        return (redeem_script, str(funding_tx), str(p2sh_address), str(lock))
Exemple #6
0
def payment_ack(serialized_Payment_message):
    """Generates a PaymentACK object, captures client refund address and returns a message"""

    pao = o.PaymentACK()
    pao.payment.ParseFromString(serialized_Payment_message)
    pao.memo = 'String shown to user after payment confirmation'

    refund_address = CBitcoinAddress.from_scriptPubKey(
        CScript(pao.payment.refund_to[0].script))

    sds_pa = pao.SerializeToString()

    open('sds_pa_blob', 'wb').write(sds_pa)
    headers = {
        'Content-Type': 'application/bitcoin-payment',
        'Accept': 'application/bitcoin-paymentack'
    }
    http_response_object = urllib2.Request('file:sds_pa_blob', None, headers)

    return http_response_object
Exemple #7
0
    def htlc_p2sh(self) -> str:
        # TODO: cache the generated address
        # We create connections on the fly because they'll time out quickly if
        # we don't
        bitcoind = rpc.Proxy()

        # We can decipher the hash of the preimage without explicitly asking
        # for it by taking it out of the payment request supplied
        decoded_pr = json.loads(
            to_json(lnd.decode_payment_request(self.bolt11_invoice)))
        hashed_preimage = decoded_pr['payment_hash']

        # Once these assignments are made, we want to lock them in so this
        # functions generates deterministically
        if not self.final_address_pubkey:
            final_address = bitcoind.getnewaddress()
            seckey = bitcoind.dumpprivkey(final_address)
            self.final_address_pubkey = seckey.pub.hex()

        if not self.redeemblock:
            curr_blockheight = bitcoind.getblockcount()
            self.redeemblock = curr_blockheight + self.lockduration

        # HTLC locking script
        txin_redeemScript = CScript([
            OP_IF, OP_SHA256,
            bytes(hashed_preimage, 'utf8'), OP_EQUALVERIFY, OP_DUP, OP_HASH160,
            bytes(Hash160(bytes(self.final_address_pubkey,
                                'utf8'))), OP_ELSE, self.redeemblock,
            OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160,
            bytes(Hash160(bytes(self.refund_address, 'utf8'))), OP_ENDIF,
            OP_EQUALVERIFY, OP_CHECKSIG
        ])

        self.save()

        # Generate a P2SH address from the locking script
        txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
        txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(
            txin_scriptPubKey)
        return str(txin_p2sh_address)
Exemple #8
0
    def setup_escrow(self, payer_pubkey, redeemer_pubkey, amount, lock_time):
        '''
            Setups a 2of2 escrow with payer and redeemer
            Also, sends a tx funding the escrow
            (Assumes payer calls the setup)
        '''

        # Set locktime relative to current block
        if not self.test:
            lock = self.proxy.getblockcount() + lock_time
            self.logger.info("setup_escrow: Locktime is %d", lock)
        else:
            lock = lock_time

        redeem_script = CScript([
            OP_IF, OP_2, payer_pubkey, redeemer_pubkey, OP_2, OP_CHECKMULTISIG,
            OP_ELSE, lock, OP_CHECKLOCKTIMEVERIFY, OP_DROP, payer_pubkey,
            OP_CHECKSIG, OP_ENDIF
        ])

        redeem = b2x(redeem_script)
        self.logger.info("setup_escrow: Redeem script is %s", redeem)

        # Get P2SH address
        # 1. Get public key
        script_pub_key = redeem_script.to_p2sh_scriptPubKey()

        # 2. Get bitcoin address
        p2sh_address = CBitcoinAddress.from_scriptPubKey(script_pub_key)
        self.logger.info("setup_escrow: P2SH is %s", str(p2sh_address))

        # 3. Fund address
        if not self.test:
            funding_tx = self.proxy.call("sendtoaddress", str(p2sh_address),
                                         amount)
            self.logger.info("setup_escrow: P2SH Fund TX is %s", funding_tx)
        else:
            funding_tx = FUNDING_TX

        return (redeem_script, str(funding_tx), str(p2sh_address), str(lock))
Exemple #9
0
 def show_details(self):
     return {
         'contract':
         self.contract.hex(),
         'contract_address':
         str(
             CBitcoinAddress.from_scriptPubKey(
                 self.contract.to_p2sh_scriptPubKey())),
         'contract_transaction':
         self.raw_transaction,
         'transaction_address':
         self.address,
         'fee':
         self.fee,
         'fee_per_kb':
         self.fee_per_kb,
         'fee_per_kb_text':
         f'{self.fee_per_kb:.8f} {self.symbol} / 1 kB',
         'fee_text':
         f'{self.fee:.8f} {self.symbol}',
         'locktime':
         self.locktime,
         'recipient_address':
         self.recipient_address,
         'refund_address':
         self.sender_address,
         'secret':
         self.secret.hex() if self.secret else '',
         'secret_hash':
         self.secret_hash.hex(),
         'size':
         self.size,
         'size_text':
         f'{self.size} bytes',
         'value':
         self.value,
         'value_text':
         f'{self.value:.8f} {self.symbol}',
     }
Exemple #10
0
 def hashtimelockcontract(self, funder, redeemer, commitment, locktime):
     funderAddr = CBitcoinAddress(funder)
     redeemerAddr = CBitcoinAddress(redeemer)
     if type(commitment) == str:
         commitment = x(commitment)
     # h = sha256(secret)
     blocknum = self.bitcoind.getblockcount()
     print("Current blocknum on Bitcoin: ", blocknum)
     redeemblocknum = blocknum + locktime
     print("Redeemblocknum on Bitcoin: ", redeemblocknum)
     redeemScript = CScript([OP_IF, OP_SHA256, commitment, OP_EQUALVERIFY,OP_DUP, OP_HASH160,
                                  redeemerAddr, OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP, OP_HASH160,
                                  funderAddr, OP_ENDIF,OP_EQUALVERIFY, OP_CHECKSIG])
     # print("Redeem script for p2sh contract on Bitcoin blockchain: {0}".format(b2x(redeemScript)))
     txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey()
     # Convert the P2SH scriptPubKey to a base58 Bitcoin address
     txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
     p2sh = str(txin_p2sh_address)
     # Import address at same time you create
     self.bitcoind.importaddress(p2sh, "", False)
     print("p2sh computed", p2sh)
     return {'p2sh': p2sh, 'redeemblocknum': redeemblocknum, 'redeemScript': b2x(redeemScript), 'redeemer': redeemer, 'funder': funder, 'locktime': locktime}
Exemple #11
0
def add_input_output(bitcoind, tx, coin, fees):
    """Add another input to the transaction to bump the feerate."""
    coin_amount = Decimal(coin["amount"]) * Decimal(COIN)
    # First get the private key from bitcoind's wallet.
    privkey = CKey(wif_decode(bitcoind.dumpprivkey(coin["address"])))

    # Add the fetched coin as a new input.
    tx.vin.append(CTxIn(COutPoint(lx(coin["txid"]), coin["vout"])))
    # And likely add an output, otherwise all goes to the fees.
    scriptPubKey = CScript([OP_0, Hash160(privkey.pub)])
    if coin_amount > fees + 294:
        # For simplicity, pay to the same script
        tx.vout.append(CTxOut(coin_amount - Decimal(fees), scriptPubKey))
    address = CBitcoinAddress.from_scriptPubKey(scriptPubKey)
    # We only do this once, sign it with ALL
    tx_hash = SignatureHash(address.to_redeemScript(), tx, 1, SIGHASH_ALL,
                            int(coin_amount), SIGVERSION_WITNESS_V0)
    sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL])
    tx.wit.vtxinwit.append(
        CTxInWitness(CScriptWitness([sig, privkey.pub]))
    )
    return tx
Exemple #12
0
    def get_address_by_path(self, path, key=None):
        path = path.replace("M/", "")
        key_index = path.split("/")[0].replace("'", "")

        if key is None:
            key = self.primary_private_key.subkey_for_path(path)

        backup_public_key = self.backup_public_key.subkey_for_path(
            path.replace("'", ""))
        blocktrail_public_key = self.blocktrail_public_keys[str(
            key_index)].subkey_for_path("/".join(path.split("/")[1:]))

        redeemScript = CScript([2] + sorted([
            key.sec(use_uncompressed=False),
            backup_public_key.sec(use_uncompressed=False),
            blocktrail_public_key.sec(use_uncompressed=False),
        ]) + [3, OP_CHECKMULTISIG])

        scriptPubKey = redeemScript.to_p2sh_scriptPubKey()
        address = CBitcoinAddress.from_scriptPubKey(scriptPubKey)

        return str(address)
    def check_for_funding(self, address):
        """
        Check to see if any of the outputs pay the given address

        Args:
            address: base58check encoded bitcoin address

        Returns: a `list` of `dict` outpoints if any of the outputs match
            the address else None.
        """

        outpoints = []
        for i in range(len(self.tx.vout)):
            addr = CBitcoinAddress.from_scriptPubKey(self.tx.vout[i].scriptPubKey)
            if str(addr) == address:
                o = {
                    "txid": b2lx(self.tx.GetHash()),
                    "vout": i,
                    "value": self.tx.vout[i].nValue,
                    "scriptPubKey": self.tx.vout[i].scriptPubKey.encode("hex")
                }
                outpoints.append(o)
        return outpoints if len(outpoints) > 0 else None
    def check_for_funding(self, address):
        """
        Check to see if any of the outputs pay the given address

        Args:
            address: base58check encoded bitcoin address

        Returns: a `list` of `dict` outpoints if any of the outputs match
            the address else None.
        """

        outpoints = []
        for i in range(len(self.tx.vout)):
            addr = CBitcoinAddress.from_scriptPubKey(self.tx.vout[i].scriptPubKey)
            if str(addr) == address:
                o = {
                    "txid": b2lx(self.tx.GetHash()),
                    "vout": i,
                    "value": self.tx.vout[i].nValue,
                    "scriptPubKey": self.tx.vout[i].scriptPubKey.encode("hex")
                }
                outpoints.append(o)
        return outpoints if len(outpoints) > 0 else None
Exemple #15
0
def partial_spend_p2sh (redeemScript,rein,daddr=None,alt_amount=None,alt_daddr=None):
    if daddr is None:
        daddr = rein.user.daddr
    txin_redeemScript = CScript(x(redeemScript))
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
    (txins,total_value) = unspent_txins(rein, txin_p2sh_address,rein.testnet)
    if len(txins)==0:
        raise ValueError('Primary escrow is empty. Please inform client to add funds.')
    txins_str = ""
    txins_obj = []
    for txid,vout in txins:
        txins_str += " "+txid+"-"+str(vout)
        txins_obj.append(CMutableTxIn(COutPoint(lx(txid),vout)))                
    fee = float(PersistConfig.get(rein, 'fee', 0.001))
    amount = round(total_value-fee,8)
    if alt_amount:
        amount = round(amount-alt_amount,8)
    if amount<=0. or alt_amount>total_value-fee:
        click.echo("amount: "+str(amount)+" alt_amount: "+str(alt_amount)+" total_value: "+str(total_value))
        raise ValueError('Primary escrow balance too low. Please inform client to add funds.')
    txouts = []
    txout = CMutableTxOut(amount*COIN, CBitcoinAddress(daddr).to_scriptPubKey())
    txouts.append(txout)
    if alt_amount:
        txout_alt = CMutableTxOut(round(alt_amount,8)*COIN, CBitcoinAddress(alt_daddr).to_scriptPubKey())
        txouts.append(txout_alt)
    tx = CMutableTransaction(txins_obj, txouts)
    ntxins = len(txins_obj)
    seckey = CBitcoinSecret(rein.user.dkey)
    sig = "";
    for i in range(0,ntxins):
        sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL)
        sig += " "+b2x(seckey.sign(sighash))+"01"
    if alt_amount:
        return (txins_str[1:],"{:.8f}".format(amount),daddr,"{:.8f}".format(alt_amount),alt_daddr,sig[1:])
    return (txins_str[1:],"{:.8f}".format(amount),daddr,sig[1:])
Exemple #16
0
def setup_escrow(payer_pubkey, redeemer_pubkey, amount, lock_time):
    '''
        Setups a 2of2 escrow with payer and redeemer
        Also, sends a tx funding the escrow
        (Assumes payer calls the setup)
    '''

    redeem_script = CScript([OP_DEPTH, 3, OP_EQUAL,  # Fixes a txid malliablity issue thanks to Nicolas
                            OP_IF, OP_2, payer_pubkey, redeemer_pubkey,
                            OP_2, OP_CHECKMULTISIG, OP_ELSE, lock_time,
                            OP_CHECKLOCKTIMEVERIFY, OP_DROP,
                            payer_pubkey, OP_CHECKSIG,
                            OP_ENDIF])

    redeem = b2x(redeem_script)
    print("setup_escrow: Redeem script is %s" % redeem)

    # Get P2SH address
    script_pub_key = redeem_script.to_p2sh_scriptPubKey()
    p2sh_address = CBitcoinAddress.from_scriptPubKey(script_pub_key)

    print("setup_escrow: P2SH is %s" %  str(p2sh_address))

    return (redeem_script, str(p2sh_address))
Exemple #17
0
def setup_preimage(payer_pubkey, redeemer_pubkey, hashes, lock_time):
    """
    Setups a P2SH that can only be redeemed if the redeemer is able
    to provide the hash preimages.

    Arguments:
        payer_pubkey (bytes): The public key of the party that funds the contract
        redeemer_pubkey (bytes): The public key of the party that wants
                                 to receive the funds
        hashes (list): The hashes that payer wants the preimages of
        lock_time (int): The time the refund should be activated at

    Returns:
        A tuple containing:
            1/ redeem_script
            2/ p2sh_address, which should be funded
    """

    script = create_hash_script(redeemer_pubkey, hashes)
    redeem_script = CScript([OP_IF] + script + [
        OP_ELSE, lock_time, OP_CHECKLOCKTIMEVERIFY, OP_DROP, payer_pubkey,
        OP_CHECKSIG, OP_ENDIF
    ])

    redeem = b2x(redeem_script)
    print("setup_preimage: Redeem script is %s" % redeem)

    # Get P2SH address
    # 1. Get public key
    script_pub_key = redeem_script.to_p2sh_scriptPubKey()

    # 2. Get bitcoin address
    p2sh_address = CBitcoinAddress.from_scriptPubKey(script_pub_key)
    print("setup_preimage: P2SH is %s" % str(p2sh_address))

    return (redeem_script, str(p2sh_address))
Exemple #18
0
def partial_spend_p2sh_mediator(redeemScript,
                                rein,
                                mediator_address,
                                mediator_sig=False):
    txin_redeemScript = CScript(x(redeemScript))
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
    (txins, total_value) = unspent_txins(txin_p2sh_address, rein.testnet)
    if len(txins) == 0:
        raise ValueError(
            'Mediator escrow is empty. Please inform client to add funds.')
    txins_str = ""
    txins_obj = []
    for txid, vout in txins:
        txins_str += " " + txid + "-" + str(vout)
        txins_obj.append(CMutableTxIn(COutPoint(lx(txid), vout)))
    fee = float(PersistConfig.get(rein, 'fee', 0.001))
    amount = round(total_value - fee, 8)
    if amount <= 0:
        raise ValueError(
            'Mediator escrow balance too low. Please inform client to add funds.'
        )
    if mediator_sig:
        txout = CMutableTxOut(
            amount * COIN,
            CBitcoinAddress(mediator_address).to_scriptPubKey())
        tx = CMutableTransaction(txins_obj, [txout])
        seckey = CBitcoinSecret(rein.user.dkey)
        ntxins = len(txins_obj)
        sig = ""
        for i in range(0, ntxins):
            sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL)
            sig += " " + b2x(seckey.sign(sighash) + x("01"))
        return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address),
                sig[1:])
    return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address))
Exemple #19
0
    def poll_for_funds(self):
        """Polls bitcoind to check for received funds.

        If we just went to know of the possession of a new output, it will
        construct the corresponding emergency transaction and spawn a thread
        to fetch emergency transactions signatures.

        Note that this main loop used to be somewhat less naïvely implemented,
        but it was both a premature and useless optimisation.
        """
        while not self.funds_poller_stop.wait(5.0):
            # What we think we have
            known_outputs = [v["txid"] for v in self.vaults]
            # What bitcoind tells we *actually* have
            current_utxos = self.bitcoind.listunspent(
                # Should not be 0 if it was "for real" (cancel_tx's id isn't
                # known for sure)
                minconf=0,
                addresses=self.vault_addresses)
            current_utxos_id = [u["txid"] for u in current_utxos]
            spent_vaults = [
                v for v in self.vaults if v["txid"] not in current_utxos_id
            ]
            new_vaults = [
                u for u in current_utxos if u["txid"] not in known_outputs
            ]

            for v in spent_vaults:
                # Is it an emergency broadcast ?
                if self.bitcoind.listunspent(
                        minconf=0, addresses=[self.emergency_address]):
                    # Game over.
                    for v in self.vaults:
                        tx = self.get_signed_emergency_tx(v).serialize().hex()
                        if tx is not None:
                            try:
                                self.bitcoind.sendrawtransaction(tx)
                            except bitcoin.rpc.JSONRPCError:
                                # Already sent!
                                pass
                        unvtx = self.get_signed_unvault_emergency_tx(v)
                        hextx = unvtx.serialize().hex()
                        if tx is not None:
                            try:
                                self.bitcoind.sendrawtransaction(hextx)
                            except bitcoin.rpc.JSONRPCError:
                                # Already sent!
                                pass
                    self.stopped = True
                    return

                # If not, it must be an unvault broadcast !
                unvault_addr = CBitcoinAddress.from_scriptPubKey(
                    v["unvault_tx"].vout[0].scriptPubKey)
                unvault_utxos = self.bitcoind.listunspent(
                    minconf=0, addresses=[str(unvault_addr)])
                if len(unvault_utxos) == 0:
                    # Maybe someone has already broadcast the cancel
                    # transaction
                    cancel_addr = CBitcoinAddress.from_scriptPubKey(
                        v["cancel_tx"].vout[0].scriptPubKey)
                    assert len(
                        self.bitcoind.listunspent(
                            minconf=0, addresses=[str(cancel_addr)])) > 0
                else:
                    if v["txid"] not in self.acked_spends:
                        try:
                            tx = self.get_signed_cancel_tx(v).serialize().hex()
                            if tx is not None:
                                self.bitcoind.sendrawtransaction(tx)
                        except bitcoin.rpc.JSONRPCError:
                            # Already sent!
                            pass
                        # FIXME wait for it to be mined ?

            # These were unvaulted
            if len(spent_vaults) > 0:
                self.vaults_lock.acquire()
                self.vaults = [v for v in self.vaults if v not in spent_vaults]
                self.vaults_lock.release()

            for utxo in new_vaults:
                self.vaults_lock.acquire()
                self.add_new_vault(utxo)
                self.vaults_lock.release()
                # Do a new bunch of watchonly imports if we get closer to
                # the maximum index we originally derived.
                # FIXME: This doesn't take address reuse into account
                self.current_index += 1
                self.max_index += 1
                if self.current_index > self.index_treshold - 20:
                    self.update_watched_addresses()

            # If we had new coins, restart the transactions signatures fetcher
            # with the updated list of vaults.
            if len(new_vaults) > 0:
                self.update_sigs_stop.set()
                try:
                    self.update_sigs_thread.join()
                except RuntimeError:
                    # Already dead
                    pass
                self.update_sigs_stop.clear()
                del self.update_sigs_thread
                self.update_sigs_thread = \
                    threading.Thread(target=self.update_all_signatures,
                                     daemon=True)
                self.update_sigs_thread.start()
Exemple #20
0
def getnewaddress_command(args):
    fund_addr = CBitcoinAddress.from_scriptPubKey(args.wallet.make_paytopubkeyhash())
    args.wallet.save()
    print('Pay to %s to fund your wallet' % fund_addr)
Exemple #21
0
 def get_vault_address(self, index):
     """Get the vault address for index {index}"""
     pubkeys = self.get_pubkeys(index)
     txo = vault_txout(pubkeys, 0)
     return str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey))
Exemple #22
0
    def __init__(self,
                 xpriv,
                 xpubs,
                 emergency_pubkeys,
                 bitcoin_conf_path,
                 cosigning_url,
                 sigserver_url,
                 acked_addresses,
                 current_index=0,
                 birthdate=None):
        """
        We need the xpub of all the other stakeholders to derive their pubkeys.

        :param xpriv: Who am I ? Has to correspond to one of the following
                      xpub. As str.
        :param xpubs: A list of the xpub of all the stakeholders (as str), in
                      the following order: 1) first trader 2) second trader
                      3) first "normie" stakeholder 4) second "normie"
                      stakeholder.
        :param emergency_pubkeys: A list of the four offline keys of the
                                  stakeholders, as bytes.
        :param bitcoin_conf_path: Path to bitcoin.conf.
        :param cosigning_url: The url of the cosigning server.
        :param sigserver_url: The url of the server to post / get the sigs from
                              other stakeholders.
        :param acked_addresses: Addresses to which we accept to spend.
        :param birthdate: The timestamp at which this wallet has been created.
                          If not passed, will assume newly-created wallet.
        """
        assert len(xpubs) == 4
        self.our_bip32 = BIP32.from_xpriv(xpriv)
        self.keychains = []
        for xpub in xpubs:
            if xpub != self.our_bip32.get_master_xpub():
                self.keychains.append(BIP32.from_xpub(xpub))
            else:
                self.keychains.append(None)
        self.all_xpubs = xpubs
        self.emergency_pubkeys = emergency_pubkeys
        # Ok, shitload of indexes. The current one is the lower bound of the
        # range we will import to bitcoind as watchonly. The max one is the
        # upper bond, the current "gen" one is to generate new addresses.
        self.current_index = current_index
        self.current_gen_index = self.current_index
        self.max_index = current_index + 500
        self.index_treshold = self.max_index

        self.birthdate = int(time.time()) if birthdate is None else birthdate

        self.bitcoind = BitcoindApi(bitcoin_conf_path)

        # First of all, watch the emergency vault
        self.watch_emergency_vault()
        # And store the corresponding address..
        txo = emergency_txout(self.emergency_pubkeys, 0)
        self.emergency_address = str(
            CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey))

        # The cosigning server, asked for its signature for the spend_tx
        self.cosigner = CosigningApi(cosigning_url)
        self.cosigner_pubkey = self.cosigner.get_pubkey()

        # The "sig" server, used to store and exchange signatures between
        # vaults and which provides us a feerate.
        # Who am I ?
        stk_id = self.keychains.index(None) + 1
        self.sigserver = ServerApi(sigserver_url, stk_id)

        self.vault_addresses = []
        self.unvault_addresses = []
        self.update_watched_addresses()

        # We keep track of each vault, see below when we fill it for details
        # about what it contains. Basically all the transactions, the
        # signatures and some useful fields (like "are all txs signed ?").
        self.vaults = []
        self.vaults_lock = threading.Lock()

        # Poll for funds until we die
        self.funds_poller_stop = threading.Event()
        self.funds_poller = threading.Thread(target=self.poll_for_funds,
                                             daemon=True)
        self.funds_poller.start()

        # Poll for spends until we die
        self.acked_addresses = acked_addresses
        self.acked_spends = []
        self.spends_poller_stop = threading.Event()
        self.spends_poller = threading.Thread(target=self.poll_for_spends,
                                              daemon=True)
        self.spends_poller.start()

        # Don't start polling for signatures just yet, we don't have any vault!
        self.update_sigs_stop = threading.Event()
        self.update_sigs_thread =\
            threading.Thread(target=self.update_all_signatures, daemon=True)

        self.stopped = False
Exemple #23
0
def make_addresses():
    # Or just hardcode it ; hwi ; m/10141'/0' ; m/84'/1'/0'/0/0
    seckey = CBitcoinSecret(
        'cTqr6cjXsev49PWpHXctTbutZQg5kpTWoGZy8z3yZ7jYgmgKYVFo')

    witver = 0
    print("wif", seckey)
    print("pubk", b2x(seckey.pub))
    print("")

    # https://en.bitcoin.it/wiki/IP_transaction
    # https://en.bitcoin.it/wiki/Script#Obsolete_pay-to-pubkey_transaction
    script = CScript([seckey.pub, OP_CHECKSIG])
    # p2pk = CBitcoinAddress.from_scriptPubKey(script) # not recognized Issue a PR

    # https://en.bitcoin.it/wiki/Transaction#Pay-to-PubkeyHash
    script = CScript(
        [OP_DUP, OP_HASH160,
         Hash160(seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG])
    p2pk = p2pkh = CBitcoinAddress.from_scriptPubKey(script)

    print("p2pk", p2pk)
    print("p2pkh", p2pkh)

    # https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki#specification
    redeemScript = CScript([seckey.pub, OP_CHECKSIG])
    script = CScript([OP_HASH160, Hash160(redeemScript), OP_EQUAL])
    print("p2sh", CBitcoinAddress.from_scriptPubKey(script))
    p2sh_redeemScript = " ".join(deserialize([b2x(redeemScript)], [0]))

    # https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh
    script = CScript([OP_0, Hash160(seckey.pub)])
    print("p2wpkh", CBitcoinAddress.from_scriptPubKey(script))

    # https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh
    witnessScript = CScript([seckey.pub, OP_CHECKSIG])
    script = CScript([OP_0, Sha256(witnessScript)])
    print("p2wsh", CBitcoinAddress.from_scriptPubKey(script))
    p2wsh_witnessScript = " ".join(deserialize([b2x(witnessScript)], [0]))

    # https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh-nested-in-bip16-p2sh
    redeemScript = CScript([OP_0, Hash160(seckey.pub)])
    script = CScript([OP_HASH160, Hash160(redeemScript), OP_EQUAL])
    print("p2sh-p2wpkh", CBitcoinAddress.from_scriptPubKey(script))
    p2sh_p2wpkh_redeemScript = " ".join(deserialize([b2x(redeemScript)], [0]))

    # https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh-nested-in-bip16-p2sh
    witnessScript = CScript([seckey.pub, OP_CHECKSIG])
    redeemScript = CScript([OP_0, Sha256(witnessScript)])
    script = CScript([OP_HASH160, Hash160(redeemScript), OP_EQUAL])
    print("p2sh-p2wsh", CBitcoinAddress.from_scriptPubKey(script))

    print("", )
    print("p2sh_redeemScript", p2sh_redeemScript)
    print("p2wsh_witnessScript", p2wsh_witnessScript)
    print("p2sh_p2wpkh_redeemScript", p2sh_p2wpkh_redeemScript)

    print("p2sh_p2wsh_witnessScript",
          " ".join(deserialize([b2x(witnessScript)], [0])))
    print("p2sh_p2wsh_redeemScript",
          " ".join(deserialize([b2x(redeemScript)], [0])))
Exemple #24
0
 def watch_emergency_vault(self):
     """There is only one emergency script"""
     script = emergency_txout(self.emergency_pubkeys, COIN).scriptPubKey
     addr = CBitcoinAddress.from_scriptPubKey(script)
     self.bitcoind.importaddress(str(addr), "revault_emergency")
Exemple #25
0
    def __init__(
        self,
        network,
        contract: str,
        raw_transaction: Optional[str]=None,
        transaction_address: Optional[str]=None
    ):

        if not raw_transaction and not transaction_address:
            raise ValueError('Provide raw_transaction or transaction_address argument.')

        self.network = network
        self.symbol = self.network.default_symbol
        self.contract = contract
        self.tx = None
        self.vout = None
        self.confirmations = None
        self.tx_address = transaction_address
        if raw_transaction:
            self.tx = self.network.deserialize_raw_transaction(raw_transaction)
            try:
                self.vout = self.tx.vout[0]
            except IndexError:
                raise ValueError('Given transaction has no outputs.')
        else:
            tx_json = get_transaction(network.default_symbol, transaction_address, network.is_test_network())
            if not tx_json:
                raise ValueError('No transaction found under given address.')
            if 'hex' in tx_json:
                # transaction from blockcypher or raven explorer
                self.tx = self.network.deserialize_raw_transaction(tx_json['hex'])
                self.vout = self.tx.vout[0]
            else:
                # transaction from cryptoid
                incorrect_cscript = script.CScript.fromhex(tx_json['outputs'][0]['script'])
                correct_cscript = script.CScript([script.OP_HASH160, list(incorrect_cscript)[2], script.OP_EQUAL])
                nValue = to_base_units(tx_json['outputs'][0]['amount'])
                self.vout = CTxOut(nValue, correct_cscript)

            if 'confirmations' in tx_json:
                self.confirmations = tx_json['confirmations']
            elif 'block_height' in tx_json:
                self.confirmations = self.network.latest_block - tx_json['block_height']
            elif 'block' in tx_json:
                self.confirmations = self.network.latest_block - tx_json['block']

        if not self.vout:
            raise ValueError('Given transaction has no outputs.')

        contract_tx_out = self.vout
        contract_script = script.CScript.fromhex(self.contract)
        script_pub_key = contract_script.to_p2sh_scriptPubKey()
        valid_p2sh = script_pub_key == contract_tx_out.scriptPubKey
        self.address = str(CBitcoinAddress.from_scriptPubKey(script_pub_key))
        self.balance = get_balance(self.network, self.address)

        script_ops = list(contract_script)
        if valid_p2sh and self.is_valid_contract_script(script_ops):
            self.recipient_address = str(P2PKHBitcoinAddress.from_bytes(script_ops[6]))
            self.refund_address = str(P2PKHBitcoinAddress.from_bytes(script_ops[13]))
            self.locktime_timestamp = int.from_bytes(script_ops[8], byteorder='little')
            self.locktime = datetime.utcfromtimestamp(self.locktime_timestamp)
            self.secret_hash = b2x(script_ops[2])
            self.value = from_base_units(contract_tx_out.nValue)
        else:
            raise ValueError('Given transaction is not a valid contract.')
# wouldn't conflict with the old one and you'd pay everyone twice!
tx2.vin = tx2.vin[0:1]

if not args.first_seen_safe and len(tx2.vout) > 0:
    # Delete the change output.
    #
    # Unfortunately there isn't any way to ask Bitcoin Core if a given address
    # is a change address; if you're sending yourself funds to test the feature
    # it's not possible to distinguish change from send-to-self outputs.
    #
    # So instead we always build transactions such that the first output is
    # change, and we delete only that output. Not pretty - you don't want to do
    # something that dumb and anti-privacy in a real wallet - but without a way
    # of keeping state this is the best we've got.
    try:
        addr = CBitcoinAddress.from_scriptPubKey(tx2.vout[0].scriptPubKey)
    except ValueError:
        pass
    else:
        # There is an edge case not handled: if we have multiple outputs but
        # didn't need a change output. But whatever, this is just a demo!
        if len(tx2.vout) > 1 and rpc.validateaddress(addr)['ismine']:
            tx2.vout = tx2.vout[1:]


# Add the new output
payment_txout = CMutableTxOut(args.amount, args.address.to_scriptPubKey())
tx2.vout.append(payment_txout)

r = rpc.fundrawtransaction(tx2)
tx2 = CMutableTransaction.from_tx(r['tx'])
Exemple #27
0
seckey_multisig = CBitcoinSecret.from_secret_bytes(os.urandom(32))
pubkey_multisig = seckey_multisig.pub

# Create script.
multisig_script = [
    OP_2, pubkey_multisig, pubkey_single, OP_2, OP_CHECKMULTISIG
]

# Sign message "1" with seckey_single and prepend to script.
HASH_ONE = b"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
sig = seckey_single.sign(HASH_ONE) + bytes([SIGHASH_SINGLE])
redeemScript = CScript([sig] + multisig_script)

# Create address from redeem script.
address = CBitcoinAddress.from_scriptPubKey(
    redeemScript.to_p2sh_scriptPubKey())
print("Burn address:", address)

# Connect to bitcoind.
bitcoin_rpc = rpc.RawProxy()
try:
    info = bitcoin_rpc.getinfo()
    if info['blocks'] > 3000:
        print("Coinbase reward not large enough to proceed. Exiting. \
               Consider cleaning your datadir (usually ~/.bitcoin/regtest)")
        exit(1)
except Exception as e:
    print(
        "There are problems with the rpc connection to bitcoind (is it running?). \
           Exception: %s" % str(e))
    exit(1)
try:
    rpc.gettransaction(args.txid)
except IndexError as err:
    parser.exit('Invalid txid: Not in wallet.')

txinfo = rpc.getrawtransaction(args.txid, True)
tx = CMutableTransaction.from_tx(txinfo['tx'])

if 'confirmations' in txinfo and txinfo['confirmations'] > 0:
    parser.exit("Transaction already mined; %d confirmations." % txinfo['confirmations'])

# Find a txout that was being used for change
change_txout = None
for vout in tx.vout:
    try:
        addr = CBitcoinAddress.from_scriptPubKey(vout.scriptPubKey)
    except ValueError:
        continue

    if rpc.validateaddress(addr)['ismine']:
        change_txout = vout
        break

if change_txout is None:
    # No suitable change txout; no txout was an address in our wallet.
    #
    # Create a new txout for use as change.
    addr = rpc.getrawchangeaddress()
    change_txout = CMutableTxOut(0, addr.to_scriptPubKey())
    tx.vout.append(change_txout)
Exemple #29
0
    rpc.gettransaction(args.txid)
except IndexError as err:
    parser.exit('Invalid txid: Not in wallet.')

txinfo = rpc.getrawtransaction(args.txid, True)
tx = CMutableTransaction.from_tx(txinfo['tx'])

if 'confirmations' in txinfo and txinfo['confirmations'] > 0:
    parser.exit("Transaction already mined; %d confirmations." %
                txinfo['confirmations'])

# Find a txout that was being used for change
change_txout = None
for vout in tx.vout:
    try:
        addr = CBitcoinAddress.from_scriptPubKey(vout.scriptPubKey)
    except ValueError:
        continue

    if rpc.validateaddress(addr)['ismine']:
        change_txout = vout
        break

if change_txout is None:
    # No suitable change txout; no txout was an address in our wallet.
    #
    # Create a new txout for use as change.
    addr = rpc.getrawchangeaddress()
    change_txout = CMutableTxOut(0, addr.to_scriptPubKey())
    tx.vout.append(change_txout)
Exemple #30
0
 def get_address_from_script(self, script):
     address = CBitcoinAddress.from_scriptPubKey(CScript(script))
     return address
Exemple #31
0
def build_2_of_3(pubkeys):
    txin_redeemScript = CScript([2, x(pubkeys[0]), x(pubkeys[1]), x(pubkeys[2]), 3, OP_CHECKMULTISIG])
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
    return (b2x(txin_redeemScript), str(txin_p2sh_address))
Exemple #32
0
def test_unvault_txout(bitcoind):
    """Test that unvault_txout() produces a valid and conform txo.

    Note that we use python-bitcoinlib for this one, as
    signrawtransactionwithkey is (apparently?) not happy dealing with exotic
    scripts.
    Note also that bitcoinlib's API uses sats, while bitcoind's one uses BTC..
    """
    amount = 50 * COIN - 500
    # The stakeholders
    stk_privkeys = [CKey(os.urandom(32)) for i in range(4)]
    stk_pubkeys = [k.pub for k in stk_privkeys]
    # The cosigning server
    serv_privkey = CKey(os.urandom(32))
    # First, pay to the unvault tx script
    txo = unvault_txout(stk_pubkeys,
                        serv_privkey.pub, amount)
    txo_addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey))
    amount_for_bitcoind = float(Decimal(amount) / Decimal(COIN))
    txid = bitcoind.pay_to(txo_addr, amount_for_bitcoind)
    # We can spend it immediately if all stakeholders sign (emergency or cancel
    # tx)
    txin = CTxIn(COutPoint(lx(txid), 0))
    amount_min_fees = amount - 500
    addr = bitcoind.getnewaddress()
    new_txo = CTxOut(amount_min_fees,
                     CBitcoinAddress(addr).to_scriptPubKey())
    tx = CMutableTransaction([txin], [new_txo], nVersion=2)
    # We can't test the signing against bitcoind, but we can at least test the
    # transaction format
    bitcoind_tx = bitcoind.rpc.createrawtransaction([
        {"txid": txid, "vout": 0}
    ], [
        {addr: float(Decimal(amount_min_fees) / Decimal(COIN))}
    ])
    assert b2x(tx.serialize()) == bitcoind_tx
    tx_hash = SignatureHash(unvault_script(*stk_pubkeys, serv_privkey.pub), tx,
                            0, SIGHASH_ALL, amount, SIGVERSION_WITNESS_V0)
    sigs = [key.sign(tx_hash) + bytes([SIGHASH_ALL])
            for key in stk_privkeys[::-1]]  # Note the reverse here
    witness_script = [*sigs,
                      unvault_script(*stk_pubkeys, serv_privkey.pub)]
    witness = CTxInWitness(CScriptWitness(witness_script))
    tx.wit = CTxWitness([witness])
    bitcoind.send_tx(b2x(tx.serialize()))
    assert bitcoind.has_utxo(addr)

    # If two out of three stakeholders sign, we need the signature from the
    # cosicosigning server and we can't spend it before 6 blocks (csv).
    # Pay back to the unvault tx script
    txo = unvault_txout(stk_pubkeys,
                        serv_privkey.pub, amount)
    txo_addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey))
    txid = bitcoind.pay_to(txo_addr, amount_for_bitcoind)
    # Reconstruct the transaction but with only two stakeholders signatures
    txin = CTxIn(COutPoint(lx(txid), 0), nSequence=6)
    amount_min_fees = amount - 500
    addr = bitcoind.getnewaddress()
    new_txo = CTxOut(amount_min_fees,
                     CBitcoinAddress(addr).to_scriptPubKey())
    tx = CMutableTransaction([txin], [new_txo], nVersion=2)
    # We can't test the signing against bitcoind, but we can at least test the
    # transaction format
    bitcoind_tx = bitcoind.rpc.createrawtransaction([
        {"txid": txid, "vout": 0, "sequence": 6}
    ], [
        {addr: float(Decimal(amount_min_fees) / Decimal(COIN))}
    ])
    assert b2x(tx.serialize()) == bitcoind_tx
    tx_hash = SignatureHash(unvault_script(*stk_pubkeys, serv_privkey.pub), tx,
                            0, SIGHASH_ALL, amount, SIGVERSION_WITNESS_V0)
    # The cosigning server
    sigs = [serv_privkey.sign(tx_hash) + bytes([SIGHASH_ALL])]
    # We fail the third CHECKSIG !!
    sigs += [empty_signature()]
    sigs += [key.sign(tx_hash) + bytes([SIGHASH_ALL])
             for key in stk_privkeys[::-1][2:]]  # Just the first two
    witness_script = [*sigs,
                      unvault_script(*stk_pubkeys, serv_privkey.pub)]
    witness = CTxInWitness(CScriptWitness(witness_script))
    tx.wit = CTxWitness([witness])
    # Relative locktime !
    for i in range(5):
        with pytest.raises(VerifyRejectedError, match="non-BIP68-final"):
            bitcoind.send_tx(b2x(tx.serialize()))
        bitcoind.generate_block(1)
    # It's been 6 blocks now
    bitcoind.send_tx(b2x(tx.serialize()))
    assert bitcoind.has_utxo(addr)
# wouldn't conflict with the old one and you'd pay everyone twice!
tx2.vin = tx2.vin[0:1]

if not args.first_seen_safe and len(tx2.vout) > 0:
    # Delete the change output.
    #
    # Unfortunately there isn't any way to ask Bitcoin Core if a given address
    # is a change address; if you're sending yourself funds to test the feature
    # it's not possible to distinguish change from send-to-self outputs.
    #
    # So instead we always build transactions such that the first output is
    # change, and we delete only that output. Not pretty - you don't want to do
    # something that dumb and anti-privacy in a real wallet - but without a way
    # of keeping state this is the best we've got.
    try:
        addr = CBitcoinAddress.from_scriptPubKey(tx2.vout[0].scriptPubKey)
    except ValueError:
        pass
    else:
        # There is an edge case not handled: if we have multiple outputs but
        # didn't need a change output. But whatever, this is just a demo!
        if len(tx2.vout) > 1 and rpc.validateaddress(addr)['ismine']:
            tx2.vout = tx2.vout[1:]

# Add the new output
payment_txout = CMutableTxOut(args.amount, args.address.to_scriptPubKey())
tx2.vout.append(payment_txout)

r = rpc.fundrawtransaction(tx2)
tx2 = CMutableTransaction.from_tx(r['tx'])
tx2_fee = r['fee']
Exemple #34
0
def build_mandatory_multisig(mandatory_pubkey, other_pubkeys):
    txin_redeemScript = CScript([x(mandatory_pubkey), OP_CHECKSIGVERIFY, 1, x(other_pubkeys[0]), x(other_pubkeys[1]), 2, OP_CHECKMULTISIG])
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
    return (b2x(txin_redeemScript), str(txin_p2sh_address))
Exemple #35
0
    def dataReceived(self, data):
        self.buffer += data
        header = MsgHeader.from_bytes(self.buffer)
        if len(self.buffer) < header.msglen + 24:
            return
        try:
            stream = BytesIO(self.buffer)
            m = MsgSerializable.stream_deserialize(stream)
            self.buffer = stream.read()

            if m.command == "verack":
                self.timeouts["verack"].cancel()
                del self.timeouts["verack"]
                if "version" not in self.timeouts:
                    self.on_handshake_complete()

            elif m.command == "version":
                self.version = m
                if m.nVersion < 70001 or m.nServices != 1:
                    self.transport.loseConnection()
                self.timeouts["version"].cancel()
                del self.timeouts["version"]
                msg_verack().stream_serialize(self.transport)
                if self.blockchain is not None:
                    self.to_download = self.version.nStartingHeight - self.blockchain.get_height()
                if "verack" not in self.timeouts:
                    self.on_handshake_complete()

            elif m.command == "getdata":
                for item in m.inv:
                    if item.hash in self.inventory and item.type == 1:
                        transaction = msg_tx()
                        transaction.tx = self.inventory[item.hash]
                        transaction.stream_serialize(self.transport)

            elif m.command == "inv":
                for item in m.inv:
                    # This is either an announcement of tx we broadcast ourselves or a tx we have already downloaded.
                    # In either case we only need to callback here.
                    if item.type == 1 and item.hash in self.subscriptions:
                        self.subscriptions[item.hash]["callback"](item.hash)

                    # This is the first time we are seeing this txid. Let's download it and check to see if it sends
                    # coins to any addresses in our subscriptions.
                    elif item.type == 1 and item.hash not in self.inventory:
                        self.timeouts[item.hash] = reactor.callLater(5, self.response_timeout, item.hash)

                        cinv = CInv()
                        cinv.type = 1
                        cinv.hash = item.hash

                        getdata_packet = msg_getdata()
                        getdata_packet.inv.append(cinv)

                        getdata_packet.stream_serialize(self.transport)

                    # The peer announced a new block. Unlike txs, we should download it, even if we've previously
                    # downloaded it from another peer, to make sure it doesn't contain any txs we didn't know about.
                    elif item.type == 2 or item.type == 3:
                        if self.state == State.DOWNLOADING:
                            self.download_tracker[0] += 1
                        cinv = CInv()
                        cinv.type = 3
                        cinv.hash = item.hash

                        getdata_packet = msg_getdata()
                        getdata_packet.inv.append(cinv)

                        getdata_packet.stream_serialize(self.transport)

                    if self.state != State.DOWNLOADING:
                        self.log.debug("Peer %s:%s announced new %s %s" % (self.transport.getPeer().host, self.transport.getPeer().port, CInv.typemap[item.type], b2lx(item.hash)))

            elif m.command == "tx":
                if m.tx.GetHash() in self.timeouts:
                    self.timeouts[m.tx.GetHash()].cancel()
                for out in m.tx.vout:
                    try:
                        addr = str(CBitcoinAddress.from_scriptPubKey(out.scriptPubKey))
                    except Exception:
                        addr = None

                    if addr in self.subscriptions:
                        if m.tx.GetHash() not in self.subscriptions:
                            # It's possible the first time we are hearing about this tx is following block
                            # inclusion. If this is the case, let's make sure we include the correct number
                            # of confirmations.
                            in_blocks = self.inventory[m.tx.GetHash()] if m.tx.GetHash() in self.inventory else []
                            confirms = []
                            if len(in_blocks) > 0:
                                for block in in_blocks:
                                    confirms.append(self.blockchain.get_confirmations(block))
                            self.subscriptions[m.tx.GetHash()] = {
                                "announced": 0,
                                "ann_threshold": self.subscriptions[addr][0],
                                "confirmations": max(confirms) if len(confirms) > 0 else 0,
                                "last_confirmation": 0,
                                "callback": self.subscriptions[addr][1],
                                "in_blocks": in_blocks,
                                "tx": m.tx
                            }
                            self.subscriptions[addr][1](m.tx.GetHash())
                        if m.tx.GetHash() in self.inventory:
                            del self.inventory[m.tx.GetHash()]

            elif m.command == "merkleblock":
                if self.blockchain is not None:
                    self.blockchain.process_block(m.block)
                    if self.state != State.DOWNLOADING:
                        self.blockchain.save()
                    # check for block inclusion of subscribed txs
                    for match in m.block.get_matched_txs():
                        if match in self.subscriptions:
                            self.subscriptions[match]["in_blocks"].append(m.block.GetHash())
                        else:
                            # stick the hash here in case this is the first we are hearing about this tx.
                            # when the tx comes over the wire after this block, we will append this hash.
                            self.inventory[match] = [m.block.GetHash()]
                    # run through subscriptions and callback with updated confirmations
                    for txid in self.subscriptions:
                        try:
                            confirms = []
                            for block in self.subscriptions[txid]["in_blocks"]:
                                confirms.append(self.blockchain.get_confirmations(block))
                            self.subscriptions[txid]["confirmations"] = max(confirms)
                            self.subscriptions[txid]["callback"](txid)
                        except Exception:
                            pass

                    # If we are in the middle of an initial chain download, let's check to see if we have
                    # either reached the end of the download or if we need to loop back around and make
                    # another get_blocks call.
                    if self.state == State.DOWNLOADING:
                        self.download_count += 1
                        percent = int((self.download_count / float(self.to_download))*100)
                        if self.download_listener is not None:
                            self.download_listener.progress(percent, self.download_count)
                            self.download_listener.on_block_downloaded((self.transport.getPeer().host, self.transport.getPeer().port), header, self.to_download - self.download_count + 1)
                        if percent == 100:
                            if self.download_listener is not None:
                                self.download_listener.download_complete()
                            self.log.info("Chain download 100% complete")
                        self.download_tracker[1] += 1
                        # We've downloaded every block in the inv packet and still have more to go.
                        if (self.download_tracker[0] == self.download_tracker[1] and
                           self.blockchain.get_height() < self.version.nStartingHeight):
                            if self.timeouts["download"].active():
                                self.timeouts["download"].cancel()
                            self.download_blocks(self.callbacks["download"])
                        # We've downloaded everything so let's callback to the client.
                        elif self.blockchain.get_height() >= self.version.nStartingHeight:
                            self.blockchain.save()
                            self.state = State.CONNECTED
                            self.callbacks["download"]()
                            if self.timeouts["download"].active():
                                self.timeouts["download"].cancel()

            elif m.command == "headers":
                if self.timeouts["download"].active():
                    self.timeouts["download"].cancel()
                for header in m.headers:
                    # If this node sent a block with no parent then disconnect from it and callback
                    # on client.check_for_more_blocks.
                    if self.blockchain.process_block(header) is None:
                        self.blockchain.save()
                        self.callbacks["download"]()
                        self.transport.loseConnection()
                        return
                    self.download_count += 1
                    percent = int((self.download_count / float(self.to_download))*100)
                    if self.download_listener is not None:
                        self.download_listener.progress(percent, self.download_count)
                        self.download_listener.on_block_downloaded((self.transport.getPeer().host, self.transport.getPeer().port), header, self.to_download - self.download_count + 1)
                    if percent == 100:
                        if self.download_listener is not None:
                            self.download_listener.download_complete()
                        self.log.info("Chain download 100% complete")
                # The headers message only comes in batches of 500 blocks. If we still have more blocks to download
                # loop back around and call get_headers again.
                if self.blockchain.get_height() < self.version.nStartingHeight:
                    self.download_blocks(self.callbacks["download"])
                else:
                    self.blockchain.save()
                    self.callbacks["download"]()
                    self.state = State.CONNECTED

            elif m.command == "ping":
                msg_pong(nonce=m.nonce).stream_serialize(self.transport)

            else:
                self.log.debug("Received message %s from %s:%s" % (m.command, self.transport.getPeer().host, self.transport.getPeer().port))

            if len(self.buffer) >= 24: self.dataReceived("")
        except Exception:
            traceback.print_exc()
Exemple #36
0
seckey = CBitcoinSecret.from_secret_bytes(h)

# Create a redeemScript. Similar to a scriptPubKey the redeemScript must be
# satisfied for the funds to be spent.
txin_redeemScript = CScript([seckey.pub, OP_CHECKSIG])
print(b2x(txin_redeemScript))

# Create the magic P2SH scriptPubKey format from that redeemScript. You should
# look at the CScript.to_p2sh_scriptPubKey() function in bitcoin.core.script to
# understand what's happening, as well as read BIP16:
# https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()

# Convert the P2SH scriptPubKey to a base58 Bitcoin address and print it.
# You'll need to send some funds to it to create a txout to spend.
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
print('Pay to:',str(txin_p2sh_address))

# Same as the txid:vout the createrawtransaction RPC call requires
#
# lx() takes *little-endian* hex and converts it to bytes; in Bitcoin
# transaction hashes are shown little-endian rather than the usual big-endian.
# There's also a corresponding x() convenience function that takes big-endian
# hex and converts it to bytes.
txid = lx('bff785da9f8169f49be92fa95e31f0890c385bfb1bd24d6b94d7900057c617ae')
vout = 0

# Create the txin structure, which includes the outpoint. The scriptSig
# defaults to being empty.
txin = CMutableTxIn(COutPoint(txid, vout))
Exemple #37
0
    def dataReceived(self, data):
        self.buffer += data
        # if self.buffer.length >= sizeof(message header)
        #   messageHeader := MessageHeader.deserialize(self.buffer)
        #   if messageHeader.payloadLength > someBigNumber
        #     throw DropConnection
        #   if self.buffer.length < messageHeader.payloadLength
        #     return
        try:
            m = MsgSerializable.from_bytes(self.buffer)
            self.buffer = ""
            if m.command == "verack":
                self.timeouts["verack"].cancel()
                del self.timeouts["verack"]
                if "version" not in self.timeouts:
                    self.on_handshake_complete()

            elif m.command == "version":
                self.version = m
                if m.nVersion < 70001:
                    self.transport.loseConnection()
                self.timeouts["version"].cancel()
                del self.timeouts["version"]
                msg_verack().stream_serialize(self.transport)
                if "verack" not in self.timeouts:
                    self.on_handshake_complete()

            elif m.command == "getdata":
                for item in m.inv:
                    if item.hash in self.inventory and item.type == 1:
                        transaction = msg_tx()
                        transaction.tx = self.inventory[item.hash]
                        transaction.stream_serialize(self.transport)

            elif m.command == "inv":
                for item in m.inv:
                    # callback tx
                    if item.type == 1 and item.hash in self.subscriptions:
                        self.subscriptions[item.hash]["callback"](item.hash)

                    # download tx and check subscription
                    elif item.type == 1 and item.hash not in self.inventory:
                        self.timeouts[item.hash] = reactor.callLater(5, self.response_timeout, item.hash)

                        cinv = CInv()
                        cinv.type = 1
                        cinv.hash = item.hash

                        getdata_packet = msg_getdata()
                        getdata_packet.inv.append(cinv)

                        getdata_packet.stream_serialize(self.transport)

                    # download block
                    elif item.type == 2 or item.type == 3:
                        cinv = CInv()
                        cinv.type = 3
                        cinv.hash = item.hash

                        getdata_packet = msg_getdata()
                        getdata_packet.inv.append(cinv)

                        getdata_packet.stream_serialize(self.transport)

                    print "Peer %s:%s announced new %s %s" % (self.transport.getPeer().host, self.transport.getPeer().port, CInv.typemap[item.type], b2lx(item.hash))

            elif m.command == "tx":
                if m.tx.GetHash() in self.timeouts:
                    self.timeouts[m.tx.GetHash()].cancel()
                for out in m.tx.vout:
                    addr = str(CBitcoinAddress.from_scriptPubKey(out.scriptPubKey))
                    if addr in self.subscriptions:
                        if m.tx.GetHash() not in self.subscriptions:
                            self.subscriptions[m.tx.GetHash()] = {
                                "announced": 0,
                                "ann_threshold": self.subscriptions[addr][0],
                                "confirmations": 0,
                                "callback": self.subscriptions[addr][1],
                                "in_blocks": self.inventory[m.tx.GetHash()] if m.tx.GetHash() in self.inventory else [],
                                "tx": m.tx
                            }
                            self.subscriptions[addr][1](m.tx.GetHash())
                        if m.tx.GetHash() in self.inventory:
                            del self.inventory[m.tx.GetHash()]

            elif m.command == "merkleblock":
                self.blockchain.process_block(m.block)
                if self.blockchain is not None:
                    # check for block inclusion of subscribed txs
                    for match in m.block.get_matched_txs():
                        if match in self.subscriptions:
                            self.subscriptions[match]["in_blocks"].append(m.block.GetHash())
                        else:
                            # stick the hash here in case this is a tx we missed on broadcast.
                            # when the tx comes over the wire after this block, we will append this hash.
                            self.inventory[match] = [m.block.GetHash()]
                    # run through subscriptions and callback with updated confirmations
                    for txid in self.subscriptions:
                        if len(txid) == 32:
                            confirms = []
                            for block in self.subscriptions[txid]["in_blocks"]:
                                confirms.append(self.blockchain.get_confirmations(block))
                            self.subscriptions[txid]["confirmations"] = max(confirms)
                            self.subscriptions[txid]["callback"](txid)

            elif m.command == "headers":
                self.timeouts["download"].cancel()
                to_download = self.version.nStartingHeight - self.blockchain.get_height()
                i = 1
                for header in m.headers:
                    self.blockchain.process_block(header)
                    if i % 50 == 0 or int((i / float(to_download))*100) == 100:
                        print "Chain download %s%% complete" % int((i / float(to_download))*100)
                    i += 1
                if self.blockchain.get_height() < self.version.nStartingHeight:
                    self.download_blocks(self.callbacks["download"])
                elif self.callbacks["download"]:
                    self.callbacks["download"]()

            else:
                print "Received message %s from %s:%s" % (m.command, self.transport.getPeer().host, self.transport.getPeer().port)
        except Exception:
            pass