Exemplo n.º 1
0
def subtract_fee_from_user_balance(tx: TX):
    """subtract fee from user's sending outputs"""
    subtract_fee = tx.gas_amount * tx.gas_price
    f_subtracted = False
    f_added = False
    for index, (address, coin_id, amount) in enumerate(tx.outputs):
        if coin_id != 0:
            continue
        elif amount < subtract_fee:
            continue
        elif not f_added and address == DUMMY_REDEEM_ADDRESS:
            # add used fee to redeem output
            tx.outputs[index] = (address, coin_id, amount + subtract_fee)
            f_added = True
        elif not f_subtracted and address != DUMMY_REDEEM_ADDRESS:
            # subtract used fee from sending output
            tx.outputs[index] = (address, coin_id, amount - subtract_fee)
            f_subtracted = True
        else:
            continue
    # check
    if f_subtracted is False or f_added is False:
        raise BlockChainError('failed to subtract fee sub={} add={} fee={}'
                              .format(f_subtracted, f_added, subtract_fee))
    return subtract_fee
Exemplo n.º 2
0
 def new_tx(data):
     try:
         new_tx = TX(binary=data['tx'])
         new_tx.signature = data['sign']
         check_tx_time(new_tx)
         check_tx(tx=new_tx, include_block=None)
         if new_tx.type in (C.TX_VALIDATOR_EDIT, C.TX_CONCLUDE_CONTRACT) and new_tx.hash in tx_builder.unconfirmed:
             # marge contract signature
             original_tx = tx_builder.unconfirmed[new_tx.hash]
             new_signature = list(set(new_tx.signature) | set(original_tx.signature))
             original_tx.signature = new_signature
             logging.info("Marge contract tx {}".format(new_tx))
         else:
             # normal tx
             tx_builder.put_unconfirmed(new_tx)
             update_mining_staking_all_info()
             logging.info("Accept new tx {}".format(new_tx))
         return True
     except BlockChainError as e:
         error = 'Failed accept new tx "{}"'.format(e)
         logging.error(error)
         return False
     except Exception:
         error = "Failed accept new tx"
         logging.error(error, exc_info=True)
         return False
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
def check_new_tx(tx: TX):
    if tx.height is not None:
        log.error('New tx, but is already confirmed, {}'.format(tx))
        return
    elif tx.message_type != C.MSG_MSGPACK:
        return
    elif tx.type == C.TX_CONCLUDE_CONTRACT:
        # 十分な署名が集まったら消す
        c_address, start_hash, c_storage = tx.encoded_message()
        v = get_validator_by_contract_info(c_address=c_address,
                                           start_hash=start_hash,
                                           stop_txhash=tx.hash)
        related_list = check_related_address(v.validators)
        if related_list:
            data = (time(), tx, related_list, c_address, start_hash, c_storage)
            watching_tx[tx.hash] = data
            if not stream.is_disposed:
                stream.on_next((C_Conclude, False, data))
    elif tx.type == C.TX_VALIDATOR_EDIT:
        # 十分な署名が集まったら消す
        v_address, new_address, flag, sig_diff = tx.encoded_message()
        v = get_validator_object(v_address=v_address, stop_txhash=tx.hash)
        related_list = check_related_address(v.validators)
        if related_list:
            data = (time(), tx, related_list, v_address, new_address, flag,
                    sig_diff)
            watching_tx[tx.hash] = data
            if not stream.is_disposed:
                stream.on_next((C_Validator, False, data))
    else:
        pass
Exemplo n.º 5
0
def load_boot_file():
    normal_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                               'boot.dat')
    extra_path = os.path.join(V.DB_HOME_DIR, 'boot.dat')
    if os.path.exists(normal_path):
        with open(normal_path, mode='br') as fp:
            data = bjson.loads(
                b64decode(fp.read().replace(b'\n', b'').replace(b'\r', b'')))
    elif os.path.exists(extra_path):
        with open(extra_path, mode='br') as fp:
            data = bjson.loads(
                b64decode(fp.read().replace(b'\n', b'').replace(b'\r', b'')))
    else:
        raise FileNotFoundError('Cannot find boot.dat "{}" or "{}" ?'.format(
            normal_path, extra_path))
    genesis_block = Block(binary=data['block'])
    genesis_block.flag = C.BLOCK_GENESIS
    genesis_block.height = 0
    for b_tx in data['txs']:
        tx = TX(binary=b_tx)
        tx.height = 0
        genesis_block.txs.append(tx)
    connections = data.get('connections', list())
    network_ver = data['network_ver']
    return genesis_block, network_ver, connections
