def draw_transactions(state): g.viewport_height = state['y'] - 2 win_transactions = curses.newwin(g.viewport_height, g.x, 1, 0) txdata = state['mempool']['transactions'] g.addstr_rjust(win_transactions, 0, "(UP/DOWN: scroll, ENTER: view, M: refresh)", curses.A_BOLD + curses.color_pair(5), 1) # reset cursor if it's been resized off the bottom if state['mempool']['cursor'] > state['mempool']['offset'] + (g.viewport_height - 2): state['mempool']['offset'] = state['mempool']['cursor'] - (g.viewport_height - 2) offset = state['mempool']['offset'] for index in xrange(offset, offset+g.viewport_height-1): if index < len(txdata): if index == int(state['mempool']['cursor']): win_transactions.addstr(index+1-offset, 1, ">", curses.A_REVERSE + curses.A_BOLD) condition = (index == offset+g.viewport_height-2) and (index+1 < len(txdata)) condition = condition or ( (index == offset) and (index > 0) ) if condition: win_transactions.addstr(index+1-offset, 3, "...") else: win_transactions.addstr(index+1-offset, 3, "{: 6,d}".format(int(index) + 1) + ": " + txdata[index]) win_transactions.refresh()
def draw_addresses(state): g.viewport_heigth = g.y - 5 win_addresses = curses.newwin(g.viewport_heigth, g.x, 4, 0) offset = state['wallet']['offset'] if 'addresses_view_string' in state['wallet']: win_addresses.addstr(0, 1, str(len(state['wallet']['addresses_view_string'])/4) + " addresses:", curses.A_BOLD + curses.color_pair(5)) g.addstr_rjust(win_addresses, 0, "(UP/DOWN: scroll)", curses.A_BOLD + curses.color_pair(5), 1) for index in xrange(offset, offset + g.viewport_heigth - 1): if index < len(state['wallet']['addresses_view_string']): condition = (index == offset + g.viewport_heigth - 2) and (index+1 < len(state['wallet']['addresses_view_string'])) condition = condition or ( (index == offset) and (index > 0) ) if condition: win_addresses.addstr(index+1-offset, 1, "...") else: win_addresses.addstr(index+1-offset, 1, state['wallet']['addresses_view_string'][index], curses.color_pair(state['wallet']['addresses_view_colorpair'][index])) else: g.addstr_cjust(win_addresses, 0, "...waiting for address information being processed...", curses.A_BOLD + curses.color_pair(3)) # win_addresses.addstr(1, 1, "...waiting for address information being processed...", curses.A_BOLD + curses.color_pair(3)) win_addresses.refresh()
def draw_outputs(state): window_height = (g.y - 4) / 2 win_outputs = curses.newwin(window_height, g.x, 3 + window_height, 0) if state['tx']['mode'] == 'outputs': win_outputs.addstr(0, 1, "outputs:", curses.A_BOLD + curses.color_pair(3)) g.addstr_rjust(win_outputs, 0, "(UP/DOWN: scroll)", curses.A_BOLD + curses.color_pair(3), 1) else: win_outputs.addstr(0, 1, "outputs:", curses.A_BOLD + curses.color_pair(5)) g.addstr_rjust(win_outputs, 0, "(TAB: switch to)", curses.A_BOLD + curses.color_pair(5), 1) offset = state['tx']['out_offset'] for index in xrange(offset, offset + window_height - 1): if index < len(state['tx']['vout_string']): condition = (index == offset + window_height - 2) and (index + 1 < len(state['tx']['vout_string'])) condition = condition or ((index == offset) and (index > 0)) if condition: win_outputs.addstr(index + 1 - offset, 1, "... ") else: string = state['tx']['vout_string'][index] if '[UNSPENT]' in string: color = curses.color_pair(1) elif '[SPENT]' in string or '[UNCONFIRMED SPEND]' in string: color = curses.color_pair(3) else: color = 0 win_outputs.addstr(index + 1 - offset, 1, string, color) win_outputs.refresh()
def draw_window(state, window, rpc_queue = None, do_clear = True): if do_clear: window.clear() window.refresh() win_header = curses.newwin(3, g.x, 0, 0) if 'peerinfo' in state: win_header.addstr(0, 1, "Connected peers: " + str(len(state['peerinfo'])), curses.A_BOLD) g.addstr_rjust(win_header, 0, "(UP/DOWN: scroll, P: refresh)", curses.A_BOLD, 1) win_header.addstr(2, 1, " Node IP Version", curses.A_BOLD + curses.color_pair(5)) header = "Recv MB Sent MB Time Height" win_header.addstr(2, (g.x - len(header) - 1 if g.x <= 100 else 99 - len(header)), header, curses.A_BOLD + curses.color_pair(5)) draw_peers(state) else: if rpc_queue.qsize() > 0: g.addstr_cjust(win_header, 0, "...waiting for peer information being processed...", curses.A_BOLD + curses.color_pair(3)) else: win_header.addstr(0, 1, "no peer information loaded.", curses.A_BOLD + curses.color_pair(3)) win_header.addstr(1, 1, "press 'P' to refresh", curses.A_BOLD) win_header.refresh() footer.draw_window(state, rpc_queue)
def draw_window(state, window, rpc_queue): window.clear() window.refresh() win_header = curses.newwin(1, g.x, 0, 0) g.addstr_rjust(win_header, 0, "(G: enter command, E: erase output)", curses.A_BOLD + curses.color_pair(5), 1) win_header.refresh() if len(state['console']['rbuffer']): draw_buffer(state) footer.draw_window(state, rpc_queue)
def draw_transactions(state): g.viewport_height = state['y'] - 6 win_transactions = curses.newwin(g.viewport_height, g.x, 5, 0) height = str(state['blocks']['browse_height']) blockdata = state['blocks'][height] tx_count = len(blockdata['tx']) bytes_per_tx = blockdata['size'] / tx_count win_transactions.addstr( 0, 1, "Transactions: " + "{: 4,d}".format(int(tx_count)) + " (" + str(bytes_per_tx) + " bytes/tx)", curses.A_BOLD + curses.color_pair(5)) g.addstr_rjust(win_transactions, 0, "(UP/DOWN: scroll, ENTER: view)", curses.A_BOLD + curses.color_pair(5), 1) # reset cursor if it's been resized off the bottom if state['blocks']['cursor'] > state['blocks']['offset'] + ( g.viewport_height - 2): state['blocks']['offset'] = state['blocks']['cursor'] - ( g.viewport_height - 2) offset = state['blocks']['offset'] for index in xrange(offset, offset + g.viewport_height - 1): if index < len(blockdata['tx']): if index == state['blocks']['cursor']: win_transactions.addstr(index + 1 - offset, 1, ">", curses.A_REVERSE + curses.A_BOLD) condition = (index == offset + g.viewport_height - 2) and (index + 1 < len(blockdata['tx'])) condition = condition or ((index == offset) and (index > 0)) if condition: win_transactions.addstr(index + 1 - offset, 3, "...") else: win_transactions.addstr( index + 1 - offset, 3, "{: 5d}".format(int(index) + 1) + ": " + blockdata['tx'][index]) win_transactions.refresh()
def draw_window(state, rpc_queue = None, only_work_indicator = False): win_footer = curses.newwin(1, g.x, g.y - 1, 0) color = curses.color_pair(1) if 'testnet' in state: if state['testnet']: color = curses.color_pair(2) if not only_work_indicator: x = 1 for mode_string in g.modes: modifier = curses.A_BOLD if state['mode'] == mode_string: modifier += curses.A_REVERSE win_footer.addstr(0, x, mode_string[0].upper(), modifier + curses.color_pair(5)) win_footer.addstr(0, x+1, mode_string[1:], modifier) x += len(mode_string) + 2 if rpc_queue is not None: if rpc_queue.qsize() > 0: working_indicator = 'wrk... (' + str(rpc_queue.qsize()) + ')' g.addstr_rjust(win_footer, 0, working_indicator, curses.A_BOLD + curses.color_pair(3), 1) win_footer.refresh()
def draw_transactions(state): g.viewport_heigth = g.y - 5 win_transactions = curses.newwin(g.viewport_heigth, g.x, 4, 0) win_transactions.addstr(0, 1, "{:,d}".format(len(state['wallet']['view_string'])/(5 if state['wallet']['verbose'] > 0 else 4)) + " transactions:", curses.A_BOLD + curses.color_pair(5)) caption = "(UP/DOWN: scroll, ENTER: view, V: less verbose)" if state['wallet']['verbose'] > 0 else "(UP/DOWN: scroll, ENTER: view, V: verbose, O: Output tx)" g.addstr_rjust(win_transactions, 0, caption, curses.A_BOLD + curses.color_pair(5), 1) offset = state['wallet']['offset'] for index in xrange(offset, offset + g.viewport_heigth - 1): if index < len(state['wallet']['view_string']): condition = (index == offset + g.viewport_heigth - 2) and (index+1 < len(state['wallet']['view_string'])) condition = condition or ( (index == offset) and (index > 0) ) if condition: win_transactions.addstr(index+1-offset, 1, "...") else: win_transactions.addstr(index+1-offset, 1, state['wallet']['view_string'][index], curses.color_pair(state['wallet']['view_colorpair'][index])) if index == (state['wallet']['cursor']* (5 if state['wallet']['verbose'] > 0 else 4) + 1): win_transactions.addstr(index+1-offset, 1, ">", curses.A_REVERSE + curses.A_BOLD) win_transactions.refresh()
def draw_window(state, window, rpc_queue=None): window.clear() window.refresh() win_header = curses.newwin(4, g.x, 0, 0) if 'chaintips' in state: win_header.addstr(0, 1, "chain tips: " + str(len(state['chaintips'])), curses.A_BOLD) g.addstr_rjust(win_header, 0, "(UP/DOWN: scroll, F: refresh)", curses.A_BOLD) win_header.addstr( 1, 1, "key: Active/Invalid/HeadersOnly/ValidFork/ValidHeaders", curses.A_BOLD) win_header.addstr(3, 1, "height, length, status, 0-prefix hash", curses.A_BOLD + curses.color_pair(5)) draw_tips(state) else: if rpc_queue.qsize() > 0: g.addstr_cjust( win_header, 0, "...waiting for chain tip information being processed...", curses.A_BOLD + curses.color_pair(3)) else: win_header.addstr(0, 1, "no chain tip information loaded.", curses.A_BOLD + curses.color_pair(3)) win_header.addstr(1, 1, "press 'F' to refresh", curses.A_BOLD) if g.coin_unit == 'BTC': win_header.addstr( 2, 1, "(note that bitcoind 0.9.3 and older do not support this feature)", curses.A_BOLD) win_header.refresh() footer.draw_window(state, rpc_queue)
def draw_window(state, window, rpc_queue=None, do_clear = True): if do_clear: window.clear() window.refresh() win_header = curses.newwin(3, g.x, 0, 0) unit = g.coin_unit if 'testnet' in state: if state['testnet']: unit = g.coin_unit_test if 'wallet' in state or 'walletinfo' in state: if 'balance' in state: balance_string = "Balance: " + "%0.8f" % state['balance'] + " " + unit if 'unconfirmedbalance' in state: if state['unconfirmedbalance'] != 0: balance_string += " (+" + "%0.8f" % state['unconfirmedbalance'] + " unconf)" if 'unconfirmed_balance' in state: if state['unconfirmed_balance'] != 0: balance_string += " (+" + "%0.8f" % state['unconfirmed_balance'] + " unconf)" window.addstr(0, 1, balance_string, curses.A_BOLD) if 'walletinfo' in state: if 'paytxfee' in state['walletinfo']: fee_string = "Fee: " + "%0.8f" % state['walletinfo']['paytxfee'] + " " + unit + " per kB" window.addstr(1, 1, fee_string, curses.A_BOLD) fee_string = "Wallet status: " if 'unlocked_until' in state['walletinfo']: if state['walletinfo']['unlocked_until'] == 0: fee_string += 'locked' window.addstr(2, 1, fee_string, curses.A_BOLD) else: try: fee_string += 'unlocked until ' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(state['walletinfo']['unlocked_until'])) except ValueError: fee_string += 'unlocked!!! (' + str(state['walletinfo']['unlocked_until'])+ ')' window.addstr(2, 1, fee_string, curses.A_BOLD + curses.A_REVERSE) else: fee_string += 'not encrypted!' window.addstr(2, 1, fee_string, curses.A_BOLD + curses.A_REVERSE) if state['wallet']['mode'] == 'tx': g.addstr_rjust(window, 0, "(W: refresh, A: list addresses, R: new address)", curses.A_BOLD, 1) g.addstr_rjust(window, 1, "(X: set tx fee, S: send " + unit + ")", curses.A_BOLD, 1) g.addstr_rjust(window, 2, "(E: export all txs, L: export wallet.dat)", curses.A_BOLD, 1) draw_transactions(state) elif state['wallet']['mode'] == 'settxfee': draw_fee_input_window(state, window, rpc_queue) elif state['wallet']['mode'] == 'newaddress': draw_new_address_window(state, window, rpc_queue) elif state['wallet']['mode'] == 'sendtoaddress': draw_send_coins_window(state, window, rpc_queue) elif state['wallet']['mode'] == 'backupwallet': draw_backup_wallet_window(state, window, rpc_queue) elif state['wallet']['mode'] == 'exporttx': draw_exporttx_window(state, window, rpc_queue) else: g.addstr_rjust(window, 0, "(W: refresh, A: list addresses, R: new address)", curses.A_BOLD, 1) g.addstr_rjust(window, 1, "(X: set tx fee, S: send " + unit + ")", curses.A_BOLD, 1) g.addstr_rjust(window, 2, "(E: export all txs, L: export wallet.dat)", curses.A_BOLD, 1) draw_addresses(state) else: if rpc_queue.qsize() > 0: g.addstr_cjust(win_header, 0, "...waiting for wallet information being processed...", curses.A_BOLD + curses.color_pair(3)) else: win_header.addstr(0, 1, "no wallet information loaded.", curses.A_BOLD + curses.color_pair(3)) win_header.addstr(1, 1, "press 'W' to refresh", curses.A_BOLD) win_header.refresh() footer.draw_window(state, rpc_queue)
def draw_window(state, window, rpc_queue=None): window.clear() window.refresh() win_header = curses.newwin(5, g.x, 0, 0) if 'browse_height' in state['blocks']: height = str(state['blocks']['browse_height']) if height in state['blocks']: blockdata = state['blocks'][height] win_header.addstr(0, 1, "Height: " + "{:,d}".format(int(height)), curses.A_BOLD) g.addstr_rjust( win_header, 0, "(J/K: browse, HOME/END: quicker, L: latest, G: seek)", curses.A_BOLD, 1) win_header.addstr(1, 1, "Hash: " + blockdata['hash'], curses.A_BOLD) win_header.addstr(2, 1, "Root: " + blockdata['merkleroot'], curses.A_BOLD) win_header.addstr( 3, 1, str("{:,d}".format(int(blockdata['size']))) + " bytes (" + str(blockdata['size'] / 1024) + " KB) ", curses.A_BOLD) g.addstr_cjust( win_header, 3, "Diff: " + "{:,d}".format(int(blockdata['difficulty'])), curses.A_BOLD, 0, 4, 2) g.addstr_rjust( win_header, 3, time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(blockdata['time'])), curses.A_BOLD, 1) version_bits = "{0:032b}".format(int(blockdata['version'])) version_bits = version_bits[0:7] + " " + version_bits[ 8:15] + " " + version_bits[16:23] + " " + version_bits[24:] win_header.addstr( 4, 1, "Version: " + str(blockdata['version']) + " (" + version_bits + ")", curses.A_BOLD) draw_transactions(state) state['blocks']['loaded'] = 1 else: if rpc_queue.qsize() > 0: g.addstr_cjust( win_header, 0, "...waiting for block information being processed...", curses.A_BOLD + curses.color_pair(3)) else: win_header.addstr(0, 1, "no block information loaded.", curses.A_BOLD + curses.color_pair(3)) win_header.addstr( 1, 1, "press 'G' to enter a block hash, height, or timestamp", curses.A_BOLD) else: if rpc_queue.qsize() > 0: g.addstr_cjust( win_header, 0, "...waiting for block information being processed...", curses.A_BOLD + curses.color_pair(3)) else: win_header.addstr(0, 1, "no block information loaded.", curses.A_BOLD + curses.color_pair(3)) win_header.addstr( 1, 1, "press 'G' to enter a block hash, height, or timestamp", curses.A_BOLD) win_header.refresh() footer.draw_window(state, rpc_queue)
def draw_inputs(state): window_height = (state['y'] - 4) / 2 window_width = state['x'] win_inputs = curses.newwin(window_height, window_width, 3, 0) if state['tx']['mode'] == 'inputs': win_inputs.addstr(0, 1, "inputs:", curses.A_BOLD + curses.color_pair(3)) g.addstr_rjust(win_inputs, 0, "(UP/DOWN: select, ENTER: view)", curses.A_BOLD + curses.color_pair(3), 1) else: win_inputs.addstr(0, 1, "inputs:", curses.A_BOLD + curses.color_pair(5)) g.addstr_rjust(win_inputs, 0, "(TAB: switch to)", curses.A_BOLD + curses.color_pair(5), 1) # reset cursor if it's been resized off the bottom if state['tx']['cursor'] > state['tx']['offset'] + (window_height - 2): state['tx']['offset'] = state['tx']['cursor'] - (window_height - 2) offset = state['tx']['offset'] for index in xrange(offset, offset + window_height - 1): if index < len(state['tx']['vin']): if 'txid' in state['tx']['vin'][index]: buffer_string = state['tx']['vin'][index][ 'txid'] + ":" + "%03d" % state['tx']['vin'][index]['vout'] if 'prev_tx' in state['tx']['vin'][index]: vout = state['tx']['vin'][index]['prev_tx'] if 'value' in vout: if vout['scriptPubKey']['type'] == "pubkeyhash": buffer_string = "% 14.8f" % vout[ 'value'] + ": " + vout['scriptPubKey'][ 'addresses'][0].ljust(34) else: if len(vout['scriptPubKey'] ['asm']) > window_width - 37: buffer_string = "% 14.8f" % vout[ 'value'] + ": ..." + vout['scriptPubKey'][ 'asm'][-(window_width - 40):] else: buffer_string = "% 14.8f" % vout[ 'value'] + ": " + vout['scriptPubKey'][ 'asm'] length = len(buffer_string) if length + 72 < window_width: buffer_string += " " + state['tx']['vin'][index][ 'txid'] + ":" + "%03d" % state['tx']['vin'][ index]['vout'] else: buffer_string += " " + state['tx']['vin'][index][ 'txid'][:(window_width - length - 14)] + "[...]:" + "%03d" % state[ 'tx']['vin'][index]['vout'] if index == (state['tx']['cursor']): win_inputs.addstr(index + 1 - offset, 1, ">", curses.A_REVERSE + curses.A_BOLD) condition = (index == offset + window_height - 2) and (index + 1 < len(state['tx']['vin'])) condition = condition or ((index == offset) and (index > 0)) if condition: win_inputs.addstr(index + 1 - offset, 3, "...") else: win_inputs.addstr(index + 1 - offset, 3, buffer_string) elif 'coinbase' in state['tx']['vin'][index]: coinbase = "[coinbase] " + state['tx']['vin'][index]['coinbase'] coinbase_string = " [strings] " + binascii.unhexlify( state['tx']['vin'][index]['coinbase']) # strip non-ASCII characters coinbase_string = ''.join( [x for x in coinbase_string if 31 < ord(x) < 127]) if len(coinbase) > window_width - 1: win_inputs.addstr(index + 1 - offset, 1, coinbase[:window_width - 5] + " ...") else: win_inputs.addstr(index + 1 - offset, 1, coinbase[:window_width - 1]) if len(coinbase_string) > window_width - 1: win_inputs.addstr( index + 2 - offset, 1, coinbase_string[:window_width - 5] + " ...") else: win_inputs.addstr(index + 2 - offset, 1, coinbase_string[:window_width - 1]) win_inputs.refresh()
def draw_window(state, window, rpc_queue): # TODO: add transaction locktime, add sequence to inputs window.clear() window.refresh() win_header = curses.newwin(3, g.x, 0, 0) unit = g.coin_unit if g.testnet: unit = g.coin_unit_test if 'tx' in state: win_header.addstr(0, 1, "txid: " + state['tx']['txid'], curses.A_BOLD) win_header.addstr( 1, 1, str(state['tx']['size']) + " bytes (" + "{:.2f}".format(float(state['tx']['size']) / 1024.0) + " KB) ", curses.A_BOLD) if 'total_outputs' in state['tx']: output_string = "%.8f" % state['tx']['total_outputs'] + " " + unit if 'total_inputs' in state['tx']: if state['tx']['total_inputs'] == 'coinbase': fee = float(0) output_string += " (coinbase)" else: # Verbose mode only try: if float(state['tx']['total_inputs']) == 0: fee = float(0) else: fee = float(state['tx']['total_inputs']) - float( state['tx']['total_outputs']) except: fee = float(state['tx']['total_inputs']) - float( state['tx']['total_outputs']) output_string += " + " + "%.8f" % fee + " " + unit + " fee" else: output_string += " + unknown fee" win_header.addstr(1, 26, output_string.rjust(45), curses.A_BOLD) if 'time' in state['tx']: output_string = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(state['tx']['time'])) else: output_string = "" if 'confirmations' in state['tx']: output_string += ("" if not len(output_string) else " / ") + "{:,d}".format( int(state['tx']['confirmations'])) + " conf" else: output_string += ("" if not len(output_string) else " / ") + "unconfirmed" win_header.addstr(2, 1, output_string[:g.x - 2], curses.A_BOLD) history_height = 0 if not 'txid_history' in state else len( state['txid_history']) - 1 if history_height <= 0: history_msg = "" else: if g.x > 79: history_msg = ", J: browse back" else: history_msg = ", J: go back" g.addstr_rjust(win_header, 2, "(V: verbose, G: enter txid" + history_msg + ")", curses.A_BOLD, 1) draw_inputs(state) draw_outputs(state) else: if rpc_queue.qsize() > 0: g.addstr_cjust( win_header, 0, "...waiting for transaction information being processed...", curses.A_BOLD + curses.color_pair(3)) else: win_header.addstr( 0, 1, "no transaction loaded or no transaction information found.", curses.A_BOLD + curses.color_pair(3)) win_header.addstr( 1, 1, "if you have entered one, consider running " + g.rpc_deamon + " with -txindex", curses.A_BOLD) win_header.addstr(2, 1, "press 'G' to enter a txid", curses.A_BOLD) win_header.refresh() footer.draw_window(state, rpc_queue)
def draw_window(state, old_window, rpc_queue, do_clear = True): window = curses.newwin(g.y - 1, g.x, 0, 0) if do_clear: old_window.clear() old_window.refresh() # display load average load_avg = os.getloadavg() g.addstr_rjust(window, 1, "Load avg: " + "{:.2f}".format(load_avg[0]) + " / " + "{:.2f}".format(load_avg[1]) + " / " + "{:.2f}".format(load_avg[2]), curses.A_BOLD, 1) # pad lines are optionial - depending on window size padline = [1, 1, 1, 1] (this_y, this_x) = window.getmaxyx() if this_y <= 15: padline[3] = 0 if this_y <= 14: padline[2] = 0 if this_y <= 13: padline[1] = 0 if this_y <= 12: padline[0] = 0 if 'version' in state: if state['testnet'] == 1: g.testnet = True; color = curses.color_pair(2) window.addstr(1, 1, g.rpc_deamon + " v" + state['version'] + " (TESTNET)", color + curses.A_BOLD) unit = g.coin_unit_test else: g.testnet = False; color = curses.color_pair(1) window.addstr(1, 1, g.rpc_deamon + " v" + state['version'] + " ", color + curses.A_BOLD) unit = g.coin_unit window.addstr(0, 1, g.rpc_deamon + "-ncurses " + g.version, color + curses.A_BOLD) if 'peers' in state: if state['peers'] > 0: color = 0 else: color = curses.color_pair(3) g.addstr_ljust(window, 0, str(state['peers']) + " peers", color + curses.A_BOLD, 0, 10, 4) if 'balance' in state and g.wallet_support: balance_string = "%0.8f" % state['balance'] + " " + unit if 'unconfirmedbalance' in state: if state['unconfirmedbalance'] != 0: balance_string += " (+" + "%0.8f" % state['unconfirmedbalance'] + " unconf)" g.addstr_ljust(window, 1, balance_string, curses.A_BOLD, 0, 10, 4) else: g.addstr_ljust(window, 1, "- wallet disabled -", curses.A_BOLD, 0, 10, 4) if 'mininginfo' in state: height = str(state['mininginfo']['blocks']) if height in state['blocks']: blockdata = state['blocks'][str(height)] if 'new' in blockdata: window.attrset(curses.A_REVERSE + curses.color_pair(5) + curses.A_BOLD) blockdata.pop('new') window.addstr(2 + padline[0], 1, "{:7d}".format(int(height)) + ": " + str(blockdata['hash'])) window.addstr(3 + padline[0], 1, "{:,d}".format(int(blockdata['size'])) + " bytes (" + "{:,.2f}".format(float(blockdata['size']/1024)) + " KB) ") tx_count = len(blockdata['tx']) bytes_per_tx = blockdata['size'] / tx_count window.addstr(4 + padline[0], 1, "Transactions: " + "{:,d}".format(int(tx_count)) + " (" + "{:,d}".format(int(bytes_per_tx)) + " bytes/tx)") if 'coinbase_amount' in blockdata: block_subsidy = float(float(g.reward_base) / (2 ** (state['mininginfo']['blocks'] // g.halving_blockamount))) if block_subsidy: coinbase_amount = float(blockdata['coinbase_amount']) total_fees = float(coinbase_amount) - block_subsidy # assumption, mostly correct if coinbase_amount > 0: fee_percentage = "%0.2f" % ((total_fees / coinbase_amount) * 100) coinbase_amount_str = "%0.8f" % coinbase_amount window.addstr(5 + padline[0] + padline[1], 1, "Total block reward: " + coinbase_amount_str + " " + unit + " (" + str(block_subsidy) + " " + unit + " +" + fee_percentage + "% fees)") if tx_count > 1: tx_count -= 1 # the coinbase can't pay a fee fees_per_tx = (total_fees / tx_count) * 1000 fees_per_kb = ((total_fees * 1024) / blockdata['size']) * 1000 total_fees_str = "%0.8f" % total_fees + " " + unit fees_per_tx = "%0.5f" % fees_per_tx + " m" + unit + "/tx" fees_per_kb = "%0.5f" % fees_per_kb + " m" + unit + "/KB" window.addstr(6 + padline[0] + padline[1], 1, "Fees: " + total_fees_str + " (avg " + fees_per_tx + ", ~" + fees_per_kb + ")") g.addstr_rjust(window, 3 + padline[0], "Block timestamp: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(blockdata['time'])), curses.A_NORMAL, 1) if state['lastblocktime'] == 0: recvdelta_string = " " else: recvdelta = int(time.time() - state['lastblocktime']) m, s = divmod(recvdelta, 60) h, m = divmod(m, 60) recvdelta_string = "{:02d}:{:02d}:{:02d}".format(h,m,s) stampdelta = int(time.time() - blockdata['time']) if stampdelta > 3600*3: # probably syncing if it's three hours old stampdelta_string = " (syncing)" elif stampdelta > 0: m, s = divmod(stampdelta, 60) h, m = divmod(m, 60) d, h = divmod(h, 24) stampdelta_string = "({:d}d {:02d}:{:02d}:{:02d} by stamp)".format(d,h,m,s) else: stampdelta_string = " (stamp in future)" g.addstr_rjust(window, 4 + padline[0], "Age: " + recvdelta_string + " " + stampdelta_string, curses.A_NORMAL, 1) if 'chainwork' in blockdata: log2_chainwork = math.log(int(blockdata['chainwork'], 16), 2) try: window.addstr(10 + padline[0] + padline[1] + padline[2] + padline[3], 1, "Chain work: 2**" + "%0.6f" % log2_chainwork) except: pass diff = int(state['mininginfo']['difficulty']) window.addstr(7 + padline[0] + padline[1] + padline[2], 1, "Diff: " + "{:,d}".format(diff)) for block_avg in state['networkhashps']: index = 7 + padline[0] + padline[1] + padline[2] if block_avg == 'diff': pass elif block_avg == 2016: index += 1 elif block_avg == g.blocks_per_day: index += 2 else: break rate = state['networkhashps'][block_avg] if block_avg != 'diff': nextdiff = (rate*600)/(2**32) if state['testnet'] == 1: nextdiff *= 2 # testnet has 1200 est. block interval, not 600 try: window.addstr(index, 1, "Est (" + str(block_avg).rjust(4) + "): ~" + "{:,d}".format(int(nextdiff))) except: window.addstr(index, 1, "Est (" + str(block_avg).rjust(4) + "): ~" + "{:,d}".format(int(nextdiff))) if rate > 10**18: rate /= 10**18 suffix = " EH/s" elif rate > 10**12: rate /= 10**12 suffix = " TH/s" else: rate /= 10**6 suffix = " MH/s" try: rate_string = "{:9.4f}".format(float(rate)) + suffix g.addstr_rjust(window, index, "Hashrate (" + str(block_avg).rjust(4) + "): " + rate_string.rjust(13), curses.A_NORMAL, 1) except: g.addstr_rjust(window, index, "Hashrate (" + str(block_avg).rjust(4) + "): ?????????????", curses.A_NORMAL, 1) index += 1 pooledtx = state['mininginfo']['pooledtx'] g.addstr_rjust(window, 10 + padline[0] + padline[1] + padline[2] + padline[3], "Mempool transactions: " + "{:5,d}".format(int(pooledtx)), curses.A_NORMAL, 1) if 'totalbytesrecv' in state: recvmb = "{:,.2f}".format(float(state['totalbytesrecv']*1.0/1048576)) sentmb = "{:,.2f}".format(float(state['totalbytessent']*1.0/1048576)) recvsent_string = "D/U: " + recvmb + " / " + sentmb + " MB" g.addstr_rjust(window, 0, recvsent_string, curses.A_BOLD, 1) if 'estimatefee' in state: string = "estimatefee:" for item in state['estimatefee']: if item['value'] > 0: string += " (" + str(item['blocks']) + ")" + "%4.2f" % (item['value']*1000) + " m" + unit if len(string) > 12: g.addstr_rjust(window, 11 + padline[0] + padline[1] + padline[2] + padline[3], string, curses.A_NORMAL, 1) if 'mininginfo' in state: if 'errors' in state['mininginfo']: errors = state['mininginfo']['errors'] else: errors = state['mininginfo']['warnings'] if len(errors): try: y = this_y-1 window.addstr(y, 1, errors[:g.x - 1], curses.color_pair(5) + curses.A_BOLD + curses.A_REVERSE) except: pass window.refresh() footer.draw_window(state, rpc_queue)