コード例 #1
0
ファイル: contract.py プロジェクト: kmn/bc4py
def contract_fill(c: Contract, best_block=None, best_chain=None, stop_txhash=None):
    # database
    c_iter = builder.db.read_contract_iter(c_address=c.c_address, start_idx=c.db_index)
    for index, start_hash, finish_hash, (c_method, c_args, c_storage) in c_iter:
        if start_hash == stop_txhash or finish_hash == stop_txhash:
            return
        c.update(db_index=index, start_hash=start_hash, finish_hash=finish_hash,
                 c_method=c_method, c_args=c_args, c_storage=c_storage)
    # memory
    if best_chain:
        _best_chain = None
    elif best_block and best_block == builder.best_block:
        _best_chain = builder.best_chain
    else:
        dummy, _best_chain = builder.get_best_chain(best_block=best_block)
    for block in reversed(best_chain or _best_chain):
        for tx in block.txs:
            if tx.hash == stop_txhash:
                return
            if tx.type != C.TX_CONCLUDE_CONTRACT:
                continue
            c_address, start_hash, c_storage = decode(tx.message)
            if c_address != c.c_address:
                continue
            if start_hash == stop_txhash:
                return
            start_tx = tx_builder.get_tx(txhash=start_hash)
            dummy, c_method, redeem_address, c_args = decode(start_tx.message)
            index = start_tx2index(start_tx=start_tx)
            c.update(db_index=index, start_hash=start_hash, finish_hash=tx.hash,
                     c_method=c_method, c_args=c_args, c_storage=c_storage)
    # unconfirmed (check validator condition satisfied)
    if best_block is None:
        unconfirmed = list()
        for conclude_tx in tuple(tx_builder.unconfirmed.values()):
            if conclude_tx.hash == stop_txhash:
                break
            if conclude_tx.type != C.TX_CONCLUDE_CONTRACT:
                continue
            c_address, start_hash, c_storage = decode(conclude_tx.message)
            if c_address != c.c_address:
                continue
            if start_hash == stop_txhash:
                break
            start_tx = tx_builder.get_tx(txhash=start_hash)
            if start_tx.height is None:
                continue
            sort_key = start_tx2index(start_tx=start_tx)
            unconfirmed.append((c_address, start_tx, conclude_tx, c_storage, sort_key))

        v = get_validator_object(c_address=c.c_address, best_block=best_block,
                                 best_chain=best_chain, stop_txhash=stop_txhash)
        for c_address, start_tx, conclude_tx, c_storage, sort_key in sorted(unconfirmed, key=lambda x: x[4]):
            if len(conclude_tx.signature) < v.require:
                continue  # ignore unsatisfied ConcludeTXs
            dummy, c_method, redeem_address, c_args = decode(start_tx.message)
            c.update(db_index=sort_key, start_hash=start_tx.hash, finish_hash=conclude_tx.hash,
                     c_method=c_method, c_args=c_args, c_storage=c_storage)
コード例 #2
0
def contract_fill(c: Contract,
                  best_block=None,
                  best_chain=None,
                  stop_txhash=None):
    assert c.index == -1, 'Already updated'
    # database
    c_iter = builder.db.read_contract_iter(c_address=c.c_address)
    for index, start_hash, finish_hash, (c_method, c_args,
                                         c_storage) in c_iter:
        if finish_hash == stop_txhash:
            return
        c.update(start_hash=start_hash,
                 finish_hash=finish_hash,
                 c_method=c_method,
                 c_args=c_args,
                 c_storage=c_storage)
    # memory
    if best_chain:
        _best_chain = None
    elif best_block and best_block == builder.best_block:
        _best_chain = builder.best_chain
    else:
        dummy, _best_chain = builder.get_best_chain(best_block=best_block)
    for block in reversed(best_chain or _best_chain):
        for tx in block.txs:
            if tx.hash == stop_txhash:
                return
            if tx.type != C.TX_CONCLUDE_CONTRACT:
                continue
            c_address, start_hash, c_storage = decode(tx.message)
            if c_address != c.c_address:
                continue
            start_tx = tx_builder.get_tx(txhash=start_hash)
            dummy, c_method, c_args = decode(start_tx.message)
            c.update(start_hash=start_hash,
                     finish_hash=tx.hash,
                     c_method=c_method,
                     c_args=c_args,
                     c_storage=c_storage)
    # unconfirmed
    if best_block is None:
        for tx in sorted(tx_builder.unconfirmed.values(),
                         key=lambda x: x.time):
            if tx.hash == stop_txhash:
                return
            if tx.type != C.TX_CONCLUDE_CONTRACT:
                continue
            c_address, start_hash, c_storage = decode(tx.message)
            if c_address != c.c_address:
                continue
            start_tx = tx_builder.get_tx(txhash=start_hash)
            dummy, c_method, c_args = decode(start_tx.message)
            c.update(start_hash=start_hash,
                     finish_hash=tx.hash,
                     c_method=c_method,
                     c_args=c_args,
                     c_storage=c_storage)
