Exemplo n.º 1
0
    def make_unsigned(cls, outpoints, outputs, tx_fee=TRANSACTION_FEE, testnet=False, out_value=None):
        """
        Build an unsigned transaction.

        Args:
            outpoints: A `list` of `dict` objects which contain a txid, vout, value, and scriptPubkey.
            outputs: If a single address the full value of the inputs (minus the tx fee) will be sent there.
                Otherwise it should be a `list` of `dict` objects containing address and value.
            tx_fee: The Bitcoin network fee to be paid on this transaction.
            testnet: Should this transaction be built for testnet?
            out_value: used if you want to specify a specific output value otherwise the full value
                of the inputs (minus the tx fee) will be used.
        """
        # build the inputs from the outpoints object
        SelectParams("testnet" if testnet else "mainnet")
        txins = []
        in_value = 0
        for outpoint in outpoints:
            in_value += outpoint["value"]
            txin = CMutableTxIn(COutPoint(lx(outpoint["txid"]), outpoint["vout"]))
            txin.scriptSig = CScript(x(outpoint["scriptPubKey"]))
            txins.append(txin)

        # build the outputs
        txouts = []
        if isinstance(outputs, list):
            for output in outputs:
                value = output["value"]
                address = output["address"]
                txouts.append(CMutableTxOut(value, CBitcoinAddress(address).to_scriptPubKey()))
        else:
            value = out_value if out_value is not None else (in_value - tx_fee)
            txouts.append(CMutableTxOut(value, CBitcoinAddress(outputs).to_scriptPubKey()))

        # make the transaction
        tx = CMutableTransaction(txins, txouts)

        return BitcoinTransaction(tx)
Exemplo n.º 2
0
def get_unsigned_tx(funding_tx, redeem_script, address, amount,
                    lock_time=0, n_sequence=0, vout=0):
    '''
           Returns a raw transaction and it's signature hash
           that pays to address from funding_tx

           Options:
           vout -> which vout of funding_tx
           nLockTime -> set's transaction locktime
    '''

    # Set P2SH funding tx in little-endian
    fx = lx(funding_tx)

    # nSequence must be any number less than 0xffffffff to enable nLockTime
    txin = CMutableTxIn(COutPoint(fx, vout), nSequence=n_sequence)

    # if(nlock_time != 0):
    #     txin = CMutableTxIn(COutPoint(fx, vout), nSequence=n_sequence)
    # else:
    #     txin = CMutableTxIn(COutPoint(fx, vout))

    # Convert amount to Satoshi's
    amount *= COIN

    # Create the txout to address
    script_pubkey = CBitcoinAddress(address).to_scriptPubKey()
    txout = CMutableTxOut(amount, script_pubkey)

    # Create the unsigned transaction.
    tx = CMutableTransaction([txin], [txout], nLockTime=lock_time)

    # Calculte TX sig hash
    sighash = SignatureHash(CScript(redeem_script), tx, 0, SIGHASH_ALL)


    return (tx.serialize(), sighash)
def generate_multisig_address(redeemscript: str, testnet: bool = False) -> str:
    """
    Generates a P2SH-multisig Bitcoin address from a redeem script

    Args:
        redeemscript: hex-encoded redeem script
                      use generate_multisig_redeem_script to create the redeem script
                      from three compressed public keys
         testnet: Should the address be testnet or mainnet?

    Example:
        TODO
    """

    if testnet:
        bitcoin.SelectParams('testnet')
    else:
        bitcoin.SelectParams('mainnet')

    redeem_script = CScript(x(redeemscript))

    addr = P2SHBitcoinAddress.from_redeemScript(redeem_script)

    return str(addr)
Exemplo n.º 4
0
def make_p2sh_encoding_redeemscript(datachunk, n, pubKey=None, multisig_pubkeys=None, multisig_pubkeys_required=None):
    _logger = logger.getChild('p2sh_encoding')
    assert len(datachunk) <= bitcoinlib.core.script.MAX_SCRIPT_ELEMENT_SIZE

    dataDropScript = [datachunk, bitcoinlib.core.script.OP_DROP] # just drop the data chunk
    cleanupScript = [n, bitcoinlib.core.script.OP_DROP, bitcoinlib.core.script.OP_DEPTH, 0, bitcoinlib.core.script.OP_EQUAL] # unique offset + prevent scriptSig malleability

    if pubKey is not None:
        # a p2pkh script looks like this: {pubkey} OP_CHECKSIGVERIFY
        verifyOwnerScript = [pubKey, bitcoinlib.core.script.OP_CHECKSIGVERIFY]
    elif multisig_pubkeys_required is not None and multisig_pubkeys:
        # a 2-of-3 multisig looks like this:
        #   2 {pubkey1} {pubkey2} {pubkey3} 3 OP_CHECKMULTISIGVERIFY
        multisig_pubkeys_required = int(multisig_pubkeys_required)
        if multisig_pubkeys_required < 2 or multisig_pubkeys_required > 15:
            raise exceptions.TransactionError('invalid multisig pubkeys value')
        verifyOwnerScript = [multisig_pubkeys_required]
        for multisig_pubkey in multisig_pubkeys:
            verifyOwnerScript.append(multisig_pubkey)
        verifyOwnerScript = verifyOwnerScript + [len(multisig_pubkeys), bitcoinlib.core.script.OP_CHECKMULTISIGVERIFY]
    else:
        raise exceptions.TransactionError('Either pubKey or multisig pubKeys must be provided')

    #redeemScript = CScript(datachunk) + CScript(dataDropScript + verifyOwnerScript + cleanupScript)
    redeemScript = CScript(dataDropScript + verifyOwnerScript + cleanupScript)

    _logger.debug('datachunk %s' % (binascii.hexlify(datachunk)))
    _logger.debug('dataDropScript %s (%s)' % (repr(CScript(dataDropScript)), binascii.hexlify(CScript(dataDropScript))))
    _logger.debug('verifyOwnerScript %s (%s)' % (repr(CScript(verifyOwnerScript)), binascii.hexlify(CScript(verifyOwnerScript))))
    _logger.debug('entire redeemScript %s (%s)' % (repr(redeemScript), binascii.hexlify(redeemScript)))

    #scriptSig = CScript([]) + redeemScript  # PUSH(datachunk) + redeemScript
    scriptSig = CScript([redeemScript])
    outputScript = redeemScript.to_p2sh_scriptPubKey()

    _logger.debug('scriptSig %s (%s)' % (repr(scriptSig), binascii.hexlify(scriptSig)))
    _logger.debug('outputScript %s (%s)' % (repr(outputScript), binascii.hexlify(outputScript)))

    # outputScript looks like OP_HASH160 {{ hash160([redeemScript]) }} OP_EQUALVERIFY
    # redeemScript looks like OP_DROP {{ pubkey }} OP_CHECKSIGVERIFY {{ n }} OP_DROP OP_DEPTH 0 OP_EQUAL
    # scriptSig is {{ datachunk }} OP_DROP {{ pubkey }} OP_CHECKSIGVERIFY {{ n }} OP_DROP OP_DEPTH 0 OP_EQUAL
    return scriptSig, redeemScript, outputScript
