Esempio n. 1
0
def listwallettransactions():
    client = get_active_rpc_client()
    txs = client.listwallettransactions(10000000)
    if not txs:
        log.warning('no transactions from api')
        return
    balance = 0
    new_transactions = []
    new_confirmations = []
    with data_db.atomic():
        for tx in txs['result']:
            if tx['valid']:
                txid = tx['txid']
                dt = datetime.fromtimestamp(tx['time'])
                description = tx.get('comment', '')
                perm = tx['permissions']
                if perm:
                    description = 'Skills grant/revoke'

                items = tx['items']
                if items:
                    first_item_type = items[0].get('type')
                    if first_item_type == 'stream':
                        description = 'Stream publishing'
                if tx.get('generated'):
                    description = 'Mining reward'

                amount = tx['balance']['amount']
                balance += amount
                confirmations = tx['confirmations']

                tx_obj, created = Transaction.get_or_create(
                    txid=txid,
                    defaults=dict(datetime=dt,
                                  comment=description,
                                  amount=amount,
                                  balance=balance,
                                  confirmations=confirmations))
                if created:
                    new_transactions.append(tx_obj)
                elif tx_obj.confirmations == 0 and confirmations != 0:
                    tx_obj.confirmations = confirmations
                    new_confirmations.append(tx_obj)
                    tx_obj.save()

    if len(new_transactions) > 0 or len(new_confirmations) > 0:
        signals.listwallettransactions.emit(new_transactions,
                                            new_confirmations)
    return len(new_transactions) != 0
Esempio n. 2
0
def listblocks() -> int:
    """Synch block data from node

    :return int: number of new blocks synched to database
    """

    # TODO: Handle blockchain forks gracefully

    client = get_active_rpc_client()

    height_node = client.getblockcount()['result']
    latest_block_obj = Block.select().order_by(Block.height.desc()).first()
    if latest_block_obj is None:
        height_db = 0
    else:
        height_db = latest_block_obj.height

    if height_db == height_node:
        return 0

    synced = 0

    for batch in batchwise(range(height_db, height_node), 100):

        new_blocks = client.listblocks(batch)

        with data_db.atomic():
            for block in new_blocks['result']:

                addr_obj, adr_created = Address.get_or_create(
                    address=block['miner'])
                block_obj, blk_created = Block.get_or_create(
                    hash=unhexlify(block['hash']),
                    defaults=dict(
                        time=datetime.fromtimestamp(block['time']),
                        miner=addr_obj,
                        txcount=block['txcount'],
                        height=block['height'],
                    ))
                if blk_created:
                    synced += 1

                log.debug('Synced block {}'.format(block_obj.height))
                signals.database_blocks_updated.emit(block_obj.height,
                                                     height_node)
    log.debug('Synced {} blocks total.'.format(synced))
    return synced
Esempio n. 3
0
def liststreamitems_alias():
    """
    Sample stream item (none verbose):
    {
        'blocktime': 1505905511,
        'confirmations': 28948,
        'data': '4d696e65722031',
        'key': 'Miner_1',
        'publishers': ['1899xJpqZN3kMQdpvTxESWqykxgFJwRddCE4Tr'],
        'txid': 'caa1155e719803b9f39096860519a5e08e78214245ae9822beeea2b37a656178'
    }
    """

    client = get_active_rpc_client()

    # TODO read and process only fresh stream data by storing a state cursor between runs
    # TODO read stream items 100 at a time
    stream_items = client.liststreamitems(Stream.alias.name, count=100000)
    if not stream_items['result']:
        log.debug('got no items from stream alias')
        return 0

    by_addr = {}  # address -> alias
    reseved = set()  # reserved aliases

    # aggregate the final state of address to alias mappings from stream
    for item in stream_items['result']:
        confirmations = item['confirmations']
        alias = item['key']
        address = item['publishers'][0]
        data = item['data']
        num_publishers = len(item['publishers'])

        # Sanity checks
        if confirmations < 1:
            log.debug('ignore alias - 0 confirmations for %s -> %s' %
                      (address, alias))
            continue
        if data:
            log.debug('ignore alias - alias item "%s" with data "%s..."' %
                      (alias, data[:8]))
            continue
        if not is_valid_username(alias):
            log.debug('ignore alias - alias does not match our regex: %s' %
                      alias)
            continue
        if num_publishers != 1:
            log.debug('ignore alias - alias has multiple publishers: %s' %
                      alias)
            continue
        if alias in reseved:
            log.debug('ignore alias - alias "%s" already reserved by "%s"' %
                      (alias, address))
            continue

        is_new_address = address not in by_addr

        if is_new_address:
            by_addr[address] = alias
            reseved.add(alias)
            continue

        is_alias_change = by_addr[address] != alias

        if is_alias_change:
            log.debug('change alias of %s from %s to %s' %
                      (address, by_addr[address], alias))
            # reserve new name
            reseved.add(alias)
            # release old name
            reseved.remove(by_addr[address])
            # set new name
            by_addr[address] = alias
            continue

    # update database
    profile = Profile.get_active()
    new_main_alias = by_addr.get(profile.address)
    if new_main_alias and profile.alias != new_main_alias:
        log.debug('sync found new alias. profile.alias from %s to %s' %
                  (profile.alias, new_main_alias))
        profile.alias = new_main_alias
        profile.save()

    with data_db.atomic():
        old_addrs = set(
            Address.select(Address.address, Address.alias).tuples())
        new_addrs = set(by_addr.items())
        # set of elements that are only in new_addr but not in old_addr
        changed_addrs = new_addrs - old_addrs
        new_rows = [dict(address=i[0], alias=i[1]) for i in changed_addrs]
        if new_rows:
            log.debug('adding new aliases %s' % changed_addrs)
            # insert rows 100 at a time.
            for idx in range(0, len(new_rows), 100):
                Address.insert_many(new_rows[idx:idx +
                                             100]).upsert(True).execute()

    return len(changed_addrs)
