示例#1
0
async def list_unspents(request):
    if not chain_builder.db.db_config['addrindex']:
        return utils.error_res('address isn\'t full indexed')
    try:
        best_height = chain_builder.best_block.height
        page = int(request.query.get('page', 0))
        limit = min(100, int(request.query.get('limit', 25)))
        start = page * limit
        finish = (page + 1) * limit - 1
        f_next_page = False
        target_address = request.query['address']
        unspents_iter = get_unspents_iter(
            target_address=set(target_address.split(',')))
        data = list()
        for index, (address, height, txhash, txindex, coin_id,
                    amount) in enumerate(unspents_iter):
            if finish < index:
                f_next_page = True
                break
            if index < start:
                continue
            data.append({
                'address': address,
                'height': height,
                'confirmed': None if height is None else best_height - height,
                'txhash': txhash.hex(),
                'txindex': txindex,
                'coin_id': coin_id,
                'amount': amount
            })
        return utils.json_res({'data': data, 'next': f_next_page})
    except Exception:
        return utils.error_res()
示例#2
0
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)
示例#3
0
def update_unspents_txs():
    global unspents_txs
    c = 50
    while previous_block is None and 0 < c:
        sleep(0.2)
        c -= 1
    previous_height = previous_block.height
    proof_txs = list()
    all_num = 0
    for address, height, txhash, txindex, coin_id, amount in get_unspents_iter(
    ):
        if height is None:
            continue
        if coin_id != 0:
            continue
        if not (previous_height + 1 > height + C.MATURE_HEIGHT):
            continue
        if not is_address(address, prefix=V.BLOCK_PREFIX):
            continue
        if amount < 100000000:
            continue
        if staking_limit < all_num:
            logging.debug("Unspents limit reached, skip by {} limits.".format(
                staking_limit))
            break
        all_num += 1
        proof_tx = TX(
            tx={
                'type': C.TX_POS_REWARD,
                'inputs': [(txhash, txindex)],
                'outputs': [(address, 0, 0)],
                'gas_price': 0,
                'gas_amount': 0,
                'message_type': C.MSG_NONE,
                'message': b''
            })
        proof_tx.height = previous_height + 1
        proof_tx.pos_amount = amount
        proof_txs.append(proof_tx)
    unspents_txs = proof_txs
    return all_num, len(proof_txs)
示例#4
0
文件: utils.py 项目: kmn/bc4py
def fill_inputs_outputs(tx,
                        cur,
                        fee_coin_id=0,
                        additional_gas=0,
                        dust_percent=0.8,
                        utxo_cashe=None):
    assert tx.gas_price > 0, "Gas params is none zero."
    # outputsの合計を取得
    output_coins = Balance()
    for address, coin_id, amount in tx.outputs.copy():
        if address == DUMMY_REDEEM_ADDRESS:
            # 償還Outputは再構築するので消す
            tx.outputs.remove((address, coin_id, amount))
            continue
        output_coins[coin_id] += amount
    # 一時的にfeeの概算
    fee_coins = Balance(coin_id=fee_coin_id,
                        amount=tx.gas_price * tx.gas_amount)
    # 必要なだけinputsを取得
    tx.inputs.clear()
    need_coins = output_coins + fee_coins
    input_coins = Balance()
    input_address = set()
    f_dust_skipped = False
    if utxo_cashe is None:
        utxo_iter = get_unspents_iter(cur)
        utxo_cashe = list()
        f_put_cashe = True
    else:
        utxo_iter = utxo_cashe
        f_put_cashe = False
    for address, height, txhash, txindex, coin_id, amount in utxo_iter:
        if f_put_cashe:
            utxo_cashe.append(
                (address, height, txhash, txindex, coin_id, amount))
        if coin_id not in need_coins:
            continue
        elif need_coins[coin_id] * dust_percent > amount:
            f_dust_skipped = True
            continue
        need_coins[coin_id] -= amount
        input_coins[coin_id] += amount
        input_address.add(address)
        tx.inputs.append((txhash, txindex))
        if need_coins.is_all_minus_amount():
            break
    else:
        if f_dust_skipped and dust_percent > 0.00001:
            new_dust_percent = round(dust_percent * 0.7, 6)
            logging.debug("Retry by lower dust percent. {}=>{}".format(
                dust_percent, new_dust_percent))
            return fill_inputs_outputs(tx=tx,
                                       cur=cur,
                                       fee_coin_id=fee_coin_id,
                                       additional_gas=additional_gas,
                                       dust_percent=new_dust_percent,
                                       utxo_cashe=utxo_cashe)
        elif len(tx.inputs) > 255:
            raise BlockChainError(
                'Too many inputs, unspent tx\'s amount is too small.')
        else:
            raise BlockChainError(
                'Insufficient balance. inputs={} needs={}'.format(
                    input_coins, need_coins))
    # redeemを計算
    redeem_coins = input_coins - output_coins - fee_coins
    for coin_id, amount in redeem_coins:
        tx.outputs.append((DUMMY_REDEEM_ADDRESS, coin_id, amount))
    # Feeをチェックし再計算するか決める
    tx.serialize()
    need_gas_amount = tx.size + len(
        input_address) * C.SIGNATURE_GAS + additional_gas
    if 0 <= tx.gas_amount - need_gas_amount < 10000:
        # input/outputを混ぜる
        return input_address
    else:
        # insufficient gas
        logging.debug("Retry calculate tx fee. [{}=>{}+{}={}]".format(
            tx.gas_amount, tx.size + len(input_address) * C.SIGNATURE_GAS,
            additional_gas, need_gas_amount))
        tx.gas_amount = need_gas_amount
        return fill_inputs_outputs(tx=tx,
                                   cur=cur,
                                   fee_coin_id=fee_coin_id,
                                   additional_gas=additional_gas,
                                   dust_percent=dust_percent,
                                   utxo_cashe=utxo_cashe)
