Пример #1
0
 def get_xpub(self, bip32_path):
     self.checkDevice()
     # bip32_path is of the form 44'/5'/1'
     # S-L-O-W - we don't handle the fingerprint directly, so compute
     # it manually from the previous node
     # This only happens once so it's bearable
     #self.get_client() # prompt for the PIN before displaying the dialog if necessary
     #self.handler.show_message("Computing master public key")
     try:
         splitPath = bip32_path.split('/')
         if splitPath[0] == 'm':
             splitPath = splitPath[1:]
             bip32_path = bip32_path[2:]
         fingerprint = 0
         if len(splitPath) > 1:
             prevPath = "/".join(splitPath[0:len(splitPath) - 1])
             nodeData = self.dongleObject.getWalletPublicKey(prevPath)
             publicKey = compress_public_key(nodeData['publicKey'])
             h = hashlib.new('ripemd160')
             h.update(hashlib.sha256(publicKey).digest())
             fingerprint = unpack(">I", h.digest()[0:4])[0]
         nodeData = self.dongleObject.getWalletPublicKey(bip32_path)
         publicKey = compress_public_key(nodeData['publicKey'])
         depth = len(splitPath)
         lastChild = splitPath[len(splitPath) - 1].split('\'')
         if len(lastChild) == 1:
             childnum = int(lastChild[0])
         else:
             childnum = 0x80000000 | int(lastChild[0])
         xpub = bitcoin.serialize_xpub(0, str(nodeData['chainCode']), str(publicKey), depth, self.i4b(fingerprint), self.i4b(childnum))
         return xpub
     except Exception as e:
         print_error(e)
         return None
Пример #2
0
    def import_masternode_conf_lines(self, conf_lines, password):
        """Import a list of MasternodeConfLine."""
        def already_have(line):
            for masternode in self.masternodes:
                # Don't let aliases collide.
                if masternode.alias == line.alias:
                    return True
                # Don't let outputs collide.
                if masternode.vin.get('prevout_hash') == line.txid and masternode.vin.get('prevout_n') == line.output_index:
                    return True
            return False

        num_imported = 0
        for conf_line in conf_lines:
            if already_have(conf_line):
                continue
            # Import delegate WIF key for signing last_ping.
            self.import_masternode_delegate(conf_line.wif)
            public_key = bitcoin.public_key_from_private_key(conf_line.wif)

            addr = conf_line.addr.split(':')
            addr = NetworkAddress(ip=addr[0], port=int(addr[1]))
            vin = {'prevout_hash': conf_line.txid, 'prevout_n': conf_line.output_index}
            mn = MasternodeAnnounce(alias=conf_line.alias, vin=vin,  
                    delegate_key = public_key, addr=addr)
            self.add_masternode(mn)
            try:
                self.populate_masternode_output(mn.alias)
            except Exception as e:
                print_error(str(e))
            num_imported += 1

        return num_imported
Пример #3
0
 def give_error(self, message, clear_client = False):
     print_error(message)
     if not self.signing:
         self.handler.show_error(message)
     else:
         self.signing = False
     if clear_client:
         self.client = None
     raise Exception(message)
 def submit_thread():
     for i, (proposal_name,
             txid) in enumerate(self.unsubmitted_proposals):
         errmsg, success = self.parent.masternode_manager.submit_proposal(
             proposal_name, save=False)
         results[i] = (proposal_name, errmsg, success)
         if success:
             print_error('Sucessfully submitted proposal "%s"' %
                         proposal_name)
         else:
             print_error('Failed to submit proposal "%s": %s' %
                         (proposal_name, errmsg))
     return results
Пример #5
0
 def hid_send_encrypt(self, msg):
     reply = ""
     try:
         secret = Hash(self.password)
         msg = EncodeAES(secret, msg)
         reply = self.hid_send_plain(msg)
         if 'ciphertext' in reply:
             reply = DecodeAES(secret, ''.join(reply["ciphertext"]))
             reply = json.loads(reply)
         if 'error' in reply:
             self.password = None
     except Exception as e:
         print_error('Exception caught ' + str(e))
     return reply
Пример #6
0
    def create_proposal_tx(self, proposal_name, password, save = True):
        """Create a fee transaction for proposal_name."""
        proposal = self.get_proposal(proposal_name)
        if proposal.fee_txid:
            print_error('Warning: Proposal "%s" already has a fee tx: %s' % (proposal_name, proposal.fee_txid))
        if proposal.submitted:
            raise Exception('Proposal has already been submitted')

        h = bitcoin.hash_decode(proposal.get_hash()).encode('hex')
        script = '6a20' + h # OP_RETURN hash
        outputs = [(bitcoin.TYPE_SCRIPT, script.decode('hex'), BUDGET_FEE_TX)]
        tx = self.wallet.mktx(outputs, password, self.config)
        proposal.fee_txid = tx.hash()
        if save:
            self.save()
        return tx