Exemplo n.º 5
0
# Make a private key with Trezor if you have one
# seckey = get_tz_priv(coin, path)

# Otherwise pull a private key from Core
# seckey = get_core_priv()

# Or just hardcode it
seckey = CBitcoinSecret('cQNjiPwYKMBr2oB3bWzf3rgBsu198xb8Nxxe51k6D3zVTA98L25N')

print("wif", seckey)
print("pubk", b2x(seckey.pub))
expiry = lx(hex(nLockTime).replace('0x', ''))

# Create a redeemScript. Similar to a scriptPubKey the redeemScript must be
# satisfied for the funds to be spent.
txin_redeemScript = CScript(
    [expiry, OP_CHECKLOCKTIMEVERIFY, OP_DROP, seckey.pub, OP_CHECKSIG])
print("redeem", 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
#
Exemplo n.º 6
0
 def deposit_redeemScript(self):
     return CScript([OP_IF] + list(self.exch_scriptPubkey) +
                    [OP_ELSE, self.locktime, OP_NOP2, OP_DROP] +
                    list(self.user_scriptPubKey) + [OP_ENDIF])
Exemplo n.º 7
0
 def T(hex_scriptpubkey, expected_str_address, expected_class):
     scriptPubKey = CScript(x(hex_scriptpubkey))
     addr = CBitcoinAddress.from_scriptPubKey(scriptPubKey)
     self.assertEqual(str(addr), expected_str_address)
     self.assertEqual(addr.__class__, expected_class)
Exemplo n.º 8
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))
    def build_claim_tx(self, txid_hex):
        if self.secret_info["plaintext"] == None:
            raise Exception("We don't know the secret yet.")

        #Create redeem script.
        redeem_script = self.fund_redeem_script(self.their)

        #Convert to p2sh address.
        their_fund_address = self.script_to_address(redeem_script, self.their)

        #Check there is enough in the p2sh address.
        their_fund_tx = self.jsonrpc[self.their].gettransaction(
            txid_hex)["details"]
        found = 0
        for tx_input in their_fund_tx:
            #Check it's the right input.
            if tx_input["address"] == their_fund_address:
                found = 1
                if tx_input["amount"] + self.recv_amount > decimal.Decimal(
                        coinbend.config["mining_fee"]["standard"]):
                    raise Exception(
                        "Their contract has not been sufficently funded.")
                break
            else:
                continue

        #Their side of the contract hasn't been funded.
        if not found:
            raise Exception("Their contract fund output was not detected.")

        #Generate address to receive redeemed output.
        if "receive" not in self.key_pairs:
            self.key_pairs["receive"] = self.key_pair_from_address(
                self.jsonrpc[self.their].getnewaddress(), self.their)

        #Load private key for signing.
        seckey = CBitcoinSecret(self.key_pairs[self.my]["priv"]["wif"])

        #Generate p2sh script pub key.
        redeem_script_hash160 = self.hash160_script(redeem_script)
        txin_script_pub_key = CScript(
            [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL])

        #Setup tx inputs and outputs.
        txid = lx(txid_hex)
        vout = 0
        txin = CTxIn(COutPoint(txid, vout))
        txout = CTxOut(
            (self.recv_amount -
             decimal.Decimal(coinbend.config["mining_fee"]["standard"])) *
            COIN,
            CBitcoinAddress(
                self.key_pairs["receive"]["addr"]["base58"]).to_scriptPubKey())

        #Create unsigned transaction.
        tx = CTransaction([txin], [txout])

        #Sign transactions.
        sighash = SignatureHash(redeem_script["bin"], tx, 0, SIGHASH_ALL)
        sig = seckey.sign(sighash) + bytes([SIGHASH_ALL])
        txin.scriptSig = CScript([
            bytes(self.secret_info["plaintext"].encode("ascii")), sig, OP_3,
            redeem_script["bin"]
        ])

        #Return signed transaction hex.
        return b2x(tx.serialize())
