Esempio n. 1
0
    def gettransaction(self, tx_id):
        tx = self.compose_request('transaction', tx_id)

        rawtx = tx['raw']
        t = Transaction.import_raw(rawtx, network=self.network)
        if tx['confirmations']:
            t.status = 'confirmed'
        else:
            t.status = 'unconfirmed'

        if t.coinbase:
            t.input_total = t.output_total
        else:
            t.input_total = tx['total_input_value']
        t.output_total = tx['total_output_value']
        t.fee = tx['total_fee']
        t.hash = tx['hash']
        t.block_hash = tx['block_hash']
        t.block_height = tx['block_height']
        t.confirmations = tx['confirmations']
        t.date = datetime.strptime(tx['block_time'], "%Y-%m-%dT%H:%M:%S+%f")
        t.size = tx['size']
        for n, i in enumerate(t.inputs):
            i.value = tx['inputs'][n]['value']
        for n, o in enumerate(t.outputs):
            if tx['outputs'][n]['address']:
                o.spent = True if 'spent_hash' in tx['outputs'][n] else False

        return t
Esempio n. 2
0
 def gettransaction(self, txid, latest_block=None):
     tx = self.compose_request('rawtx', txid)
     raw_tx = self.getrawtransaction(txid)
     t = Transaction.import_raw(raw_tx, self.network)
     input_total = 0
     for n, i in enumerate(t.inputs):
         if 'prev_out' in tx['inputs'][n]:
             i.value = tx['inputs'][n]['prev_out']['value']
             input_total += i.value
     for n, o in enumerate(t.outputs):
         o.spent = tx['out'][n]['spent']
     if 'block_height' in tx and tx['block_height']:
         if not latest_block:
             latest_block = self.blockcount()
         t.status = 'confirmed'
         t.date = datetime.utcfromtimestamp(tx['time'])
         t.block_height = tx['block_height']
         t.confirmations = 1
         if latest_block > t.block_height:
             t.confirmations = latest_block - t.block_height
     else:
         t.status = 'unconfirmed'
         t.confirmations = 0
         t.date = None
     t.rawtx = to_bytes(raw_tx)
     t.size = tx['size']
     t.network_name = self.network
     t.locktime = tx['lock_time']
     t.version = struct.pack('>L', tx['ver'])
     t.input_total = input_total
     t.fee = t.input_total - t.output_total
     return t
Esempio n. 3
0
 def gettransaction(self, tx_id):
     tx = self.compose_request('txs',
                               tx_id,
                               variables={'includeHex': 'true'})
     t = Transaction.import_raw(tx['hex'])
     t.hash = tx_id
     if tx['confirmations']:
         t.status = 'confirmed'
     else:
         t.status = 'unconfirmed'
     t.date = datetime.strptime(tx['confirmed'][:19], "%Y-%m-%dT%H:%M:%S")
     t.confirmations = tx['confirmations']
     t.block_height = tx['block_height']
     t.block_hash = tx['block_hash']
     t.fee = tx['fees']
     t.rawtx = tx['hex']
     t.size = tx['size']
     t.network_name = self.network
     t.input_total = 0
     if t.coinbase:
         t.input_total = t.output_total
     for n, i in enumerate(t.inputs):
         if 'output_value' in tx['inputs'][n]:
             i.value = tx['inputs'][n]['output_value']
             t.input_total += i.value
     for n, o in enumerate(t.outputs):
         if 'spent_by' in tx['outputs'][n]:
             o.spent = True
     return t
Esempio n. 4
0
 def gettransaction(self, tx_id):
     tx = self.compose_request('rawtx', tx_id)
     raw_tx = self.getrawtransaction(tx_id)
     t = Transaction.import_raw(raw_tx)
     input_total = None
     for n, i in enumerate(t.inputs):
         if 'prev_out' in tx['inputs'][n]:
             i.value = tx['inputs'][n]['prev_out']['value']
             input_total = input_total + i.value if input_total is not None else i.value
     for n, o in enumerate(t.outputs):
         o.spent = tx['out'][n]['spent']
     # if tx['relayed_by'] == '0.0.0.0':
     if tx['block_height']:
         t.status = 'confirmed'
     else:
         t.status = 'unconfirmed'
     t.hash = tx_id
     t.date = datetime.fromtimestamp(tx['time'])
     t.block_height = tx['block_height']
     t.rawtx = raw_tx
     t.size = tx['size']
     t.network_name = self.network
     t.locktime = tx['lock_time']
     t.version = struct.pack('>L', tx['ver'])
     t.input_total = input_total
     t.fee = t.input_total - t.output_total
     return t