コード例 #3
0
def amount_check(tx, payfee_coin_id):
    # Inputs
    input_coins = Balance()
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash)
        if input_tx is None:
            raise BlockChainError('Not found input tx {}'.format(txhash.hex()))
        address, coin_id, amount = input_tx.outputs[txindex]
        input_coins[coin_id] += amount

    # Outputs
    output_coins = Balance()
    for address, coin_id, amount in tx.outputs:
        if amount <= 0:
            raise BlockChainError('Input amount is more than 0')
        output_coins[coin_id] += amount

    # Fee
    fee_coins = Balance(coin_id=payfee_coin_id,
                        amount=tx.gas_price * tx.gas_amount)

    # Check all plus amount
    remain_amount = input_coins - output_coins - fee_coins
    if not remain_amount.is_empty():
        raise BlockChainError(
            '77 Don\'t match input/output. {}={}-{}-{}'.format(
                remain_amount, input_coins, output_coins, fee_coins))
コード例 #4
0
async def conclude_contract(request):
    start = time()
    post = await web_base.content_type_json_check(request)
    try:
        c_address = post['c_address']
        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']))
        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,
                                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()
コード例 #5
0
ファイル: workhash.py プロジェクト: volbil/bc4py
def update_work_hash(block):
    if block.flag == C.BLOCK_GENESIS:
        block.work_hash = b'\xff' * 32
    elif block.flag == C.BLOCK_COIN_POS:
        proof_tx = block.txs[0]
        if proof_tx.pos_amount is None:
            from bc4py.database.builder import tx_builder
            txhash, txindex = proof_tx.inputs[0]
            output_tx = tx_builder.get_tx(txhash)
            if output_tx is None:
                raise BlockChainError('Not found output {} of {}'.format(
                    proof_tx, block))
            address, coin_id, amount = output_tx.outputs[txindex]
            proof_tx.pos_amount = amount
        block.work_hash = get_stake_coin_hash(
            tx=proof_tx, previous_hash=block.previous_hash)
    elif block.flag == C.BLOCK_CAP_POS:
        proof_tx = block.txs[0]
        address, coin_id, amount = proof_tx.outputs[0]
        scope_hash = poc_hash(address=address, nonce=block.nonce)
        index = scope_index(block.previous_hash)
        block.work_hash = poc_work(time=block.time,
                                   scope_hash=scope_hash[index *
                                                         32:index * 32 + 32],
                                   previous_hash=block.previous_hash)
    elif block.flag == C.BLOCK_FLK_POS:
        raise BlockChainError("unimplemented")
    else:
        # POW_???
        hash_fnc = get_workhash_fnc(block.flag)
        block.work_hash = hash_fnc(block.b)