Exemplo n.º 10
0
 def test_from_redeemScript(self):
     addr = P2SHBitcoinAddress.from_redeemScript(CScript())
     self.assertEqual(str(addr), '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
Exemplo n.º 11
0
    def __do_bitcoin(self):
        """Do Bitcoin-related maintenance"""

        # FIXME: we shouldn't have to create a new proxy each time, but with
        # current python-bitcoinlib and the RPC implementation it seems that
        # the proxy connection can timeout w/o recovering properly.
        proxy = bitcoin.rpc.Proxy()

        new_blocks = self.known_blocks.update_from_proxy(proxy)

        for (block_height, block_hash) in new_blocks:
            logging.info("New block %s at height %d" % (b2lx(block_hash), block_height))

            # Save commitments to disk that have reached min_confirmations
            confirmed_tx = self.txs_waiting_for_confirmation.pop(block_height - self.min_confirmations + 1, None)
            if confirmed_tx is not None:
                self.__save_confirmed_timestamp_tx(confirmed_tx)

            # If there already are txs waiting for confirmation at this
            # block_height, there was a reorg and those pending commitments now
            # need to be added back to the pool
            reorged_tx = self.txs_waiting_for_confirmation.pop(block_height, None)
            if reorged_tx is not None:
                # FIXME: the reorged transaction might get mined in another
                # block, so just adding the commitments for it back to the pool
                # isn't ideal, but it is safe
                logging.info('tx %s at height %d removed by reorg, adding %d commitments back to pending' % (b2lx(reorged_tx.tx.GetHash()), block_height, len(reorged_tx.commitment_timestamps)))
                for reorged_commitment_timestamp in reorged_tx.commitment_timestamps:
                    self.pending_commitments.add(reorged_commitment_timestamp.msg)

            # Check if this block contains any of the pending transactions

            try:
                block = proxy.getblock(block_hash)
            except KeyError:
                # Must have been a reorg or something, return
                logging.error("Failed to get block")
                return

            # Check all potential pending txs against this block.
            for unconfirmed_tx in self.unconfirmed_txs:
                block_timestamp = make_timestamp_from_block(unconfirmed_tx.tip_timestamp.msg, block, block_height)

                if block_timestamp is None:
                    continue

                # Success!
                (tip_timestamp, commitment_timestamps) = self.__pending_to_merkle_tree(unconfirmed_tx.n)
                mined_tx = TimestampTx(unconfirmed_tx.tx, tip_timestamp, commitment_timestamps)
                assert tip_timestamp.msg == unconfirmed_tx.tip_timestamp.msg

                mined_tx.tip_timestamp.merge(block_timestamp)

                for commitment in tuple(self.pending_commitments)[0:unconfirmed_tx.n]:
                    self.pending_commitments.remove(commitment)
                    logging.debug("Removed commitment %s from pending" % b2x(commitment))

                assert self.min_confirmations > 1
                logging.info("Success! %d commitments timestamped, now waiting for %d more confirmations" %
                             (len(mined_tx.commitment_timestamps), self.min_confirmations - 1))

                # Add pending_tx to the list of timestamp transactions that
                # have been mined, and are waiting for confirmations.
                self.txs_waiting_for_confirmation[block_height] = mined_tx

                # Since all unconfirmed txs conflict with each other, we can clear the entire lot
                self.unconfirmed_txs.clear()

                # And finally, we can reset the last time a timestamp
                # transaction was mined to right now.
                self.last_timestamp_tx = time.time()

                break


        time_to_next_tx = int(self.last_timestamp_tx + self.min_tx_interval - time.time())
        if time_to_next_tx > 0:
            # Minimum interval between transactions hasn't been reached, so do nothing
            logging.debug("Waiting %ds before next tx" % time_to_next_tx)
            return

        prev_tx = None
        if self.pending_commitments and not self.unconfirmed_txs:
            # Find the biggest unspent output that's confirmed
            unspent = find_unspent(proxy)

            if not len(unspent):
                logging.error("Can't timestamp; no spendable outputs")
                return

            # For the change scriptPubKey, we can save a few bytes by using
            # a pay-to-pubkey rather than the usual pay-to-pubkeyhash
            change_addr = proxy.getnewaddress()
            change_pubkey = proxy.validateaddress(change_addr)['pubkey']
            change_scriptPubKey = CScript([change_pubkey, OP_CHECKSIG])

            prev_tx = self.__create_new_timestamp_tx_template(unspent[-1]['outpoint'], unspent[-1]['amount'], change_scriptPubKey)

            logging.debug('New timestamp tx, spending output %r, value %s' % (unspent[-1]['outpoint'], str_money_value(unspent[-1]['amount'])))

        elif self.unconfirmed_txs:
            assert self.pending_commitments
            (prev_tx, prev_tip_timestamp, prev_commitment_timestamps) = self.unconfirmed_txs[-1]

        # Send the first transaction even if we don't have a new block
        if prev_tx and (new_blocks or not self.unconfirmed_txs):
            (tip_timestamp, commitment_timestamps) = self.__pending_to_merkle_tree(len(self.pending_commitments))

            # make_merkle_tree() seems to take long enough on really big adds
            # that the proxy dies
            proxy = bitcoin.rpc.Proxy()

            sent_tx = None
            relay_feerate = self.relay_feerate
            while sent_tx is None:
                unsigned_tx = self.__update_timestamp_tx(prev_tx, tip_timestamp.msg,
                                                         proxy.getblockcount(), relay_feerate)

                fee = _get_tx_fee(unsigned_tx, proxy)
                if fee is None:
                    logging.debug("Can't determine txfee of transaction; skipping")
                    return
                if fee > self.max_fee:
                    logging.error("Maximum txfee reached!")
                    return

                r = proxy.signrawtransaction(unsigned_tx)
                if not r['complete']:
                    logging.error("Failed to sign transaction! r = %r" % r)
                    return
                signed_tx = r['tx']

                try:
                    txid = proxy.sendrawtransaction(signed_tx)
                except bitcoin.rpc.JSONRPCError as err:
                    if err.error['code'] == -26:
                        logging.debug("Err: %r" % err.error)
                        # Insufficient priority - basically means we didn't
                        # pay enough, so try again with a higher feerate
                        relay_feerate *= 2
                        continue

                    else:
                        raise err  # something else, fail!

                sent_tx = signed_tx

            if self.unconfirmed_txs:
                logging.info("Sent timestamp tx %s, replacing %s; %d total commitments; %d prior tx versions" %
                                (b2lx(sent_tx.GetHash()), b2lx(prev_tx.GetHash()), len(commitment_timestamps), len(self.unconfirmed_txs)))
            else:
                logging.info("Sent timestamp tx %s; %d total commitments" % (b2lx(sent_tx.GetHash()), len(commitment_timestamps)))

            self.unconfirmed_txs.append(UnconfirmedTimestampTx(sent_tx, tip_timestamp, len(commitment_timestamps)))
Exemplo n.º 12
0
def create_txout(amount, scriptPubKey):
    return CMutableTxOut(amount * COIN, CScript(scriptPubKey))
Exemplo n.º 13
0
    def htlc_tx(self, commit_tx: CMutableTransaction, outnum: int, side: Side,
                amount_sat: int, locktime: int) -> CMutableTransaction:
        # BOLT #3:
        # ## HTLC-Timeout and HTLC-Success Transactions
        #
        # These HTLC transactions are almost identical, except the
        # HTLC-timeout transaction is timelocked. Both
        # HTLC-timeout/HTLC-success transactions can be spent by a valid
        # penalty transaction.

        # BOLT #3:
        # ## HTLC-Timeout and HTLC-Success Transactions
        # ...
        # * txin count: 1
        # * `txin[0]` outpoint: `txid` of the commitment transaction and
        #    `output_index` of the matching HTLC output for the HTLC transaction
        # * `txin[0]` sequence: `0`
        # * `txin[0]` script bytes: `0`
        txin = CTxIn(COutPoint(commit_tx.GetTxid(), outnum), nSequence=0x0)

        # BOLT #3:
        # ## HTLC-Timeout and HTLC-Success Transactions
        # ...
        # * txout count: 1
        # * `txout[0]` amount: the HTLC amount minus fees (see [Fee
        #    Calculation](#fee-calculation))
        # * `txout[0]` script: version-0 P2WSH with witness script as shown below
        #
        # The witness script for the output is:
        # OP_IF
        #     # Penalty transaction
        #     <revocationpubkey>
        # OP_ELSE
        #     `to_self_delay`
        #     OP_CHECKSEQUENCEVERIFY
        #     OP_DROP
        #     <local_delayedpubkey>
        # OP_ENDIF
        # OP_CHECKSIG
        redeemscript = script.CScript([
            script.OP_IF,
            self.revocation_pubkey(side).format(), script.OP_ELSE,
            self.self_delay[side], script.OP_CHECKSEQUENCEVERIFY,
            script.OP_DROP,
            self.delayed_pubkey(side).format(), script.OP_ENDIF,
            script.OP_CHECKSIG
        ])
        print("htlc redeemscript = {}".format(redeemscript.hex()))
        txout = CTxOut(amount_sat,
                       CScript([script.OP_0,
                                sha256(redeemscript).digest()]))

        # BOLT #3:
        # ## HTLC-Timeout and HTLC-Success Transactions
        # ...
        # * version: 2
        # * locktime: `0` for HTLC-success, `cltv_expiry` for HTLC-timeout
        return CMutableTransaction(vin=[txin],
                                   vout=[txout],
                                   nVersion=2,
                                   nLockTime=locktime)
Exemplo n.º 14
0
from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret

OP_CHECKSEQUENCEVERIFY = OP_NOP3  #unlike other op-codes, python-bitcoinlib doesn't define OP_CHECKSEQUENCEVERIFY, so I define it myself here

SelectParams('testnet')

# parameterize these
privKeySender = str(sys.argv[1])
addressReceiver = str(sys.argv[2])

secret = CBitcoinSecret(privKeySender)

# per instructor message in the COMP541-01-S-2019 Moodle classroom forum, use '0xc800' (200 blocks) for relative timelock amount
# 0xc800 is calculated as little-endian hex of 200, plus '00' tacked on the end because it's necessary to add sign for values which are less than half a byte, otherwise interpreted as negative
redeem_script = CScript([
    0xc800, OP_CHECKSEQUENCEVERIFY, OP_DROP, OP_DUP, OP_HASH160,
    Hash160(secret.pub), OP_EQUALVERIFY, OP_CHECKSIG
])

txin_scriptPubKey = redeem_script.to_p2sh_scriptPubKey()
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
print('Pay to:', str(txin_p2sh_address))

proxy = bitcoin.rpc.Proxy()

# the below functionality is to be run from cmd line in between send_to_p2sh_timelock.py and this program
# uncomment to run programmatically for testing purposes
# transactionid = proxy.sendtoaddress(str(txin_p2sh_address), 0.0001*COIN)
# print('transaction id: ' + b2lx(transactionid))

# find the set of UTXO transactions that have been sent to the script address
txins = []  # inputs to the spending transaction we will create
Exemplo n.º 15
0
    def _unsigned_tx(
            self,
            side: Side) -> Tuple[CMutableTransaction, List[Optional[HTLC]]]:
        """Create the commitment transaction.

Returns it and a list of matching HTLCs for each output

        """
        ocn = self.obscured_commit_num(
            self.keyset[self.opener].raw_payment_basepoint(),
            self.keyset[not self.opener].raw_payment_basepoint(),
            self.commitnum)

        # BOLT #3:
        # ## Commitment Transaction
        # ...
        # * txin count: 1
        #    * `txin[0]` outpoint: `txid` and `output_index` from `funding_created` message
        #    * `txin[0]` sequence: upper 8 bits are 0x80, lower 24 bits are upper 24 bits of the obscured commitment number
        #    * `txin[0]` script bytes: 0
        #    * `txin[0]` witness: `0 <signature_for_pubkey1> <signature_for_pubkey2>`
        txin = CTxIn(COutPoint(bytes.fromhex(self.funding.txid),
                               self.funding.output_index),
                     nSequence=0x80000000 | (ocn >> 24))

        # txouts, with ctlv_timeouts (for htlc output tiebreak) and htlc
        txouts: List[Tuple[CTxOut, int, Optional[HTLC]]] = []

        for htlc in self.untrimmed_htlcs(side):
            if htlc.owner == side:
                redeemscript, sats = self._offered_htlc_output(htlc, side)
            else:
                redeemscript, sats = self._received_htlc_output(htlc, side)
            print("*** Got htlc redeemscript {} / {}".format(
                redeemscript, redeemscript.hex()))
            txouts.append(
                (CTxOut(sats,
                        CScript([script.OP_0,
                                 sha256(redeemscript).digest()])),
                 htlc.cltv_expiry, htlc))

        num_untrimmed_htlcs = len(txouts)
        fee = self._fee(num_untrimmed_htlcs)

        out_redeemscript, sats = self._to_local_output(fee, side)
        if sats >= self.dust_limit[side]:
            txouts.append((CTxOut(
                sats, CScript([script.OP_0,
                               sha256(out_redeemscript).digest()])), 0, None))

        # BOLT #3:
        # #### `to_remote` Output
        #
        # This output sends funds to the other peer and thus is a simple
        # P2WPKH to `remotepubkey`.
        amount_to_other = self.amounts[not side] // 1000
        if not side == self.opener:
            amount_to_other -= fee

        if amount_to_other >= self.dust_limit[side]:
            txouts.append((CTxOut(
                amount_to_other,
                CScript([
                    script.OP_0,
                    Hash160(self.to_remote_pubkey(side).format())
                ])), 0, None))

        # BOLT #3:
        # ## Transaction Input and Output Ordering
        #
        # Lexicographic ordering: see
        # [BIP69](https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki).
        # In the case of identical HTLC outputs, the outputs are ordered in
        # increasing `cltv_expiry` order.

        # First sort by cltv_expiry
        txouts.sort(key=lambda txout: txout[1])
        # Now sort by BIP69
        txouts.sort(key=lambda txout: txout[0].serialize())

        # BOLT #3:
        # ## Commitment Transaction
        #
        # * version: 2
        # * locktime: upper 8 bits are 0x20, lower 24 bits are the
        #   lower 24 bits of the obscured commitment number
        return (CMutableTransaction(vin=[txin],
                                    vout=[txout[0] for txout in txouts],
                                    nVersion=2,
                                    nLockTime=0x20000000 | (ocn & 0x00FFFFFF)),
                [txout[2] for txout in txouts])
Exemplo n.º 16
0
def create_signed_transaction(txin, txout, txin_scriptPubKey, txin_scriptSig):
    tx = CMutableTransaction([txin], [txout])
    txin.scriptSig = CScript(txin_scriptSig)
    VerifyScript(txin.scriptSig, CScript(txin_scriptPubKey), tx, 0,
                 (SCRIPT_VERIFY_P2SH, ))
    return tx
Exemplo n.º 17
0
def create_OP_CHECKSIG_signature(txin, txout, txin_scriptPubKey, seckey):
    tx = CMutableTransaction([txin], [txout])
    sighash = SignatureHash(CScript(txin_scriptPubKey), tx, 0, SIGHASH_ALL)
    sig = seckey.sign(sighash) + bytes([SIGHASH_ALL])
    return sig
Exemplo n.º 18
0
def sign_BCY(tx, txin_scriptPubKey):
    sighash = SignatureHash(CScript(txin_scriptPubKey), tx, 0, SIGHASH_ALL)
    sig = alice_secret_key_BCY.sign(sighash) + bytes([SIGHASH_ALL])
    return sig
    def build_fund_tx(self, redeem_script):
        if type(self.send_amount) != decimal.Decimal:
            raise Exception("Please only use decimal types for the amount.")
        if self.send_amount < decimal.Decimal(
                coinbend.config["minimum_trade"]):
            raise Exception("Amount is too small.")

        #Because every Satoshi counts.
        decimal.getcontext().prec = 50

        #Create a change address.
        if "change" not in self.key_pairs:
            self.key_pairs["change"] = self.key_pair_from_address(
                self.jsonrpc[self.my].getnewaddress(), self.my)

        #Get wallet balance.
        balance = self.jsonrpc[self.my].getbalance()

        #Check we have enough.
        if balance < self.send_amount:
            raise Exception("Insufficent balance to cover fund.")

        #List unclaimed outputs.
        unspent_outputs = self.jsonrpc[self.my].listunspent()

        #Setup tx inputs.
        change_amount = decimal.Decimal("0")
        txins = []
        total = decimal.Decimal("0")
        indexes = []
        i = 0
        for unspent_output in unspent_outputs:
            #Skip outputs that don't satisfy min confirmations.
            if unspent_output["confirmations"] < self.minimum_confirmations:
                i += 1
                continue

            #Check scriptPubKey is pay to pub key hash.
            if self.jsonrpc[self.my].decodescript(
                    unspent_output["scriptPubKey"])["type"] != "pubkeyhash":
                i += 1
                continue

            #Record key pairs.
            if unspent_output["address"] not in self.key_pairs:
                self.key_pairs[
                    unspent_output["address"]] = self.key_pair_from_address(
                        unspent_output["address"], self.my)

            #Build new txin.
            txid = lx(unspent_output["txid"])
            vout = unspent_output["vout"]
            txin = CTxIn(COutPoint(txid, vout))
            txins.append(txin)
            indexes.append(i)
            total += unspent_output["amount"]
            i += 1

            if total > self.send_amount:
                break

            if total == self.send_amount:
                break

        #Insufficent funds.
        if total < self.send_amount:
            raise Exception("Not enough valid inputs to fund contract.")

        #Calculate change.
        change = total - self.send_amount

        #Build txouts.
        txouts = []
        redeem_script_hash160 = self.hash160_script(redeem_script)
        p2sh_script_pub_key = CScript(
            [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL])
        txouts.append(
            CTxOut(
                (self.send_amount -
                 decimal.Decimal(coinbend.config["mining_fee"]["standard"])) *
                COIN, p2sh_script_pub_key))
        if change > decimal.Decimal("0"):
            change_seckey = CBitcoinSecret(
                self.key_pairs["change"]["priv"]["wif"])
            change_script_pub_key = CScript([
                OP_DUP, OP_HASH160,
                Hash160(change_seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG
            ])
            txouts.append(CTxOut(change * COIN, change_script_pub_key))

        #Build unsigned transaction.
        tx = CTransaction(txins, txouts)
        unsigned_tx_hex = b2x(tx.serialize())

        #Sign transaction.
        signed_tx_hex = self.jsonrpc[self.my].signrawtransaction(
            unsigned_tx_hex)["hex"]
        return signed_tx_hex
Exemplo n.º 20
0
def create_timestamp(timestamp, calendar_urls, args):
    """Create a timestamp

    calendar_urls - List of calendar's to use
    setup_bitcoin - False if Bitcoin timestamp not desired; set to
                    args.setup_bitcoin() otherwise.
    """

    setup_bitcoin = args.setup_bitcoin if args.use_btc_wallet else False
    if setup_bitcoin:
        proxy = setup_bitcoin()

        unfunded_tx = CTransaction(
            [], [CTxOut(0, CScript([OP_RETURN, timestamp.msg]))])
        r = proxy.fundrawtransaction(unfunded_tx)  # FIXME: handle errors
        funded_tx = r['tx']

        r = proxy.signrawtransaction(funded_tx)
        assert r['complete']
        signed_tx = r['tx']

        txid = proxy.sendrawtransaction(signed_tx)
        logging.info('Sent timestamp tx')

        blockhash = None
        while blockhash is None:
            logging.info('Waiting for timestamp tx %s to confirm...' %
                         b2lx(txid))
            time.sleep(1)

            r = proxy.gettransaction(txid)

            if 'blockhash' in r:
                # FIXME: this will break when python-bitcoinlib adds RPC
                # support for gettransaction, due to formatting differences
                blockhash = lx(r['blockhash'])

        logging.info('Confirmed by block %s' % b2lx(blockhash))

        block = proxy.getblock(blockhash)

        r = proxy.getblockheader(blockhash, True)
        blockheight = r['height']

        # We have a block hash! We can now generate the attestation from the block.
        block_timestamp = make_timestamp_from_block(timestamp.msg, block,
                                                    blockheight)
        assert block_timestamp is not None
        timestamp.merge(block_timestamp)

    m = args.m
    n = len(calendar_urls)
    if m > n or m <= 0:
        logging.error(
            "m (%d) cannot be greater than available calendar%s (%d) neither less or equal 0"
            % (m, "" if n == 1 else "s", n))
        sys.exit(1)

    logging.debug("Doing %d-of-%d request, timeout is %d second%s" %
                  (m, n, args.timeout, "" if n == 1 else "s"))

    q = Queue()
    for calendar_url in calendar_urls:
        submit_async(calendar_url, timestamp.msg, q, args.timeout)

    start = time.time()
    merged = 0
    for i in range(n):
        try:
            remaining = max(0, args.timeout - (time.time() - start))
            result = q.get(block=True, timeout=remaining)
            try:
                if isinstance(result, Timestamp):
                    timestamp.merge(result)
                    merged += 1
                else:
                    logging.debug(str(result))
            except Exception as error:
                logging.debug(str(error))

        except Empty:
            # Timeout
            continue

    if merged < m:
        logging.error(
            "Failed to create timestamp: need at least %d attestation%s but received %s within timeout"
            % (m, "" if m == 1 else "s", merged))
        sys.exit(1)
    logging.debug("%.2f seconds elapsed" % (time.time() - start))
Exemplo n.º 21
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))
Exemplo n.º 22
0
from io import BytesIO
from riemann.tests import helpers
from bitcoin.core import CMutableTransaction
from bitcoin.core.script import SIGHASH_ANYONECANPAY, CScript
from bitcoin.core.script import SignatureHash, SIGHASH_ALL, SIGHASH_SINGLE