Пример #7
0
    def masternode_subscription_response(self, response):
        """Callback for when a masternode's status changes."""
        collateral = response['params'][0]
        mn = None
        for masternode in self.masternodes:
            if masternode.get_collateral_str() == collateral:
                mn = masternode
                break

        if not mn:
            return

        status = response['result']
        if status is None:
            status = False
        print_error('Received updated status for masternode %s: "%s"' % (mn.alias, status))
        self.masternode_statuses[collateral] = status
Пример #8
0
 def hid_send_plain(self, msg):
     reply = ""
     try:
         serial_number = self.dbb_hid.get_serial_number_string()
         if "v2.0." in serial_number or "v1." in serial_number:
             hidBufSize = 4096
             self.dbb_hid.write('\0' + bytearray(msg) + '\0' * (hidBufSize - len(msg)))
             r = []
             while len(r) < hidBufSize:
                 r = r + self.dbb_hid.read(hidBufSize)
         else:
             self.hid_send_frame(msg)
             r = self.hid_read_frame()
         r = str(bytearray(r)).rstrip(' \t\r\n\0')
         r = r.replace("\0", '')
         reply = json.loads(r)
     except Exception as e:
         print_error('Exception caught ' + str(e))
     return reply
Пример #9
0
def parse_proposals_subscription_result(results):
    """Parse the proposals subscription response."""
    proposals = []
    for k, result in results.items():
        kwargs = {'proposal_name': result['Name'], 'proposal_url': result['URL'],
                'start_block': int(result['BlockStart']), 'end_block': int(result['BlockEnd']),
                'payment_amount': result['MonthlyPayment'], 'address': result['PaymentAddress']}

        fee_txid_key = 'FeeTXHash' if result.get('FeeTXHash') else 'FeeHash'
        kwargs['fee_txid'] = result[fee_txid_key]
        yes_count_key = 'YesCount' if result.get('YesCount') else 'Yeas'
        kwargs['yes_count'] = result[yes_count_key]
        no_count_key = 'NoCount' if result.get('NoCount') else 'Nays'
        kwargs['no_count'] = result[no_count_key]

        payment_amount = Decimal(str(kwargs['payment_amount']))
        kwargs['payment_amount'] = pow(10, 8) * payment_amount
        proposals.append(BudgetProposal.from_dict(kwargs))

    print_error('Received updated budget proposal information (%d proposals)' % len(proposals))
    return proposals