コード例 #6
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()
コード例 #7
0
def contract_signature_check(extra_tx: TX, v: Validator, include_block: Block):
    signed_cks = get_signed_cks(extra_tx)
    accept_cks = signed_cks & set(v.validators)
    if include_block:
        # check satisfy require?
        if len(accept_cks) < v.require:
            raise BlockChainError('Not satisfied require signature. [signed={}, accepted={}, require={}]'
                                  .format(signed_cks, accept_cks, v.require))
    else:
        # check can marge?
        original_tx = tx_builder.get_tx(txhash=extra_tx.hash)
        if original_tx is None:
            # not accept before
            if 0 < v.require and len(accept_cks) == 0:
                raise BlockChainError('No acceptable signature. signed={}'.format(signed_cks))
        else:
            # need to marge signature
            if original_tx.height is not None:
                raise BlockChainError('Already included tx. height={}'.format(original_tx.height))
            if v.require == 0:
                raise BlockChainError('Don\t need to marge signature.')
            original_cks = get_signed_cks(original_tx)
            accept_new_cks = (signed_cks - original_cks) & set(v.validators)
            if len(accept_new_cks) == 0:
                raise BlockChainError('No new acceptable cks. ({} - {}) & {}'
                                      .format(signed_cks, original_cks, set(v.validators)))
コード例 #8
0
ファイル: contracttx.py プロジェクト: volbil/bc4py
async def conclude_contract(request):
    start = time()
    post = await utils.content_type_json_check(request)
    try:
        start_hash = a2b_hex(post['start_hash'])
        start_tx = tx_builder.get_tx(txhash=start_hash)
        if start_tx is None:
            return utils.error_res('Not found start_tx {}'.format(
                post['start_hash']))
        c_address, c_method, redeem_address, c_args = start_tx.encoded_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 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()
コード例 #9
0
ファイル: synchronize.py プロジェクト: yoosofan/bc4py
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()))
コード例 #10
0
ファイル: utils.py プロジェクト: yoosofan/bc4py
def amount_check(tx, payfee_coin_id):
    # Inputs
    input_coins = CoinObject()
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash)
        if input_tx is None:
            raise BlockChainError('Not found input tx {}'.format(
                hexlify(txhash).decode()))
        address, coin_id, amount = input_tx.outputs[txindex]
        input_coins[coin_id] += amount

    # Outputs
    output_coins = CoinObject()
    for address, coin_id, amount in tx.outputs:
        if amount <= 0:
            raise BlockChainError('Input amount is more than 0')
        output_coins[coin_id] += amount

    # Fee
    fee_coins = CoinObject(coin_id=payfee_coin_id,
                           amount=tx.gas_price * tx.gas_amount)

    # Check all plus amount
    remain_amount = input_coins - output_coins - fee_coins
    if not remain_amount.is_all_plus_amount():
        raise BlockChainError(
            'There are minus amount coins. {}={}-{}-{}'.format(
                remain_amount, input_coins, output_coins, fee_coins))
コード例 #11
0
ファイル: contracttx.py プロジェクト: volbil/bc4py
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()
コード例 #12
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()
コード例 #13
0
ファイル: jsonrpc.py プロジェクト: yoosofan/bc4py
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.'
コード例 #14
0
ファイル: contract.py プロジェクト: kmn/bc4py
def start_tx2index(start_hash=None, start_tx=None):
    if start_hash:
        start_tx = tx_builder.get_tx(txhash=start_hash)
    block = builder.get_block(blockhash=builder.get_block_hash(height=start_tx.height))
    if block is None:
        raise BlockChainError('Not found block of start_tx included? {}'.format(start_tx))
    if start_tx not in block.txs:
        raise BlockChainError('Not found start_tx in block? {}'.format(block))
    return start_tx.height * 0xffffffff + block.txs.index(start_tx)