Exemplo n.º 6
0
def put_to_block_stack(r, before_waiter):
    block_tmp = dict()
    batch_txs = list()
    for block_b, block_height, block_flag, txs in r:
        block = Block(binary=block_b)
        block.height = block_height
        block.flag = block_flag
        for tx_b, tx_signature in txs:
            tx = TX(binary=tx_b)
            tx.height = None
            tx.signature = tx_signature
            tx_from_database = tx_builder.get_tx(txhash=tx.hash)
            if tx_from_database:
                block.txs.append(tx_from_database)
            else:
                block.txs.append(tx)
        block_tmp[block_height] = block
        batch_txs.extend(block.txs)
    # check
    if len(block_tmp) == 0:
        return None
    batch_sign_cashe(batch_txs)
    before_waiter.wait()
    with write_protect_lock:
        block_stack.update(block_tmp)
    return batch_workhash(tuple(block_tmp.values()))
Exemplo n.º 7
0
def finish_contract_tx(start_tx, f_limit=True):
    assert start_tx.height is None, 'StartTX height is None.'
    assert P.VALIDATOR_OBJ, 'You are not a validator.'
    c_address, c_data, c_args, c_redeem = bjson.loads(start_tx.message)
    if f_limit:
        gas_limit = start_tx.gas_amount - start_tx.getsize()
    else:
        gas_limit = None
    status, result, estimate_gas, line = try_emulate(start_tx, gas_limit)
    if status:
        # 成功時
        outputs, cs_result = result
        if cs_result is None:
            message = bjson.dumps((True, start_tx.hash, None), compress=False)
        else:
            cs = get_contract_storage(c_address)
            cs_diff = cs.diff_dev(new_key_value=cs_result.key_value)
            message = bjson.dumps((True, start_tx.hash, cs_diff),
                                  compress=False)
        try:
            check_output_format(outputs)
        except BlockChainError as e:
            logging.debug("Contract failed `emulate success` {}".format(e))
            return failed_finish_tx(start_tx), estimate_gas

    else:
        # 失敗時
        outputs = None
        logging.debug("Contract failed `emulate failed` {}".format(result))
        return failed_finish_tx(start_tx), 0
    # finish tx 作成
    finish_tx = TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_FINISH_CONTRACT,
            'time': start_tx.time,
            'deadline': start_tx.deadline,
            'inputs': list(),
            'outputs': outputs or list(),
            'gas_price': start_tx.gas_price,
            'gas_amount': 1,
            'message_type': C.MSG_BYTE,
            'message': message
        })
    to_user_redeem = (c_redeem, 0, 0)
    finish_tx.outputs.append(to_user_redeem)  # gas_amountを返す
    # fill input/output
    # TODO: c_redeemを用いてFeeを還元
    redeem_gas = start_tx.gas_amount - start_tx.getsize() - estimate_gas
    if not fill_inputs_outputs(finish_tx, c_address, start_tx.hash,
                               redeem_gas):
        return failed_finish_tx(start_tx), estimate_gas
    redeem_idx = finish_tx.outputs.index(to_user_redeem)
    redeem_amount = -1 * finish_tx.gas_amount * finish_tx.gas_price
    finish_tx.outputs[redeem_idx] = (c_redeem, 0, redeem_amount)
    replace_redeem_dummy_address(finish_tx, c_address)
    finish_tx.serialize()
    return finish_tx, estimate_gas