示例#5
0
文件: utils.py 项目: volbil/bc4py
def fill_inputs_outputs(tx,
                        target_address=None,
                        cur=None,
                        signature_num=None,
                        fee_coin_id=0,
                        additional_gas=0,
                        dust_percent=0.8,
                        utxo_cashe=None,
                        depth=0):
    if MAX_RECURSIVE_DEPTH < depth:
        raise BlockChainError('over max recursive depth on filling inputs_outputs!')
    # outputsの合計を取得
    output_coins = Balance()
    for address, coin_id, amount in tx.outputs.copy():
        if address == DUMMY_REDEEM_ADDRESS:
            # 償還Outputは再構築するので消す
            tx.outputs.remove((address, coin_id, amount))
            continue
        output_coins[coin_id] += amount
    # 一時的にfeeの概算
    fee_coins = Balance(coin_id=fee_coin_id, amount=tx.gas_price * tx.gas_amount)
    # 必要なだけinputsを取得
    tx.inputs.clear()
    need_coins = output_coins + fee_coins
    input_coins = Balance()
    input_address = set()
    f_dust_skipped = False
    if utxo_cashe is None:
        if target_address:
            utxo_iter = get_unspents_iter(target_address=target_address)
        elif cur:
            utxo_iter = get_my_unspents_iter(cur=cur)
        else:
            raise Exception('target_address and cur is None?')
        cashe = list()
        utxo_cashe = [cashe, utxo_iter]
    else:
        cashe, utxo_iter = utxo_cashe
    for is_cashe, (address, height, txhash, txindex, coin_id, amount) in sum_utxo_iter(cashe, utxo_iter):
        if not is_cashe:
            cashe.append((address, height, txhash, txindex, coin_id, amount))
        if coin_id not in need_coins:
            continue
        if need_coins[coin_id] * dust_percent > amount:
            f_dust_skipped = True
            continue
        need_coins[coin_id] -= amount
        input_coins[coin_id] += amount
        input_address.add(address)
        tx.inputs.append((txhash, txindex))
        if need_coins.is_all_minus_amount():
            break
    else:
        if f_dust_skipped and dust_percent > 0.00001:
            new_dust_percent = round(dust_percent * 0.7, 6)
            log.debug("Retry by lower dust percent. {}=>{}".format(dust_percent, new_dust_percent))
            return fill_inputs_outputs(
                tx=tx,
                target_address=target_address,
                cur=cur,
                signature_num=signature_num,
                fee_coin_id=fee_coin_id,
                additional_gas=additional_gas,
                dust_percent=new_dust_percent,
                utxo_cashe=utxo_cashe,
                depth=depth+1)
        elif len(tx.inputs) > 255:
            raise BlockChainError('TX inputs is too many num={}'.format(len(tx.inputs)))
        else:
            raise BlockChainError('Insufficient balance. inputs={} needs={}'.format(input_coins, need_coins))
    # redeemを計算
    redeem_coins = input_coins - output_coins - fee_coins
    for coin_id, amount in redeem_coins:
        tx.outputs.append((DUMMY_REDEEM_ADDRESS, coin_id, amount))
    # Feeをチェックし再計算するか決める
    tx.serialize()
    if signature_num is None:
        need_gas_amount = tx.size + additional_gas + len(input_address) * C.SIGNATURE_GAS
    else:
        need_gas_amount = tx.size + additional_gas + signature_num * C.SIGNATURE_GAS
    if tx.gas_amount > need_gas_amount:
        # swap overflowed gas, gas_amount => redeem_output
        swap_amount = (tx.gas_amount - need_gas_amount) * tx.gas_price
        for index, (address, coin_id, amount) in enumerate(tx.outputs):
            if address != DUMMY_REDEEM_ADDRESS:
                continue
            elif coin_id != fee_coin_id:
                continue
            else:
                tx.outputs[index] = (address, coin_id, amount + swap_amount)
                break
        else:
            raise BlockChainError('cannot swap overflowed gas amount={}'.format(swap_amount))
        # success swap
        tx.gas_amount = need_gas_amount
        tx.serialize()
        return input_address
    elif tx.gas_amount < need_gas_amount:
        # retry insufficient gas
        log.info("retry calculate fee gasBefore={} gasNext={}".format(tx.gas_amount, need_gas_amount))
        tx.gas_amount = need_gas_amount
        return fill_inputs_outputs(
            tx=tx,
            target_address=target_address,
            cur=cur,
            signature_num=signature_num,
            fee_coin_id=fee_coin_id,
            additional_gas=additional_gas,
            dust_percent=dust_percent,
            utxo_cashe=utxo_cashe,
            depth=depth+1)
    else:
        # tx.gas_amount == need_gas_amount
        return input_address