コード例 #15
0
def get_contract_storage(c_address, best_block=None, best_chain=None):
    # DataBaseより
    cs = ContractStorage()
    for dummy, index, start_hash, finish_hash in builder.db.read_contract_iter(c_address):
        if index == 0:
            start_tx = tx_builder.get_tx(start_hash)
            dummy, c_bin, c_cs = bjson.loads(start_tx.message)
            cs.key_value = c_cs or dict()
        else:
            finish_tx = tx_builder.get_tx(finish_hash)
            c_status, dummy, c_diff = bjson.loads(finish_tx.message)
            cs.marge(c_diff)
    # Memoryより
    best_chain = best_chain or _get_best_chain_all(best_block)
    for block in reversed(best_chain):
        for tx in block.txs:
            if tx.type == C.TX_CREATE_CONTRACT:
                check_address, c_bin, c_cs = bjson.loads(tx.message)
                if c_address == check_address:
                    cs.key_value = c_cs or dict()
            elif tx.type == C.TX_START_CONTRACT:
                pass
            elif tx.type == C.TX_FINISH_CONTRACT:
                c_status, start_hash, c_diff = bjson.loads(tx.message)
                start_tx = tx_builder.get_tx(start_hash)
                check_address, c_bin, c_cs = bjson.loads(start_tx.message)
                if c_address == check_address:
                    cs.marge(c_diff)
    # Unconfirmedより
    if best_block is None:
        for tx in sorted(tx_builder.unconfirmed.values(), key=lambda x: x.time):
            if tx.type == C.TX_CREATE_CONTRACT:
                check_address, c_bin, c_cs = bjson.loads(tx.message)
                cs.key_value = c_cs or dict()
            elif tx.type == C.TX_START_CONTRACT:
                pass
            elif tx.type == C.TX_FINISH_CONTRACT:
                c_status, start_hash, c_diff = bjson.loads(tx.message)
                start_tx = tx_builder.get_tx(start_hash)
                check_address, c_bin, c_cs = bjson.loads(start_tx.message)
                if c_address == check_address:
                    cs.marge(c_diff)
    return cs
コード例 #16
0
ファイル: tools.py プロジェクト: volbil/bc4py
def get_unspents_iter(target_address, best_block=None, best_chain=None):
    failed = 0
    while failed < 20:
        if best_chain is None:
            best_chain = _get_best_chain_all(best_block)
        if best_chain:
            break
        failed += 1
        sleep(0.05)
    else:
        raise BlockChainError('Cannot get best_chain by {}'.format(best_block))
    allow_mined_height = best_chain[0].height - C.MATURE_HEIGHT
    # DataBaseより
    for address in target_address:
        for dummy, txhash, txindex, coin_id, amount, f_used in chain_builder.db.read_address_idx_iter(
                address):
            if f_used is False:
                if txindex in get_usedindex(txhash=txhash,
                                            best_block=best_block,
                                            best_chain=best_chain):
                    continue  # Used
                tx = tx_builder.get_tx(txhash)
                if tx.type in (C.TX_POW_REWARD, C.TX_POS_REWARD):
                    if tx.height is not None and tx.height < allow_mined_height:
                        yield address, tx.height, txhash, txindex, coin_id, amount
                else:
                    yield address, tx.height, txhash, txindex, coin_id, amount
    # Memoryより
    for block in reversed(best_chain):
        for tx in block.txs:
            used_index = get_usedindex(txhash=tx.hash,
                                       best_block=best_block,
                                       best_chain=best_chain)
            for index, (address, coin_id, amount) in enumerate(tx.outputs):
                if index in used_index:
                    continue  # Used
                elif address in target_address:
                    if tx.type in (C.TX_POW_REWARD, C.TX_POS_REWARD):
                        if tx.height is not None and tx.height < allow_mined_height:
                            yield address, tx.height, tx.hash, index, coin_id, amount
                    else:
                        yield address, tx.height, tx.hash, index, coin_id, amount
    # Unconfirmedより
    if best_block is None:
        for tx in sorted(tx_builder.unconfirmed.values(),
                         key=lambda x: x.create_time):
            used_index = get_usedindex(txhash=tx.hash,
                                       best_block=best_block,
                                       best_chain=best_chain)
            for index, (address, coin_id, amount) in enumerate(tx.outputs):
                if index in used_index:
                    continue  # Used
                elif address in target_address:
                    yield address, None, tx.hash, index, coin_id, amount
コード例 #17
0
ファイル: __init__.py プロジェクト: kmn/bc4py
def calc_tx_movement(tx, c_address, redeem_address, emulate_gas):
    """ Calc tx inner movement """
    account = Accounting()
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash=txhash)
        address, coin_id, amount = input_tx.outputs[txindex]
        account[address][coin_id] -= amount
    account[redeem_address][0] += (tx.gas_amount+emulate_gas) * tx.gas_price
    account[c_address][0] -= emulate_gas * tx.gas_price
    for address, coin_id, amount in tx.outputs:
        account[address][coin_id] += amount
    return account