Exemplo n.º 8
0
async def submitblock(block_hex_or_obj, **kwargs):
    if isinstance(block_hex_or_obj, str):
        block_bin = unhexlify(block_hex_or_obj.encode())
        # Block
        mined_block = Block(binary=block_bin[:80])
        if mined_block.previous_hash != builder.best_block.hash:
            return 'PreviousHash don\'t match.'
        previous_block = builder.get_block(mined_block.previous_hash)
        mined_block.height = previous_block.height + 1
        mined_block.flag = int(kwargs['password'])
        # tx length
        storage_flag = int.from_bytes(block_bin[80:81], 'little')
        if storage_flag < 0xfd:
            tx_len = storage_flag
            pos = 81
        elif storage_flag == 0xfd:
            tx_len = int.from_bytes(block_bin[81:83], 'little')
            pos = 83
        elif storage_flag == 0xfe:
            tx_len = int.from_bytes(block_bin[81:85], 'little')
            pos = 85
        else:  # == 0xff
            tx_len = int.from_bytes(block_bin[81:89], 'little')
            pos = 89
        if F_HEAVY_DEBUG:
            logging.debug("RpcSubmit block: pos={}, tx_len={}".format(
                pos, tx_len))
        # correct txs
        while len(block_bin) > pos:
            tx = TX()
            tx.b = block_bin
            tx.deserialize(first_pos=pos, f_raise=False)
            if tx.version != __chain_version__:
                return 'tx_ver do not match [{}!={}]'.format(
                    tx.version, __chain_version__)
            pos += len(tx.b)
            mined_block.txs.append(
                tx_builder.get_tx(txhash=tx.hash, default=tx))
            # check
            if tx_len != len(mined_block.txs):
                return 'Do not match txlen [{}!={}]'.format(
                    tx_len, len(mined_block.txs))
            if pos != len(block_bin):
                return 'Do not match pos [{}!={}]'.format(pos, len(block_bin))
    elif isinstance(block_hex_or_obj, Block):
        mined_block = block_hex_or_obj
        previous_block = builder.get_block(mined_block.previous_hash)
        mined_block.height = previous_block.height + 1
        mined_block.flag = int(kwargs['password'])
    else:
        return 'Unknown input? -> {}'.format(block_hex_or_obj)
    mined_block.update_pow()
    if mined_block.pow_check():
        confirmed_generating_block(mined_block)
        return None  # accepted
    else:
        return 'not satisfied work.'
