def richlist(self, data=None): """ only feasible while chain is small.. :param data: :return: """ logger.info('<<< API richlist call') if not data: data = 5 error = { 'status': 'error', 'error': 'invalid argument', 'method': 'richlist', 'parameter': data } try: n = int(data) except: return json_print_telnet(error) if n <= 0 or n > 20: return json_print_telnet(error) if not self.factory.state.state_uptodate( self.factory.chain.m_blockheight()): return json_print_telnet({ 'status': 'error', 'error': 'leveldb failed', 'method': 'richlist' }) addr = self.factory.state.return_all_addresses() richlist = sorted(addr, key=itemgetter(1), reverse=True) rl = {'richlist': {}} if len(richlist) < n: n = len(richlist) for rich in richlist[:n]: rl['richlist'][richlist.index(rich) + 1] = {} rl['richlist'][richlist.index(rich) + 1]['address'] = rich[0].decode() rl['richlist'][richlist.index(rich) + 1]['balance'] = self._format_qrlamount(rich[1]) rl['status'] = 'ok' return json_print_telnet(rl)
def last_block(self, data=None): logger.info('<<< API last_block call') error = { 'status': 'error', 'error': 'invalid argument', 'method': 'last_block', 'parameter': data } if not data: data = 1 try: n = int(data) except: return json_print_telnet(error) if n <= 0 or n > 20: return json_print_telnet(error) lb = [] beginning = self.factory.chain.height() - n for blocknum in range(self.factory.chain.height(), beginning - 1, -1): block = self.factory.chain.m_get_block(blocknum) lb.append(block) last_blocks = {'blocks': []} i = 0 for block in lb[1:]: i += 1 tmp_block = { 'blocknumber': block.blockheader.blocknumber, 'block_reward': self._format_qrlamount(block.blockheader.block_reward), 'blockhash': bin2hstr(block.blockheader.prev_blockheaderhash), 'timestamp': block.blockheader.timestamp, 'block_interval': lb[i - 1].blockheader.timestamp - block.blockheader.timestamp, 'number_transactions': len(block.transactions) } last_blocks['blocks'].append(tmp_block) last_blocks['status'] = 'ok' return json_print_telnet(last_blocks)
def richlist(self, n=None): """ only feasible while chain is small.. :param n: :return: """ if not n: n = 5 error = { 'status': 'error', 'error': 'invalid argument', 'method': 'richlist', 'parameter': n } try: n = int(n) except: return json_print_telnet(error) if n <= 0 or n > 20: return json_print_telnet(error) if not self.state.state_uptodate(self.m_blockheight()): return json_print_telnet({ 'status': 'error', 'error': 'leveldb failed', 'method': 'richlist' }) addr = self.state.db.return_all_addresses() richlist = sorted(addr, key=itemgetter(1), reverse=True) rl = {'richlist': {}} if len(richlist) < n: n = len(richlist) for rich in richlist[:n]: rl['richlist'][richlist.index(rich) + 1] = {} rl['richlist'][richlist.index(rich) + 1]['address'] = rich[0] rl['richlist'][richlist.index(rich) + 1]['balance'] = rich[1] / 100000000.000000000 rl['status'] = 'ok' return json_print_telnet(rl)
def empty(self, data=None): error = { 'status': 'error', 'error': 'no method supplied', 'methods available': self.api_list } return json_print_telnet(error)
def last_block(self, n=1): error = { 'status': 'error', 'error': 'invalid argument', 'method': 'last_block', 'parameter': n } try: n = int(n) except: return json_print_telnet(error) if n <= 0 or n > 20: return json_print_telnet(error) lb = [] beginning = self.height() - n for blocknum in range(self.height(), beginning - 1, -1): block = self.m_get_block(blocknum) lb.append(block) last_blocks = {'blocks': []} i = 0 for block in lb[1:]: i += 1 tmp_block = { 'blocknumber': block.blockheader.blocknumber, 'block_reward': block.blockheader.block_reward / 100000000.00000000, 'blockhash': block.blockheader.prev_blockheaderhash, 'timestamp': block.blockheader.timestamp, 'block_interval': lb[i - 1].blockheader.timestamp - block.blockheader.timestamp, 'number_transactions': len(block.transactions) } last_blocks['blocks'].append(tmp_block) last_blocks['status'] = 'ok' return json_print_telnet(last_blocks)
def basic_info(self, address): addr = {} if not self.state.state_address_used(address): addr['status'] = 'error' addr['error'] = 'Address not found' addr['parameter'] = address return json_print_telnet(addr) nonce, balance, _ = self.state.state_get_address(address) addr['state'] = {} addr['state']['address'] = address addr['state']['balance'] = balance / 100000000.000000000 addr['state']['nonce'] = nonce addr['state']['transactions'] = self.state.state_get_txn_count(address) addr['status'] = 'ok' return json_print_telnet(addr)
def last_tx(self, data=None): logger.info('<<< API last_tx call') if not data: data = 1 addr = {'transactions': []} error = { 'status': 'error', 'error': 'invalid argument', 'method': 'last_tx', 'parameter': data } try: n = int(data) except: return json_print_telnet(error) if n <= 0 or n > 20: return json_print_telnet(error) try: last_txn = self.factory.state.db.get('last_txn') except Exception: error['error'] = 'txnhash not found' return json_print_telnet(error) n = min(len(last_txn), n) while n > 0: n -= 1 tx_meta = last_txn[n] tx = SimpleTransaction().json_to_transaction(tx_meta[0]) tmp_txn = { 'txhash': bin2hstr(tx.txhash), 'block': tx_meta[1], 'timestamp': tx_meta[2], 'amount': self._format_qrlamount(tx.amount), 'type': tx.subtype } addr['transactions'].append(tmp_txn) addr['status'] = 'ok' return json_print_telnet(addr)
def ping(self, data=None): logger.info('<<< API network latency ping call') self.factory.pos.p2pFactory.ping_peers() # triggers ping for all connected peers at timestamp now. after pong response list is collated. previous list is delivered. pings = {'status': 'ok', 'peers': self.factory.chain.ping_list} return json_print_telnet(pings)
def stats(self, data=None): logger.info('<<< API stats call') # FIXME: Review all this. Most math is flawed # calculate staked/emission % total_at_stake = 0 total_supply = self.factory.state.total_coin_supply() for staker in self.factory.state.stake_validators_list.sv_list: total_at_stake += self.factory.state.state_balance(staker) staked = 100 * total_at_stake / total_supply # calculate average blocktime over last 100 blocks.. z = 0 t = [] last_n_block = 100 last_block = self.factory.chain.m_blockchain[-1] for _ in range(last_n_block): if last_block.blockheader.blocknumber <= 0: break prev_block = self.factory.chain.m_get_block(last_block.blockheader.blocknumber - 1) x = last_block.blockheader.timestamp - prev_block.blockheader.timestamp last_block = prev_block t.append(x) z += x block_one = self.factory.chain.m_get_block(1) network_uptime = 0 if block_one: network_uptime = time.time() - block_one.blockheader.timestamp block_time = 0 block_time_variance = 0 if len(t) > 0: block_time = z / len(t) block_time_variance = max(t) - min(t) # FIXME: This is not the variance! net_stats = {'status': 'ok', 'version': config.dev.version_number, 'block_reward': self.factory.format_qrlamount(self.factory.chain.m_blockchain[-1].blockheader.block_reward), 'stake_validators': len(self.factory.chain.state.stake_validators_list.sv_list), 'epoch': self.factory.chain.m_blockchain[-1].blockheader.epoch, 'staked_percentage_emission': staked, 'network': 'qrl testnet', 'network_uptime': network_uptime, 'block_time': block_time, 'block_time_variance': block_time_variance, 'blockheight': self.factory.chain.m_blockheight(), 'nodes': len(self.factory.peers) + 1, # FIXME: Magic number? Unify 'emission': self._format_qrlamount(self.factory.state.total_coin_supply()), 'unmined': config.dev.total_coin_supply - float(self._format_qrlamount(self.factory.state.total_coin_supply()))} return json_print_telnet(net_stats)
def ip_geotag(self, data=None): ip = {'status': 'ok', 'ip_geotag': self.ip_list} x = 0 for i in self.ip_list: ip['ip_geotag'][x] = i x += 1 return json_print_telnet(ip)
def parse_cmd(self, data): data = data.split() # typical request will be: "GET /api/{command}/{parameter} HTTP/1.1" if len(data) == 0: return if data[0] != b'GET' and data[0] != b'OPTIONS': return False if data[0] == b'OPTIONS': http_header_OPTIONS = ("HTTP/1.1 200 OK\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Methods: GET\r\n" "Access-Control-Allow-Headers: x-prototype-version,x-requested-with\r\n" "Content-Length: 0\r\n" "Access-Control-Max-Age: 2520\r\n" "\r\n") self.transport.write(http_header_OPTIONS) return data = data[1].decode('ascii')[1:].split('/') if data[0].lower() != 'api': return False if len(data) == 1: data.append('') if data[1] == '': data[1] = 'empty' if data[1].lower() not in self.api_list: # supported {command} in api_list error = {'status': 'error', 'error': 'supported method not supplied', 'parameter': data[1]} self.transport.write(json_print_telnet(error)) return False api_call = getattr(self, data[1].lower()) if len(data) < 3: json_txt = api_call() else: json_txt = api_call(data[2]) http_header_GET = ("HTTP/1.1 200 OK\r\n" "Content-Type: application/json\r\n" "Content-Length: %s\r\n" "Access-Control-Allow-Headers: x-prototype-version,x-requested-with\r\n" "Access-Control-Max-Age: 2520\r\n" "Access-Control-Allow-Origin: *\r\n" "Access-Control-Allow-Methods: GET\r\n" "\r\n") % (str(len(json_txt))) self.transport.write(bytes(http_header_GET + json_txt, 'utf-8')) return
def _json_block(self, args): if not args: self.output['message'].write( helper.json_print_telnet(self.factory.chain.m_get_last_block()) + '\r\n') return True try: int(args[0]) except: self.output['message'].write( '>>> Try "json_block <block number>" \r\n') return True if int(args[0]) > self.factory.chain.m_blockheight(): self.output['message'].write('>>> Block > Blockheight\r\n') return True self.output['status'] = 0 self.output['message'].write( helper.json_print_telnet( self.factory.chain.m_get_block(int(args[0]))) + '\r\n')
def ip_geotag(self, data=None): logger.info('<<< API ip_geotag call') self.factory.pos.p2pFactory.ip_geotag_peers() ip = {'status': 'ok', 'ip_geotag': self.factory.chain.ip_list} x = 0 for i in self.factory.chain.ip_list: ip['ip_geotag'][x] = i x += 1 return json_print_telnet(ip)
def last_tx(self, n=1): addr = {'transactions': []} error = { 'status': 'error', 'error': 'invalid argument', 'method': 'last_tx', 'parameter': n } try: n = int(n) except: return json_print_telnet(error) if n <= 0 or n > 20: return json_print_telnet(error) try: last_txn = self.state.db.get('last_txn') except Exception: error['error'] = 'txnhash not found' return json_print_telnet(error) n = min(len(last_txn), n) while n > 0: n -= 1 tx_meta = last_txn[n] tx = SimpleTransaction().json_to_transaction(tx_meta[0]) tmp_txn = { 'txhash': tx.txhash, 'block': tx_meta[1], 'timestamp': tx_meta[2], 'amount': tx.amount / 100000000.000000000, 'type': tx.subtype } addr['transactions'].append(tmp_txn) addr['status'] = 'ok' return json_print_telnet(addr)
def stake_reveal_ones(self, data=None): sr = {'status': 'ok', 'reveals': {}} for c in self.stake_reveal_one: sr['reveals'][str(c[1]) + '-' + str(c[2])] = {} sr['reveals'][str(c[1]) + '-' + str(c[2])]['stake_address'] = c[0] sr['reveals'][str(c[1]) + '-' + str(c[2])]['block_number'] = c[2] sr['reveals'][str(c[1]) + '-' + str(c[2])]['headerhash'] = c[1] sr['reveals'][str(c[1]) + '-' + str(c[2])]['reveal'] = c[3] return json_print_telnet(sr)
def last_unconfirmed_tx(self, data=None): logger.info('<<< API last_unconfirmed_tx call') addr = {'transactions': []} error = { 'status': 'error', 'error': 'invalid argument', 'method': 'last_tx', 'parameter': data } if not data: data = 1 try: n = int(data) except: return json_print_telnet(error) if n <= 0 or n > 20: return json_print_telnet(error) tx_num = len(self.factory.chain.transaction_pool) while tx_num > 0: tx_num -= 1 tx = self.factory.chain.transaction_pool[tx_num] if tx.subtype != TX_SUBTYPE_TX: continue tmp_txn = { 'txhash': bin2hstr(tx.txhash), 'block': 'unconfirmed', 'timestamp': 'unconfirmed', 'amount': self._format_qrlamount(tx.amount), 'type': tx.subtype } tmp_txn['type'] = Transaction.tx_id_to_name(tmp_txn['type']) addr['transactions'].append(tmp_txn) addr['status'] = 'ok' return json_print_telnet(addr)
def search_txhash(self, txhash): # txhash is unique due to nonce. err = { 'status': 'Error', 'error': 'txhash not found', 'method': 'txhash', 'parameter': txhash } for tx in self.transaction_pool: if tx.txhash == txhash: logger.info('%s found in transaction pool..', txhash) tx_new = copy.deepcopy(tx) tx_new.block = 'unconfirmed' tx_new.hexsize = len(json_bytestream(tx_new)) tx_new.status = 'ok' return json_print_telnet(tx_new) try: txn_metadata = self.state.db.get(txhash) except: logger.info( '%s does not exist in memory pool or local blockchain..', txhash) return json_print_telnet(err) json_tx = json.loads(txn_metadata[0]) if json_tx['subtype'] == transaction.TX_SUBTYPE_TX: tx = SimpleTransaction().json_to_transaction(txn_metadata[0]) elif json_tx['subtype'] == transaction.TX_SUBTYPE_COINBASE: tx = CoinBase().json_to_transaction(txn_metadata[0]) tx_new = copy.deepcopy(tx) tx_new.block = txn_metadata[1] tx_new.timestamp = txn_metadata[2] tx_new.confirmations = self.m_blockheight() - txn_metadata[1] tx_new.hexsize = len(json_bytestream(tx_new)) tx_new.amount = tx_new.amount / 100000000.000000000 if json_tx['subtype'] == transaction.TX_SUBTYPE_TX: tx_new.fee = tx_new.fee / 100000000.000000000 logger.info('%s found in block %s', txhash, str(txn_metadata[1])) tx_new.status = 'ok' return json_print_telnet(tx_new)
def stake_commits(self, data=None): sc = {'status': 'ok', 'commits': {}} for c in self.stake_commit: # [stake_address, block_number, merkle_hash_tx, commit_hash] sc['commits'][str(c[1]) + '-' + c[3]] = {} sc['commits'][str(c[1]) + '-' + c[3]]['stake_address'] = c[0] sc['commits'][str(c[1]) + '-' + c[3]]['block_number'] = c[1] sc['commits'][str(c[1]) + '-' + c[3]]['merkle_hash_tx'] = c[2] sc['commits'][str(c[1]) + '-' + c[3]]['commit_hash'] = c[3] return json_print_telnet(sc)
def stake_reveals(self, data=None): sr = {'status': 'ok', 'reveals': {}} # chain.stake_reveal.append([stake_address, block_number, merkle_hash_tx, reveal]) for c in self.stake_reveal: sr['reveals'][str(c[1]) + '-' + c[3]] = {} sr['reveals'][str(c[1]) + '-' + c[3]]['stake_address'] = c[0] sr['reveals'][str(c[1]) + '-' + c[3]]['block_number'] = c[1] sr['reveals'][str(c[1]) + '-' + c[3]]['merkle_hash_tx'] = c[2] sr['reveals'][str(c[1]) + '-' + c[3]]['reveal'] = c[3] return json_print_telnet(sr)
def balance(self, data=None): logger.info('<<< API balance call %s', data) address = data addr = {} if not self.factory.state.state_address_used(address): addr['status'] = 'error' addr['error'] = 'Address not found' addr['parameter'] = address return json_print_telnet(addr) nonce, balance, _ = self.factory.state.state_get_address(address) addr['state'] = {} addr['state']['address'] = address addr['state']['balance'] = balance / 100000000.000000000 addr['state']['nonce'] = nonce addr['state']['transactions'] = self.factory.state.state_get_txn_count( address) addr['status'] = 'ok' return json_print_telnet(addr)
def next_stakers(self, data=None): # (stake -> address, hash_term, nonce) next_stakers = {'status': 'ok', 'stake_list': []} for s in self.state.next_stake_list_get(): tmp_stakers = { 'address': s[0], 'balance': self.state.state_balance(s[0]) / 100000000.00000000, 'hash_terminator': s[1], 'nonce': s[2] } next_stakers['stake_list'].append(tmp_stakers) return json_print_telnet(next_stakers)
def stakers(self, data=None): logger.info('<<< API stakers call') stakers = {'status': 'ok', 'stake_list': []} for staker in self.factory.state.stake_validators_list.sv_list: sv = self.factory.state.stake_validators_list.sv_list[staker] tmp_stakers = {'address': sv.stake_validator, 'balance': self.factory.format_qrlamount(sv.balance), 'hash_terminator': [], 'nonce': sv.nonce} for i in range(len(sv.hashchain_terminators)): tmp_stakers['hash_terminator'].append(bin2hstr(sv.hashchain_terminators[i])) stakers['stake_list'].append(tmp_stakers) return json_print_telnet(stakers)
def search_address(self, address): addr = {'transactions': []} txnhash_added = set() if not self.state.state_address_used(address): addr['status'] = 'error' addr['error'] = 'Address not found' addr['parameter'] = address return json_print_telnet(addr) nonce, balance, pubhash_list = self.state.state_get_address(address) addr['state'] = {} addr['state']['address'] = address addr['state']['balance'] = balance / 100000000.000000000 addr['state']['nonce'] = nonce for s in self.state.stake_list_get(): if address == s[0]: addr['stake'] = {} addr['stake']['selector'] = s[2] # pubhashes used could be put here.. tmp_transactions = [] for tx in self.transaction_pool: if tx.subtype not in (transaction.TX_SUBTYPE_TX, transaction.TX_SUBTYPE_COINBASE): continue if tx.txto == address or tx.txfrom == address: logger.info('%s found in transaction pool', address) tmp_txn = { 'subtype': tx.subtype, 'txhash': tx.txhash, 'block': 'unconfirmed', 'amount': tx.amount / 100000000.000000000, 'nonce': tx.nonce, 'ots_key': tx.ots_key, 'txto': tx.txto, 'txfrom': tx.txfrom, 'timestamp': 'unconfirmed' } if tx.subtype == transaction.TX_SUBTYPE_TX: tmp_txn['fee'] = tx.fee / 100000000.000000000 tmp_transactions.append(tmp_txn) txnhash_added.add(tx.txhash) addr['transactions'] = tmp_transactions my_txn = [] try: my_txn = self.state.db.get('txn_' + address) except: pass for txn_hash in my_txn: txn_metadata = self.state.db.get(txn_hash) dict_txn_metadata = json.loads(txn_metadata[0]) if dict_txn_metadata['subtype'] == transaction.TX_SUBTYPE_TX: tx = SimpleTransaction().json_to_transaction(txn_metadata[0]) elif dict_txn_metadata[ 'subtype'] == transaction.TX_SUBTYPE_COINBASE: tx = CoinBase().json_to_transaction(txn_metadata[0]) if (tx.txto == address or tx.txfrom == address) and tx.txhash not in txnhash_added: logger.info('%s found in block %s', address, str(txn_metadata[1])) tmp_txn = { 'subtype': tx.subtype, 'txhash': tx.txhash, 'block': txn_metadata[1], 'timestamp': txn_metadata[2], 'amount': tx.amount / 100000000.000000000, 'nonce': tx.nonce, 'ots_key': tx.ots_key, 'txto': tx.txto, 'txfrom': tx.txfrom } if tx.subtype == transaction.TX_SUBTYPE_TX: tmp_txn['fee'] = tx.fee / 100000000.000000000 addr['transactions'].append(tmp_txn) txnhash_added.add(tx.txhash) if len(addr['transactions']) > 0: addr['state']['transactions'] = len(addr['transactions']) if addr == {'transactions': {}}: addr = { 'status': 'error', 'error': 'address not found', 'method': 'address', 'parameter': address } else: addr['status'] = 'ok' return json_print_telnet(addr)
def exp_win(data=None): # TODO: incomplete ew = {'status': 'ok', 'expected_winner': {}} return json_print_telnet(ew)
def parse_cmd(self, data): # Get entered line as an array of strings delimited by "space." # Will chomp away any extra spaces data = data.split() # Arguments include anything beyond the first index if len(data) != 0: # if anything was entered command = data[0] args = None if len(data) > 0: # args optional args = data[1:] if command.decode('utf-8') in self.cmd_list: # Use switch cases when porting to a different language if command == b'create': self.factory.p2pFactory.pos.create_next_block(int(args[0])) self.output['status'] = 0 self.output['message'].write('Creating blocknumber #' + str(args[0])) elif command == b'getnewaddress': self.getnewaddress(args) elif command == b'hexseed': for addr_bundle in self.factory.chain.wallet.address_bundle: if isinstance(addr_bundle.xmss, XMSS): self.output['status'] = 0 self.output['message'].write( 'Address: ' + addr_bundle.xmss.get_address() + '\r\n') self.output['message'].write( 'Recovery seed: ' + addr_bundle.xmss.get_hexseed() + '\r\n') self.output['keys'] += ['Address', 'Recovery seed'] self.output[ 'Address'] = addr_bundle.xmss.get_address() self.output[ 'Recovery seed'] = addr_bundle.xmss.get_hexseed( ) elif command == b'seed': for addr_bundle in self.factory.chain.wallet.address_bundle: if isinstance(addr_bundle.xmss, XMSS): self.output['status'] = 0 self.output['message'].write( 'Address: ' + addr_bundle.xmss.get_address() + '\r\n') self.output['message'].write( 'Recovery seed: ' + addr_bundle.xmss.get_mnemonic() + '\r\n') self.output['keys'] += ['Address', 'Recovery seed'] elif command == b'search': if not args: self.output['status'] = 1 self.output['message'].write( '>>> Usage: search <txhash or Q-address>\r\n') return tmp_output = None if args[0][0] == 'Q': tmp_output = json.loads( self.factory.chain.search_address(args[0])) self.output['message'].write('Address: ' + str(args[0])) self.output['message'].write( '\r\nBalance: ' + str(tmp_output['state']['balance'])) self.output['message'].write( '\r\nTransactions: ' + str(tmp_output['state']['transactions'])) for tx in tmp_output['transactions']: self.output['message'].write(str(tx['txhash'])) self.output['message'].write(' ') self.output['message'].write(str(tx['txfrom'])) self.output['message'].write(' ') self.output['message'].write(str(tx['txto'])) self.output['message'].write(' ') self.output['message'].write(str(tx['amount'])) self.output['message'].write('\r\n') else: tmp_output = json.loads( self.factory.chain.search_txhash(args[0])) self.output['message'].write('Txnhash: ') self.output['message'].write(args[0]) if tmp_output['status'] == 'Error': self.output['message'].write('\r\n') self.output['message'].write( str(tmp_output['error'])) self.output['message'].write('\r\n') return True self.output['message'].write('\r\nTimestamp: ') self.output['message'].write(tmp_output['timestamp']) self.output['message'].write('\r\nBlockNumber: ') self.output['message'].write(tmp_output['block']) self.output['message'].write('\r\nConfirmations: ') self.output['message'].write( tmp_output['confirmations']) self.output['message'].write('\r\nAmount: ') self.output['message'].write(tmp_output['amount']) self.output['message'].write('\r\n') if not tmp_output: self.output['status'] = 1 self.output['message'].write( '>>> No Information available') return True for key in list(tmp_output.keys()): self.output['keys'] += [str(key)] self.output[key] = tmp_output[key] self.output['status'] = 0 self.output['message'].write('') elif command == b'json_block': if not args: self.output['message'].write( helper.json_print_telnet( self.factory.chain.m_get_last_block()) + '\r\n') return True try: int(args[0]) except: self.output['message'].write( '>>> Try "json_block <block number>" \r\n') return True if int(args[0]) > self.factory.chain.m_blockheight(): self.output['message'].write( '>>> Block > Blockheight\r\n') return True self.output['status'] = 0 self.output['message'].write( helper.json_print_telnet( self.factory.chain.m_get_block(int(args[0]))) + '\r\n') elif command == b'savenewaddress': self.savenewaddress() elif command == b'recoverfromhexseed': if not args or not hexseed_to_seed(args[0]): self.output['message'].write( '>>> Usage: recoverfromhexseed <paste in hexseed>\r\n' ) self.output['message'].write( '>>> Could take up to a minute..\r\n') self.output['message'].write( '>>> savenewaddress if Qaddress matches expectations..\r\n' ) return True self.output['status'] = 0 addr = self.factory.chain.wallet.get_new_address( address_type='XMSS', seed=hexseed_to_seed(args[0])) self.factory.newaddress = addr self.output['message'].write('>>> Recovery address: ' + addr[1].get_address() + '\r\n') self.output['message'].write('>>> Recovery seed phrase: ' + addr[1].get_mnemonic() + '\r\n') self.output['message'].write('>>> hexSEED confirm: ' + addr[1].get_hexseed() + '\r\n') self.output['message'].write( '>>> savenewaddress if Qaddress matches expectations..\r\n' ) self.output['keys'] += [ 'recovery_address', 'recovery_seed_phrase', 'hexseed_confirm' ] self.output['recovery_address'] = addr[1].get_address() self.output['recovery_seed_phrase'] = addr[1].get_mnemonic( ) self.output['hexseed_confirm'] = addr[1].get_hexseed() elif command == b'recoverfromwords': if not args: self.output['message'].write( '>>> Usage: recoverfromwords <paste in 32 mnemonic words>\r\n' ) return True self.output['message'].write( '>>> trying..this could take up to a minute..\r\n') if len(args) != 32: self.output['message'].write( '>>> Usage: recoverfromwords <paste in 32 mnemonic words>\r\n' ) return True args = ' '.join(args) addr = self.factory.chain.wallet.get_new_address( address_type='XMSS', seed=mnemonic2bin(args, wordlist)) self.factory.newaddress = addr self.output['status'] = 0 self.output['message'].write('>>> Recovery address: ' + addr[1].get_address() + '\r\n') self.output['message'].write('>>> Recovery hexSEED: ' + addr[1].get_hexseed() + '\r\n') self.output['message'].write('>>> Mnemonic confirm: ' + addr[1].get_mnemonic() + '\r\n') self.output['message'].write( '>>> savenewaddress if Qaddress matches expectations..\r\n' ) self.output['keys'] += [ 'recovery_address', 'recovery_hexseed', 'mnemonic_confirm' ] self.output['recovery_address'] = addr[1].get_address() self.output['recovery_hexseed'] = addr[1].get_hexseed() self.output['mnemonic_confirm'] = addr[1].get_mnemonic() elif command == b'stake': self.output['status'] = 0 self.output['message'].write( '>> Toggling stake from: ' + str(self.factory.p2pFactory.stake) + ' to: ' + str(not self.factory.p2pFactory.stake) + '\r\n') self.factory.p2pFactory.stake = not self.factory.p2pFactory.stake logger.info( ('STAKING set to: ', self.factory.p2pFactory.stake)) self.output['keys'] += ['stake'] self.output['stake'] = self.factory.p2pFactory.stake elif command == b'stakenextepoch': self.output['status'] = 0 self.output['message'].write( '>>> Sending a stake transaction for address: ' + self.factory.chain.mining_address + ' to activate next epoch(' + str(config.dev.blocks_per_epoch - (self.factory.chain.m_blockchain[-1].blockheader. blocknumber - (self.factory.chain.m_blockchain[-1].blockheader. epoch * config.dev.blocks_per_epoch))) + ' blocks time)\r\n') logger.info(('STAKE for address:', self.factory.chain.mining_address)) blocknumber = self.factory.chain.block_chain_buffer.height( ) + 1 self.factory.p2pFactory.pos.make_st_tx( blocknumber=blocknumber, first_hash=None) elif command == b'send': self.send_tx(args) elif command == b'mempool': self.output['status'] = 0 self.output['message'].write( '>>> Number of transactions in memory pool: ' + str(len(self.factory.chain.transaction_pool)) + '\r\n') self.output['keys'] += ['txn_nos'] self.output['txn_nos'] = len( self.factory.chain.transaction_pool) elif command == b'help': self.output['status'] = 0 self.output['message'].write( '>>> QRL ledger help: try {}'.format(', '.join( self.cmd_list)) + '\r\n') # removed 'hrs, hrs_check,' elif command == b'quit' or command == b'exit': self.transport.loseConnection() elif command == b'listaddresses': addresses, num_sigs, types = self.factory.chain.wallet.inspect_wallet( ) self.output['status'] = 0 self.output['keys'] += ['addresses'] self.output['addresses'] = [] for addr_bundle in range(len(addresses)): self.output['message'].write( str(addr_bundle) + ', ' + addresses[addr_bundle] + '\r\n') self.output['addresses'] += [addresses[addr_bundle]] elif command == b'wallet': self.wallet() elif command == b'getinfo': self.output['status'] = 0 self.output['message'].write( '>>> Version: ' + self.factory.chain.version_number + '\r\n') self.output['message'].write('>>> Uptime: ' + str(time.time() - self.factory.start_time) + '\r\n') self.output['message'].write( '>>> Nodes connected: ' + str(len(self.factory.p2pFactory.peer_connections)) + '\r\n') self.output['message'].write( '>>> Staking set to: ' + str(self.factory.p2pFactory.stake) + '\r\n') self.output['message'].write( '>>> Sync status: ' + self.factory.p2pFactory.nodeState.state.name + '\r\n') self.output['keys'] += [ 'version', 'uptime', 'nodes_connected', 'staking_status', 'sync_status' ] self.output['version'] = self.factory.chain.version_number self.output['uptime'] = str(time.time() - self.factory.start_time) self.output['nodes_connected'] = str( len(self.factory.p2pFactory.peer_connections)) self.output['staking_status'] = str( self.factory.p2pFactory.stake) self.output[ 'sync_status'] = self.factory.p2pFactory.nodeState.state.name elif command == b'blockheight': self.output['status'] = 0 self.output['message'].write( '>>> Blockheight: ' + str(self.factory.chain.m_blockheight()) + '\r\n') self.output['message'].write( '>>> Headerhash: ' + bin2hstr(self.factory.chain.m_blockchain[-1]. blockheader.headerhash) + '\r\n') self.output['keys'] += ['blockheight', 'headerhash'] self.output[ 'blockheight'] = self.factory.chain.m_blockheight() self.output['headerhash'] = bin2hstr( self.factory.chain.m_blockchain[-1].blockheader. headerhash) elif command == b'peers': self.output['status'] = 0 self.output['message'].write('>>> Connected Peers:\r\n') self.output['keys'] += ['peers'] self.output['peers'] = {} for peer in self.factory.p2pFactory.peer_connections: self.output['message'].write('>>> ' + peer.conn_identity + " [" + peer.version + "] blockheight: " + str(peer.blockheight) + '\r\n') self.output['peers'][peer.conn_identity] = {} self.output['peers'][ peer.conn_identity]['version'] = peer.version self.output['peers'][peer.conn_identity][ 'blockheight'] = peer.blockheight elif command == b'reboot': if len(args) < 1: self.output['message'].write( '>>> reboot <password>\r\n') self.output['message'].write('>>> or\r\n') self.output['message'].write( '>>> reboot <password> <nonce>\r\n') self.output['message'].write('>>> or\r\n') self.output['message'].write( '>>> reboot <password> <nonce> <trim_blocknum>\r\n' ) return True json_hash, err = None, None if len(args) == 3: json_hash, status = self.factory.chain.generate_reboot_hash( args[0], args[1], args[2]) self.output['message'].write( str(args[0]) + str(args[1]) + str(args[2])) elif len(args) == 2: json_hash, status = self.factory.chain.generate_reboot_hash( args[0], args[1]) else: json_hash, status = self.factory.chain.generate_reboot_hash( args[0]) if json_hash: self.factory.p2pFactory.send_reboot(json_hash) # self.factory.state.update(NState.synced) self.output['message'].write(status) else: return False return True
def _search_address(self, address): addr = {'transactions': []} txnhash_added = set() # FIXME: breaking encapsulation and accessing DB/cache directly from API if not self.factory.state.state_address_used(address): addr['status'] = 'error' addr['error'] = 'Address not found' addr['parameter'] = address return json_print_telnet(addr) # FIXME: This is a duplicate of balance # FIXME: breaking encapsulation and accessing DB/cache directly from API nonce, balance, pubhash_list = self.factory.state.state_get_address( address) addr['state'] = {} addr['state']['address'] = address addr['state']['balance'] = self._format_qrlamount(balance) addr['state']['nonce'] = nonce for s in self.factory.state.stake_list_get(): if address == s[0]: addr['stake'] = {} addr['stake']['selector'] = s[2] # pubhashes used could be put here.. tmp_transactions = [] for tx in self.factory.chain.transaction_pool: if tx.subtype not in (TX_SUBTYPE_TX, TX_SUBTYPE_COINBASE): continue if tx.txto == address or tx.txfrom == address: logger.info('%s found in transaction pool', address) tmp_txn = { 'subtype': tx.subtype, 'txhash': bin2hstr(tx.txhash), 'block': 'unconfirmed', 'amount': self._format_qrlamount(tx.amount), 'nonce': tx.nonce, 'ots_key': tx.ots_key, 'txto': tx.txto, 'txfrom': tx.txfrom, 'timestamp': 'unconfirmed' } if tx.subtype == TX_SUBTYPE_TX: tmp_txn['fee'] = self._format_qrlamount(tx.fee) tmp_txn.subtype = Transaction.tx_id_to_name(tx.subtype) tmp_transactions.append(tmp_txn) txnhash_added.add(tx.txhash) addr['transactions'] = tmp_transactions my_txn = [] try: my_txn = self.factory.state.db.get('txn_' + address) except: pass for txn_hash in my_txn: txn_metadata = self.factory.state.db.get(txn_hash) dict_txn_metadata = json.loads(txn_metadata[0]) if dict_txn_metadata['subtype'] == TX_SUBTYPE_TX: tx = SimpleTransaction().json_to_transaction(txn_metadata[0]) elif dict_txn_metadata['subtype'] == TX_SUBTYPE_COINBASE: tx = CoinBase().json_to_transaction(txn_metadata[0]) if (tx.txto == address or tx.txfrom == address) and tx.txhash not in txnhash_added: logger.info('%s found in block %s', address, str(txn_metadata[1])) tmp_txn = { 'subtype': tx.subtype, 'txhash': bin2hstr(tx.txhash), 'block': txn_metadata[1], 'timestamp': txn_metadata[2], 'amount': self._format_qrlamount(tx.amount), 'nonce': tx.nonce, 'ots_key': tx.ots_key, 'txto': tx.txto, 'txfrom': tx.txfrom } if tx.subtype == TX_SUBTYPE_TX: tmp_txn['fee'] = self._format_qrlamount(tx.fee) tmp_txn['subtype'] = Transaction.tx_id_to_name( tmp_txn['subtype']) addr['transactions'].append(tmp_txn) txnhash_added.add(tx.txhash) if len(addr['transactions']) > 0: addr['state']['transactions'] = len(addr['transactions']) if addr == {'transactions': {}}: addr = { 'status': 'error', 'error': 'address not found', 'method': 'address', 'parameter': address } else: addr['status'] = 'ok' return json_print_telnet(addr)
def stats(self, data=None): logger.info('<<< API stats call') # calculate staked/emission % b = 0 for staker in self.factory.state.stake_validators_list.sv_list: b += self.factory.state.state_balance(staker) staked = decimal.Decimal( (b / 100000000.000000000) / (self.factory.state.total_coin_supply() / 100000000.000000000) * 100).quantize(decimal.Decimal('1.00')) # /100000000.000000000) staked = float(str(staked)) # calculate average blocktime over last 100 blocks.. z = 0 t = [] last_n_block = 100 last_block = self.factory.chain.m_blockchain[-1] for _ in range(last_n_block): if last_block.blockheader.blocknumber <= 0: break prev_block = self.factory.chain.m_get_block( last_block.blockheader.blocknumber - 1) x = last_block.blockheader.timestamp - prev_block.blockheader.timestamp last_block = prev_block t.append(x) z += x block_one = self.factory.chain.m_get_block(1) network_uptime = 0 if block_one: network_uptime = time.time() - block_one.blockheader.timestamp block_time = 0 block_time_variance = 0 if len(t) > 0: block_time = z / len(t) block_time_variance = max(t) - min( t) # FIXME: This is not the variance! net_stats = { 'status': 'ok', 'version': self.factory.chain.version_number, 'block_reward': self._format_qrlamount( self.factory.chain.m_blockchain[-1].blockheader.block_reward), 'stake_validators': len(self.factory.chain.state.stake_validators_list.sv_list), 'epoch': self.factory.chain.m_blockchain[-1].blockheader.epoch, 'staked_percentage_emission': staked, 'network': 'qrl testnet', 'network_uptime': network_uptime, 'block_time': block_time, 'block_time_variance': block_time_variance, 'blockheight': self.factory.chain.m_blockheight(), 'nodes': len(self.factory.peers) + 1, 'emission': self._format_qrlamount(self.factory.state.total_coin_supply()), 'unmined': config.dev.total_coin_supply - self.factory.state.total_coin_supply() / 100000000.000000000 } return json_print_telnet(net_stats)