Esempio n. 5
0
 def gettransaction(self, txid):
     tx = self.proxy.getrawtransaction(txid, 1)
     t = Transaction.import_raw(tx['hex'], network=self.network)
     t.confirmations = tx['confirmations']
     if t.confirmations:
         t.status = 'confirmed'
         t.verified = True
     for i in t.inputs:
         if i.prev_hash == b'\x00' * 32:
             i.value = t.output_total
             i.script_type = 'coinbase'
             continue
         txi = self.proxy.getrawtransaction(to_hexstring(i.prev_hash), 1)
         i.value = int(
             round(
                 float(txi['vout'][i.output_n_int]['value']) /
                 self.network.denominator))
     for o in t.outputs:
         o.spent = None
     t.block_hash = tx['blockhash']
     t.version = struct.pack('>L', tx['version'])
     t.date = datetime.utcfromtimestamp(tx['blocktime'])
     t.hash = txid
     t.update_totals()
     return t
Esempio n. 6
0
 def _parse_transaction(self, tx):
     t = Transaction.import_raw(tx['rawTx'], network=self.network)
     t.status = 'unconfirmed'
     if tx['confirmations']:
         t.status = 'confirmed'
     t.hash = tx['txId']
     if 'timestamp' in tx and tx['timestamp']:
         t.date = datetime.fromtimestamp(tx['timestamp'])
     elif 'blockTime' in tx and tx['blockTime']:
         t.date = datetime.fromtimestamp(tx['blockTime'])
     t.confirmations = tx['confirmations']
     if 'blockHeight' in tx:
         t.block_height = tx['blockHeight']
         t.block_hash = tx['blockHash']
     t.fee = tx['fee']
     t.rawtx = tx['rawTx']
     t.size = tx['size']
     t.network = self.network
     if not t.coinbase:
         for i in t.inputs:
             i.value = tx['vIn'][str(i.index_n)]['amount']
     for o in t.outputs:
         if tx['vOut'][str(o.output_n)]['spent']:
             o.spent = True
     if t.coinbase:
         t.input_total = tx['outputsAmount'] - t.fee
     else:
         t.input_total = tx['inputsAmount']
     t.output_total = tx['outputsAmount']
     return t
Esempio n. 7
0
 def _parse_db_transaction(db_tx):
     if not db_tx.raw:
         return False
     t = Transaction.import_raw(db_tx.raw, db_tx.network_name)
     # locktime, version, coinbase?, witness_type
     # t = Transaction(locktime=tx['locktime'], version=tx['version'], network=self.network,
     #                 fee=tx['fee'], size=tx['size'], hash=tx['txid'],
     #                 date=tdate, input_total=tx['input_total'], output_total=tx['output_total'],
     #                 confirmations=confirmations, block_height=block_height, status=tx['status'],
     #                 coinbase=tx['coinbase'], rawtx=tx['raw_hex'], witness_type=tx['witness_type'])
     for n in db_tx.nodes:
         if n.is_input:
             t.inputs[n.output_n].value = n.value
             t.inputs[n.output_n].address = n.address
         else:
             t.outputs[n.output_n].spent = n.spent
             t.outputs[n.output_n].spending_txid = n.spending_txid
             t.outputs[n.output_n].spending_index_n = n.spending_index_n
     t.hash = to_bytes(db_tx.txid)
     t._txid = db_tx.txid
     t.date = db_tx.date
     t.block_hash = db_tx.block_hash
     t.block_height = db_tx.block_height
     t.confirmations = db_tx.confirmations
     t.status = 'confirmed'
     t.fee = db_tx.fee
     t.update_totals()
     if t.coinbase:
         t.input_total = t.output_total
     _logger.info("Retrieved transaction %s from cache" % t.txid)
     return t
Esempio n. 8
0
 def gettransaction(self, tx_id):
     res = self.compose_request('get_tx', tx_id)
     tx = res['data']
     raw_tx = tx['tx_hex']
     t = Transaction.import_raw(raw_tx, network=self.network)
     input_total = 0
     output_total = 0
     for n, i in enumerate(t.inputs):
         i.value = int(round(float(tx['inputs'][n]['value']) * self.units, 0))
         input_total += i.value
     for o in t.outputs:
         # TODO: Check if output is spent (still neccessary?)
         o.spent = None
         output_total += o.value
     t.hash = tx_id
     t.block_hash = tx['blockhash']
     t.date = datetime.fromtimestamp(tx['time'])
     t.rawtx = raw_tx
     t.size = tx['size']
     t.network = self.network
     t.locktime = tx['locktime']
     t.input_total = input_total
     t.output_total = output_total
     t.fee = t.input_total - t.output_total
     t.confirmations = tx['confirmations']
     if tx['confirmations']:
         t.status = 'confirmed'
     else:
         t.status = 'unconfirmed'
     return t