Exemplo n.º 9
0
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()
Exemplo n.º 10
0
async def sign_raw_tx(request):
    post = await utils.content_type_json_check(request)
    try:
        binary = a2b_hex(post['hex'])
        other_pairs = dict()
        for sk in post.get('pairs', list()):
            sk = a2b_hex(sk)
            keypair: PyKeyPair = PyKeyPair.from_secret_key(sk)
            r, s = keypair.get_single_sign(binary)
            pk = keypair.get_public_key()
            ck = get_address(pk=pk, hrp=V.BECH32_HRP, ver=C.ADDR_NORMAL_VER)
            other_pairs[ck] = (pk, r, s)
        tx = TX.from_binary(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(
                    sign_message_by_address(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 utils.json_res({
            'hash': data['hash'],
            'signature': data['signature'],
            'hex': tx.b.hex()
        })
    except Exception:
        return utils.error_res()
Exemplo n.º 11
0
def create_signed_tx_as_validator(tx: TX):
    tx = deepcopy(tx)
    if tx.type == C.TX_VALIDATOR_EDIT:
        v_address, new_address, flag, sig_diff = tx.encoded_message()
        v = get_validator_object(v_address=v_address, stop_txhash=tx.hash)
    elif tx.type == C.TX_CONCLUDE_CONTRACT:
        c_address, start_hash, c_storage = tx.encoded_message()
        v = get_validator_by_contract_info(c_address=c_address,
                                           start_hash=start_hash)
    else:
        raise BlockChainError('Not found tx type {}'.format(tx))
    # sign and check how many add signs
    if setup_contract_signature(tx, v.validators) == 0:
        raise BlockChainError(
            'Cannot sign, you are not validator or already signed')
    return tx
Exemplo n.º 12
0
def check_tx_create_contract(tx: TX, include_block: Block):
    if len(tx.inputs) == 0 or len(tx.outputs) == 0:
        raise BlockChainError('No inputs or outputs.')
    elif tx.message_type != C.MSG_BYTE:
        raise BlockChainError('create contract tx is bytes msg.')
    elif V.BLOCK_CONTRACT_PREFIX is None:
        raise BlockChainError('Not set contract prefix ?')
    elif V.BLOCK_CONTRACT_PREFIX == V.BLOCK_PREFIX:
        raise BlockChainError('normal prefix same with contract prefix.')
    # GAS量チェック
    estimate_gas = tx.getsize() + C.CONTRACT_CREATE_FEE
    if estimate_gas > tx.gas_amount:
        raise BlockChainError('Insufficient gas [{}>{}]'.format(
            estimate_gas, tx.gas_amount))
    # Contractをデコードできるか
    c_address, c_bin, c_cs = bjson.loads(tx.message)
    binary2contract(c_bin)
    # ContractStorageの初期値チェック
    if c_cs:
        for k, v in c_cs.items():
            if not isinstance(k, bytes) or not isinstance(v, bytes):
                raise BlockChainError('cs format is wrong. {}'.format(c_cs))
    if not is_address(c_address, V.BLOCK_CONTRACT_PREFIX):
        raise BlockChainError('Is not contract address. {}'.format(c_address))
    # 既に登録されていないかチェック
    cs = get_contract_storage(c_address, include_block)
    if cs.version != 0:
        raise BlockChainError('Already created contract. {}'.format(tx))
Exemplo n.º 13
0
def make_block_by_node(blockhash):
    """ create Block by outside node """
    r = ask_node(cmd=DirectCmd.BLOCK_BY_HASH, data={'blockhash': blockhash})
    if isinstance(r, str):
        raise BlockChainError('make_block_by_node() failed, by "{}"'.format(hexlify(blockhash).decode(), r))
    block = Block(binary=r['block'])
    block.flag = r['flag']
    before_block = builder.get_block(blockhash=block.previous_hash)
    if before_block is None:
        raise BlockChainError('Not found BeforeBeforeBlock {}'.format(hexlify(block.previous_hash).decode()))
    block.height = before_block.height + 1
    for tx in r['txs']:
        _tx = TX(binary=tx['tx'])
        _tx.height = block.height
        _tx.signature = tx['sign']
        block.txs.append(_tx)
    return block
Exemplo n.º 14
0
async def broadcast_tx(request):
    start = time()
    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({
            '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 BaseException:
        return web_base.error_res()
Exemplo n.º 15
0
Arquivo: builder.py Projeto: kmn/bc4py
 def read_tx(self, txhash):
     if self.is_batch_thread() and txhash in self.batch['_tx']:
         b = self.batch['_tx'][txhash]
     elif is_plyvel:
         b = self._tx.get(txhash, default=None)
     else:
         b = self._tx.Get(txhash, default=None)
     if b is None:
         return None
     b = bytes(b)
     height, _time, bin_len, sign_len = struct_tx.unpack_from(b)
     b_tx = b[16:16+bin_len]
     b_sign = b[16+bin_len:16+bin_len+sign_len]
     assert len(b) == 16+bin_len+sign_len, 'Wrong len [{}={}]'\
         .format(len(b), 16+bin_len+sign_len)
     tx = TX(binary=b_tx)
     tx.height = height
     tx.signature = bin2signature(b_sign)
     return tx
Exemplo n.º 16
0
 def new_tx(data):
     try:
         new_tx = TX(binary=data['tx'])
         new_tx.signature = data['sign']
         check_tx(tx=new_tx, include_block=None)
         check_tx_time(new_tx)
         tx_builder.put_unconfirmed(new_tx)
         update_mining_staking_all_info()
         logging.info("Accept new tx {}".format(new_tx))
         return True
     except BlockChainError as e:
         error = 'Failed accept new tx "{}"'.format(e)
         logging.error(error)
         add_failed_mark(error)
         return False
     except BaseException:
         error = "Failed accept new tx"
         logging.error(error, exc_info=True)
         add_failed_mark(error)
         return False
Exemplo n.º 17
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)
Exemplo n.º 18
0
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
Exemplo n.º 19
0
def check_unconfirmed_order(best_block, ordered_unconfirmed_txs):
    if len(ordered_unconfirmed_txs) == 0:
        return None
    s = time()
    dummy_proof_tx = TX()
    dummy_proof_tx.type = C.TX_POW_REWARD,
    dummy_block = Block()
    dummy_block.height = best_block.height + 1
    dummy_block.previous_hash = best_block.hash
    dummy_block.txs.append(dummy_proof_tx)  # dummy for proof tx
    dummy_block.txs.extend(ordered_unconfirmed_txs)
    tx = None
    try:
        for tx in ordered_unconfirmed_txs:
            if tx.type == C.TX_GENESIS:
                pass
            elif tx.type == C.TX_POS_REWARD:
                pass
            elif tx.type == C.TX_POW_REWARD:
                pass
            elif tx.type == C.TX_TRANSFER:
                pass
            elif tx.type == C.TX_MINT_COIN:
                check_tx_mint_coin(tx=tx, include_block=dummy_block)
            elif tx.type == C.TX_VALIDATOR_EDIT:
                check_tx_validator_edit(tx=tx, include_block=dummy_block)
            elif tx.type == C.TX_CONCLUDE_CONTRACT:
                check_tx_contract_conclude(tx=tx, include_block=dummy_block)
            else:
                raise BlockChainError('Unknown tx type "{}"'.format(tx.type))
        else:
            log.debug('Finish unconfirmed order check {}mSec'.format(
                int((time() - s) * 1000)))
            return None
    except Exception as e:
        log.warning(e, exc_info=True)
    # return errored tx
    return tx
Exemplo n.º 20
0
def create_validator_edit_tx(v_address,
                             cur,
                             new_address=None,
                             flag=F_NOP,
                             sig_diff=0,
                             gas_price=None,
                             retention=10800):
    assert not (flag == F_NOP and sig_diff == 0), 'No edit info'
    if new_address is None and flag != F_NOP:
        raise BlockChainError('No cosigner edit, but flag is not NOP')
    # validator object
    v = get_validator_object(v_address=v_address)
    if v.version == -1:
        if new_address is None or flag != F_ADD or sig_diff != 1:
            raise BlockChainError('Not correct info')
    else:
        next_require = v.require + sig_diff
        next_validator_num = len(v.validators)
        if flag == F_ADD:
            next_validator_num += 1
        elif flag == F_REMOVE:
            next_validator_num -= 1
        if not (0 < next_require <= next_validator_num):
            raise BlockChainError('ReqError, 0 < {} <= {}'.format(
                next_require, next_validator_num))
    # tx create
    message = msgpack.packb((v_address, new_address, flag, sig_diff),
                            use_bin_type=True)
    tx = TX.from_dict(
        tx={
            'type': C.TX_VALIDATOR_EDIT,
            'gas_price': gas_price or V.COIN_MINIMUM_PRICE,
            'gas_amount': 0,
            'message_type': C.MSG_MSGPACK,
            'message': message
        })
    tx.gas_amount = tx.size
    tx.update_time(retention)
    # fill unspents
    additional_gas = C.VALIDATOR_EDIT_GAS + v.require * C.SIGNATURE_GAS
    input_address = fill_inputs_outputs(tx=tx,
                                        cur=cur,
                                        additional_gas=additional_gas)
    assert len(input_address & set(v.validators)) == 0, 'Not implemented?'
    # replace dummy address
    replace_redeem_dummy_address(tx=tx, cur=cur)
    setup_signature(tx, input_address)
    if v.version > -1 and setup_contract_signature(tx, v.validators) == 0:
        raise BlockChainError('Cannot sign, you are not validator')
    return tx
Exemplo n.º 21
0
def create_mining_block(consensus):
    global mining_address
    # create proof_tx
    mining_address = mining_address or V.MINING_ADDRESS or new_key()
    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(
        tx={
            'type': C.TX_POW_REWARD,
            'inputs': list(),
            'outputs': [(mining_address, 0, reward + fees)],
            'gas_price': 0,
            'gas_amount': 0,
            'message_type': C.MSG_PLAIN if V.MINING_MESSAGE else C.MSG_NONE,
            'message': V.MINING_MESSAGE if V.MINING_MESSAGE else b''
        })
    proof_tx.update_time()
    # create mining block
    bits, target = get_bits_by_hash(previous_hash=previous_block.hash,
                                    consensus=consensus)
    mining_block = Block(
        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)
    mining_block.txs.extend(unconfirmed_txs)
    mining_block.update_merkleroot()
    mining_block.update_time(proof_tx.time)
    return mining_block
Exemplo n.º 22
0
def update_unspents_txs(time_limit=0.2):
    global unspents_txs
    c = 100
    while previous_block is None:
        if c < 0:
            raise Exception('Timeout on update unspents')
        sleep(0.1)
        c -= 1
    s = time()
    previous_height = previous_block.height
    proof_txs = list()
    all_num = 0
    with create_db(V.DB_ACCOUNT_PATH) as db:
        cur = db.cursor()
        for address, height, txhash, txindex, coin_id, amount in get_my_unspents_iter(
                cur):
            if time() - s > time_limit:
                break
            if height is None:
                continue
            if coin_id != 0:
                continue
            if not (previous_height + 1 > height + C.MATURE_HEIGHT):
                continue
            if not is_address(
                    ck=address, hrp=V.BECH32_HRP, ver=C.ADDR_NORMAL_VER):
                continue
            if amount < 100000000:
                continue
            if staking_limit < all_num:
                log.debug("Unspents limit reached, skip by {} limits".format(
                    staking_limit))
                break
            all_num += 1
            proof_tx = TX.from_dict(
                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)
Exemplo n.º 23
0
def failed_finish_tx(start_tx):
    message = bjson.dumps((False, start_tx.hash, None), compress=False)
    return TX(
        tx={
            'version': __chain_version__,
            'type': C.TX_FINISH_CONTRACT,
            'time': start_tx.time,
            'deadline': start_tx.deadline,
            'inputs': list(),
            'outputs': list(),
            'gas_price': start_tx.gas_price,
            'gas_amount': 0,
            'message_type': C.MSG_BYTE,
            'message': message
        })
Exemplo n.º 24
0
async def create_raw_tx(request):
    # [version=1] [type=TRANSFER] [time=now] [deadline=now+10800]
    # [inputs:list()] [outputs:list()]
    # [gas_price=MINIMUM_PRICE] [gas_amount=MINIMUM_AMOUNT]
    # [message_type=None] [message=None]
    post = await web_base.content_type_json_check(request)
    try:
        publish_time = post.get('time',
                                int(time.time() - V.BLOCK_GENESIS_TIME))
        deadline_time = post.get('deadline', publish_time + 10800)
        message_type = post.get('message_type', C.MSG_NONE)
        if message_type == C.MSG_NONE:
            message = b''
        elif message_type == C.MSG_BYTE:
            message = unhexlify(post['message'].encode())
        elif message_type == C.MSG_PLAIN:
            message = post['message'].encode()
        else:
            message_type = C.MSG_NONE
            message = b''
        inputs = list()
        input_address = set()
        for txhash, txindex in post.get('inputs', list()):
            txhash = unhexlify(txhash.encode())
            inputs.append((txhash, txindex))
            input_tx = tx_builder.get_tx(txhash)
            address, coin_id, amount = input_tx.outputs[txindex]
            input_address.add(address)
        tx = TX(
            tx={
                'version': post.get('version', __chain_version__),
                'type': post.get('type', C.TX_TRANSFER),
                'time': publish_time,
                'deadline': deadline_time,
                'inputs': inputs,
                'outputs': post.get('outputs', list()),
                'gas_price': post.get('gas_price', V.COIN_MINIMUM_PRICE),
                'gas_amount': 0,
                'message_type': message_type,
                'message': message
            })
        tx_size = tx.getsize() + len(input_address) * 96
        tx.gas_amount = post.get('gas_amount', tx_size)
        tx.serialize()
        return web_base.json_res({
            'tx': tx.getinfo(),
            'hex': hexlify(tx.b).decode()
        })
    except BaseException:
        return web_base.error_res()
Exemplo n.º 25
0
def fill_newblock_info(data):
    new_block = Block(binary=data['block'])
    logging.debug("Fill newblock={}".format(hexlify(new_block.hash).decode()))
    proof = TX(binary=data['proof'])
    new_block.txs.append(proof)
    new_block.flag = data['block_flag']
    proof.signature = data['sign']
    # Check the block is correct info
    if not new_block.pow_check():
        raise BlockChainError('Proof of work is not satisfied.')
    my_block = builder.get_block(new_block.hash)
    if my_block:
        raise BlockChainError('Already inserted block {}'.format(my_block))
    before_block = builder.get_block(new_block.previous_hash)
    if before_block is None:
        logging.debug("Cannot find beforeBlock {}, try to ask outside node."
                      .format(hexlify(new_block.previous_hash).decode()))
        # not found beforeBlock, need to check other node have the the block
        new_block.inner_score *= 0.70  # unknown previousBlock, score down
        before_block = make_block_by_node(blockhash=new_block.previous_hash)
        if not new_insert_block(before_block, time_check=True):
            # require time_check, it was generated only a few seconds ago
            # print([block for block in builder.chain.values()])
            raise BlockChainError('Failed insert beforeBlock {}'.format(before_block))
    new_height = before_block.height + 1
    proof.height = new_height
    new_block.height = new_height
    # Append general txs
    for txhash in data['txs'][1:]:
        tx = tx_builder.get_tx(txhash)
        if tx is None:
            new_block.inner_score *= 0.75  # unknown tx, score down
            logging.debug("Unknown tx, try to download.")
            r = ask_node(cmd=DirectCmd.TX_BY_HASH, data={'txhash': txhash}, f_continue_asking=True)
            if isinstance(r, str):
                raise BlockChainError('Failed unknown tx download "{}"'.format(r))
            tx = TX(binary=r['tx'])
            tx.signature = r['sign']
            check_tx(tx, include_block=None)
            tx_builder.put_unconfirmed(tx)
            logging.debug("Success unknown tx download {}".format(tx))
        tx.height = new_height
        new_block.txs.append(tx)
    return new_block
Exemplo n.º 26
0
Arquivo: boot.py Projeto: volbil/bc4py
def load_boot_file(url=None):
    normal_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                               'boot.json')
    extra_path = os.path.join(V.DB_HOME_DIR, 'boot.json')
    if url:
        data = requests.get(url=url).json()
    elif os.path.exists(normal_path):
        with open(normal_path, mode='r') as fp:
            data = json.load(fp)
    elif os.path.exists(extra_path):
        with open(extra_path, mode='r') as fp:
            data = json.load(fp)
    else:
        raise FileNotFoundError('Cannot find boot.json "{}" or "{}" ?'.format(
            normal_path, extra_path))
    # load from exist boot.json
    genesis_block = Block.from_binary(binary=a2b_hex(data['genesis_binary']))
    assert genesis_block.hash == a2b_hex(data['genesis_hash'])
    genesis_block.flag = C.BLOCK_GENESIS
    genesis_block.height = 0
    for tx_dct in data['txs']:
        tx = TX.from_binary(binary=a2b_hex(tx_dct['binary']))
        assert tx.hash == a2b_hex(tx_dct['hash'])
        tx.height = 0
        genesis_block.txs.append(tx)
    connections = data['connections']
    network_ver = data['network_ver']
    if isinstance(data['params'], dict):
        # new type boot.json
        params = data['params']
        params['consensus'] = {
            int(k): v
            for k, v in params['consensus'].items()
        }
    elif isinstance(data['params'], str):
        # old type boot.json
        params = original_mpk.unpackb(a2b_hex(data['params']),
                                      raw=True,
                                      encoding='utf8')
    else:
        raise Exception('Unknown type params')
    return genesis_block, params, network_ver, connections
Exemplo n.º 27
0
def fill_newblock_info(data):
    new_block = Block(binary=data['block'])
    proof = TX(binary=data['proof'])
    new_block.txs.append(proof)
    new_block.flag = data['block_flag']
    proof.signature = data['sign']
    # Check the block is correct info
    if not new_block.pow_check():
        raise BlockChainError('Proof of work is not satisfied.')
    if builder.get_block(new_block.hash):
        raise BlockChainError('Already inserted block.')
    before_block = builder.get_block(new_block.previous_hash)
    if before_block is None:
        raise BlockChainError('Not found beforeBlock {}.'.format(
            hexlify(new_block.previous_hash).decode()))
    new_height = before_block.height + 1
    proof.height = new_height
    new_block.height = new_height
    # Append general txs
    for txhash in data['txs'][1:]:
        tx = tx_builder.get_tx(txhash)
        if tx is None:
            new_block.inner_score *= 0.75  # unknown tx, score down
            logging.debug("Unknown tx, try to download.")
            r = ask_node(cmd=DirectCmd.TX_BY_HASH,
                         data={'txhash': txhash},
                         f_continue_asking=True)
            if isinstance(r, str):
                raise BlockChainError(
                    'Failed unknown tx download "{}"'.format(r))
            tx = TX(binary=r['tx'])
            tx.signature = r['sign']
            check_tx(tx, include_block=None)
            tx_builder.put_unconfirmed(tx)
            logging.debug("Success unknown tx download {}".format(tx))
        tx.height = new_height
        new_block.txs.append(tx)
    return new_block
Exemplo n.º 28
0
async def broadcast_tx(request):
    start = time()
    post = await utils.content_type_json_check(request)
    try:
        binary = a2b_hex(post['hex'])
        new_tx = TX.from_binary(binary=binary)
        new_tx.signature = [(a2b_hex(pk), a2b_hex(sig))
                            for pk, sig in post['signature']]
        if 'R' in post:
            new_tx.R = a2b_hex(post['R'])
        if not send_newtx(new_tx=new_tx):
            raise BlockChainError('Failed to send new tx')
        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()
Exemplo n.º 29
0
def object_hook(dct):
    if isinstance(dct, dict) and '_bc4py_class_' in dct:
        if dct['_bc4py_class_'] == 'Block':
            block = Block.from_binary(binary=dct['binary'])
            block.height = dct['height']
            block.flag = dct['flag']
            block.txs.extend(object_hook(tx) for tx in dct['txs'])
            for tx in block.txs:
                tx.height = block.height
            return block
        elif dct['_bc4py_class_'] == 'TX':
            tx = TX.from_binary(binary=dct['binary'])
            tx.height = dct['height']
            tx.signature.extend(tuple(sig) for sig in dct['signature'])
            tx.R = dct['R']
            return tx
        else:
            raise Exception('Not found class name "{}"'.format(
                dct['_bc4py_class_']))
    else:
        return dct
Exemplo n.º 30
0
async def create_raw_tx(request):
    # [version=1] [type=TRANSFER] [time=now] [deadline=now+10800]
    # [inputs:list()] [outputs:list()]
    # [gas_price=MINIMUM_PRICE] [gas_amount=MINIMUM_AMOUNT]
    # [message_type=None] [message=None]
    post = await utils.content_type_json_check(request)
    try:
        publish_time = post.get('time', int(time() - V.BLOCK_GENESIS_TIME))
        deadline_time = post.get('deadline', publish_time + 10800)
        message_type = post.get('message_type', C.MSG_NONE)
        message = type2message(message_type, post.get('message'))
        inputs = list()
        input_address = set()
        for txhash, txindex in post.get('inputs', list()):
            txhash = a2b_hex(txhash)
            inputs.append((txhash, txindex))
            input_tx = tx_builder.get_tx(txhash)
            address, coin_id, amount = input_tx.outputs[txindex]
            input_address.add(address)
        tx = TX.from_dict(
            tx={
                'version': post.get('version', __chain_version__),
                'type': post.get('type', C.TX_TRANSFER),
                'time': publish_time,
                'deadline': deadline_time,
                'inputs': inputs,
                'outputs': post.get('outputs', list()),
                'gas_price': post.get('gas_price', V.COIN_MINIMUM_PRICE),
                'gas_amount': 0,
                'message_type': message_type,
                'message': message
            })
        require_gas = tx.size + len(input_address) * C.SIGNATURE_GAS
        tx.gas_amount = post.get('gas_amount', require_gas)
        tx.serialize()
        return utils.json_res({'tx': tx.getinfo(), 'hex': tx.b.hex()})
    except Exception:
        return utils.error_res()