async def contract_storage(request): try: c_address = request.query['c_address'] f_confirmed = bool(request.query.get('confirmed', False)) best_block = builder.best_block if f_confirmed else None c = get_contract_object(c_address=c_address, best_block=best_block) if c is None: return web_base.json_res({}) storage = {decode(k): decode(v) for k, v in c.storage.items()} return web_base.json_res(storage) except Exception as e: logging.error(e) return web_base.error_res()
async def get_block_by_height(request): f_pickled = request.query.get('pickle', False) height = int(request.query['height']) blockhash = builder.get_block_hash(height) if blockhash is None: return web.Response(text="Not found height.", status=400) block = builder.get_block(blockhash) if f_pickled: block = pickle.dumps(block) return web_base.json_res(b64encode(block).decode()) data = block.getinfo() data['size'] = block.getsize() data['hex'] = hexlify(block.b).decode() return web_base.json_res(data)
async def contract_transfer(request): start = time() post = await web_base.content_type_json_check(request) try: c_address = post['c_address'] c_method = post['c_method'] c_args = post['c_args'] send_pairs = post.get('send_pairs', None) sender_name = post.get('from', C.ANT_NAME_UNKNOWN) with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() sender = read_name2user(sender_name, cur) tx = create_contract_transfer_tx(c_address=c_address, cur=cur, c_method=c_method, c_args=c_args, send_pairs=send_pairs, sender=sender) if not send_newtx(new_tx=tx, outer_cur=cur): raise Exception('Failed to send new tx.') db.commit() return web_base.json_res({ 'hash': hexlify(tx.hash).decode(), 'gas_amount': tx.gas_amount, 'gas_price': tx.gas_price, 'fee': tx.gas_amount * tx.gas_price, 'time': round(time() - start, 3) }) except Exception: return web_base.error_res()
async def validate_unconfirmed(request): start = time() post = await web_base.content_type_json_check(request) try: txhash = unhexlify(post['hash'].encode()) tx = tx_builder.get_tx(txhash=txhash) if tx is None or tx.height is not None: return web_base.error_res('You cannot validate tx. {}'.format(tx)) with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() new_tx = create_signed_tx_as_validator(tx=tx) assert tx is not new_tx, 'tx={}, new_tx={}'.format( id(tx), id(new_tx)) if not send_newtx(new_tx=new_tx, outer_cur=cur): raise Exception('Failed to send new tx.') db.commit() return web_base.json_res({ 'hash': hexlify(new_tx.hash).decode(), 'gas_amount': new_tx.gas_amount, 'gas_price': new_tx.gas_price, 'fee': new_tx.gas_amount * new_tx.gas_price, 'time': round(time() - start, 3) }) except Exception: return web_base.error_res()
async def validator_edit(request): start = time() post = await web_base.content_type_json_check(request) c_address = post.get('c_address', None) new_address = post.get('new_address', None) flag = int(post.get('flag', F_NOP)) sig_diff = int(post.get('sig_diff', 0)) try: with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() if c_address is None: c_address = create_new_user_keypair(name=C.ANT_NAME_CONTRACT, cur=cur) tx = create_validator_edit_tx(c_address=c_address, new_address=new_address, flag=flag, sig_diff=sig_diff) if not send_newtx(new_tx=tx, outer_cur=cur): raise Exception('Failed to send new tx.') db.commit() return web_base.json_res({ 'hash': hexlify(tx.hash).decode(), 'gas_amount': tx.gas_amount, 'gas_price': tx.gas_price, 'fee': tx.gas_amount * tx.gas_price, 'time': round(time() - start, 3) }) except Exception: return web_base.error_res()
async def conclude_contract(request): start = time() post = await web_base.content_type_json_check(request) try: start_hash = unhexlify(post['start_hash'].encode()) start_tx = tx_builder.get_tx(txhash=start_hash) if start_tx is None: return web_base.error_res('Not found start_tx {}'.format( post['start_hash'])) c_address, c_method, redeem_address, c_args = bjson.loads( start_tx.message) send_pairs = post.get('send_pairs', None) c_storage = post.get('storage', None) tx = create_conclude_tx(c_address=c_address, start_tx=start_tx, redeem_address=redeem_address, send_pairs=send_pairs, c_storage=c_storage) if not send_newtx(new_tx=tx): raise Exception('Failed to send new tx.') return web_base.json_res({ 'hash': hexlify(tx.hash).decode(), 'gas_amount': tx.gas_amount, 'gas_price': tx.gas_price, 'fee': tx.gas_amount * tx.gas_price, 'time': round(time() - start, 3) }) except Exception: return web_base.error_res()
async def chain_info(request): best_height = builder.best_block.height best_block = builder.best_block old_block_height = builder.best_chain[0].height - 1 old_block_hash = hexlify(builder.get_block_hash(old_block_height)).decode() data = {'best': best_block.getinfo()} difficulty = dict() for consensus, ratio in V.BLOCK_CONSENSUSES.items(): name = C.consensus2name[consensus] target = get_bits_by_hash(previous_hash=best_block.hash, consensus=consensus)[1] block_time = round(V.BLOCK_TIME_SPAN / ratio * 100) diff = (MAX_256_INT // target) / 100000000 bias = get_bias_by_hash(previous_hash=best_block.previous_hash, consensus=consensus) difficulty[name] = { 'number': consensus, 'diff': round(diff / 100000000, 8), 'bias': round(bias, 8), 'fixed_diff': round(diff / bias, 8), 'hashrate(kh/s)': round((MAX_256_INT//target)/block_time/1000, 3), 'is_base': V.BLOCK_BASE_CONSENSUS == consensus, } data['mining'] = difficulty data['size'] = best_block.getsize() data['checkpoint'] = {'height': old_block_height, 'blockhash': old_block_hash} data['money_supply'] = GompertzCurve.calc_total_supply(best_height) data['total_supply'] = GompertzCurve.k return web_base.json_res(data)
async def sign_raw_tx(request): post = await web_base.content_type_json_check(request) try: binary = unhexlify(post['hex'].encode()) other_pairs = dict() for sk in post.get('pairs', list()): pk = public_key(sk=sk) ck = get_address(pk=pk, prefix=V.BLOCK_PREFIX) other_pairs[ck] = (pk, sign(msg=binary, sk=sk, pk=pk)) tx = TX(binary=binary) for txhash, txindex in tx.inputs: input_tx = tx_builder.get_tx(txhash) address, coin_id, amount = input_tx.outputs[txindex] try: tx.signature.append( message2signature(raw=tx.b, address=address)) except BlockChainError: if address not in other_pairs: raise BlockChainError( 'Not found secret key "{}"'.format(address)) tx.signature.append(other_pairs[address]) data = tx.getinfo() return web_base.json_res({ 'hash': data['hash'], 'signature': data['signature'], 'hex': hexlify(tx.b).decode() }) except BaseException: return web_base.error_res()
async def change_mint_tx(request): post = await web_base.content_type_json_check(request) with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() try: user_name = post.get('account', C.ANT_NAME_UNKNOWN) sender = read_name2user(user_name, cur) mint, mintcoin_tx = change_mintcoin( mint_id=int(post['mint_id']), cur=cur, amount=int(post.get('amount', 0)), message=post.get('message', None), image=post.get('image', None), additional_issue=bool(post['additional_issue']) if 'additional_issue' in post else None, sender=sender) if not send_newtx(new_tx=mintcoin_tx, outer_cur=cur): raise BaseException('Failed to send new tx.') db.commit() data = mintcoin_tx.getinfo() return web_base.json_res({ 'txhash': data['hash'], 'mintcoin': mint.getinfo() }) except BaseException: return web_base.error_res()
async def contract_create(request): post = await web_base.content_type_json_check(request) with closing(create_db(V.DB_ACCOUNT_PATH, f_on_memory=True)) as db: cur = db.cursor() try: # バイナリをピックルしオブジェクトに戻す c_bin = unhexlify(post['hex'].encode()) c_cs = { k.encode(errors='ignore'): v.encode(errors='ignore') for k, v in post.get('c_cs', dict()).items() } binary2contract(c_bin) # can compile? sender_name = post.get('account', C.ANT_NAME_UNKNOWN) sender_id = read_name2user(sender_name, cur) c_address, c_tx = create_contract_tx(c_bin, cur, sender_id, c_cs) if not send_newtx(new_tx=c_tx, outer_cur=cur): raise BaseException('Failed to send new tx.') db.commit() data = { 'txhash': hexlify(c_tx.hash).decode(), 'c_address': c_address, 'time': c_tx.time, 'fee': { 'gas_price': c_tx.gas_price, 'gas_amount': c_tx.gas_amount, 'total': c_tx.gas_price * c_tx.gas_amount } } return web_base.json_res(data) except BaseException: return web_base.error_res()
async def send_many_user(request): start = time.time() if P.F_NOW_BOOTING: return web.Response(text='Now booting...', status=403) post = await web_base.content_type_json_check(request) with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() try: user_name = post.get('from', C.ANT_NAME_UNKNOWN) user_id = read_name2user(user_name, cur) send_pairs = list() for address, coin_id, amount in post['pairs']: send_pairs.append((address, int(coin_id), int(amount))) message = post.get('message', None) if message: msg_type = C.MSG_PLAIN msg_body = message.encode() else: msg_type = C.MSG_NONE msg_body = b'' new_tx = send_many(user_id, send_pairs, cur, msg_type=msg_type, msg_body=msg_body) if not send_newtx(new_tx=new_tx, outer_cur=cur): raise BaseException('Failed to send new tx.') db.commit() return web_base.json_res({ 'txhash': hexlify(new_tx.hash).decode(), 'time': round(time.time() - start, 3) }) except Exception as e: db.rollback() return web_base.error_res()
async def watching_info(request): try: f_pickle = bool(request.query.get('pickle', False)) if not P.F_WATCH_CONTRACT: return web_base.error_res( errors='You need to enable watching option!') return web_base.json_res([{ 'hash': hexlify(txhash).decode(), 'type': tx.type, 'tx': b64encode(pickle.dumps(tx)).decode() if f_pickle else str(tx), 'time': time, 'c_address': c_address, 'related': related_list, 'args': tuple(map(decode, args)), } for txhash, (time, tx, related_list, c_address, *args) in watching_tx.items()]) except Exception as e: logging.error(e) return web_base.error_res()
async def issue_mint_tx(request): start = time() post = await web_base.content_type_json_check(request) with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() try: user_name = post.get('from', C.ANT_NAME_UNKNOWN) sender = read_name2user(user_name, cur) mint_id, tx = issue_mintcoin( name=post['name'], unit=post['unit'], digit=post.get('digit', 8), amount=post['amount'], cur=cur, description=post.get('description', None), image=post.get('image', None), additional_issue=post.get('additional_issue', True), sender=sender) if not send_newtx(new_tx=tx, outer_cur=cur): raise BaseException('Failed to send new tx.') db.commit() return web_base.json_res({ 'hash': hexlify(tx.hash).decode(), 'gas_amount': tx.gas_amount, 'gas_price': tx.gas_price, 'fee': tx.gas_amount * tx.gas_price, 'time': round(time() - start, 3), 'mint_id': mint_id }) except BaseException: return web_base.error_res()
async def change_mint_tx(request): start = time() post = await web_base.content_type_json_check(request) with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() try: user_name = post.get('from', C.ANT_NAME_UNKNOWN) sender = read_name2user(user_name, cur) tx = change_mintcoin(mint_id=post['mint_id'], cur=cur, amount=post.get('amount'), description=post.get('description'), image=post.get('image'), setting=post.get('setting'), new_address=post.get('new_address'), sender=sender) if not send_newtx(new_tx=tx, outer_cur=cur): raise BaseException('Failed to send new tx.') db.commit() return web_base.json_res({ 'hash': hexlify(tx.hash).decode(), 'gas_amount': tx.gas_amount, 'gas_price': tx.gas_price, 'fee': tx.gas_amount * tx.gas_price, 'time': round(time() - start, 3) }) except BaseException: return web_base.error_res()
async def get_mintcoin_info(request): try: mint_id = int(request.query.get('mint_id', 0)) m = get_mintcoin_object(coin_id=mint_id) return web_base.json_res(m.info) except Exception: return web_base.error_res()
async def get_block_by_hash(request): try: f_pickled = request.query.get('pickle', False) blockhash = request.query.get('hash') blockhash = unhexlify(blockhash.encode()) block = builder.get_block(blockhash) if block is None: return web.Response(text="Not found block.", status=400) if f_pickled: block = pickle.dumps(block) return web_base.json_res(b64encode(block).decode()) data = block.getinfo() data['size'] = block.getsize() data['hex'] = hexlify(block.b).decode() return web_base.json_res(data) except Exception as e: return web_base.error_res()
async def list_balance(request): confirm = int(request.query.get('confirm', 6)) users = user_account.get_balance(confirm) data = dict() with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() for user, balance in users.items(): data[read_user2name(user, cur)] = balance.coins return web_base.json_res(data)
async def get_block_by_height(request): height = int(request.query.get('height', 0)) blockhash = builder.get_block_hash(height) if blockhash is None: return web.Response(text="Not found height.", status=400) block = builder.get_block(blockhash) data = block.getinfo() data['size'] = block.getsize() data['hex'] = hexlify(block.b).decode() return web_base.json_res(data)
async def get_mintcoin_info(request): try: mint_id = int(request.query.get('mint_id', 0)) mint = get_mintcoin(mint_id) if mint: return web_base.json_res(mint.getinfo()) else: return web.Response(text='Not found mintcoin {}'.format(mint_id), status=400) except BaseException: return web_base.error_res()
async def validator_info(request): try: c_address = request.query['c_address'] f_confirmed = bool(request.query.get('confirmed', False)) best_block = builder.best_block if f_confirmed else None v = get_validator_object(c_address=c_address, best_block=best_block) return web_base.json_res(v.info) except Exception as e: logging.error(e) return web_base.error_res()
async def new_address(request): with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() user_name = request.query.get('account', C.ANT_NAME_UNKNOWN) user_id = read_name2user(user_name, cur) address = create_new_user_keypair(user_name, cur) db.commit() if user_id == C.ANT_CONTRACT: address = convert_address(address, V.BLOCK_CONTRACT_PREFIX) return web_base.json_res({'account': user_name, 'user_id': user_id, 'address': address})
async def system_info(request): data = { 'system_ver': __version__, 'api_ver': __api_version__, 'chain_ver': __chain_version__, 'booting': P.F_NOW_BOOTING, 'connections': len(V.PC_OBJ.p2p.user), 'unconfirmed': [hexlify(txhash).decode() for txhash in tx_builder.unconfirmed.keys()], 'access_time': int(time.time()), 'start_time': start_time} return web_base.json_res(data)
async def get_tx_by_hash(request): try: f_pickled = request.query.get('pickle', False) txhash = request.query.get('hash') txhash = unhexlify(txhash.encode()) tx = tx_builder.get_tx(txhash) if tx is None: return web.Response(text="Not found tx.", status=400) if f_pickled: tx = pickle.dumps(tx) return web_base.json_res(b64encode(tx).decode()) data = tx.getinfo() data['size'] = tx.size data['total_size'] = tx.size + len(tx.signature) * 96 data['hex'] = hexlify(tx.b).decode() data['signature'] = [(pubkey, hexlify(sign).decode()) for pubkey, sign in tx.signature] return web_base.json_res(data) except Exception as e: return web_base.error_res()
async def lock_database(request): with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() if is_locked_database(cur): return web.Response(text='Already locked database.', status=400) new_key = AESCipher.create_key() change_encrypt_key(new_key, cur) V.ENCRYPT_KEY = new_key if is_locked_database(cur): return web.Response(text='Failed unlock check filed.', status=400) db.commit() return web_base.json_res({'key': new_key})
async def validator_info(request): try: validator_cks, required_num = get_validator_info() return web_base.json_res({ 'im_a_validator': im_a_validator(), 'validator_address': V.CONTRACT_VALIDATOR_ADDRESS, 'validators': list(validator_cks), 'all': len(validator_cks), 'require': required_num }) except BaseException: return web_base.error_res()
async def broadcast_tx(request): post = await web_base.content_type_json_check(request) try: binary = unhexlify(post['hex'].encode()) new_tx = TX(binary=binary) new_tx.signature = [(pk, unhexlify(sign.encode())) for pk, sign in post['signature']] if not send_newtx(new_tx=new_tx): raise BaseException('Failed to send new tx.') return web_base.json_res({'txhash': hexlify(new_tx.hash).decode()}) except BaseException: return web_base.error_res()
async def list_transactions(request): page = int(request.query.get('page', 0)) limit = int(request.query.get('limit', 25)) data = list() f_next_page = False for tx_dict in user_account.get_movement_iter(start=page, f_dict=True): if limit == 0: f_next_page = True break data.append(tx_dict) limit -= 1 return web_base.json_res({'txs': data, 'next': f_next_page})
async def get_mintcoin_history(request): try: mint_id = int(request.query.get('mint_id', 0)) data = list() for index, txhash, params, setting in builder.db.read_coins_iter(coin_id=mint_id): data.append({ 'index': index, 'txhash': hexlify(txhash).decode(), 'params': params, 'setting': setting}) return web_base.json_res(data) except BaseException: return web_base.error_res()
async def list_unspents(request): data = list() best_height = builder.best_block.height for address, height, txhash, txindex, coin_id, amount in get_unspents_iter(): data.append({ 'address': address, 'height': height, 'confirmed': None if height is None else best_height - height, 'txhash': hexlify(txhash).decode(), 'txindex': txindex, 'coin_id': coin_id, 'amount': amount}) return web_base.json_res(data)
async def get_keypair(request): with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() try: address = request.query['address'] uuid, sk, pk = read_address2keypair(address, cur) return web_base.json_res({ 'uuid': uuid, 'address': address, 'private_key': sk, 'public_key': pk}) except BlockChainError as e: return web.Response(text=str(e), status=400)