Esempio n. 9
0
def transaction_decompose(network):
    rawtx = request.args.get('rawtx', type=str)
    form = TransactionDecomposeForm()
    srv = SmurferService(network)
    if form.validate_on_submit():
        try:
            t = Transaction.import_raw(form.rawtx.data, network=srv.network)
        except Exception as e:
            flash(_('Invalid raw transaction hex, could not parse: %s' % e),
                  category='error')
        else:
            # TODO: Retreiving prev_tx input values should be included in bitcoinlib
            try:
                for n, i in enumerate(t.inputs):
                    ti = srv.gettransaction(i.prev_txid.hex())
                    t.inputs[n].value = ti.outputs[i.output_n_int].value
                t.verify()
            except TransactionError as e:
                flash(_('Could not verify transaction: %s' % e),
                      category='warning')
            t_json = t.as_json()
            return render_template(
                'explorer/transaction_elements.html',
                title=_('Decomposed Transaction'),
                subtitle=_('Transaction elements as dictionary'),
                transaction_dict=t_json,
                rawtx=form.rawtx.data,
                network=network)
    form.rawtx.data = rawtx
    return render_template('explorer/transaction_decompose.html',
                           title=_('Decompose Transaction'),
                           subtitle=_('Decompose your raw transaction hex'),
                           form=form,
                           network=network)
Esempio n. 10
0
 def gettransaction(self, txid, block_height=None, get_input_values=True):
     tx = self.proxy.getrawtransaction(txid, 1)
     t = Transaction.import_raw(tx['hex'], network=self.network)
     t.confirmations = tx['confirmations']
     if t.confirmations:
         t.status = 'confirmed'
         t.verified = True
     for i in t.inputs:
         if i.prev_txid == b'\x00' * 32:
             i.value = t.output_total
             i.script_type = 'coinbase'
             continue
         if get_input_values:
             txi = self.proxy.getrawtransaction(i.prev_txid.hex(), 1)
             i.value = int(
                 round(
                     float(txi['vout'][i.output_n_int]['value']) /
                     self.network.denominator))
     for o in t.outputs:
         o.spent = None
     t.version = tx['version'].to_bytes(4, 'big')
     t.date = datetime.fromtimestamp(tx['blocktime'])
     t.block_height = block_height
     t.update_totals()
     return t
Esempio n. 11
0
 def gettransaction(self, txid, block_height=None):
     res = self.compose_request('get_tx', txid)
     tx = res['data']
     rawtx = tx['tx_hex']
     t = Transaction.import_raw(rawtx, network=self.network)
     input_total = 0
     output_total = 0
     if not t.coinbase:
         for n, i in enumerate(t.inputs):
             i.value = int(
                 round(float(tx['inputs'][n]['value']) * self.units, 0))
             input_total += i.value
     for o in t.outputs:
         o.spent = None
         output_total += o.value
     if not t.block_height:
         t.block_height = self.getblock(tx['blockhash'], False, 1,
                                        1)['height']
     t.block_hash = tx['blockhash']
     t.date = datetime.utcfromtimestamp(tx['time'])
     t.rawtx = bytes.fromhex(rawtx)
     t.size = tx['size']
     t.network = self.network
     t.locktime = tx['locktime']
     t.input_total = input_total
     t.output_total = output_total
     t.fee = 0
     if t.input_total:
         t.fee = t.input_total - t.output_total
     t.confirmations = tx['confirmations']
     if tx['confirmations']:
         t.status = 'confirmed'
     else:
         t.status = 'unconfirmed'
     return t
Esempio n. 12
0
 def gettransaction(self, txid):
     tx = self.compose_request('txs', txid, variables={'includeHex': 'true'})
     t = Transaction.import_raw(tx['hex'], network=self.network)
     if tx['confirmations']:
         t.status = 'confirmed'
         t.date = datetime.strptime(tx['confirmed'][:19], "%Y-%m-%dT%H:%M:%S")
     else:
         t.status = 'unconfirmed'
     t.confirmations = tx['confirmations']
     t.block_height = tx['block_height'] if tx['block_height'] > 0 else None
     t.fee = tx['fees']
     t.rawtx = bytes.fromhex(tx['hex'])
     t.size = int(len(tx['hex']) / 2)
     t.network = self.network
     t.input_total = 0
     if len(t.inputs) != len(tx['inputs']):
         raise ClientError("Invalid number of inputs provided. Raw tx: %d, blockcypher: %d" %
                           (len(t.inputs), len(tx['inputs'])))
     for n, i in enumerate(t.inputs):
         if not t.coinbase and not (tx['inputs'][n]['output_index'] == i.output_n_int and
                                    tx['inputs'][n]['prev_hash'] == i.prev_txid.hex()):
             raise ClientError("Transaction inputs do not match raw transaction")
         if 'output_value' in tx['inputs'][n]:
             if not t.coinbase:
                 i.value = tx['inputs'][n]['output_value']
             t.input_total += i.value
     if len(t.outputs) != len(tx['outputs']):
         raise ClientError("Invalid number of outputs provided. Raw tx: %d, blockcypher: %d" %
                           (len(t.outputs), len(tx['outputs'])))
     for n, o in enumerate(t.outputs):
         if 'spent_by' in tx['outputs'][n]:
             o.spent = True
             o.spending_txid = tx['outputs'][n]['spent_by']
     return t
