Exemplo n.º 1
0
def register_token(token_address, name, short_name, register_on_chain):
    try:
        Token.objects.get(address=remove_0x_prefix(token_address))
        raise ValueError(
            'Token {} already registered in local db.'.format(token_address))
    except Token.DoesNotExist:
        pass

    if register_on_chain:
        NOCUSTContractInterface().register_ERC20(token_address)
        print('Registration transaction queued.')

    token = Token.objects.create(address=remove_0x_prefix(token_address),
                                 name=name,
                                 short_name=short_name,
                                 trail=Token.objects.count(),
                                 block=LocalViewInterface.latest_block())
    print('Token locally registered.')

    register_owner_account(token)

    if same_hex_value(token_address, settings.SLA_TOKEN_ADDRESS):
        register_sla_recipient_account()

    return token
Exemplo n.º 2
0
def concurrently_retrieve_state(contract_interface, contract_event_decoder,
                                verbose):
    logger.info('Retrieve blocks.')
    latest_chain_block = contract_interface.current_block() - 1
    if not settings.DEBUG:
        latest_chain_block += 1

    logger.info('Latest chain block: {}'.format(latest_chain_block))

    running_from = LocalViewInterface.latest_block() + 1
    running_until = latest_chain_block

    if running_from > running_until:
        logger.info('No new blocks {}-{}.'.format(running_from, running_until))
        return 0

    confirm_from = LocalViewInterface.confirmed_block() + 1
    confirm_until = running_until - contract_interface.get_blocks_for_confirmation(
    )

    if confirm_from > confirm_until:
        logger.info('No new blocks to confirm.')

    update_from = min(running_from, confirm_from)
    update_until = min(update_from + 11, running_until + 1)
    skipped = running_until + 1 - update_until

    contract_state_tasks = []
    contract_state_tasks_block_numbers = []

    logger.info('Fetching [{},{})'.format(update_from, update_until))
    for block_number in range(update_from, update_until):
        if confirm_from <= block_number and block_number <= confirm_until:
            contract_state_tasks.append(
                fetch_confirmed_block.delay(block_number=block_number))
            contract_state_tasks_block_numbers.append(block_number)
        elif running_from <= block_number and block_number <= running_until:
            contract_state_tasks.append(
                fetch_running_block.delay(block_number=block_number))
            contract_state_tasks_block_numbers.append(block_number)

    for task_index, contract_state_task in enumerate(contract_state_tasks):
        block_number = contract_state_tasks_block_numbers[task_index]

        try:
            task_result = contract_state_task.get(
                timeout=settings.HUB_BLOCK_FETCH_TIMEOUT,
                disable_sync_subtasks=False)
        except exceptions.TimeoutError:
            logger.error('Timed-out fetching block {}'.format(block_number))
            for cleanup_index, task_to_clean_up in enumerate(
                    contract_state_tasks):
                if cleanup_index >= task_index:
                    try:
                        task_to_clean_up.forget()
                    except NotImplementedError as e:
                        logger.error('Could not forget task results.')
                        logger.error(e)
            break

        if confirm_from <= block_number and block_number <= confirm_until:
            confirmed_contract_state_dictionary, confirmed_contract_ledger_state_dictionaries, block_logs = task_result

            confirmed_contract_state = ContractState.from_dictionary_form(
                confirmed_contract_state_dictionary)
            confirmed_ledger_states = [
                ContractLedgerState.from_dictionary_form(
                    ledger_state, confirmed_contract_state) for ledger_state in
                confirmed_contract_ledger_state_dictionaries
            ]
            with transaction.atomic():
                if running_from <= block_number and block_number <= running_until:
                    confirmed_contract_state.save()
                    for ledger_state in confirmed_ledger_states:
                        ledger_state.contract_state = confirmed_contract_state
                        ledger_state.save()

                logger.info('Decoding logs for block {}.'.format(
                    confirmed_contract_state.block))
                decoded_logs = contract_event_decoder.decode_many(block_logs)
                eon_number = confirmed_contract_state.eon_number()
                logger.info(
                    "Processing decoded logs in block %d eon %s: %d logs" %
                    (confirmed_contract_state.block, eon_number,
                     len(decoded_logs)))
                for log in decoded_logs:

                    if log.get(u'name') in event_interpreter_map:
                        interpreter = event_interpreter_map.get(
                            log.get(u'name'))
                        interpreter.interpret(
                            decoded_event=log.get('data'),
                            txid=log.get('txid'),
                            block_number=confirmed_contract_state.block,
                            eon_number=eon_number,
                            verbose=verbose) if interpreter else None
                    else:
                        logger.error('UNKNOWN EVENT LOG {} '.format(log))
                        send_admin_email(
                            subject='Chain Sync Error: Unknown Log',
                            content='{}'.format(log))

                running_contract_state = LocalViewInterface.running(
                    block_number=confirmed_contract_state.block)

                if running_contract_state.confirm(confirmed_contract_state,
                                                  confirmed_ledger_states):
                    logger.info('Block {} confirmed.'.format(
                        confirmed_contract_state.block))
                else:
                    logger.error('Block {} failed to confirm.'.format(
                        confirmed_contract_state.block))
                    send_admin_email(
                        subject='Chain Sync Confirmation Failure {}'.format(
                            confirmed_contract_state.block),
                        content='{}'.format(confirmed_contract_state))
                    raise Exception()
        elif running_from <= block_number and block_number <= running_until:
            logger.info('Process running block {}'.format(block_number))
            confirmed_contract_state_dictionary, confirmed_contract_ledger_state_dictionaries = task_result

            contract_state = ContractState.from_dictionary_form(
                confirmed_contract_state_dictionary)
            contract_state.save()
            ledger_states = [
                ContractLedgerState.from_dictionary_form(
                    ledger_state, contract_state) for ledger_state in
                confirmed_contract_ledger_state_dictionaries
            ]
            for ledger_state in ledger_states:
                ledger_state.save()
            logger.info('Running block {} stored.'.format(
                contract_state.block))
        else:
            logger.info('Running from {} to {}.'.format(
                running_from, running_until))
            logger.info('Confirm from {} to {}.'.format(
                confirm_from, confirm_until))
            logger.info('Update from {} to {}.'.format(update_from,
                                                       update_until))
            logger.error('Unexpected block number {}'.format(block_number))
            send_admin_email(
                subject='Chain Sync Unexpected Block {}'.format(block_number),
                content='Out of order processing.')
            raise Exception()
    return skipped