Пример #10
0
    def sign_transaction(self, tx, password):
        if tx.is_complete():
            return

        try:
            p2shTransaction = False
            derivations = self.get_tx_derivations(tx)
            inputhasharray = []
            hasharray = []
            pubkeyarray = []
            
            # Build hasharray from inputs
            for i, txin in enumerate(tx.inputs()):
                if txin['type'] == 'coinbase':
                    self.give_error("Coinbase not supported") # should never happen
                
                if txin['type'] in ['p2sh']:
                    p2shTransaction = True
                
                for x_pubkey in txin['x_pubkeys']:
                    if x_pubkey in derivations:
                        index = derivations.get(x_pubkey)
                        inputPath = "%s/%d/%d" % (self.get_derivation(), index[0], index[1])
                        inputHash = Hash(tx.serialize_preimage(i).decode('hex'))
                        hasharray_i = {'hash': inputHash.encode('hex'), 'keypath': inputPath}
                        hasharray.append(hasharray_i)
                        inputhasharray.append(inputHash)
                        break
                else:
                    self.give_error("No matching x_key for sign_transaction") # should never happen
           
            # Sanity check
            if p2shTransaction:
                for txinput in tx.inputs():
                    if txinput['type'] != 'p2sh':
                        self.give_error("P2SH / regular input mixed in same transaction not supported") # should never happen
            
            # Build pubkeyarray from outputs (unused because echo for smart verification not implemented)
            if not p2shTransaction:
                for _type, address, amount in tx.outputs():
                    assert _type == TYPE_ADDRESS
                    info = tx.output_info.get(address)
                    if info is not None:
                        index, xpubs, m = info
                        changePath = self.get_derivation() + "/%d/%d" % index
                        changePubkey = self.derive_pubkey(index[0], index[1])
                        pubkeyarray_i = {'pubkey': changePubkey, 'keypath': changePath}
                        pubkeyarray.append(pubkeyarray_i)
            
            # Build sign command
            dbb_signatures = []
            steps = math.ceil(1.0 * len(hasharray) / self.maxInputs)
            for step in range(int(steps)):
                hashes = hasharray[step * self.maxInputs : (step + 1) * self.maxInputs]
                
                msg = '{"sign": {"meta":"%s", "data":%s, "checkpub":%s} }' % \
                       (Hash(tx.serialize()).encode('hex'), json.dumps(hashes), json.dumps(pubkeyarray))
                
                dbb_client = self.plugin.get_client(self)
                
                if not dbb_client.is_paired():
                    raise Exception("Could not sign transaction.")
                
                reply = dbb_client.hid_send_encrypt(msg)
                
                if 'error' in reply:
                    raise Exception(reply['error']['message'])
                
                if 'echo' not in reply:
                    raise Exception("Could not sign transaction.")
                
                if steps > 1:
                    self.handler.show_message(_("Signing large transaction. Please be patient ...\r\n\r\n" \
                                                "To continue, touch the Digital Bitbox's blinking light for 3 seconds. " \
                                                "(Touch " + str(step + 1) + " of " + str(int(steps)) + ")\r\n\r\n" \
                                                "To cancel, briefly touch the blinking light or wait for the timeout.\r\n\r\n"))
                else:
                    self.handler.show_message(_("Signing transaction ...\r\n\r\n" \
                                                "To continue, touch the Digital Bitbox's blinking light for 3 seconds.\r\n\r\n" \
                                                "To cancel, briefly touch the blinking light or wait for the timeout."))
               
                reply = dbb_client.hid_send_encrypt(msg) # Send twice, first returns an echo for smart verification (not implemented)
                self.handler.clear_dialog()
                
                if 'error' in reply:
                    raise Exception(reply['error']['message'])
                
                if 'sign' not in reply:
                    raise Exception("Could not sign transaction.")
                
                dbb_signatures.extend(reply['sign'])
            
            # Fill signatures
            if len(dbb_signatures) <> len(tx.inputs()):
                raise Exception("Incorrect number of transactions signed.") # Should never occur
            for i, txin in enumerate(tx.inputs()):
                num = txin['num_sig']
                for pubkey in txin['pubkeys']:
                    signatures = filter(None, txin['signatures'])
                    if len(signatures) == num:
                        break # txin is complete
                    ii = txin['pubkeys'].index(pubkey)
                    signed = dbb_signatures[i]
                    if 'recid' in signed:
                        # firmware > v2.1.1
                        recid = int(signed['recid'], 16)
                        s = signed['sig'].decode('hex')
                        h = inputhasharray[i]
                        pk = MyVerifyingKey.from_signature(s, recid, h, curve = SECP256k1)
                        pk = point_to_ser(pk.pubkey.point, True).encode('hex')
                    elif 'pubkey' in signed:
                        # firmware <= v2.1.1
                        pk = signed['pubkey']
                    if pk != pubkey:
                        continue
                    sig_r = int(signed['sig'][:64], 16)
                    sig_s = int(signed['sig'][64:], 16)
                    sig = sigencode_der(sig_r, sig_s, generator_secp256k1.order())
                    txin['signatures'][ii] = sig.encode('hex') + '01'
                    tx._inputs[i] = txin

        except BaseException as e:
            self.give_error(e, True)
        else:
            print_error("Transaction is_complete", tx.is_complete())
            tx.raw = tx.serialize()
Пример #11
0
import sys
import platform

from electrum_desire.plugins import BasePlugin, hook
from electrum_desire_gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog
from electrum_desire.util import print_msg, print_error
from electrum_desire.i18n import _

from PyQt4.QtGui import *
from PyQt4.QtCore import *

try:
    import amodem.audio
    import amodem.main
    import amodem.config
    print_error('Audio MODEM is available.')
    amodem.log.addHandler(amodem.logging.StreamHandler(sys.stderr))
    amodem.log.setLevel(amodem.logging.INFO)
except ImportError:
    amodem = None
    print_error('Audio MODEM is not found.')


class Plugin(BasePlugin):
    def __init__(self, parent, config, name):
        BasePlugin.__init__(self, parent, config, name)
        if self.is_available():
            self.modem_config = amodem.config.slowest()
            self.library_name = {'Linux': 'libportaudio.so'}[platform.system()]

    def is_available(self):
 def sign_done(proposal, tx):
     print_error('proposal tx sign done: %s' % proposal.proposal_name)
     if tx:
         label = _('Budget Proposal Tx: ') + proposal.proposal_name
         self.parent.broadcast_transaction(tx, label)
         self.parent.masternode_manager.save()