def transaction_broadcast(network):
    rawtx = request.data
    srv = SmurferService(network)
    errors = []
    txid = ''
    res = {}
    try:
        t = Transaction.import_raw(rawtx)
    except Exception as e:
        errors.append(_('Invalid raw transaction hex, could not parse: %s' % e))
    else:
        known_tx = srv.gettransaction(t.txid)
        if known_tx:
            errors.append(_('This transaction %s is already included in the blockchain' % t.txid))
        else:
            res = srv.sendrawtransaction(rawtx)
            if not res or 'txid' not in res:
                # TODO: Get decent error message, without private details
                errors.append(_('Could not send raw transaction. %s' % srv.errors.get('bcoin', '')))
    data = {
        'success': True if txid else False,
        'txid': txid,
        'errors': ','.join(errors),
        'raw_response': res
    }
    return jsonify(data), 200 if txid else 400
Esempio n. 14
0
 def _parse_transaction(self, tx, block_height=None, get_input_values=True):
     t = Transaction.import_raw(tx['hex'], network=self.network)
     t.confirmations = None if 'confirmations' not in tx else tx[
         'confirmations']
     if t.confirmations or block_height:
         t.status = 'confirmed'
         t.verified = True
     for i in t.inputs:
         if i.prev_hash == b'\x00' * 32:
             i.script_type = 'coinbase'
             continue
         if get_input_values:
             txi = self.proxy.getrawtransaction(to_hexstring(i.prev_hash),
                                                1)
             i.value = int(
                 round(
                     float(txi['vout'][i.output_n_int]['value']) /
                     self.network.denominator))
     for o in t.outputs:
         o.spent = None
     t.block_hash = tx.get('block_hash', tx['txid'])  # FIXME, use only one
     t.block_height = block_height
     t.version = struct.pack('>L', tx['version'])
     t.date = datetime.utcfromtimestamp(tx['time'])
     t.update_totals()
     return t
Esempio n. 15
0
 def gettransaction(self, txid):
     variables = {'id': txid, 'hex': None}
     tx = self.compose_request(path_type='explorer', variables=variables)
     t = Transaction.import_raw(tx['hex'], self.network)
     variables = {'t': txid}
     tx_api = self.compose_request('txinfo',
                                   path_type='api',
                                   variables=variables)
     for n, i in enumerate(t.inputs):
         if i.script_type != 'coinbase':
             i.value = int(
                 round(tx_api['inputs'][n]['amount'] * self.units, 0))
         else:
             i.value = 0
             t.coinbase = True
     for n, o in enumerate(t.outputs):
         o.spent = None
     if tx['confirmations']:
         t.status = 'confirmed'
     else:
         t.status = 'unconfirmed'
     t.date = datetime.utcfromtimestamp(tx['time'])
     t.block_height = tx_api['block']
     t.block_hash = tx['blockhash']
     t.confirmations = tx['confirmations']
     t.rawtx = to_bytes(tx['hex'])
     t.size = tx['size']
     t.network = self.network
     t.locktime = tx['locktime']
     t.version = struct.pack('>L', tx['version'])
     t.output_total = int(round(tx_api['total_output'] * self.units, 0))
     t.input_total = t.output_total
     t.fee = t.input_total - t.output_total
     return t
Esempio n. 16
0
 def getrawtransaction(self, tx_id):
     tx = self.compose_request('rawtx', tx_id)
     t = Transaction.import_raw(tx['rawtx'], network=self.network)
     for i in t.inputs:
         if not i.address:
             raise ClientError("Address missing in input. Provider might not support segwit transactions")
     return tx['rawtx']