コード例 #18
0
async def get_tx_by_hash(request):
    try:
        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)
        data = tx.getinfo()
        data['size'] = tx.getsize()
        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()
コード例 #19
0
def validator_tx2index(txhash=None, tx=None):
    if txhash:
        tx = tx_builder.get_tx(txhash=txhash)
    if tx is None:
        raise BlockChainError('Not found ValidatorTX {}'.format(tx))
    if tx.height is None:
        raise BlockChainError('Not confirmed ValidatorTX {}'.format(tx))
    block = chain_builder.get_block(height=tx.height)
    if block is None:
        raise BlockChainError(
            'Not found block of start_tx included? {}'.format(tx))
    if tx not in block.txs:
        raise BlockChainError('Not found start_tx in block? {}'.format(block))
    return tx.height * 0xffffffff + block.txs.index(tx)
コード例 #20
0
ファイル: createtx.py プロジェクト: yoosofan/bc4py
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()
コード例 #21
0
def signature_check(tx):
    need_cks = set()
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash)
        if input_tx is None:
            raise BlockChainError('Not found input tx {}'.format(hexlify(txhash).decode()))
        address, coin_id, amount = input_tx.outputs[txindex]
        if is_address(address, V.BLOCK_PREFIX):
            need_cks.add(address)  # 通常のアドレスのみ
        else:
            raise BlockChainError('Not common address {} {}.'.format(address, tx))

    signed_cks = get_signed_cks(tx)
    if need_cks != signed_cks:
        raise BlockChainError('Signature verification failed. [{}={}]'.format(need_cks, signed_cks))
コード例 #22
0
def input_output_digest(tx):
    require_cks = set()
    coins = CoinObject()
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash=txhash)
        if input_tx is None:
            raise BlockChainError('input tx is None. {}:{}'.format(
                hexlify(txhash).decode(), txindex))
        address, coin_id, amount = input_tx.outputs[txindex]
        require_cks.add(address)
        coins[coin_id] += amount
    coins[0] -= tx.gas_amount * tx.gas_price
    for address, coin_id, amount in tx.outputs:
        coins[coin_id] -= amount
    return require_cks, coins
コード例 #23
0
ファイル: tx_reward.py プロジェクト: yoosofan/bc4py
def check_tx_pos_reward(tx, include_block):
    # POS報酬TXの検査
    if not (len(tx.inputs) == len(tx.outputs) == 1):
        raise BlockChainError('Inputs and outputs is only 1 len.')
    elif include_block.txs.index(tx) != 0:
        raise BlockChainError('Proof tx is index 0.')
    elif not (tx.gas_price == 0 and tx.gas_amount == 0):
        raise BlockChainError('Pos gas info is wrong. [{}, {}]'.format(
            tx.gas_price, tx.gas_amount))
    elif not (tx.message_type == C.MSG_NONE and tx.message == b''):
        raise BlockChainError('Pos msg is None type. [{},{}]'.format(
            tx.message_type, tx.message))

    txhash, txindex = tx.inputs[0]
    base_tx = tx_builder.get_tx(txhash)
    if base_tx is None:
        print(list(tx_builder.chained_tx.values()))
        raise BlockChainError('Not found PosBaseTX:{} of {}.'.format(
            hexlify(txhash).decode(), tx))
    input_address, input_coin_id, input_amount = base_tx.outputs[txindex]
    tx.pos_amount = input_amount
    output_address, output_coin_id, output_amount = tx.outputs[0]
    reward = GompertzCurve.calc_block_reward(include_block.height)
    include_block.bits2target()

    if input_address != output_address:
        raise BlockChainError(
            'Input address differ from output address. [{}!={}]'.format(
                input_address, output_address))
    elif not (input_coin_id == output_coin_id == 0):
        raise BlockChainError('Input and output coinID is zero.')
    elif input_amount + reward != output_amount:
        raise BlockChainError('Inout amount wrong [{}+{}!={}]'.format(
            input_amount, reward, output_amount))
    elif tx.version != __chain_version__ or tx.message_type != C.MSG_NONE:
        raise BlockChainError('Not correct tx version or msg_type.')
    elif base_tx.height is None:
        raise BlockChainError('Source TX is unconfirmed. {}'.format(base_tx))
    elif not (include_block.height > base_tx.height + C.MATURE_HEIGHT):
        raise BlockChainError(
            'Source TX height is too young. [{}>{}+{}]'.format(
                include_block.height, base_tx.height, C.MATURE_HEIGHT))
    elif not (include_block.time == tx.time == tx.deadline - 10800):
        raise BlockChainError('TX time is wrong 1. [{}={}={}-10800]'.format(
            include_block.time, tx.time, tx.deadline))
    elif not tx.pos_check(include_block.previous_hash,
                          include_block.target_hash):
        raise BlockChainError('Proof of stake check is failed.')