def send_queued_transactions():
    contract_interface = NOCUSTContractInterface()

    latest_block = LocalViewInterface.latest_block()

    with EthereumTransaction.global_lock(auto_renewal=True):
        pending_transactions = EthereumTransaction.objects.all().order_by('nonce')

        for transaction in pending_transactions:
            if transaction.ethereumtransactionattempt_set.filter(confirmed=True).exists():
                continue

            if transaction.ethereumtransactionattempt_set.exists():
                last_attempt = transaction.ethereumtransactionattempt_set.order_by(
                    'gas_price').last()
            else:
                initial_gas_price = contract_interface.web3.toWei(
                    '100', 'gwei')
                signed_tx = contract_interface.sign_for_delivery_as_owner(
                    transaction, initial_gas_price)
                try:
                    logger.info('Publishing Signed TX: {}'.format(transaction))
                    hash = contract_interface.send_raw_transaction(
                        signed_tx.rawTransaction)
                except ValueError as e:
                    send_admin_email(
                        subject='INITIAL TRANSACTION ATTEMPT ERROR',
                        content='{}: {}'.format(transaction.tag, e))
                    continue
                last_attempt = EthereumTransactionAttempt.objects.create(
                    transaction=transaction,
                    block=latest_block,
                    gas_price=initial_gas_price,
                    signed_attempt=signed_tx.rawTransaction.hex(),
                    hash=remove_0x_prefix(hash.hex()),
                    mined=False,
                    confirmed=False)

            if transaction.ethereumtransactionattempt_set.filter(mined=True).exists():
                try:
                    mined_transaction = transaction.ethereumtransactionattempt_set.get(
                        mined=True)
                except EthereumTransactionAttempt.DoesNotExist:
                    logger.error('Mined Transaction Attempt Inconsistency')
                    continue

                receipt = contract_interface.get_transaction_receipt_hex(
                    add_0x_prefix(mined_transaction.hash))

                if receipt is not None:
                    if receipt.get('blockNumber') - latest_block > settings.HUB_LQD_CONTRACT_CONFIRMATIONS:
                        logger.info('Transaction confirmed! {}'.format(
                            last_attempt.hash))
                        mined_transaction.confirmed = True
                        mined_transaction.save()
                    continue

                logger.warning(
                    'Transaction UNMINED: {}'.format(last_attempt.hash))
                mined_transaction.mined = False
                mined_transaction.save()

            receipt = contract_interface.get_transaction_receipt_hex(
                add_0x_prefix(last_attempt.hash))
            if receipt is not None:
                last_attempt.mined = True
                last_attempt.save()
                continue

            if latest_block - last_attempt.block > 10:
                new_gas_price = 2 * int(last_attempt.gas_price)
                signed_tx = contract_interface.sign_for_delivery_as_owner(
                    transaction, new_gas_price)
                try:
                    hash = contract_interface.send_raw_transaction(
                        signed_tx.rawTransaction)
                except ValueError as e:
                    send_admin_email(
                        subject='TRANSACTION RE-ATTEMPT ERROR',
                        content='{}: {}'.format(transaction.tag, e))
                    continue

                EthereumTransactionAttempt.objects.create(
                    transaction=transaction,
                    block=latest_block,
                    gas_price=new_gas_price,
                    signed_attempt=signed_tx.rawTransaction.hex(),
                    hash=remove_0x_prefix(hash.hex()),
                    mined=False,
                    confirmed=False)

                send_admin_email(
                    subject='Transaction Reattempt',
                    content='{}: {}'.format(transaction.tag, new_gas_price))