def poll_confidence(request, coin_symbol, tx_hash): transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol, limit=1, show_confidence=True, api_key=BLOCKCYPHER_API_KEY, ) confidence = transaction_details.get('confidence') if confidence: confidence_pct = min(round(confidence * 100, 2), 99.99) else: confidence_pct = None json_dict = { 'confidence': confidence, 'confidence_pct': confidence_pct, 'confidence_pct_scaled': scale_confidence(confidence), 'double_spend_detected': transaction_details['double_spend'], 'receive_cnt': transaction_details.get('receive_count'), } json_response = json.dumps(json_dict, cls=DjangoJSONEncoder) return HttpResponse(json_response, content_type='application/json')
def decode_tx(request, coin_symbol): ''' Decode a raw transaction ''' initial = {'coin_symbol': coin_symbol} form = RawTXForm(initial=initial) tx_in_json_str, tx_uri, tx_hex = '', '', '' if request.method == 'POST': form = RawTXForm(data=request.POST) if form.is_valid(): # Display the TX tx_hex = form.cleaned_data['tx_hex'] coin_symbol_to_use = form.cleaned_data['coin_symbol'] tx_in_json = decodetx( tx_hex=tx_hex, coin_symbol=coin_symbol_to_use, api_key=BLOCKCYPHER_API_KEY, ) # import pprint; pprint.pprint(tx_in_json, width=1) tx_in_json_str = json.dumps(tx_in_json, indent=4, sort_keys=True) tx_hash = tx_in_json.get('hash') if tx_hash and 'error' not in tx_in_json: # check for existing TX in blockchain transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol_to_use, limit=1, api_key=BLOCKCYPHER_API_KEY, ) if 'error' not in transaction_details: kwargs = { 'coin_symbol': coin_symbol_to_use, 'tx_hash': tx_hash, } tx_uri = reverse('transaction_overview', kwargs=kwargs) elif request.method == 'GET': # Preseed tx hex if passed through GET string tx_hex = request.GET.get('t') if tx_hex: initial['tx_hex'] = tx_hex form = RawTXForm(initial=initial) return { 'coin_symbol': coin_symbol, 'form': form, 'tx_in_json_str': tx_in_json_str, 'tx_uri': tx_uri, 'tx_hex': tx_hex, 'is_input_page': True, }
def decode_tx(request, coin_symbol): """ Decode a raw transaction """ initial = {"coin_symbol": coin_symbol} form = RawTXForm(initial=initial) tx_in_json_str, tx_uri, tx_hex = "", "", "" if request.method == "POST": form = RawTXForm(data=request.POST) if form.is_valid(): # Display the TX tx_hex = form.cleaned_data["tx_hex"] coin_symbol_to_use = form.cleaned_data["coin_symbol"] tx_in_json = decodetx(tx_hex=tx_hex, coin_symbol=coin_symbol_to_use) # import pprint; pprint.pprint(tx_in_json, width=1) tx_in_json_str = json.dumps(tx_in_json, indent=4, sort_keys=True) tx_hash = tx_in_json.get("hash") if tx_hash and "error" not in tx_in_json: # check for existing TX in blockchain transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol_to_use, limit=1, api_key=BLOCKCYPHER_API_KEY ) if "error" not in transaction_details: kwargs = {"coin_symbol": coin_symbol_to_use, "tx_hash": tx_hash} tx_uri = reverse("transaction_overview", kwargs=kwargs) elif request.method == "GET": # Preseed tx hex if passed through GET string tx_hex = request.GET.get("t") if tx_hex: initial["tx_hex"] = tx_hex form = RawTXForm(initial=initial) return { "coin_symbol": coin_symbol, "form": form, "tx_in_json_str": tx_in_json_str, "tx_uri": tx_uri, "tx_hex": tx_hex, }
def poll_confidence(request, coin_symbol, tx_hash): transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol, limit=1, api_key=BLOCKCYPHER_API_KEY ) confidence = transaction_details.get("confidence") if confidence: confidence_pct = min(round(confidence * 100, 2), 99.99) else: confidence_pct = None json_dict = { "confidence": confidence, "confidence_pct": confidence_pct, "confidence_pct_scaled": scale_confidence(confidence), "double_spend_detected": transaction_details["double_spend"], "receive_cnt": transaction_details.get("receive_count"), } json_response = json.dumps(json_dict, cls=DjangoJSONEncoder) return HttpResponse(json_response, content_type="application/json")
def home(request): form = SearchForm( initial={ 'search_string': '16Fg2yjwrbtC6fZp61EV9mNVKmwCzGasw5', 'coin_symbol': 'btc', }) if request.method == 'POST': form = SearchForm(data=request.POST) if form.is_valid(): redirect_url = None search_string = form.cleaned_data['search_string'] coin_symbol = form.cleaned_data['coin_symbol'] kwargs = {'coin_symbol': coin_symbol} if is_valid_block_num(search_string): kwargs['block_representation'] = search_string redirect_url = reverse('block_overview', kwargs=kwargs) elif is_valid_hash(search_string): if coin_symbol in SHA_COINS: if is_valid_sha_block_hash(search_string): kwargs['block_representation'] = search_string redirect_url = reverse('block_overview', kwargs=kwargs) else: kwargs['tx_hash'] = search_string redirect_url = reverse('transaction_overview', kwargs=kwargs) elif coin_symbol in SCRYPT_COINS: # Try to see if it's a valid TX hash tx_details = get_transaction_details( tx_hash=search_string, coin_symbol=coin_symbol, limit=1, api_key=BLOCKCYPHER_API_KEY, ) if 'error' in tx_details: # Not a valid TX hash, see if it's a block hash by checking blockchain block_details = get_block_overview( block_representation=search_string, coin_symbol=coin_symbol, txn_limit=1, api_key=BLOCKCYPHER_API_KEY, ) if 'error' in block_details: msg = _( "Sorry, '%(search_string)s' is not a valid transaction or block hash for %(currency)s" % { 'currency': coin_symbol, 'search_string': search_string, }) messages.error(request, msg) else: kwargs['block_representation'] = search_string redirect_url = reverse('block_overview', kwargs=kwargs) else: kwargs['tx_hash'] = search_string redirect_url = reverse('transaction_overview', kwargs=kwargs) elif is_valid_address(search_string): # It's an address kwargs['address'] = search_string first_char = search_string[0] # Override coin_symbol if we can infer it from the blockchain # There is now generic constants in the python library (constants.py) # Not migrating because this is custom (those constants have overlap/ambiguity) if first_char in ('1', ): # Do not force addresses starting with 3 to be BTC because that's also used by LTC kwargs['coin_symbol'] = 'btc' elif first_char in ('m', 'n', '2'): # Note that addresses starting in 2 can be LTC testnet, but since we don't support that it's okay to include kwargs['coin_symbol'] = 'btc-testnet' elif first_char in ('9', 'A'): kwargs['coin_symbol'] = 'doge' elif first_char in ('L', ): # Do not force addresses starting with 3 to be LTC because that's also used by BTC kwargs['coin_symbol'] = 'ltc' elif first_char in ('B', 'C'): kwargs['coin_symbol'] = 'bcy' redirect_url = reverse('address_overview', kwargs=kwargs) elif is_valid_wallet_name(search_string): addr = lookup_wallet_name(search_string, kwargs['coin_symbol']) if addr: kwargs['address'] = addr kwargs['wallet_name'] = search_string redirect_url = reverse('address_overview', kwargs=kwargs) else: msg = _("Sorry, that's not a valid wallet name") messages.error(request, msg) if redirect_url: return HttpResponseRedirect(redirect_url) else: currency = COIN_SYMBOL_MAPPINGS[ request.POST['coin_symbol']]['display_shortname'] msg = _( "Sorry, '%(search_string)s' is not a valid %(currency)s address, wallet name, transaction or block" % { 'currency': currency, 'search_string': request.POST['search_string'], }) messages.error(request, msg) return {'is_home': True, 'form': form}
def transaction_overview(request, coin_symbol, tx_hash): try: TX_LIMIT = 50 transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol, limit=TX_LIMIT, api_key=BLOCKCYPHER_API_KEY, include_hex=False, show_confidence=True, ) except AssertionError: msg = _('Invalid Transaction Hash') messages.warning(request, msg) redir_url = reverse('coin_overview', kwargs={'coin_symbol': coin_symbol}) return HttpResponseRedirect(redir_url) # import pprint; pprint.pprint(transaction_details, width=1) if 'error' in transaction_details: # Corner case, such as a validly formed tx hash with no matching transaction msg = _('No transaction found with the hash %(tx_hash)s' % {'tx_hash': tx_hash}) messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) confidence = transaction_details.get('confidence') if confidence: confidence_pct = confidence * 100 confidence_pct_scaled = scale_confidence(confidence) else: confidence_pct, confidence_pct_scaled = None, None received_at = transaction_details['received'] confirmed_at = transaction_details.get('confirmed') inputs = transaction_details['inputs'] outputs = transaction_details['outputs'] total_satoshis = transaction_details['total'] fee_in_satoshis = transaction_details['fees'] if confirmed_at: if received_at >= confirmed_at: diff = received_at - confirmed_at else: diff = confirmed_at - received_at if diff.seconds < 60*20: time_to_use = received_at else: time_to_use = confirmed_at else: time_to_use = received_at if 'prev_hash' in inputs[0]: is_coinbase_tx = False total_satoshis_coinbase, fee_in_satoshis_coinbase = None, None coinbase_msg = None else: is_coinbase_tx = True total_satoshis_coinbase, fee_in_satoshis_coinbase = 0, 0 coinbase_msg = str(unhexlify(inputs[0]['script'])) api_url = 'https://api.blockcypher.com/v1/%s/%s/txs/%s?limit=%s&includeHex=true' % ( COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_code'], COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_network'], tx_hash, TX_LIMIT, ) return { 'coin_symbol': coin_symbol, 'tx_hash': tx_hash, 'api_url': api_url, 'is_coinbase_tx': is_coinbase_tx, 'coinbase_msg': coinbase_msg, 'received_at': received_at, 'confirmed_at': confirmed_at, 'time_to_use': time_to_use, 'total_satoshis': total_satoshis, 'total_satoshis_coinbase': total_satoshis_coinbase, 'fee_in_satoshis': fee_in_satoshis, 'fee_in_satoshis_coinbase': fee_in_satoshis_coinbase, 'inputs': inputs, 'outputs': outputs, 'confidence_pct': confidence_pct, 'confidence_pct_scaled': confidence_pct_scaled, 'transaction': transaction_details, 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }
def transaction_overview(request, coin_symbol, tx_hash): try: TX_LIMIT = 50 transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol, limit=TX_LIMIT, api_key=BLOCKCYPHER_API_KEY, include_hex=False, show_confidence=True, ) except AssertionError: msg = _('Invalid Transaction Hash') messages.warning(request, msg) redir_url = reverse('coin_overview', kwargs={'coin_symbol': coin_symbol}) return HttpResponseRedirect(redir_url) # import pprint; pprint.pprint(transaction_details, width=1) if 'error' in transaction_details: # Corner case, such as a validly formed tx hash with no matching transaction msg = _('No transaction found with the hash %(tx_hash)s' % {'tx_hash': tx_hash}) messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) confidence = transaction_details.get('confidence') if confidence: confidence_pct = confidence * 100 confidence_pct_scaled = scale_confidence(confidence) else: confidence_pct, confidence_pct_scaled = None, None received_at = transaction_details['received'] confirmed_at = transaction_details.get('confirmed') inputs = transaction_details['inputs'] outputs = transaction_details['outputs'] total_satoshis = transaction_details['total'] fee_in_satoshis = transaction_details['fees'] if confirmed_at: if received_at >= confirmed_at: diff = received_at - confirmed_at else: diff = confirmed_at - received_at if diff.seconds < 60*20: time_to_use = received_at else: time_to_use = confirmed_at else: time_to_use = received_at if 'prev_hash' in inputs[0]: is_coinbase_tx = False total_satoshis_coinbase, fee_in_satoshis_coinbase = None, None coinbase_msg = None else: is_coinbase_tx = True total_satoshis_coinbase = inputs[0]['output_value'] fee_in_satoshis_coinbase = total_satoshis - total_satoshis_coinbase coinbase_msg = str(unhexlify(inputs[0]['script'])) api_url = 'https://api.blockcypher.com/v1/%s/%s/txs/%s?limit=%s&includeHex=true' % ( COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_code'], COIN_SYMBOL_MAPPINGS[coin_symbol]['blockcypher_network'], tx_hash, TX_LIMIT, ) return { 'coin_symbol': coin_symbol, 'tx_hash': tx_hash, 'api_url': api_url, 'is_coinbase_tx': is_coinbase_tx, 'coinbase_msg': coinbase_msg, 'received_at': received_at, 'confirmed_at': confirmed_at, 'time_to_use': time_to_use, 'total_satoshis': total_satoshis, 'total_satoshis_coinbase': total_satoshis_coinbase, 'fee_in_satoshis': fee_in_satoshis, 'fee_in_satoshis_coinbase': fee_in_satoshis_coinbase, 'inputs': inputs, 'outputs': outputs, 'confidence_pct': confidence_pct, 'confidence_pct_scaled': confidence_pct_scaled, 'transaction': transaction_details, 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }
def home(request): form = SearchForm(initial={ 'search_string': '16Fg2yjwrbtC6fZp61EV9mNVKmwCzGasw5', 'coin_symbol': 'btc', }) if request.method == 'POST': form = SearchForm(data=request.POST) if form.is_valid(): redirect_url = None search_string = form.cleaned_data['search_string'] coin_symbol = form.cleaned_data['coin_symbol'] kwargs = {'coin_symbol': coin_symbol} if is_valid_block_num(search_string): kwargs['block_representation'] = search_string redirect_url = reverse('block_overview', kwargs=kwargs) elif is_valid_hash(search_string): if coin_symbol in SHA_COINS: if is_valid_sha_block_hash(search_string): kwargs['block_representation'] = search_string redirect_url = reverse('block_overview', kwargs=kwargs) else: kwargs['tx_hash'] = search_string redirect_url = reverse('transaction_overview', kwargs=kwargs) elif coin_symbol in SCRYPT_COINS: # Try to see if it's a valid TX hash tx_details = get_transaction_details( tx_hash=search_string, coin_symbol=coin_symbol, limit=1, api_key=BLOCKCYPHER_API_KEY, ) if 'error' in tx_details: # Not a valid TX hash, see if it's a block hash by checking blockchain block_details = get_block_overview( block_representation=search_string, coin_symbol=coin_symbol, txn_limit=1, api_key=BLOCKCYPHER_API_KEY, ) if 'error' in block_details: msg = _("Sorry, that's not a valid transaction or block hash for %(currency)s" % {'currency': coin_symbol}) messages.error(request, msg) else: kwargs['block_representation'] = search_string redirect_url = reverse('block_overview', kwargs=kwargs) else: kwargs['tx_hash'] = search_string redirect_url = reverse('transaction_overview', kwargs=kwargs) elif is_valid_address(search_string): # It's an address kwargs['address'] = search_string first_char = search_string[0] # Override coin_symbol if we can infer it from the blockchain # There is now generic constants in the python library (constants.py) # Not migrating because this is custom (those constants have overlap/ambiguity) if first_char in ('1', ): # Do not force addresses starting with 3 to be BTC because that's also used by LTC kwargs['coin_symbol'] = 'btc' elif first_char in ('m', 'n', '2'): # Note that addresses starting in 2 can be LTC testnet, but since we don't support that it's okay to include kwargs['coin_symbol'] = 'btc-testnet' elif first_char in ('9', 'A'): kwargs['coin_symbol'] = 'doge' elif first_char in ('L', ): # Do not force addresses starting with 3 to be LTC because that's also used by BTC kwargs['coin_symbol'] = 'ltc' elif first_char in ('U', ): kwargs['coin_symbol'] = 'uro' elif first_char in ('B', 'C'): kwargs['coin_symbol'] = 'bcy' redirect_url = reverse('address_overview', kwargs=kwargs) elif is_valid_wallet_name(search_string): addr = lookup_wallet_name(search_string, kwargs['coin_symbol']) if addr: kwargs['address'] = addr kwargs['wallet_name'] = search_string redirect_url = reverse('address_overview', kwargs=kwargs) else: msg = _("Sorry, that's not a valid wallet name") messages.error(request, msg) if redirect_url: return HttpResponseRedirect(redirect_url) else: currency = COIN_SYMBOL_MAPPINGS[request.POST['coin_symbol']]['display_shortname'] msg = _("Sorry, that's not a valid %(currency)s address, wallet name, transaction or block" % { 'currency': currency}) messages.error(request, msg) return { 'is_home': True, 'form': form }
def transaction_overview(request, coin_symbol, tx_hash): try: TX_LIMIT = 10000 transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol, limit=TX_LIMIT, api_key=BLOCKCYPHER_API_KEY, include_hex=True ) except AssertionError: msg = _("Invalid Transaction Hash") messages.warning(request, msg) redir_url = reverse("coin_overview", kwargs={"coin_symbol": coin_symbol}) return HttpResponseRedirect(redir_url) # import pprint; pprint.pprint(transaction_details, width=1) if "error" in transaction_details: # Corner case, such as a validly formed tx hash with no matching transaction msg = _("No transaction found with the hash %(tx_hash)s" % {"tx_hash": tx_hash}) messages.warning(request, msg) return HttpResponseRedirect(reverse("home")) confidence = transaction_details.get("confidence") if confidence: confidence_pct = confidence * 100 confidence_pct_scaled = scale_confidence(confidence) else: confidence_pct, confidence_pct_scaled = None, None received_at = transaction_details["received"] confirmed_at = transaction_details.get("confirmed") inputs = transaction_details["inputs"] outputs = transaction_details["outputs"] total_satoshis = transaction_details["total"] fee_in_satoshis = transaction_details["fees"] if confirmed_at: if received_at >= confirmed_at: diff = received_at - confirmed_at else: diff = confirmed_at - received_at if diff.seconds < 60 * 20: time_to_use = received_at else: time_to_use = confirmed_at else: time_to_use = received_at if "prev_hash" in inputs[0]: is_coinbase_tx = False total_satoshis_coinbase, fee_in_satoshis_coinbase = None, None coinbase_msg = None else: is_coinbase_tx = True total_satoshis_coinbase = inputs[0]["output_value"] fee_in_satoshis_coinbase = total_satoshis - total_satoshis_coinbase coinbase_msg = str(unhexlify(inputs[0]["script"])) api_url = "https://api.blockcypher.com/v1/%s/%s/txs/%s?limit=%s&includeHex=true" % ( COIN_SYMBOL_MAPPINGS[coin_symbol]["blockcypher_code"], COIN_SYMBOL_MAPPINGS[coin_symbol]["blockcypher_network"], tx_hash, TX_LIMIT, ) return { "coin_symbol": coin_symbol, "tx_hash": tx_hash, "api_url": api_url, "is_coinbase_tx": is_coinbase_tx, "coinbase_msg": coinbase_msg, "received_at": received_at, "confirmed_at": confirmed_at, "time_to_use": time_to_use, "total_satoshis": total_satoshis, "total_satoshis_coinbase": total_satoshis_coinbase, "fee_in_satoshis": fee_in_satoshis, "fee_in_satoshis_coinbase": fee_in_satoshis_coinbase, "inputs": inputs, "outputs": outputs, "confidence_pct": confidence_pct, "confidence_pct_scaled": confidence_pct_scaled, "transaction": transaction_details, "BLOCKCYPHER_PUBLIC_KEY": BLOCKCYPHER_PUBLIC_KEY, }
def transaction_overview(request, coin_symbol, tx_hash): transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol, limit=500, api_key=BLOCKCYPHER_API_KEY, ) # FIXME: fails silently on pagination if there are > 20 inputs or outputs #import pprint; pprint.pprint(transaction_details, width=1) if 'error' in transaction_details: # Corner case, such as a validly formed tx hash with no matching transaction msg = _('No transaction found with the hash %(tx_hash)s' % {'tx_hash': tx_hash}) messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) confidence = transaction_details.get('confidence') if confidence: confidence_pct = confidence * 100 else: confidence_pct = None received_at = transaction_details['received'] confirmed_at = transaction_details.get('confirmed') inputs = transaction_details['inputs'] outputs = transaction_details['outputs'] total_satoshis = transaction_details['total'] fee_in_satoshis = transaction_details['fees'] if confirmed_at: if received_at >= confirmed_at: diff = received_at - confirmed_at else: diff = confirmed_at - received_at if diff.seconds < 60*20: time_to_use = received_at else: time_to_use = confirmed_at else: time_to_use = received_at if 'prev_hash' in inputs[0]: is_coinbase_tx = False total_satoshis_coinbase, fee_in_satoshis_coinbase = None, None coinbase_msg = None else: is_coinbase_tx = True total_satoshis_coinbase = inputs[0]['output_value'] fee_in_satoshis_coinbase = total_satoshis - total_satoshis_coinbase coinbase_msg = str(unhexlify(inputs[0]['script'])) api_url = get_transaction_url(tx_hash=tx_hash, coin_symbol=coin_symbol) return { 'coin_symbol': coin_symbol, 'tx_hash': tx_hash, 'api_url': api_url, 'is_coinbase_tx': is_coinbase_tx, 'coinbase_msg': coinbase_msg, 'received_at': received_at, 'confirmed_at': confirmed_at, 'time_to_use': time_to_use, 'total_satoshis': total_satoshis, 'total_satoshis_coinbase': total_satoshis_coinbase, 'fee_in_satoshis': fee_in_satoshis, 'fee_in_satoshis_coinbase': fee_in_satoshis_coinbase, 'inputs': inputs, 'outputs': outputs, 'confidence_pct': confidence_pct, 'transaction': transaction_details, 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }
def transaction_overview(request, coin_symbol, tx_hash): transaction_details = get_transaction_details( tx_hash=tx_hash, coin_symbol=coin_symbol, limit=500, api_key=BLOCKCYPHER_API_KEY, ) # FIXME: fails silently on pagination if there are > 20 inputs or outputs #import pprint; pprint.pprint(transaction_details, width=1) if 'error' in transaction_details: # Corner case, such as a validly formed tx hash with no matching transaction msg = _('No transaction found with the hash %(tx_hash)s' % {'tx_hash': tx_hash}) messages.warning(request, msg) return HttpResponseRedirect(reverse('home')) confidence = transaction_details.get('confidence') if confidence: confidence_pct = confidence * 100 else: confidence_pct = None received_at = transaction_details['received'] confirmed_at = transaction_details.get('confirmed') inputs = transaction_details['inputs'] outputs = transaction_details['outputs'] total_satoshis = transaction_details['total'] fee_in_satoshis = transaction_details['fees'] if confirmed_at: if received_at >= confirmed_at: diff = received_at - confirmed_at else: diff = confirmed_at - received_at if diff.seconds < 60 * 20: time_to_use = received_at else: time_to_use = confirmed_at else: time_to_use = received_at if inputs[0]['addresses']: is_coinbase_tx = False total_satoshis_coinbase, fee_in_satoshis_coinbase = None, None coinbase_msg = None else: is_coinbase_tx = True total_satoshis_coinbase = inputs[0]['output_value'] fee_in_satoshis_coinbase = total_satoshis - total_satoshis_coinbase coinbase_msg = str(unhexlify(inputs[0]['script'])) api_url = get_transaction_url(tx_hash=tx_hash, coin_symbol=coin_symbol) return { 'coin_symbol': coin_symbol, 'tx_hash': tx_hash, 'api_url': api_url, 'is_coinbase_tx': is_coinbase_tx, 'coinbase_msg': coinbase_msg, 'double_of_tx': transaction_details.get('double_of'), 'received_at': received_at, 'confirmed_at': confirmed_at, 'time_to_use': time_to_use, 'total_satoshis': total_satoshis, 'total_satoshis_coinbase': total_satoshis_coinbase, 'fee_in_satoshis': fee_in_satoshis, 'fee_in_satoshis_coinbase': fee_in_satoshis_coinbase, 'block_height': transaction_details['block_height'], 'block_hash': transaction_details.get('block_hash'), 'inputs': inputs, 'outputs': outputs, 'num_confirmations': transaction_details['confirmations'], 'relayed_by': transaction_details['relayed_by'], 'num_inputs': transaction_details['vin_sz'], 'num_outputs': transaction_details['vout_sz'], 'confidence_pct': confidence_pct, 'preference': transaction_details.get('preference'), 'receive_cnt': transaction_details.get('receive_count'), 'BLOCKCYPHER_PUBLIC_KEY': BLOCKCYPHER_PUBLIC_KEY, }