Beispiel #1
0
    async def _do_get_member(self, member_adr):
        is_member = await self.call('network.xbr.console.is_member', member_adr)
        if is_member:
            member_data = await self.call('network.xbr.console.get_member_by_wallet', member_adr)

            member_data['address'] = web3.Web3.toChecksumAddress(member_data['address'])
            member_data['oid'] = uuid.UUID(bytes=member_data['oid'])
            member_data['balance']['eth'] = web3.Web3.fromWei(unpack_uint256(member_data['balance']['eth']), 'ether')
            member_data['balance']['xbr'] = web3.Web3.fromWei(unpack_uint256(member_data['balance']['xbr']), 'ether')
            member_data['created'] = np.datetime64(member_data['created'], 'ns')

            member_level = member_data['level']
            MEMBER_LEVEL_TO_STR = {
                # Member is active.
                1: 'ACTIVE',
                # Member is active and verified.
                2: 'VERIFIED',
                # Member is retired.
                3: 'RETIRED',
                # Member is subject to a temporary penalty.
                4: 'PENALTY',
                # Member is currently blocked and cannot current actively participate in the market.
                5: 'BLOCKED',
            }
            member_data['level'] = MEMBER_LEVEL_TO_STR.get(member_level, None)

            self.log.info('Member found:\n\n{member_data}\n', member_data=pformat(member_data))
        else:
            self.log.warn('Address 0x{member_adr} is not a member in the XBR network',
                          member_adr=binascii.b2a_hex(member_adr).decode())
Beispiel #2
0
    async def _do_get_actor(self, market_oid, actor_adr):
        is_member = await self.call('network.xbr.console.is_member', actor_adr)
        if is_member:
            actor = await self.call('network.xbr.console.get_member_by_wallet', actor_adr)
            actor_oid = actor['oid']
            actor_adr = web3.Web3.toChecksumAddress(actor['address'])
            actor_level = actor['level']
            actor_balance_eth = int(unpack_uint256(actor['balance']['eth']) / 10 ** 18)
            actor_balance_xbr = int(unpack_uint256(actor['balance']['xbr']) / 10 ** 18)
            self.log.info('Found member with address {member_adr}, member level {member_level}: {member_balance_eth} ETH, {member_balance_xbr} XBR',
                          member_adr=actor_adr, member_level=actor_level, member_balance_eth=actor_balance_eth,
                          member_balance_xbr=actor_balance_xbr)

            if market_oid:
                # FIXME
                raise NotImplementedError()
            else:
                market_oids = await self.call('network.xbr.console.get_markets_by_actor', actor_oid)
                if market_oids:
                    self.log.info('Member is actor in {cnt_markets} markets!', cnt_markets=len(market_oids))
                    for market_oid in market_oids:
                        market = await self.call('network.xbr.console.get_market', market_oid)
                        self.log.info('Actor is joined to market {market_oid} (market owner 0x{owner_oid})',
                                      market_oid=uuid.UUID(bytes=market_oid),
                                      owner_oid=binascii.b2a_hex(market['owner']).decode())
                else:
                    self.log.info('Member is not yet actor in any market!')
        else:
            self.log.warn('Address 0x{member_adr} is not a member in the XBR network',
                          member_adr=binascii.b2a_hex(actor_adr).decode())
Beispiel #3
0
 async def _do_get_active_paying_channel(self, market_oid, delegate_adr):
     channel = await self.call('xbr.marketmaker.get_active_paying_channel', delegate_adr)
     self.log.debug('{channel}', channel=pformat(channel))
     if channel:
         self.log.info('Active seller (paying) channel found: {amount} amount',
                       amount=int(unpack_uint256(channel['amount']) / 10 ** 18))
         balance = await self.call('xbr.marketmaker.get_paying_channel_balance', channel['channel_oid'])
         self.log.debug('{balance}', channel=pformat(balance))
         self.log.info('Current off-chain amount remaining: {remaining} [sequence {sequence}]',
                       remaining=int(unpack_uint256(balance['remaining']) / 10 ** 18), sequence=balance['seq'])
     else:
         self.log.info('No active seller (paying) channel found!')