def parse_tx(hex_tx):
    # NB: The deserialize function reads from a stream.
    raw_tx = BytesIO(binascii.unhexlify(hex_tx))
    tx = CMutableTransaction.stream_deserialize(raw_tx)
    return tx


prevout_pk_script = \
    CScript(helpers.P2WPKH['ser']['ins'][0]['pk_script'])  # bytes
tx_hex = helpers.P2WPKH['ser']['tx']['unsigned'].hex()  # raw hex
index = helpers.P2WPKH['human']['ins'][0]['index']  # integer
a = parse_tx(tx_hex)

int_value = helpers.P2WPKH['human']['ins'][0]['value']  # integer of tx value

print('Sighash All:')
print(
    SignatureHash(prevout_pk_script,
                  a,
                  index,
                  SIGHASH_ALL,
                  sigversion=1,
                  amount=(int_value)).hex())
print('Sighash All, Anyone Can Pay:')
Exemplo n.º 23
0
    def create_signature(self) -> None:
        """Signs a given transaction"""
        # Keys are derived in base.py

        if self.testnet:
            SelectParams('testnet')
        else:
            SelectParams('mainnet')

        # Construct Inputs
        tx_inputs = []
        parsed_redeem_scripts = {}
        for input in self.inputs:
            if input['redeem_script'] not in parsed_redeem_scripts:
                parsed_redeem_scripts[input['redeem_script']] = CScript(
                    bitcoin.core.x(input['redeem_script']))

            txid = bitcoin.core.lx(input['txid'])
            vout = input['index']
            tx_inputs.append(CMutableTxIn(COutPoint(txid, vout)))

        # Construct Outputs
        tx_outputs = []

        for output in self.outputs:
            output_script = (CBitcoinAddress(
                output['address']).to_scriptPubKey())
            tx_outputs.append(CMutableTxOut(output['amount'], output_script))

        # Construct Transaction
        tx = CTransaction(tx_inputs, tx_outputs)

        # Construct data for each signature (1 per input)
        signature_hashes = []
        keys = {}
        for input_index, input in enumerate(self.inputs):
            redeem_script = input['redeem_script']
            bip32_path = input['bip32_path']

            # Signature Hash
            signature_hashes.append(
                SignatureHash(parsed_redeem_scripts[redeem_script], tx,
                              input_index, SIGHASH_ALL))

            # Only need to generate keys once per unique BIP32 path
            if keys.get(bip32_path) is None:
                keys[bip32_path] = self.generate_child_keys(bip32_path)
                keys[bip32_path]['signing_key'] = ecdsa.SigningKey.from_string(
                    bytes.fromhex(keys[bip32_path]['private_key']),
                    curve=ecdsa.SECP256k1)

        # Construct signatures (1 per input)
        #
        # WARNING: We do not append the SIGHASH_ALL byte,
        # transaction constructioin should account for that.
        #
        signatures = []
        for input_index, input in enumerate(self.inputs):
            input = self.inputs[input_index]
            signature_hash = signature_hashes[input_index]
            signing_key = keys[input['bip32_path']]['signing_key']
            signatures.append(
                signing_key.sign_digest_deterministic(
                    signature_hash,
                    sha256,
                    sigencode=ecdsa.util.sigencode_der_canonize).hex())

        # Assign result
        result = {"signatures": signatures}

        self.signature = result