Esempio n. 17
0
    def _parse_transaction(self, tx, block_height=None, get_input_values=True):
        t = Transaction.import_raw(tx['hex'], network=self.network)
        t.confirmations = tx.get('confirmations')
        t.block_hash = tx.get('blockhash')
        t.status = 'unconfirmed'
        for i in t.inputs:
            if i.prev_txid == b'\x00' * 32:
                i.script_type = 'coinbase'
                continue
            if get_input_values:
                txi = self.proxy.getrawtransaction(i.prev_txid.hex(), 1)
                i.value = int(
                    round(
                        float(txi['vout'][i.output_n_int]['value']) /
                        self.network.denominator))
        for o in t.outputs:
            o.spent = None

        if not block_height and t.block_hash:
            block_height = self.proxy.getblock(t.block_hash, 1)['height']
        t.block_height = block_height
        if not t.confirmations and block_height is not None:
            if not self.latest_block:
                self.latest_block = self.blockcount()
            t.confirmations = (self.latest_block - block_height) + 1
        if t.confirmations or block_height:
            t.status = 'confirmed'
            t.verified = True
        t.version = tx['version'].to_bytes(4, 'big')
        t.version_int = tx['version']
        t.date = None if 'time' not in tx else datetime.utcfromtimestamp(
            tx['time'])
        t.update_totals()
        return t
    def get_transactions(self):
        if not self.created:
            return succeed([])

        # Update all transactions
        self.wallet.transactions_update(network=self.network)

        # TODO: 'Access to a protected member _session of a class'
        txs = self.wallet._session.query(DbTransaction.raw, DbTransaction.confirmations,
                                         DbTransaction.date, DbTransaction.fee) \
            .filter(DbTransaction.wallet_id == self.wallet.wallet_id) \
            .all()
        transactions = []

        for db_result in txs:
            transaction = Transaction.import_raw(db_result[0], network=self.network)
            transaction.confirmations = db_result[1]
            transaction.date = db_result[2]
            transaction.fee = db_result[3]
            transactions.append(transaction)

        # Sort them based on locktime
        transactions.sort(key=lambda tx: tx.locktime, reverse=True)

        my_keys = [key.address for key in self.wallet.keys(network=self.network, is_active=False)]

        transactions_list = []
        for transaction in transactions:
            value = 0
            input_addresses = []
            output_addresses = []
            for tx_input in transaction.inputs:
                input_addresses.append(tx_input.address)
                if tx_input.address in my_keys:
                    # At this point, we do not have the value of the input so we should do a database query for it
                    db_res = self.wallet._session.query(DbTransactionInput.value).filter(
                        hexlify(tx_input.prev_hash) == DbTransactionInput.prev_hash,
                        tx_input.output_n_int == DbTransactionInput.output_n).all()
                    if db_res:
                        value -= db_res[0][0]  # TODO: db_res[0][0] not an int, but hash string (value/fee expected?)

            for tx_output in transaction.outputs:
                output_addresses.append(tx_output.address)
                if tx_output.address in my_keys:
                    value += tx_output.value

            transactions_list.append({
                'id': transaction.hash,
                'outgoing': value < 0,
                'from': ','.join(input_addresses),
                'to': ','.join(output_addresses),
                'amount': abs(value),
                'fee_amount': transaction.fee,
                'currency': self.currency,
                'timestamp': time.mktime(transaction.date.timetuple()),
                'description': f'Confirmations: {transaction.confirmations}'
            })

        return succeed(transactions_list)
Esempio n. 19
0
 def sendrawtransaction(self, rawtx):
     res = self.compose_request('broadcast',
                                variables={'tx': rawtx},
                                method='post')
     txid = ''
     if 'success' in res and res['success']:
         t = Transaction.import_raw(rawtx)
         txid = t.txid
     return {'txid': txid, 'response_dict': res}
Esempio n. 20
0
def transaction_broadcast(network):
    rawtx = request.args.get('rawtx', type=str)
    form = TransactionSendForm()
    if form.validate_on_submit():
        srv = SmurferService(network)
        try:
            t = Transaction.import_raw(form.rawtx.data, network=srv.network)
        except Exception as e:
            flash(_('Invalid raw transaction hex, could not parse: %s' % e),
                  category='error')
        else:
            # TODO: Retreiving prev_tx input values should be included in bitcoinlib
            try:
                for n, i in enumerate(t.inputs):
                    ti = srv.gettransaction(i.prev_hash)
                    t.inputs[n].value = ti.outputs[i.output_n_int].value
                t.verify()
            except TransactionError as e:
                flash(_('Could not verify transaction: %s' % e),
                      category='warning')

            known_tx = srv.gettransaction(t.txid)
            if known_tx:
                flash(_(
                    'This transaction %s is already included in the blockchain'
                    % t.txid),
                      category='error')
            elif not t.verified:
                flash(
                    _('Invalid transaction, could not verify transaction %s' %
                      t.txid),
                    category='error')
            else:
                res = srv.sendrawtransaction(form.rawtx.data)
                if not res or 'txid' not in res:
                    # TODO: Get decent error message, without private details
                    flash(_('Could not send raw transaction. %s' %
                            srv.errors.get('bcoin', '')),
                          category='error')
                return render_template(
                    'explorer/transaction_send.html',
                    title=_('Transaction Send'),
                    subtitle=_(
                        'Your Transaction was broadcasted successfully!'),
                    txid=res['txid'],
                    network=network)
    form.rawtx.data = rawtx
    return render_template(
        'explorer/transaction_broadcast.html',
        title=_('Send Transaction'),
        rawtx=rawtx,
        subtitle=_('Broadcast your transaction on the network'),
        form=form,
        network=network)
Esempio n. 21
0
 def gettransaction(self, txid):
     tx = self.proxy.getrawtransaction(txid, 1)
     t = Transaction.import_raw(tx['hex'], network=self.network)
     t.confirmations = tx['confirmations']
     if t.confirmations:
         t.status = 'confirmed'
         t.verified = True
     for i in t.inputs:
         txi = self.proxy.getrawtransaction(to_hexstring(i.prev_hash), 1)
         value = int(float(txi['vout'][i.output_n_int]['value']) / self.network.denominator)
         i.value = value
     t.block_hash = tx['blockhash']
     t.version = tx['version']
     t.date = datetime.fromtimestamp(tx['blocktime'])
     t.update_totals()
     return t