Beispiel #4
0
    async def _do_get_actor(self, market_oid, actor_adr):
        is_member = await self.call('network.xbr.console.is_member', actor_adr)
        if is_member:
            actor = await self.call('network.xbr.console.get_member_by_wallet', actor_adr)
            actor_oid = uuid.UUID(bytes=actor['oid'])
            actor_adr = web3.Web3.toChecksumAddress(actor['address'])
            actor_level = actor['level']
            actor_balance_eth = web3.Web3.fromWei(unpack_uint256(actor['balance']['eth']), 'ether')
            actor_balance_xbr = web3.Web3.fromWei(unpack_uint256(actor['balance']['xbr']), 'ether')
            self.log.info('Found member with address {member_adr} (member level {member_level}, balances: {member_balance_eth} ETH, {member_balance_xbr} XBR)',
                          member_adr=hlid(actor_adr),
                          member_level=hlval(actor_level),
                          member_balance_eth=hlval(actor_balance_eth),
                          member_balance_xbr=hlval(actor_balance_xbr))

            if market_oid:
                market_oids = [market_oid.bytes]
            else:
                market_oids = await self.call('network.xbr.console.get_markets_by_actor', actor_oid.bytes)

            if market_oids:
                for market_oid in market_oids:
                    # market = await self.call('network.xbr.console.get_market', market_oid)
                    result = await self.call('network.xbr.console.get_actor_in_market', market_oid, actor['address'])
                    for actor in result:
                        actor['actor'] = web3.Web3.toChecksumAddress(actor['actor'])
                        actor['timestamp'] = np.datetime64(actor['timestamp'], 'ns')
                        actor['joined'] = unpack_uint256(actor['joined']) if actor['joined'] else None
                        actor['market'] = uuid.UUID(bytes=actor['market'])
                        actor['security'] = web3.Web3.fromWei(unpack_uint256(actor['security']), 'ether') if actor['security'] else None
                        actor['signature'] = '0x' + binascii.b2a_hex(actor['signature']).decode() if actor['signature'] else None
                        actor['tid'] = '0x' + binascii.b2a_hex(actor['tid']).decode() if actor['tid'] else None

                        actor_type = actor['actor_type']
                        ACTOR_TYPE_TO_STR = {
                            # Actor is a XBR Provider.
                            1: 'PROVIDER',
                            # Actor is a XBR Consumer.
                            2: 'CONSUMER',
                            # Actor is both a XBR Provider and XBR Consumer.
                            3: 'PROVIDER_CONSUMER',
                        }
                        actor['actor_type'] = ACTOR_TYPE_TO_STR.get(actor_type, None)

                        self.log.info('Actor is joined to market {market_oid}:\n\n{actor}\n',
                                      market_oid=hlid(uuid.UUID(bytes=market_oid)), actor=pformat(actor))
            else:
                self.log.info('Member is not yet actor in any market!')
        else:
            self.log.warn('Address 0x{member_adr} is not a member in the XBR network',
                          member_adr=binascii.b2a_hex(actor_adr).decode())
Beispiel #5
0
 async def _do_get_member(self, member_adr):
     is_member = await self.call('network.xbr.console.is_member', member_adr)
     if is_member:
         member_data = await self.call('network.xbr.console.get_member_by_wallet', member_adr)
         member_adr = web3.Web3.toChecksumAddress(member_data['address'])
         member_level = member_data['level']
         member_balance_eth = int(unpack_uint256(member_data['balance']['eth']) / 10 ** 18)
         member_balance_xbr = int(unpack_uint256(member_data['balance']['xbr']) / 10 ** 18)
         self.log.info('Found member with address {member_adr}, member level {member_level}: {member_balance_eth} ETH, {member_balance_xbr} XBR',
                       member_adr=member_adr, member_level=member_level, member_balance_eth=member_balance_eth,
                       member_balance_xbr=member_balance_xbr)
     else:
         self.log.warn('Address 0x{member_adr} is not a member in the XBR network',
                       member_adr=binascii.b2a_hex(member_adr).decode())
