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())
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())
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!')
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())
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())
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)
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
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