コード例 #24
0
ファイル: workhash.py プロジェクト: yoosofan/bc4py
def update_work_hash(block):
    if block.flag == C.BLOCK_GENESIS:
        block.work_hash = b'\xff' * 32
    elif block.flag == C.BLOCK_POS:
        proof_tx = block.txs[0]
        if proof_tx.pos_amount is None:
            from bc4py.database.builder import tx_builder
            txhash, txindex = proof_tx.inputs[0]
            output_tx = tx_builder.get_tx(txhash)
            address, coin_id, amount = output_tx.outputs[txindex]
            proof_tx.pos_amount = amount
        block.work_hash = proof_tx.get_pos_hash(block.previous_hash)
    else:
        # POW_???
        hash_fnc = get_workhash_fnc(block.flag)
        block.work_hash = hash_fnc(block.b)
コード例 #25
0
ファイル: chaininfo.py プロジェクト: volbil/bc4py
async def get_tx_by_hash(request):
    try:
        f_pickled = request.query.get('pickle', False)
        txhash = request.query.get('hash')
        txhash = a2b_hex(txhash)
        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 utils.json_res(b64encode(tx).decode())
        data = tx.getinfo()
        data['hex'] = tx.b.hex()
        return utils.json_res(data)
    except Exception as e:
        return utils.error_res()
コード例 #26
0
ファイル: contractinfo.py プロジェクト: kmn/bc4py
async def get_contract_history(request):
    try:
        c_address = request.query['c_address']
        data = list()
        # database
        for index, start_hash, finish_hash, (c_method, c_args, c_storage) in\
                builder.db.read_contract_iter(c_address=c_address):
            data.append({
                'index': index,
                'height': index // 0xffffffff,
                'start_hash': hexlify(start_hash).decode(),
                'finish_hash': hexlify(finish_hash).decode(),
                'c_method': c_method,
                'c_args': [decode(a) for a in c_args],
                'c_storage':
                {decode(k): decode(v)
                 for k, v in c_storage.items()} if c_storage else None
            })
        # memory
        for block in reversed(builder.best_chain):
            for tx in block.txs:
                if tx.type != C.TX_CONCLUDE_CONTRACT:
                    continue
                _c_address, start_hash, c_storage = bjson.loads(tx.message)
                if _c_address != c_address:
                    continue
                start_tx = tx_builder.get_tx(txhash=start_hash)
                dummy, c_method, redeem_address, c_args = bjson.loads(
                    start_tx.message)
                index = start_tx2index(start_tx=start_tx)
                data.append({
                    'index': index,
                    'height': tx.height,
                    'start_hash': hexlify(start_hash).decode(),
                    'finish_hash': hexlify(tx.hash).decode(),
                    'c_method': c_method,
                    'c_args': [decode(a) for a in c_args],
                    'c_storage':
                    {decode(k): decode(v)
                     for k, v in c_storage.items()} if c_storage else None,
                    # 'redeem_address': redeem_address,
                })
        return web_base.json_res(data)
    except Exception as e:
        logging.error(e)
        return web_base.error_res()
コード例 #27
0
def input_output_digest(tx):
    require_cks = set()
    coins = Balance()
    # inputs
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash=txhash)
        if input_tx is None:
            raise BlockChainError('input tx is None. {}:{}'.format(txhash.hex(), txindex))
        address, coin_id, amount = input_tx.outputs[txindex]
        require_cks.add(address)
        coins[coin_id] += amount
    # outputs
    for address, coin_id, amount in tx.outputs:
        coins[coin_id] -= amount
    # fee
    coins[0] -= tx.gas_amount * tx.gas_price
    return require_cks, coins