Esempio n. 4
0
def getblock():
    """Process detailed data from individual blocks to find last votes from guardians"""

    # TODO cleanup this deeply nested mess :)

    client = get_active_rpc_client()
    global getblock_proccessed_height
    blockchain_params = client.getblockchainparams()['result']
    pubkeyhash_version = blockchain_params['address-pubkeyhash-version']
    checksum_value = blockchain_params['address-checksum-value']

    block_objs = Block.multi_tx_blocks().where(
        Block.height > getblock_proccessed_height)

    votes_changed = False

    with data_db.atomic():
        for block_obj in block_objs:
            height = block_obj.height
            block_info = client.getblock("{}".format(height))['result']
            for txid in block_info['tx']:
                transaction = client.getrawtransaction(txid, 4)
                if transaction['error'] is None:
                    if 'vout' in transaction['result']:
                        vout = transaction['result']['vout']
                        permissions = []
                        start_block = None
                        end_block = None
                        for vout_key, entry in enumerate(vout):
                            if len(entry['permissions']) > 0:
                                for key, perm in entry['permissions'][0].items(
                                ):
                                    if perm and key in permission_candidates:
                                        permissions.append(key)
                                    if key == 'startblock':
                                        start_block = perm
                                    if key == 'endblock':
                                        end_block = perm
                                in_entry = transaction['result']['vin'][
                                    vout_key]
                                public_key = in_entry['scriptSig'][
                                    'asm'].split(' ')[1]
                                from_pubkey = public_key_to_address(
                                    public_key, pubkeyhash_version,
                                    checksum_value)
                                given_to = entry['scriptPubKey']['addresses']
                                for addr in given_to:
                                    log.debug(
                                        'Grant or Revoke {} given by {} to {} at time {}'
                                        .format(permissions, from_pubkey, addr,
                                                block_obj.time))
                                    addr_from_obj, _ = Address.get_or_create(
                                        address=from_pubkey)
                                    addr_to_obj, _ = Address.get_or_create(
                                        address=addr)
                                    vote_obj, created = Vote.get_or_create(
                                        txid=txid,
                                        defaults=dict(
                                            from_address=addr_from_obj,
                                            to_address_id=addr_to_obj,
                                            time=block_obj.time))
                                    if created:
                                        votes_changed = True

            getblock_proccessed_height = height

    if votes_changed:
        signals.votes_changed.emit()
Esempio n. 5
0
def listpermissions():
    client = get_active_rpc_client()
    node_height = client.getblockcount()['result']

    perms = client.listpermissions()
    if not perms:
        log.warning('no permissions from api')
        return
    new_perms, new_votes = False, False

    Permission.delete().execute()
    CurrentVote.delete().execute()

    admin_addresses = set()
    miner_addresses = set()

    with data_db.atomic():
        profile = Profile.get_active()

        for perm in perms['result']:
            perm_type = perm['type']
            perm_start = perm['startblock']
            perm_end = perm['endblock']

            if perm_type not in Permission.PERM_TYPES:
                continue

            if perm_type == Permission.ADMIN and perm_start < node_height < perm_end:
                admin_addresses.add(perm['address'])

            if perm_type == Permission.MINE and perm_start < node_height < perm_end:
                miner_addresses.add(perm['address'])

            addr_obj, created = Address.get_or_create(address=perm['address'])

            for vote in perm['pending']:
                # If candidate has already the permission continue.
                if vote['startblock'] == perm['startblock'] and vote[
                        'endblock'] == perm['endblock']:
                    continue
                start_block = vote['startblock']
                end_block = vote['endblock']
                # new stuff start
                for admin in vote['admins']:
                    admin_obj, created = Address.get_or_create(address=admin)
                    vote_obj, created = CurrentVote.get_or_create(
                        address=addr_obj,
                        perm_type=perm_type,
                        start_block=start_block,
                        end_block=end_block,
                        given_from=admin_obj)
                    vote_obj.set_vote_type()
                # new stuff end
                approbations = len(vote['admins'])
                # TODO: Fix: current time of syncing is not the time of first_vote!

            start_block = perm['startblock']
            end_block = perm['endblock']
            # TODO Why get_or_create ... we just deleted all Permission objects
            perm_obj, created = Permission.get_or_create(
                address=addr_obj,
                perm_type=perm_type,
                defaults=dict(start_block=start_block, end_block=end_block))
            if created:
                new_perms = True
            else:
                perm_obj.save()

    new_is_admin = profile.address in admin_addresses
    if profile.is_admin != new_is_admin:
        profile.is_admin = new_is_admin

    new_is_miner = profile.address in miner_addresses
    if profile.is_miner != new_is_miner:
        profile.is_miner = new_is_miner

    if profile.dirty_fields:
        profile.save()

    # Todo: maybe only trigger table updates on actual change?
    signals.listpermissions.emit()  # triggers community tab updates
    signals.votes_changed.emit()  # triggers community tab updates
    return {'new_perms': new_perms, 'new_votes': new_votes}