Exemplo n.º 24
0
from bitcoin import SelectParams
from bitcoin.core import b2x, lx, COIN, COutPoint, CMutableTxOut, CMutableTxIn, CMutableTransaction, Hash160
from bitcoin.core.script import CScript, OP_DUP, OP_HASH160, OP_EQUALVERIFY, OP_CHECKSIG, SignatureHash, SIGHASH_ALL
from bitcoin.core.scripteval import VerifyScript, SCRIPT_VERIFY_P2SH
from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret

SelectParams('mainnet')

# Create the (in)famous correct brainwallet secret key.
h = hashlib.sha256(b'correct horse battery staple').digest()
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
#
Exemplo n.º 25
0
 def parse_from_binary(self, script_data):
     self.script = CScript(script_data)
     return self.script
Exemplo n.º 26
0
# proxy.getnewaddress() returns CBitcoinAddress
recipientpubkey = proxy.getnewaddress()
senderpubkey = proxy.getnewaddress()
# privkey of the recipient, used to sign the redeemTx
seckey = proxy.dumpprivkey(senderpubkey)
#proxy.importprivkey(seckey)
lockduration = 10
blocknum = proxy.getblockcount()
print("current block num:", blocknum)
redeemblocknum = blocknum + lockduration
# Create a htlc redeemScript. Similar to a scriptPubKey the redeemScript must be
# satisfied for the funds to be spent.
txin_redeemScript = CScript([
    OP_IF, OP_SHA256, h, OP_EQUALVERIFY, OP_DUP, OP_HASH160, recipientpubkey,
    OP_ELSE, redeemblocknum, OP_CHECKLOCKTIMEVERIFY, OP_DROP, OP_DUP,
    OP_HASH160, senderpubkey, OP_ENDIF, OP_EQUALVERIFY, OP_CHECKSIG
])
print("redeem script:", b2x(txin_redeemScript))