コード例 #28
0
def signature_check(tx, include_block):
    require_cks = set()
    checked_cks = set()
    signed_cks = set(tx.verified_list)
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash)
        if input_tx is None:
            raise BlockChainError('Not found input tx {}'.format(txhash.hex()))
        if len(input_tx.outputs) <= txindex:
            raise BlockChainError('txindex is over range {}<={}'.format(
                len(input_tx.outputs), txindex))
        address, coin_id, amount = input_tx.outputs[txindex]
        if address in checked_cks:
            continue
        elif is_address(ck=address, hrp=V.BECH32_HRP, ver=C.ADDR_NORMAL_VER):
            require_cks.add(address)
        elif is_address(ck=address, hrp=V.BECH32_HRP,
                        ver=C.ADDR_VALIDATOR_VER):
            v_before = get_validator_object(v_address=address,
                                            best_block=include_block,
                                            stop_txhash=tx.hash)
            if v_before.version == -1:
                raise BlockChainError('Not init validator {}'.format(address))
            if len(signed_cks & v_before.validators) < v_before.require:
                raise BlockChainError(
                    'Don\'t satisfy required signature {}<{}'.format(
                        len(signed_cks & v_before.validators),
                        v_before.require))
            require_cks.update(v_before.validators)
        elif is_address(ck=address, hrp=V.BECH32_HRP, ver=C.ADDR_CONTRACT_VER):
            raise BlockChainError(
                'Not allow ContractAddress include in normal Transfer. {}'.
                format(address, tx))
        else:
            raise BlockChainError('Not common address {} {}'.format(
                address, tx))
        # success check
        checked_cks.add(address)

    if not (0 < len(require_cks) < 256):
        raise BlockChainError('require signature is over range num={}'.format(
            len(require_cks)))
    if require_cks != signed_cks:
        raise BlockChainError('Signature verification failed. [{}={}]'.format(
            require_cks, signed_cks))
コード例 #29
0
ファイル: utils.py プロジェクト: yoosofan/bc4py
def inputs_origin_check(tx, include_block):
    # Blockに取り込まれているなら
    # TXのInputsも既に取り込まれているはずだ
    limit_height = builder.best_block.height - C.MATURE_HEIGHT
    for txhash, txindex in tx.inputs:
        input_tx = tx_builder.get_tx(txhash)
        if input_tx is None:
            # InputのOriginが存在しない
            raise BlockChainError('Not found input tx. {}:{}'.format(
                hexlify(txhash).decode(), txindex))
        elif input_tx.height is None:
            # InputのOriginはUnconfirmed
            if include_block:
                raise BlockChainError(
                    'TX {} is include'
                    ', but input origin {} is unconfirmed.'.format(
                        tx, input_tx))
            else:
                # UnconfirmedTXの受け入れなので、txもinput_txもUnconfirmed
                pass  # OK
        elif input_tx.type in (C.TX_POS_REWARD, C.TX_POW_REWARD) and \
                input_tx.height > limit_height:
            raise BlockChainError('input origin is proof tx, {}>{}'.format(
                input_tx.height, limit_height))
        else:
            # InputのOriginは既に取り込まれている
            pass  # OK
        # 使用済みかチェック
        if txindex in get_usedindex(txhash=txhash, best_block=include_block):
            sticky_failed_txhash.append(tx.hash)
            raise BlockChainError(
                '1 Input of {} is already used! {}:{}'.format(
                    tx,
                    hexlify(txhash).decode(), txindex))
        # 同一Block内で使用されていないかチェック
        if include_block:
            for input_tx in include_block.txs:
                if input_tx == tx:
                    break
                for input_hash, input_index in input_tx.inputs:
                    if input_hash == txhash and input_index == txindex:
                        sticky_failed_txhash.append(tx.hash)
                        raise BlockChainError(
                            '2 Input of {} is already used by {}'.format(
                                tx, input_tx))
コード例 #30
0
ファイル: broadcast.py プロジェクト: kmn/bc4py
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