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 contract_init(request): start = time() post = await web_base.content_type_json_check(request) try: c_address = post['c_address'] c_bin = unhexlify(post['hex'].encode()) c_extra_imports = post.get('extra_imports', None) c_settings = post.get('settings', None) send_pairs = post.get('send_pairs', None) binary2contract(c_bin=c_bin, extra_imports=c_extra_imports) # can compile? 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_init_tx(c_address=c_address, c_bin=c_bin, cur=cur, c_extra_imports=c_extra_imports, c_settings=c_settings, 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 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()
def get_unspents_iter(outer_cur=None, best_chain=None): target_address = set() with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = outer_cur or db.cursor() for (uuid, address, user) in read_pooled_address_iter(cur): target_address.add(address) return get_utxo_iter(target_address=target_address, best_block=None, best_chain=best_chain)
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()
def get_balance(self, confirm=6): assert confirm < builder.cashe_limit - builder.batch_size, 'Too few cashe size.' assert builder.best_block, 'Not DataBase init.' # DataBase balance = self.db_balance.copy() with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() # Memory limit_height = builder.best_block.height - confirm for block in builder.best_chain: for tx in block.txs: move_log = read_txhash2log(tx.hash, cur) if move_log is None: if tx.hash in self.memory_movement: move_log = self.memory_movement[tx.hash] if move_log: for user, coins in move_log.movement.items(): for coin_id, amount in coins: if limit_height < block.height: if amount < 0: balance.add_coins(user, coin_id, amount) else: balance.add_coins(user, coin_id, amount) # Unconfirmed for tx in list(tx_builder.unconfirmed.values()): move_log = read_txhash2log(tx.hash, cur) if move_log is None: if tx.hash in self.memory_movement: move_log = self.memory_movement[tx.hash] if move_log: for user, coins in move_log.movement.items(): for coin_id, amount in coins: if amount < 0: balance.add_coins(user, coin_id, amount) return balance
async def issue_mint_tx(request): start = time() post = await utils.content_type_json_check(request) with create_db(V.DB_ACCOUNT_PATH, f_strict=True) as db: cur = db.cursor() try: user_name = post.get('from', C.account2name[C.ANT_UNKNOWN]) sender = read_name2userid(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 BlockChainError('Failed to send new tx') db.commit() return utils.json_res({ 'hash': tx.hash.hex(), '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 Exception: return utils.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 list_account_address(request): with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() user_name = request.query.get('account', C.account2name[C.ANT_UNKNOWN]) user_id = read_name2userid(user_name, cur) address_list = list() for uuid, address, user in read_pooled_address_iter(cur): if user_id == user: if user == C.ANT_VALIDATOR: address_list.append( convert_address(ck=address, hrp=V.BECH32_HRP, ver=C.ADDR_VALIDATOR_VER)) elif user == C.ANT_CONTRACT: address_list.append( convert_address(ck=address, hrp=V.BECH32_HRP, ver=C.ADDR_CONTRACT_VER)) else: address_list.append(address) return utils.json_res({ 'account': user_name, 'user_id': user_id, 'address': address_list })
async def contract_transfer(request): start = time() post = await utils.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.account2name[C.ANT_UNKNOWN]) with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() sender = read_name2userid(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 utils.json_res({ 'hash': tx.hash.hex(), '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 utils.error_res()
async def change_mint_tx(request): start = time() post = await utils.content_type_json_check(request) with create_db(V.DB_ACCOUNT_PATH, f_strict=True) as db: cur = db.cursor() try: user_name = post.get('from', C.account2name[C.ANT_UNKNOWN]) sender = read_name2userid(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 BlockChainError('Failed to send new tx') db.commit() return utils.json_res({ 'hash': tx.hash.hex(), '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 utils.error_res()
async def validator_edit(request): start = time() post = await utils.content_type_json_check(request) v_address = post.get('v_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 create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() if v_address is None: v_address = generate_new_address_by_userid( user=C.ANT_VALIDATOR, cur=cur) tx = create_validator_edit_tx(v_address=v_address, cur=cur, 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 utils.json_res({ 'hash': tx.hash.hex(), '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 utils.error_res()
async def validate_unconfirmed(request): start = time() post = await utils.content_type_json_check(request) try: txhash = a2b_hex(post['hash']) tx = tx_builder.get_tx(txhash=txhash) if tx is None or tx.height is not None: return utils.error_res('You cannot validate tx. {}'.format(tx)) with 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 utils.json_res({ 'hash': new_tx.hash.hex(), '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 utils.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 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()
def _callback(data_list): if isinstance(data_list[0], str): logging.error("Callback error, {}".format(data_list[0])) return with closing(create_db(V.DB_ACCOUNT_PATH)) as db: insert_keypairs(data_list, db.cursor()) db.commit() logging.debug("Generate {} keypairs.".format(len(data_list)))
def im_a_validator(best_block=None): validator_cks, required_num = get_validator_info(best_block) with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() for address in validator_cks: if read_address2user(address, cur): return address return None
def message2signature(raw, address): # sign by address with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() uuid, sk, pk = read_address2keypair(address, cur) if sk is None: raise BlockChainError('Not found address {}'.format(address)) return pk, sign(msg=raw, sk=sk, pk=pk)
def sign_message_by_address(raw, address): """sign raw bytes by address""" with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() uuid, keypair, _ = read_address2keypair(address, cur) r, s = keypair.get_single_sign(raw) pk = keypair.get_public_key() return pk, r, s
def check_related_address(address_list): r = list() with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() for address in address_list: user = read_address2userid(address=address, cur=cur) if user: r.append((read_userid2name(user, cur), address)) return r
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 list_balance(request): confirm = int(request.query.get('confirm', 6)) data = dict() with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() users = user_account.get_balance(confirm=confirm, outer_cur=cur) for user, balance in users.items(): data[read_userid2name(user, cur)] = dict(balance) return utils.json_res(data)
async def sendtoaddress(*args, **kwargs): """ Send an amount to a given address. Arguments: 1. "address" (string, required) The bitcoin address to send to. 2. "amount" (numeric or string, required) The amount in BTC to send. eg 0.1 3. "comment" (string, optional) A comment used to store what the transaction is for. This is not part of the transaction, just kept in your wallet. 4. "comment_to" (string, optional) A comment to store the name of the person or organization to which you're sending the transaction. This is not part of the transaction, just kept in your wallet. 5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. Result: "txid" (string) The transaction id. """ if len(args) < 2: raise ValueError('too few arguments num={}'.format(len(args))) address, amount, *options = args if not is_address(address, V.BECH32_HRP, 0): raise ValueError('address is invalid') amount = int(amount * pow(10, V.COIN_DIGIT)) _comment = str( options[0]) if 0 < len(options) else None # do not use by Yiimp _comment_to = str( options[1]) if 1 < len(options) else None # do not use by Yiimp subtract_fee_amount = bool(options[2]) if 2 < len(options) else False # execute send error = None from_id = C.ANT_UNKNOWN coin_id = 0 coins = Balance(coin_id, amount) with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() try: new_tx = send_from(from_id, address, coins, cur, subtract_fee_amount=subtract_fee_amount) if send_newtx(new_tx=new_tx, outer_cur=cur): db.commit() else: error = 'Failed to send new tx' db.rollback() except Exception as e: error = str(e) log.debug("sendtoaddress", exc_info=True) db.rollback() # submit result if error: raise ValueError(error) return new_tx.hash.hex()
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})
def init(self): with closing(create_db(V.DB_ACCOUNT_PATH)) as db: cur = db.cursor() memory_sum = UserCoins() for move_log in read_log_iter(cur): # logに記録されてもBlockに取り込まれていないならTXは存在せず if builder.db.read_tx(move_log.txhash): memory_sum += move_log.movement else: logging.warning("It's unknown log {}".format(move_log)) # delete_log(move_log.txhash, cur) self.db_balance += memory_sum
def create_mining_block(consensus): global mining_address # setup mining address for PoW with mining_address_lock: if mining_address is None: if V.MINING_ADDRESS is None: with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() mining_address = generate_new_address_by_userid( C.ANT_UNKNOWN, cur) db.commit() else: mining_address = V.MINING_ADDRESS if unconfirmed_txs is None: raise FailedGenerateWarning('unconfirmed_txs is None') if previous_block is None: raise FailedGenerateWarning('previous_block is None') # create proof_tx reward = GompertzCurve.calc_block_reward(previous_block.height + 1) fees = sum(tx.gas_amount * tx.gas_price for tx in unconfirmed_txs) proof_tx = TX.from_dict( tx={ 'type': C.TX_POW_REWARD, 'inputs': list(), 'outputs': [(mining_address, 0, reward + fees)], 'gas_price': 0, 'gas_amount': 0, 'message_type': C.MSG_NONE, 'message': b'' }) proof_tx.update_time() # create mining block bits, target = get_bits_by_hash(previous_hash=previous_block.hash, consensus=consensus) mining_block = Block.from_dict( block={ 'merkleroot': b'\xff' * 32, 'time': 0, 'previous_hash': previous_block.hash, 'bits': bits, 'nonce': b'\xff\xff\xff\xff' }) proof_tx.height = previous_block.height + 1 mining_block.height = proof_tx.height mining_block.flag = consensus mining_block.bits2target() mining_block.txs.append(proof_tx) if unconfirmed_txs is None: raise FailedGenerateWarning('unconfirmed_txs is None') mining_block.txs.extend(unconfirmed_txs) mining_block.update_merkleroot() mining_block.update_time(proof_tx.time) return mining_block
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})
def _debug(sql, path, explain=True): with create_db(path) as db: db.set_trace_callback(sql_info) cur = db.cursor() f = cur.execute(('explain query plan ' if explain else '') + sql) if explain: print(f.fetchone()[-1]) else: c = 0 for d in f.fetchall(): print(c, ':', ', '.join(map(str, d))) c += 1
async def sendmany(*args, **kwargs): """ Send multiple times. Amounts are double-precision floating point numbers. Requires wallet passphrase to be set with walletpassphrase call. Arguments: 1. "fromaccount" (string, required) DEPRECATED. The account to send the funds from. Should be "" for the default account 2. "amounts" (string, required) A json object with addresses and amounts { "address":amount (numeric or string) The monacoin address is the key, the numeric amount (can be string) in MONA is the value ,... } 3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times. 4. "comment" (string, optional) A comment Result: "txid" (string) The transaction id for the send. Only 1 transaction is created regardless of the number of addresses. """ if len(args) < 2: raise ValueError('too few arguments num={}'.format(len(args))) from_account, pairs, *options = args _minconf = options[0] if 0 < len(options) else 1 # ignore _comment = options[1] if 1 < len(options) else None # ignore # replace account "" to "@Unknown" from_account = C.account2name[ C.ANT_UNKNOWN] if from_account == '' else from_account error = None with create_db(V.DB_ACCOUNT_PATH) as db: cur = db.cursor() try: user_id = read_name2userid(from_account, cur) send_pairs = list() multiple = pow(10, V.COIN_DIGIT) for address, amount in pairs.items(): send_pairs.append((address, 0, int(amount * multiple))) new_tx = send_many(user_id, send_pairs, cur) if send_newtx(new_tx=new_tx, outer_cur=cur): db.commit() else: error = 'Failed to send new tx' db.rollback() except Exception as e: error = str(e) log.debug("sendmany", exc_info=True) db.rollback() # submit result if error: raise ValueError(error) return new_tx.hash.hex()
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)