Beispiel #6
0
    def get_member(self, ethadr_raw):
        if self.is_attached():
            is_member = yield self.call('xbr.network.is_member', ethadr_raw)
            if is_member:
                member_data = yield self.call(
                    'xbr.network.get_member_by_wallet', ethadr_raw)

                member_data['address'] = web3.Web3.toChecksumAddress(
                    member_data['address'])
                member_data['oid'] = uuid.UUID(bytes=member_data['oid'])
                member_data['balance']['eth'] = web3.Web3.fromWei(
                    unpack_uint256(member_data['balance']['eth']), 'ether')
                member_data['balance']['xbr'] = web3.Web3.fromWei(
                    unpack_uint256(member_data['balance']['xbr']), 'ether')
                member_data['created'] = np.datetime64(member_data['created'],
                                                       'ns')

                member_level = member_data['level']
                member_data['level'] = {
                    # Member is active.
                    1: 'ACTIVE',
                    # Member is active and verified.
                    2: 'VERIFIED',
                    # Member is retired.
                    3: 'RETIRED',
                    # Member is subject to a temporary penalty.
                    4: 'PENALTY',
                    # Member is currently blocked and cannot current actively participate in the market.
                    5: 'BLOCKED',
                }.get(member_level, None)

                self.log.info(
                    'Member {member_oid} found for address 0x{member_adr} - current member level {member_level}',
                    member_level=hlval(member_data['level']),
                    member_oid=hlid(member_data['oid']),
                    member_adr=hlval(member_data['address']))

                return member_data
            else:
                self.log.warn(
                    'Address {output_ethadr} is not a member in the XBR network',
                    output_ethadr=ethadr_raw)
        else:
            self.log.warn(
                'not connected: could not retrieve member data for address {output_ethadr}',
                output_ethadr=ethadr_raw)
Beispiel #7
0
 def registered(self) -> int:
     """
     Block number (on the blockchain) when the member (originally) registered.
     """
     if self._registered is None and self._from_fbs:
         if self._from_fbs.RegisteredLength():
             _registered = self._from_fbs.RegisteredAsBytes()
             self._registered = unpack_uint256(bytes(_registered))
         else:
             self._registered = 0
     return self._registered