# Create P2SH scriptPubKey from redeemScript.
txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
print("p2sh_scriptPubKey", b2x(txin_scriptPubKey))

# Convert the P2SH scriptPubKey to a base58 Bitcoin address
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
p2sh = str(txin_p2sh_address)
print('Pay to:', p2sh)

# AUTOMATE Send funds to p2sh
amount = 1.0 * COIN
Exemplo n.º 27
0
def parameterize_witness_template_by_signing(some_input, parameters):
    """
    Take a specific witness template, a bag of parameters, and a
    transaction, and then produce a parameterized witness (including all
    necessary valid signatures).

    Make a sighash for the bitcoin transaction.
    """
    p2wsh_redeem_script = some_input.utxo.p2wsh_redeem_script
    tx = some_input.transaction.bitcoin_transaction
    txin_index = some_input.transaction.inputs.index(some_input)

    computed_witness = []

    selection = some_input.witness_template_selection
    script_template = some_input.utxo.script_template
    witness_template = script_template.witness_templates[selection]

    amount = some_input.utxo.amount

    # TODO: Might have to update the witness_templates values to give a
    # correct ordering for which signature should be supplied first.
    # (already did this? Re-check for VerifyScript errors)

    witness_tmp = witness_template.split(" ")
    for (idx, section) in enumerate(witness_tmp):
        if section[0] == "<" and section[-1] == ">":
            section = section[1:-1]
            if section == "user_key":
                computed_witness.append(parameters["user_key"]["public_key"])
                continue
            elif section not in script_template.witness_template_map.keys():
                raise VaultException(
                    "Missing key mapping for {}".format(section))

            key_param_name = script_template.witness_template_map[section]
            private_key = parameters[key_param_name]["private_key"]

            if script_template != UserScriptTemplate:
                # This is a P2WSH transaction.
                redeem_script = p2wsh_redeem_script
            elif script_template == UserScriptTemplate:
                # This is a P2WPKH transaction.
                user_address = P2WPKHBitcoinAddress.from_scriptPubKey(
                    CScript(
                        [OP_0,
                         Hash160(parameters["user_key"]["public_key"])]))
                redeem_script = user_address.to_redeemScript()
                # P2WPKH redeemScript: OP_DUP OP_HASH160 ....

            sighash = SignatureHash(redeem_script,
                                    tx,
                                    txin_index,
                                    SIGHASH_ALL,
                                    amount=amount,
                                    sigversion=SIGVERSION_WITNESS_V0)
            signature = private_key.sign(sighash) + bytes([SIGHASH_ALL])
            computed_witness.append(signature)

        else:
            # dunno what to do with this, probably just pass it on really..
            computed_witness.append(section)

    if script_template == UserScriptTemplate:
        # P2WPKH
        # Witness already completed. No redeem_script to append.
        pass
    else:
        # P2WSH
        # Append the p2wsh redeem script.
        computed_witness.append(p2wsh_redeem_script)

    computed_witness = CScript(computed_witness)
    some_input.witness = computed_witness
    return computed_witness