Esempio n. 22
0
    def SignRemoteHTLCToUs(self, request, context):
        """BOLT #3 - HTLC Outputs, phase 1 Sign an htlc-success tx on a
        remote HTLC output offered to us, assuming we know the preimage,
        at force-close time
        """
        node_id = request.node_id.data
        node = self.nodes.get(node_id)
        logger.debug("SignRemoteHTLCToUs node:%s" % node_id.hex())

        channel_nonce = request.channel_nonce.data
        channel = node.channels.get(channel_nonce)

        remote_per_commit_point = request.remote_per_commit_point.data

        tx = request.tx
        amount = tx.input_descs[0].prev_output.value_sat
        redeemscript = tx.input_descs[0].redeem_script

        reply = remotesigner_pb2.SignatureReply()

        htlc_key = Key(
            import_key=channel.basepoints.keys.htlc_basepoint_secret,
            is_private=True)
        htlc_basepoint = htlc_key.public_compressed_byte

        local_priv_key = derive_priv_key(
            remote_per_commit_point, htlc_basepoint,
            channel.basepoints.keys.htlc_basepoint_secret)

        local_key = Key(import_key=local_priv_key, is_private=True)
        keys = [local_key]

        tx = Transaction.import_raw(tx.raw_tx_bytes, self.network)
        tx.inputs[0].script_type = "p2wsh"
        tx.inputs[0].witness_type = 'segwit'
        tx.inputs[0].redeemscript = redeemscript
        tx.inputs[0].value = amount
        tx.witness_type = 'segwit'
        tx.sign(keys=keys, tid=0)

        logger.debug("remote_per_commit_point %s" %
                     remote_per_commit_point.hex())
        logger.debug("channel.basepoints.funding_pk %s" %
                     channel.basepoints.funding_pk.hex())
        reply.signature.data = tx.inputs[0].signatures[0].as_der_encoded(
        ) + b'\x01'
        return reply
Esempio n. 23
0
 def gettransaction(self, tx_id):
     tx = self.compose_request('tx', tx_id)
     t = Transaction.import_raw(tx['hex'], network=self.network)
     if tx['confirmations']:
         t.status = 'confirmed'
     t.hash = tx_id
     t.date = datetime.strptime(tx['date'], "%Y-%m-%dT%H:%M:%S.%fZ")
     t.confirmations = tx['confirmations']
     if 'height' in tx:
         t.block_height = tx['height']
         t.block_hash = tx['blockhash']
     t.fee = tx['fee']
     t.rawtx = tx['hex']
     t.size = len(tx['hex']) // 2
     t.network = self.network
     if t.coinbase:
         input_values = []
         t.input_total = t.output_total
     else:
         input_values = [(inp['account'], -inp['value'])
                         for inp in tx['entries'] if inp['value'] < 0]
         if len(input_values) >= 49:
             raise ClientError(
                 "More then 49 transaction inputs not supported by bitgo")
         t.input_total = sum([x[1] for x in input_values])
     for i in t.inputs:
         if not i.address:
             raise ClientError(
                 "Address missing in input. Provider might not support segwit transactions"
             )
         if len(t.inputs) != len(input_values):
             i.value = None
             continue
         value = [x[1] for x in input_values if x[0] == i.address]
         if len(value) != 1:
             _logger.warning(
                 "BitGoClient: Address %s input value should be found exactly 1 times in value list"
                 % i.address)
             i.value = None
         else:
             i.value = value[0]
     for o in t.outputs:
         o.spent = None
     if t.input_total != t.output_total + t.fee:
         t.input_total = t.output_total + t.fee
     return t
Esempio n. 24
0
    def SignLocalHTLCTx(self, request, context):
        """BOLT #3 - HTLC Outputs, phase 1
        Sign an htlc-success tx spending a local HTLC output, assuming we
        know the preimage, at force-close time
        """
        node_id = request.node_id.data
        node = self.nodes.get(node_id)
        logger.debug("SignLocalHTLCTx node:%s" % node_id.hex())

        channel_nonce = request.channel_nonce.data
        channel = node.channels.get(channel_nonce)

        n = request.n

        tx = request.tx
        amount = tx.input_descs[0].prev_output.value_sat
        redeemscript = tx.input_descs[0].redeem_script

        reply = remotesigner_pb2.SignatureReply()

        htlc_basepoint = channel.basepoints.htlc

        element = shachain_derive(channel.shaelement, START_INDEX - n)
        per_commitment_point_prv = coincurve.PrivateKey(
            secret=bytes(element.secret))
        local_per_commit_point = per_commitment_point_prv.public_key.format()

        local_priv_key = derive_priv_key(
            local_per_commit_point, htlc_basepoint,
            channel.basepoints.keys.htlc_basepoint_secret)

        local_key = Key(import_key=local_priv_key, is_private=True)
        keys = [local_key]

        tx = Transaction.import_raw(tx.raw_tx_bytes, self.network)
        tx.inputs[0].script_type = "p2wsh"
        tx.inputs[0].witness_type = 'segwit'
        tx.inputs[0].redeemscript = redeemscript
        tx.inputs[0].value = amount
        tx.witness_type = 'segwit'
        tx.sign(keys=keys, tid=0)

        reply.signature.data = tx.inputs[0].signatures[0].as_der_encoded(
        ) + b'\x01'
        return reply
