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
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
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
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
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
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
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
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
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)
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
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
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
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
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
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']
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)
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}
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)
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
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
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
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
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
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
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
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
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
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
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)