Exemplo n.º 28
0
# There's also a corresponding x() convenience function that takes big-endian
# hex and converts it to bytes.
txid = lx('7e195aa3de827814f172c362fcf838d92ba10e3f9fdd9c3ecaf79522b311b22d')
vout = 0

# Create the txin structure, which includes the outpoint. The scriptSig
# defaults to being empty.
txin = CMutableTxIn(COutPoint(txid, vout))

# We also need the scriptPubKey of the output we're spending because
# SignatureHash() replaces the transaction scriptSig's with it.
#
# Here we'll create that scriptPubKey from scratch using the pubkey that
# corresponds to the secret key we generated above.
txin_scriptPubKey = CScript(
    [OP_DUP, OP_HASH160,
     Hash160(seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG])

# Create the txout. This time we create the scriptPubKey from a Bitcoin
# address.
txout = CMutableTxOut(
    0.001 * COIN,
    CBitcoinAddress('1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8').to_scriptPubKey())

# Create the unsigned transaction.
tx = CMutableTransaction([txin], [txout])

# Calculate the signature hash for that transaction.
sighash = SignatureHash(txin_scriptPubKey, tx, 0, SIGHASH_ALL)

# Now sign it. We have to append the type of signature we want to the end, in
Exemplo n.º 29
0
def parameterize_planned_utxo(planned_utxo, parameters=None):
    """
    Parameterize a PlannedUTXO based on the runtime parameters. Populate and
    construct the output scripts based on the assigned script templates.
    """
    script_template = planned_utxo.script_template
    miniscript_policy_definitions = script_template.miniscript_policy_definitions
    script = copy(planned_utxo.script_template.script_template)

    for some_variable in miniscript_policy_definitions.keys():
        some_param = parameters[some_variable]
        if type(some_param) == dict:
            some_public_key = b2x(some_param["public_key"])
        elif script_template == UserScriptTemplate and type(
                some_param) == str and some_variable == "user_key_hash160":
            some_public_key = some_param
        else:
            # some_param is already the public key
            some_public_key = b2x(some_param)
        script = script.replace("<" + some_variable + ">", some_public_key)

    # Insert the appropriate relative timelocks, based on the timelock
    # multiplier.
    relative_timelocks = planned_utxo.script_template.relative_timelocks
    timelock_multiplier = planned_utxo.timelock_multiplier
    if relative_timelocks not in [{}, None]:
        replacements = relative_timelocks["replacements"]

        # Update these values to take into account the timelock multiplier.
        replacements = dict((key, value * timelock_multiplier)
                            for (key, value) in replacements.items())

        # Insert the new value into the script. The value has to be
        # converted to the right value (vch), though.
        for (replacement_name, replacement_value) in replacements.items():
            replacement_value = bitcoin.core._bignum.bn2vch(replacement_value)
            replacement_value = b2x(replacement_value)

            script = script.replace("<" + replacement_name + ">",
                                    replacement_value)

            # For testing later:
            #   int.from_bytes(b"\x40\x38", byteorder="little") == 144*100
            #   b2x(bitcoin.core._bignum.bn2vch(144*100)) == "4038"
            #   bitcoin.core._bignum.vch2bn(b"\x90\x00") == 144

    # There might be other things in the script that need to be replaced.
    #script = script.replace("<", "")
    #script = script.replace(">", "")
    if "<" in script:
        raise VaultException("Script not finished cooking? {}".format(script))

    # remove newlines
    script = script.replace("\n", " ")
    # reduce any excess whitespace
    while (" " * 2) in script:
        script = script.replace("  ", " ")

    # remove whitespace at the front, like for the cold storage UTXO script
    if script[0] == " ":
        script = script[1:]

    # remove trailing whitespace
    if script[-1] == " ":
        script = script[0:-1]

    # hack for python-bitcoinlib
    # see https://github.com/petertodd/python-bitcoinlib/pull/226
    # TODO: this shouldn't be required anymore (v0.11.0 was released)
    script = script.replace("OP_CHECKSEQUENCEVERIFY", "OP_NOP3")

    # convert script into a parsed python object
    script = script.split(" ")
    script_items = []
    for script_item in script:
        if script_item in bitcoin.core.script.OPCODES_BY_NAME.keys():
            parsed_script_item = bitcoin.core.script.OPCODES_BY_NAME[
                script_item]
            script_items.append(parsed_script_item)
        else:
            script_items.append(x(script_item))

    p2wsh_redeem_script = CScript(script_items)

    scriptpubkey = CScript([OP_0, sha256(bytes(p2wsh_redeem_script))])
    p2wsh_address = P2WSHBitcoinAddress.from_scriptPubKey(scriptpubkey)

    planned_utxo.scriptpubkey = scriptpubkey
    planned_utxo.p2wsh_redeem_script = p2wsh_redeem_script
    planned_utxo.p2wsh_address = p2wsh_address

    amount = planned_utxo.amount
    planned_utxo.bitcoin_output = CTxOut(amount, scriptpubkey)
    planned_utxo.is_finalized = True

    logger.info("UTXO name: {}".format(planned_utxo.name))
    logger.info("final script: {}".format(script))
Exemplo n.º 30
0
 def script(self):
     return CScript([
         OP_IF, OP_SHA256, self.secret, OP_EQUALVERIFY, self.paypubkey,
         OP_ELSE, self.timeout, OP_CLTV, OP_DROP, self.refundpubkey,
         OP_ENDIF, OP_CHECKSIG
     ])
Exemplo n.º 31
0
 def sign_spend(self, tx, vin):
     txhash = mkhash(self.script, tx, vin, SIGHASH_ALL)
     sig = mksig(self.privkey, txhash, SIGHASH_ALL)
     assert bitcoin.core.script.IsLowDERSignature(sig)
     return CScript([sig, self.script])
Exemplo n.º 32
0
 def script(self):
     return CScript(
         [self.timeout, OP_CLTV, OP_DROP, self.pubkey, OP_CHECKSIG])
Exemplo n.º 33
-1
    def do_step(self):
        """Returns whether another step can be done."""
        if self.step_counter == -1:
            txt = str(self.tx_script.toPlainText())
            scr = CScript(txt.decode('hex'))
            # So we can show the opcode in the stack log
            self.script_ops = [i for i in scr.raw_iter()]
            self.stack.set_script(scr, self.tx, self.inIdx)
            self.stack_iterator = self.stack.step()
            self.stack_log.clear()
            self.step_counter += 1

        step_again = False
        try:
            self.step_counter += 1
            stack_state, action = self.stack_iterator.next()
            new_stack = [i.encode('hex') for i in reversed(stack_state)]
            self.stack_view.clear()
            self.stack_view.addItems(new_stack)

            op_name = OPCODE_NAMES.get(self.script_ops[self.step_counter - 1][0], 'PUSHDATA')
            self.highlight_step(self.script_ops[self.step_counter - 1])
            item = QTreeWidgetItem(map(lambda i: str(i), [self.step_counter, op_name, action]))
            item.setTextAlignment(0, Qt.AlignLeft)
            item.setToolTip(1, 'Step {} operation'.format(self.step_counter))
            item.setToolTip(2, 'Result of step {}'.format(self.step_counter))
            self.stack_log.insertTopLevelItem(0, item)
            self.stack_result.setText(action)
            self.stack_result.setProperty('hasError', False)
            step_again = True
        except StopIteration:
            self.stack_result.setText('End of script.')
        except Exception as e:
            self.stack_result.setText(str(e))
            self.stack_result.setProperty('hasError', True)
        finally:
            self.style().polish(self.stack_result)

        return step_again