Esempio n. 25
0
    def SignDelayedPaymentToUs(self, request, context):
        """BOLT #5 - Unilateral Close Handling, phase 1
        Sign a delayed to-local output - either from the commitment tx or
        from an HTLC, at force-close time
        """
        node_id = request.node_id.data
        node = self.nodes.get(node_id)
        logger.debug("SignDelayedPaymentToUs node:%s" % node_id.hex())

        channel_nonce = request.channel_nonce.data
        channel = node.channels.get(channel_nonce)

        n = request.n

        tx = request.tx
        amount = tx.input_descs[0].prev_output.value_sat
        redeemscript = tx.input_descs[0].redeem_script

        reply = remotesigner_pb2.SignatureReply()

        delayed_payment_basepoint = channel.basepoints.delayed_payment

        element = shachain_derive(channel.shaelement, START_INDEX - n)
        per_commitment_point_prv = coincurve.PrivateKey(
            secret=bytes(element.secret))
        local_per_commit_point = per_commitment_point_prv.public_key.format()

        local_priv_key = derive_priv_key(
            local_per_commit_point, delayed_payment_basepoint,
            channel.basepoints.keys.delayed_payment_basepoint_secret)

        local_key = Key(import_key=local_priv_key, is_private=True)
        keys = [local_key]

        tx = Transaction.import_raw(tx.raw_tx_bytes, self.network)
        tx.inputs[0].script_type = "p2wsh"
        tx.inputs[0].witness_type = 'segwit'
        tx.inputs[0].redeemscript = redeemscript
        tx.inputs[0].value = amount
        tx.witness_type = 'segwit'
        tx.sign(keys=keys, tid=0)

        reply.signature.data = tx.inputs[0].signatures[0].as_der_encoded(
        ) + b'\x01'
        return reply
Esempio n. 26
0
 def _parse_db_transaction(self, db_tx):
     t = Transaction.import_raw(db_tx.raw, db_tx.network_name)
     for n in db_tx.nodes:
         if n.is_input:
             t.inputs[n.output_n].value = n.value
             t.inputs[n.output_n].address = n.address
         else:
             t.outputs[n.output_n].spent = n.spent
     t.hash = db_tx.txid
     t.date = db_tx.date
     t.confirmations = db_tx.confirmations
     t.block_hash = db_tx.block_hash
     t.block_height = db_tx.block_height
     t.status = 'confirmed'
     t.fee = db_tx.fee
     t.update_totals()
     if t.coinbase:
         t.input_total = t.output_total
     _logger.info("Retrieved transaction %s from cache" % t.hash)
     return t
Esempio n. 27
0
 def _parse_transaction(self, tx):
     status = 'unconfirmed'
     if tx['confirmations']:
         status = 'confirmed'
     t = Transaction.import_raw(tx['hex'])
     t.locktime = tx['locktime']
     t.network = self.network
     t.fee = tx['fee']
     t.date = datetime.utcfromtimestamp(tx['time']) if tx['time'] else None
     t.confirmations = tx['confirmations']
     t.block_height = tx['height'] if tx['height'] > 0 else None
     t.block_hash = tx['block']
     t.status = status
     if not t.coinbase:
         for i in t.inputs:
             i.value = tx['inputs'][t.inputs.index(i)]['coin']['value']
     for o in t.outputs:
         o.spent = None
     t.update_totals()
     return t
Esempio n. 28
0
 def _parse_transaction(self, tx):
     t = Transaction.import_raw(tx['raw_hex'], network=self.network)
     if t.hash != tx['txid']:
         raise ClientError(
             "Different hash from Blocksmurfer when parsing transaction")
     t.block_height = None if not tx['block_height'] else tx['block_height']
     t.confirmations = tx['confirmations']
     t.date = None if not tx['date'] else datetime.strptime(
         tx['date'][:19], "%Y-%m-%dT%H:%M:%S")
     if t.block_height and not t.confirmations and tx[
             'status'] == 'confirmed':
         block_count = self.blockcount()
         t.confirmations = block_count - t.block_height
     t.status = tx['status']
     t.fee = tx['fee']
     for ti in t.inputs:
         t.inputs[ti.index_n].value = tx['inputs'][ti.index_n]['value']
     for to in t.outputs:
         t.outputs[to.output_n].spent = tx['outputs'][to.output_n]['spent']
     t.update_totals()
     return t