Beispiel #8
0
    def _monitor_blockchain(self, gateway_config, scan_from_block, period=300):
        """

        :param gateway_config:
        :param scan_from_block:
        :param period:
        :return:
        """
        w3 = make_w3(gateway_config)
        initial_delay = 2

        self.log.info(
            'Start monitoring of blockchain ({blockchain_type}) on thread {thread_id} in {initial_delay} seconds, iterating every {period} seconds  ..',
            blockchain_type=str(self._bc_gw_config['type']),
            initial_delay=hlval(initial_delay),
            period=hlval(period),
            thread_id=hlval(int(threading.get_ident())))

        # using normal blocking call here, as we are running on a background thread!
        time.sleep(initial_delay)

        def _process_Token_Transfer(transactionHash, blockHash, args):
            # event Transfer(address indexed from, address indexed to, uint256 value);
            self.log.info(
                '{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) - {value} XBR token transferred (on-chain) from {_from} to {_to})',
                event=hlcontract('XBRToken.Transfer'),
                tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()),
                value=hlval(int(args.value / 10**18)),
                _from=hlval(args['from']),
                _to=hlval(args.to))

            stored = False
            with self._db.begin(write=True) as txn:

                transactionHash = bytes(transactionHash)

                token_transfer = self._xbr.token_transfers[txn, transactionHash]
                if token_transfer:
                    self.log.warn('{contract}(tx_hash={tx_hash}) record already stored in database.',
                                  contract=hlcontract('TokenTransfer'),
                                  tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()))
                else:
                    token_transfer = cfxdb.xbr.token.TokenTransfer()

                    token_transfer.tx_hash = transactionHash
                    token_transfer.block_hash = bytes(blockHash)
                    token_transfer.from_address = bytes(HexBytes(args['from']))
                    token_transfer.to_address = bytes(HexBytes(args.to))
                    token_transfer.value = args.value

                    self._xbr.token_transfers[txn, transactionHash] = token_transfer
                    stored = True

            if stored:
                self.log.info('new {contract}(tx_hash={tx_hash}) record stored database!',
                              contract=hlcontract('TokenTransfer'),
                              tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()))

        def _process_Token_Approval(transactionHash, blockHash, args):
            # event Approval(address indexed from, address indexed to, uint256 value);
            self.log.info(
                '{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) - {value} XBR token approved (on-chain) from owner {owner} to spender {spender})',
                event=hlcontract('XBRToken.Approval'),
                tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()),
                value=hlval(int(args.value / 10**18)),
                owner=hlval(args.owner),
                spender=hlval(args.spender))

            stored = False
            with self._db.begin(write=True) as txn:

                transactionHash = bytes(transactionHash)

                token_approval = self._xbr.token_approvals[txn, transactionHash]
                if token_approval:
                    self.log.warn('{contract}(tx_hash={tx_hash}) record already stored in database.',
                                  contract=hlcontract('TokenApproval'),
                                  tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()))
                else:
                    token_approval = cfxdb.xbr.token.TokenApproval()

                    token_approval.tx_hash = transactionHash
                    token_approval.block_hash = bytes(blockHash)
                    token_approval.owner_address = bytes(HexBytes(args.owner))
                    token_approval.spender_address = bytes(HexBytes(args.spender))
                    token_approval.value = args.value

                    self._xbr.token_approvals[txn, transactionHash] = token_approval
                    stored = True

            if stored:
                self.log.info('new {contract}(tx_hash={tx_hash}) record stored database!',
                              contract=hlcontract('TokenApproval'),
                              tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()))

        def _process_Network_MemberRegistered(transactionHash, blockHash, args):
            #     /// Event emitted when a new member joined the XBR Network.
            #     event MemberCreated (address indexed member, string eula, string profile, MemberLevel level);
            self.log.info(
                '{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) - XBR member created at address {address})',
                event=hlcontract('XBRNetwork.MemberCreated'),
                tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()),
                address=hlid(args.member))

            member_adr = bytes(HexBytes(args.member))

            if args.eula:
                h = multihash.decode(multihash.from_b58_string(args.eula))
                if h.name != 'sha2-256':
                    self.log.warn(
                        'WARNING: XBRNetwork.MemberCreated - eula "{eula}" is not an IPFS (sha2-256) b58-encoded multihash',
                        eula=hlval(args.eula))

            if args.profile:
                h = multihash.decode(multihash.from_b58_string(args.profile))
                if h.name != 'sha2-256':
                    self.log.warn(
                        'WARNING: XBRNetwork.MemberCreated - profile "{profile}" is not an IPFS (sha2-256) b58-encoded multihash',
                        eula=hlval(args.profile))

            stored = False
            with self._db.begin(write=True) as txn:

                member = self._xbr.members[txn, member_adr]
                if member:
                    self.log.warn('{contract}(tx_hash={tx_hash}) record already stored in database.',
                                  contract=hlcontract('TokenApproval'),
                                  tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()))
                else:
                    member = cfxdb.xbr.member.Member()
                    member.address = member_adr
                    member.timestamp = np.datetime64(time_ns(), 'ns')
                    member.registered = args.registered
                    member.eula = args.eula
                    member.profile = args.profile
                    member.level = args.level

                    self._xbr.members[txn, member_adr] = member
                    stored = True

            if stored:
                self.log.info('new {contract}(member_adr={member_adr}) record stored database!',
                              contract=hlcontract('MemberCreated'),
                              member_adr=hlid('0x' + binascii.b2a_hex(member_adr).decode()))

        def _process_Network_MemberRetired(transactionHash, blockHash, args):
            #     /// Event emitted when a member leaves the XBR Network.
            #     event MemberRetired (address member);
            self.log.warn('_process_Network_MemberRetired not implemented')

        def _process_Market_MarketCreated(transactionHash, blockHash, args):
            #     /// Event emitted when a new market was created.
            #     event MarketCreated (bytes16 indexed marketId, uint32 marketSeq, address owner, string terms, string meta,
            #         address maker, uint256 providerSecurity, uint256 consumerSecurity, uint256 marketFee);
            self.log.info(
                '{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) - XBR market created with ID {market_id})',
                event=hlcontract('XBRMarket.MarketCreated'),
                tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()),
                market_id=hlid(uuid.UUID(bytes=args.marketId)))

            market_id = uuid.UUID(bytes=args.marketId)

            if args.terms:
                h = multihash.decode(multihash.from_b58_string(args.terms))
                if h.name != 'sha2-256':
                    self.log.warn(
                        'WARNING: XBRMarket.MarketCreated - terms "{terms}" is not an IPFS (sha2-256) b58-encoded multihash',
                        terms=hlval(args.terms))

            if args.meta:
                h = multihash.decode(multihash.from_b58_string(args.meta))
                if h.name != 'sha2-256':
                    self.log.warn(
                        'WARNING: XBRMarket.MarketCreated - meta "{meta}" is not an IPFS (sha2-256) b58-encoded multihash',
                        meta=hlval(args.meta))

            stored = False
            with self._db.begin(write=True) as txn:

                market = self._xbr.markets[txn, market_id]
                if market:
                    self.log.warn('{contract}(tx_hash={tx_hash}) record already stored in database.',
                                  contract=hlcontract('MarketCreated'),
                                  tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()))
                else:
                    market = cfxdb.xbr.market.Market()
                    market.market = market_id
                    market.timestamp = np.datetime64(time_ns(), 'ns')

                    # FIXME
                    # market.created = args.created

                    market.seq = args.marketSeq
                    market.owner = bytes(HexBytes(args.owner))
                    market.terms = args.terms
                    market.meta = args.meta
                    market.maker = bytes(HexBytes(args.maker))
                    market.provider_security = args.providerSecurity
                    market.consumer_security = args.consumerSecurity
                    market.market_fee = args.marketFee

                    self._xbr.markets[txn, market_id] = market
                    stored = True

            if stored:
                self.log.info('new {contract}(market_id={market_id}) record stored database!',
                              contract=hlcontract('MarketCreated'),
                              market_id=hlid(market_id))

        def _process_Market_MarketUpdated(transactionHash, blockHash, args):
            #     /// Event emitted when a market was updated.
            #     event MarketUpdated (bytes16 indexed marketId, uint32 marketSeq, address owner, string terms, string meta,
            #         address maker, uint256 providerSecurity, uint256 consumerSecurity, uint256 marketFee);
            self.log.warn('_process_Market_MarketUpdated not implemented')

        def _process_Market_MarketClosed(transactionHash, blockHash, args):
            #     /// Event emitted when a market was closed.
            #     event MarketClosed (bytes16 indexed marketId);
            self.log.warn('_process_Market_MarketClosed not implemented')

        def _process_Market_ActorJoined(transactionHash, blockHash, args):
            # Event emitted when a new actor joined a market.
            # event ActorJoined (bytes16 indexed marketId, address actor, uint8 actorType, uint joined, uint256 security, string meta);
            self.log.info(
                '{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) - XBR market actor {actor} joined market {market_id})',
                event=hlcontract('XBRMarket.ActorJoined'),
                tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()),
                actor=hlid(args.actor),
                market_id=hlid(uuid.UUID(bytes=args.marketId)))

            market_id = uuid.UUID(bytes=args.marketId)
            actor_adr = bytes(HexBytes(args.actor))
            actor_type = int(args.actorType)

            if args.meta:
                h = multihash.decode(multihash.from_b58_string(args.meta))
                if h.name != 'sha2-256':
                    self.log.warn(
                        'WARNING: XBRMarket.MarketCreated - meta "{meta}" is not an IPFS (sha2-256) b58-encoded multihash',
                        terms=hlval(args.meta))

            stored = False
            with self._db.begin(write=True) as txn:

                actor = self._xbr.actors[txn, (market_id, actor_adr, actor_type)]
                if actor:
                    self.log.warn('{contract}(tx_hash={tx_hash}) record already stored in database.',
                                  contract=hlcontract('MarketCreated'),
                                  tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()))
                else:
                    actor = cfxdb.xbr.actor.Actor()
                    actor.timestamp = np.datetime64(time_ns(), 'ns')
                    actor.market = market_id
                    actor.actor = actor_adr
                    actor.actor_type = actor_type

                    actor.joined = args.joined
                    actor.security = args.security
                    actor.meta = args.meta

                    self._xbr.actors[txn, (market_id, actor_adr, actor_type)] = actor
                    stored = True

            if stored:
                self.log.info(
                    'new {contract}(market_id={market_id}, actor_adr={actor_adr}, actor_type={actor_type}) record stored database!',
                    contract=hlcontract('ActorJoined'),
                    market_id=hlid(market_id),
                    actor_adr=hlid('0x' + binascii.b2a_hex(actor_adr).decode()),
                    actor_type=hlid(actor_type))

        def _process_Market_ActorLeft(transactionHash, blockHash, args):
            self.log.warn('_process_Market_ActorLeft not implemented')

        def _process_Market_ConsentSet(transactionHash, blockHash, args):
            # Event emitted when a consent is set
            # emit ConsentSet(member, updated, marketId, delegate, delegateType,
            #                 apiCatalog, consent, servicePrefix);
            self.log.info('{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) ..',
                          event=hlcontract('XBRMarket.ConsentSet'),
                          tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                          block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()))

            catalog_oid = uuid.UUID(bytes=args.apiCatalog)
            member = uuid.UUID(bytes=args.member)
            delegate = args.delegate
            delegate_type = args.delegateType
            market_oid = uuid.UUID(bytes=args.marketId)
            with self._db.begin(write=True) as txn:
                consent = self._xbr.consents[txn, (catalog_oid, member, delegate, delegate_type, market_oid)]
                consent.synced = True

        def _process_Catalog_CatalogCreated(transactionHash, blockHash, args):
            # Event emitted when a new API catalog is created
            # emit CatalogCreated(catalogId, created, catalogSeq, owner, terms, meta);
            self.log.info('{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) ..',
                          event=hlcontract('XBRCatalog.CatalogCreated'),
                          tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                          block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()))

            catalog_oid = uuid.UUID(bytes=args.catalogId)
            owner = bytes(HexBytes(args.owner))
            created = np.datetime64(time_ns(), 'ns')
            with self._db.begin(write=True) as txn:
                catalog = cfxdb.xbr.catalog.Catalog()
                catalog.oid = catalog_oid
                catalog.timestamp = created
                catalog.seq = args.catalogSeq
                catalog.owner = owner
                catalog.terms = args.terms
                catalog.meta = args.meta
                self._xbr.catalogs[txn, catalog_oid] = catalog

            deferToThread(self._download_ipfs_file, args.meta)

        def _process_Catalog_ApiPublished(transactionHash, blockHash, args):
            self.log.warn('_process_Catalog_ApiPublished not implemented')

        def _process_Channel_Opened(transactionHash, blockHash, args):
            # Event emitted when a new XBR data market has opened.
            # event Opened(XBRTypes.ChannelType ctype, bytes16 indexed marketId, bytes16 indexed channelId,
            #              address actor, address delegate, address marketmaker, address recipient,
            #              uint256 amount, bytes signature);
            self.log.info('{event}: processing event (tx_hash={tx_hash}, block_hash={block_hash}) ..',
                          event=hlcontract('XBRChannel.Opened'),
                          tx_hash=hlid('0x' + binascii.b2a_hex(transactionHash).decode()),
                          block_hash=hlid('0x' + binascii.b2a_hex(blockHash).decode()))

            channel_oid = uuid.UUID(bytes=args.channelId)
            marketmaker_adr = bytes(HexBytes(args.marketmaker))
            marketmaker_adr_str = web3.Web3.toChecksumAddress(marketmaker_adr)

            # we only persist data for xbr markets operated by one of the market makers we run in this worker
            if marketmaker_adr_str not in self._maker_adr2id or self._maker_adr2id[
                    marketmaker_adr_str] not in self._makers:
                self.log.info(
                    '{event}: skipping channel (channel {channel_oid} in market with market maker address {marketmaker_adr} is in for any market in this markets worker)',
                    event=hlcontract('XBRChannel.Opened'),
                    channel_oid=hlid(channel_oid),
                    marketmaker_adr=hlid(marketmaker_adr_str))
                return

            # prepare new channel data
            channel_type = int(args.ctype)
            market_oid = uuid.UUID(bytes=args.marketId)
            actor_adr = bytes(HexBytes(args.actor))
            delegate_adr = bytes(HexBytes(args.delegate))
            recipient_adr = bytes(HexBytes(args.recipient))
            amount = int(args.amount)
            # FIXME
            # signature = bytes(HexBytes(args.signature))
            # FIXME
            # member_oid = uuid.UUID()

            # get the market maker by address
            maker = self._makers[self._maker_adr2id[marketmaker_adr_str]]

            # the market maker specific embedded database and schema
            db = maker.db
            xbrmm = maker.schema

            # depending on channel type, different database schema classes and tables are used
            if channel_type == cfxdb.xbrmm.ChannelType.PAYMENT:
                channel = cfxdb.xbrmm.PaymentChannel()
                channels = xbrmm.payment_channels
                channels_by_delegate = xbrmm.idx_payment_channel_by_delegate
                balance = cfxdb.xbrmm.PaymentChannelBalance()
                balances = xbrmm.payment_balances
            elif channel_type == cfxdb.xbrmm.ChannelType.PAYING:
                channel = cfxdb.xbrmm.PayingChannel()
                channels = xbrmm.paying_channels
                channels_by_delegate = xbrmm.idx_paying_channel_by_delegate
                balance = cfxdb.xbrmm.PayingChannelBalance()
                balances = xbrmm.paying_balances
            else:
                assert False, 'should not arrive here'

            # fill in information for newly replicated channel
            channel.market_oid = market_oid
            # FIXME
            # channel.member_oid = member_oid
            channel.channel_oid = channel_oid
            channel.timestamp = np.datetime64(time_ns(), 'ns')
            # channel.open_at = None

            # FIXME: should read that from even args after deployment of
            # https://github.com/crossbario/xbr-protocol/pull/138
            channel.seq = 1
            channel.channel_type = channel_type
            channel.marketmaker = marketmaker_adr
            channel.actor = actor_adr
            channel.delegate = delegate_adr
            channel.recipient = recipient_adr
            channel.amount = amount

            # FIXME
            channel.timeout = 0
            channel.state = cfxdb.xbrmm.ChannelState.OPEN
            # FIXME
            # channel.open_sig = signature

            # create an off-chain balance record for the channel with remaining == initial amount
            balance.remaining = channel.amount
            # FIXME: should read that from even args after deployment of
            # https://github.com/crossbario/xbr-protocol/pull/138
            balance.seq = 1

            # now store the new channel and balance in the database
            stored = False
            cnt_channels_before = 0
            cnt_channels_by_delegate_before = 0
            cnt_channels_after = 0
            cnt_channels_by_delegate_after = 0
            with db.begin(write=True) as txn:
                if channels[txn, channel_oid]:
                    self.log.warn('{event}: channel already stored in database [channel_oid={channel_oid}]',
                                  event=hlcontract('XBRChannel.Opened'),
                                  channel_oid=hlid(channel_oid))
                else:
                    cnt_channels_before = channels.count(txn)
                    cnt_channels_by_delegate_before = channels_by_delegate.count(txn)

                    # store the channel along with the off-chain balance
                    channels[txn, channel_oid] = channel
                    balances[txn, channel_oid] = balance
                    stored = True

                    cnt_channels_after = channels.count(txn)
                    cnt_channels_by_delegate_after = channels_by_delegate.count(txn)

            self.log.info(
                '{event} DB result: stored={stored}, cnt_channels_before={cnt_channels_before}, cnt_channels_by_delegate_before={cnt_channels_by_delegate_before}, cnt_channels_after={cnt_channels_after}, cnt_channels_by_delegate_after={cnt_channels_by_delegate_after}',
                event=hlcontract('XBRChannel.Opened'),
                stored=hlval(stored),
                cnt_channels_before=hlval(cnt_channels_before),
                cnt_channels_by_delegate_before=hlval(cnt_channels_by_delegate_before),
                cnt_channels_after=hlval(cnt_channels_after),
                cnt_channels_by_delegate_after=hlval(cnt_channels_by_delegate_after))
            if stored:
                # FIXME: publish WAMP event
                self.log.info(
                    '{event}: new channel stored in database [actor_adr={actor_adr}, channel_type={channel_type}, market_oid={market_oid}, member_oid={member_oid}, channel_oid={channel_oid}]',
                    event=hlcontract('XBRChannel.Opened'),
                    market_oid=hlid(market_oid),
                    # FIXME
                    member_oid=hlid(None),
                    channel_oid=hlid(channel_oid),
                    actor_adr=hlid('0x' + binascii.b2a_hex(actor_adr).decode()),
                    channel_type=hlid(channel_type))

        def _process_Channel_Closing(transactionHash, blockHash, args):
            self.log.warn('_process_Channel_Closing not implemented')

        def _process_Channel_Closed(transactionHash, blockHash, args):
            self.log.warn('_process_Channel_Closed not implemented')

        # map XBR contract log event to event processing function
        Events = [
            (xbr.xbrtoken.events.Transfer, _process_Token_Transfer),
            (xbr.xbrtoken.events.Approval, _process_Token_Approval),
            (xbr.xbrnetwork.events.MemberRegistered, _process_Network_MemberRegistered),
            (xbr.xbrnetwork.events.MemberRetired, _process_Network_MemberRetired),
            (xbr.xbrmarket.events.MarketCreated, _process_Market_MarketCreated),
            (xbr.xbrmarket.events.MarketUpdated, _process_Market_MarketUpdated),
            (xbr.xbrmarket.events.MarketClosed, _process_Market_MarketClosed),
            (xbr.xbrmarket.events.ActorJoined, _process_Market_ActorJoined),
            (xbr.xbrmarket.events.ActorLeft, _process_Market_ActorLeft),
            (xbr.xbrmarket.events.ConsentSet, _process_Market_ConsentSet),
            (xbr.xbrcatalog.events.CatalogCreated, _process_Catalog_CatalogCreated),
            (xbr.xbrcatalog.events.ApiPublished, _process_Catalog_ApiPublished),
            (xbr.xbrchannel.events.Opened, _process_Channel_Opened),
            (xbr.xbrchannel.events.Closing, _process_Channel_Closing),
            (xbr.xbrchannel.events.Closed, _process_Channel_Closed),
        ]

        # determine the block number, starting from which we scan the blockchain for XBR events
        current = w3.eth.getBlock('latest')
        last_processed = scan_from_block - 1
        with self._db.begin() as txn:
            for block_number in self._xbr.blocks.select(txn, return_values=False, reverse=True, limit=1):
                last_processed = unpack_uint256(block_number)
        if last_processed > current.number:
            raise ApplicationError(
                'wamp.error.invalid_argument',
                'last processed block number {} (or configured "scan_from" block number) is larger than then current block number {}'
                .format(last_processed, current.number))
        else:
            self.log.info(
                'Start scanning blockchain: current block is {current_block}, last processed is {last_processed} ..',
                current_block=hlval(current.number),
                last_processed=hlval(last_processed + 1))

        iteration = 1

        while not self._stop_monitor and not self._run_monitor.is_set():
            # current last block
            current = w3.eth.getBlock('latest')

            # track number of blocks processed
            cnt_blocks_success = 0
            cnt_blocks_error = 0
            cnt_xbr_events = 0

            # synchronize on-change changes locally by processing blockchain events
            if last_processed < current.number:
                while last_processed < current.number:
                    last_processed += 1
                    try:
                        self.log.info('Now processing blockchain block {last_processed} ..',
                                      last_processed=hlval(last_processed))
                        cnt_xbr_events += self._process_block(w3, last_processed, Events)
                    except:
                        self.log.failure()
                        cnt_blocks_error += 1
                    else:
                        cnt_blocks_success += 1

                self.log.info(
                    'Monitor blockchain iteration {iteration} completed: new block processed (last_processed={last_processed}, thread_id={thread_id}, period={period}, cnt_xbr_events={cnt_xbr_events}, cnt_blocks_success={cnt_blocks_success}, cnt_blocks_error={cnt_blocks_error})',
                    iteration=hlval(iteration),
                    last_processed=hlval(last_processed),
                    thread_id=hlval(int(threading.get_ident())),
                    period=hlval(period),
                    cnt_xbr_events=hlval(cnt_xbr_events, color='green') if cnt_xbr_events else hlval(cnt_xbr_events),
                    cnt_blocks_success=hlval(cnt_blocks_success, color='green')
                    if cnt_xbr_events else hlval(cnt_blocks_success),
                    cnt_blocks_error=hlval(cnt_blocks_error, color='red')
                    if cnt_blocks_error else hlval(cnt_blocks_error))
            else:
                self.log.info(
                    'Monitor blockchain iteration {iteration} completed: no new blocks found (last_processed={last_processed}, thread_id={thread_id}, period={period})',
                    iteration=hlval(iteration),
                    last_processed=hlval(last_processed),
                    thread_id=hlval(int(threading.get_ident())),
                    period=hlval(period))

            # sleep (using normal blocking call here, as we are running on a background thread!)
            self._run_monitor.wait(period)

            iteration += 1