Esempio n. 29
0
    def SignRemoteCommitmentTx(self, request, context):
        """BOLT #3 - Commitment Transaction, phase 1
        Sign the remote commitment tx, at commitment time
        """
        node_id = request.node_id.data
        node = self.nodes.get(node_id)
        logger.debug("SignRemoteCommitmentTx node:%s" % node_id.hex())

        channel_nonce = request.channel_nonce.data
        channel = node.channels.get(channel_nonce)

        tx = request.tx
        amount = tx.input_descs[0].prev_output.value_sat

        reply = remotesigner_pb2.SignatureReply()

        local_key = Key(import_key=channel.funding_privkey, is_private=True)
        remote_pub = channel.remote_basepoints.funding_pubkey
        remote_pubkey = Key(
            import_key=channel.remote_basepoints.funding_pubkey)

        pubs = sorted([remote_pub, local_key.public_compressed_byte])
        if remote_pub == pubs[0]:
            keys = [remote_pubkey, local_key]
        else:
            keys = [local_key, remote_pubkey]

        tx = Transaction.import_raw(tx.raw_tx_bytes, self.network)
        tx.inputs[0].script_type = "p2wsh"
        tx.inputs[0].witness_type = 'segwit'
        tx.inputs[0].sigs_required = 2
        tx.inputs[0].value = amount
        tx.witness_type = 'segwit'
        tx.sign(keys=keys, tid=0)

        logger.debug("channel.basepoints.funding_pk %s" %
                     channel.basepoints.funding_pk.hex())
        reply.signature.data = tx.inputs[0].signatures[0].as_der_encoded(
        ) + b'\x01'
        return reply
Esempio n. 30
0
    def SignPenaltyToUs(self, request, context):
        """BOLT #5 - Unilateral Close Handling, phase 1
        Sign a penalty tx to us - either sweeping the to-local commitment
        tx output or sweeping an HTLC tx output, after the remote
        broadcast a revoked commitment transaction.
        """
        node_id = request.node_id.data
        node = self.nodes.get(node_id)
        logger.debug("SignPenaltyToUs node:%s" % node_id.hex())

        channel_nonce = request.channel_nonce.data
        channel = node.channels.get(channel_nonce)

        revocation_secret = request.revocation_secret.data

        tx = request.tx
        amount = tx.input_descs[0].prev_output.value_sat
        redeemscript = tx.input_descs[0].redeem_script
        index = request.input

        revocationprivkey = derive_blinded_privkey(
            revocation_secret,
            channel.basepoints.keys.revocation_basepoint_secret)

        local_key = Key(import_key=revocationprivkey, is_private=True)
        keys = [local_key]

        tx = Transaction.import_raw(tx.raw_tx_bytes, self.network)
        tx.inputs[index].script_type = "p2wsh"
        tx.inputs[index].witness_type = 'segwit'
        tx.inputs[index].redeemscript = redeemscript
        tx.inputs[index].value = amount
        tx.witness_type = 'segwit'
        tx.sign(keys=keys, tid=index)

        reply = remotesigner_pb2.SignatureReply()
        reply.signature.data = tx.inputs[index].signatures[0].as_der_encoded(
        ) + b'\x01'

        return reply
Esempio n. 31
0
    def get_transactions(self):
        if not self.created:
            return succeed([])

        from bitcoinlib.transactions import Transaction
        from bitcoinlib.wallets import DbTransaction, DbTransactionInput

        # Update all transactions
        self.wallet.transactions_update(network=self.network)

        txs = self.wallet._session.query(DbTransaction.raw, DbTransaction.confirmations,
                                         DbTransaction.date, DbTransaction.fee)\
            .filter(DbTransaction.wallet_id == self.wallet.wallet_id)\
            .all()
        transactions = []

        for db_result in txs:
            transaction = Transaction.import_raw(db_result[0], network=self.network)
            transaction.confirmations = db_result[1]
            transaction.date = db_result[2]
            transaction.fee = db_result[3]
            transactions.append(transaction)

        # Sort them based on locktime
        transactions.sort(key=lambda tx: tx.locktime, reverse=True)

        my_keys = [key.address for key in self.wallet.keys(network=self.network, is_active=False)]

        transactions_list = []
        for transaction in transactions:
            value = 0
            input_addresses = []
            output_addresses = []
            for tx_input in transaction.inputs:
                input_addresses.append(tx_input.address)
                if tx_input.address in my_keys:
                    # At this point, we do not have the value of the input so we should do a database query for it
                    db_res = self.wallet._session.query(DbTransactionInput.value).filter(
                        hexlify(tx_input.prev_hash) == DbTransactionInput.prev_hash,
                        tx_input.output_n_int == DbTransactionInput.output_n).all()
                    if db_res:
                        value -= db_res[0][0]

            for tx_output in transaction.outputs:
                output_addresses.append(tx_output.address)
                if tx_output.address in my_keys:
                    value += tx_output.value

            transactions_list.append({
                'id': transaction.hash,
                'outgoing': value < 0,
                'from': ','.join(input_addresses),
                'to': ','.join(output_addresses),
                'amount': abs(value),
                'fee_amount': transaction.fee,
                'currency': 'BTC',
                'timestamp': time.mktime(transaction.date.timetuple()),
                'description': 'Confirmations: %d' % transaction.confirmations
            })

        return succeed(transactions_list)