def start(self): """ Start the blockchain client using the configured blockchain gateway. """ assert self._w3 is None if self._gateway: w3 = web3.Web3(web3.Web3.HTTPProvider(self._gateway)) else: # using automatic provider detection: from web3.auto import w3 # check we are connected, and check network ID if not w3.isConnected(): emsg = 'could not connect to Web3/Ethereum at: {}'.format( self._gateway or 'auto') self.log.warn(emsg) raise RuntimeError(emsg) else: print('connected to network {} at provider "{}"'.format( w3.version.network, self._gateway or 'auto')) self._w3 = w3 # set new provider on XBR library xbr.setProvider(self._w3)
async def _do_market_realm(self, details): self._w3 = make_w3(_INFURA_CONFIG) xbr.setProvider(self._w3) command = self.config.extra['command'] assert command in ['open-channel', 'get-channel'] if command == 'get-channel': market_oid = self.config.extra['market'] delegate = self.config.extra['delegate'] channel_type = self.config.extra['channel_type'] if channel_type == ChannelType.PAYMENT: await self._do_get_active_payment_channel(market_oid, delegate) elif channel_type == ChannelType.PAYING: await self._do_get_active_paying_channel(market_oid, delegate) else: assert False, 'should not arrive here' elif command == 'open-channel': market_oid = self.config.extra['market'] channel_oid = self.config.extra['channel'] channel_type = self.config.extra['channel_type'] delegate = self.config.extra['delegate'] amount = self.config.extra['amount'] await self._do_open_channel(market_oid, channel_oid, channel_type, delegate, amount) else: assert False, 'should not arrive here'
def __init__(self, config=None, reactor=None, personality=None): # WorkerController derives of NativeProcess, which will set self._reactor WorkerController.__init__(self, config=config, reactor=reactor, personality=personality) worker_options_extra = dict(config.extra.extra) self._database_config = worker_options_extra['database'] self._blockchain_config = worker_options_extra['blockchain'] self._ipfs_files_directory = worker_options_extra.get('ipfs_files_directory', './.ipfs_files') # xbrmm worker status self._status = None # map of market makers by ID self._makers = {} self._maker_adr2id = {} # open xbrmm worker database, containing a replicate of xbr on-chain data (other than # channels, which are market specific and stored in the market maker database of the maker of that market) self._dbpath = os.path.abspath( self._database_config.get('dbpath', './.xbrmm-{}-db'.format(config.extra.worker))) self._db = zlmdb.Database(dbpath=self._dbpath, maxsize=self._database_config.get('maxsize', 2**30), readonly=False, sync=True) self._db.__enter__() # generic database object metadata self._meta = cfxdb.meta.Schema.attach(self._db) # xbr database schema self._xbr = cfxdb.xbr.Schema.attach(self._db) # xbr market maker schema self._xbrmm = cfxdb.xbrmm.Schema.attach(self._db) # event object too coordinate exit of blockchain monitor background check self._run_monitor = None # blockchain gateway configuration self._bc_gw_config = self._blockchain_config['gateway'] self.log.info('Initializing Web3 from blockchain gateway configuration\n\n{gateway}\n', gateway=pformat(self._bc_gw_config)) self._w3 = make_w3(self._bc_gw_config) xbr.setProvider(self._w3) self._chain_id = self._blockchain_config.get('chain_id', 1) self.log.info('Using chain ID {chain_id}', chain_id=hlid(self._chain_id)) # To be initiated once cbdir variable gets available self._ipfs_files_dir = os.path.join(config.extra.cbdir, self._ipfs_files_directory)
async def _do_market_realm(self, details): profile = self.config.extra['profile'] blockchain_gateway = { "type": "infura", "network": profile.infura_network, "key": profile.infura_key, "secret": profile.infura_secret } self._w3 = make_w3(blockchain_gateway) xbr.setProvider(self._w3) command = self.config.extra['command'] assert command in ['open-channel', 'get-channel'] if command == 'get-channel': market_oid = self.config.extra['market'] delegate = self.config.extra['delegate'] channel_type = self.config.extra['channel_type'] if channel_type == ChannelType.PAYMENT: await self._do_get_active_payment_channel(market_oid, delegate) elif channel_type == ChannelType.PAYING: await self._do_get_active_paying_channel(market_oid, delegate) else: assert False, 'should not arrive here' elif command == 'open-channel': # market in which to open the new buyer/seller (payment/paying) channel market_oid = self.config.extra['market'] # read UUID of the new channel to be created from command line OR auto-generate a new one channel_oid = self.config.extra['channel'] or uuid.uuid4() # buyer/seller (payment/paying) channel channel_type = self.config.extra['channel_type'] # the delgate allowed to use the channel delegate = self.config.extra['delegate'] # amount of market coins for initial channel balance amount = self.config.extra['amount'] # now open the channel .. await self._do_open_channel(market_oid, channel_oid, channel_type, delegate, amount) else: assert False, 'should not arrive here'
def load_config(self, configfile=None): """ Load the node configuration of CFC itself. The base node configuration is built into CFC, but can be overridden (partially) and extended by providing a regular, local node configuration file. When such a file exists: - and it contains a controller section, these take precedence over the builtin values. - and it contains a workers section (a list of workers), these are _added_ to the builtin workers. """ # load builtin node configuration as default # filename = pkg_resources.resource_filename('crossbar', self.DEFAULT_CONFIG_PATH) with open(filename) as f: config = json.load(f) config_path = filename config_source = self.CONFIG_SOURCE_DEFAULT # self.personality.check_config(self.personality, config) self.log.debug('Built-in node configuration loaded and checked') # try loading node configuration from blockchain (overwriting the previously loaded default config) # FIXME: domain/node configuration was removed from the XBRNetwork contract (for now) # see: https://github.com/crossbario/xbr-protocol/pull/36 if False: gateway_config = { "type": "user", "http": "http://localhost:1545", } self._w3 = make_w3(gateway_config) xbr.setProvider(self._w3) if self._w3.isConnected(): self.log.info( 'Connected to Ethereum network {network} at gateway "{gateway_url}"', network=self._w3.version.network, gateway_url=gateway_config['http']) if 'XBR_DEBUG_TOKEN_ADDR' in os.environ: self.log.info( 'XBR Token contract address {token_addr} set from environment', token_addr=hlid(os.environ['XBR_DEBUG_TOKEN_ADDR'])) if 'XBR_DEBUG_NETWORK_ADDR' in os.environ: self.log.info( 'XBR Network contract address {network_addr} set from environment', network_addr=hlid( os.environ['XBR_DEBUG_NETWORK_ADDR'])) xbr_node_id = xbr.xbrnetwork.functions.getNodeByKey( self.key.public_key()).call() if xbr_node_id != b'\x00' * 16: assert (len(xbr_node_id) == 16) xbr_node_domain = xbr.xbrnetwork.functions.getNodeDomain( xbr_node_id).call() xbr_node_type = xbr.xbrnetwork.functions.getNodeType( xbr_node_id).call() xbr_node_config = xbr.xbrnetwork.functions.getNodeConfig( xbr_node_id).call() # FIXME: for testing use hard-coded "trial license" (no. 20010) xbr_node_license = 20010 # xbr_node_license = xbr.xbrnetwork.functions.getNodeLicense(xbr_node_id).call() self.log.info( 'Node is configured for XBR (xbr_node_id="{xbr_node_id}", xbr_node_domain="{xbr_node_domain}", xbr_node_type="{xbr_node_type}", xbr_node_license="{xbr_node_license}", xbr_node_config="{xbr_node_config}")', xbr_node_id=hlid( '0x' + binascii.b2a_hex(xbr_node_id).decode()), xbr_node_domain=hlid( '0x' + binascii.b2a_hex(xbr_node_domain).decode()), xbr_node_type=hlid(xbr_node_type), xbr_node_config=hlid(xbr_node_config), xbr_node_license=hlid(xbr_node_license)) self._license = License(xbr_node_license) self.log.info( 'Node is registered in the XBR network with license type={license}', license=self._license.type) if xbr_node_config: if 'IPFS_GATEWAY_URL' in os.environ: ipfs_gateway_url = os.environ['IPFS_GATEWAY_URL'] self.log.info( 'Using explicit IPFS gateway URL {ipfs_gateway_url} from environment variable IPFS_GATEWAY_URL', ipfs_gateway_url=hlid(ipfs_gateway_url)) else: ipfs_gateway_url = 'https://ipfs.infura.io:5001' self.log.info( 'Using default IPFS Infura gateway URL {ipfs_gateway_url}', ipfs_gateway_url=hlid(ipfs_gateway_url)) ipfs_config_url = '{}/api/v0/cat?arg={}&encoding=json'.format( ipfs_gateway_url, xbr_node_config) resp = requests.get(ipfs_config_url) xbr_node_config_data = resp.json() from pprint import pprint pprint(xbr_node_config_data) self.personality.check_config(self.personality, xbr_node_config_data) if 'controller' not in xbr_node_config_data: xbr_node_config_data['controller'] = {} if 'id' not in xbr_node_config_data['controller']: xbr_node_config_data['controller']['id'] = str( uuid.UUID(bytes=xbr_node_id)) self.log.info( 'Deriving node ID {node_id} from XBR network node ID', node_id=hlid( xbr_node_config_data['controller']['id'])) else: self.log.info( 'Setting node ID {node_id} from XBR network node configuration', node_id=hlid( xbr_node_config_data['controller']['id'])) self._config = xbr_node_config_data self.log.info( 'Node configuration loaded from XBR network (xbr_node_id="{xbr_node_id}")', xbr_node_id=hlid( '0x' + binascii.b2a_hex(xbr_node_id).decode())) else: self.log.debug( 'There is no node configuration stored in XBR network (xbr_node_id="{xbr_node_id}")', xbr_node_id=hlid( '0x' + binascii.b2a_hex(xbr_node_id).decode())) config_source = self.CONFIG_SOURCE_XBRNETWORK else: self.log.warn( 'Could not find node public key on blockchain yet') else: self.log.warn('Could not connect to Ethereum blockchain') # allow extending/overriding the node configuration loaded with local config files # if configfile: config_source = self.CONFIG_SOURCE_LOCALFILE config_path = os.path.abspath(os.path.join(self._cbdir, configfile)) self.log.info( 'Expanding built-in node configuration from local file {configpath}', configpath=hlid(config_path)) with open(config_path) as f: custom_config = json.load(f) # as an overriding config file does not need to be a fully valid config in itself, do _not_ check it! # self.personality.check_config(self.personality, custom_config) config = merge_config(config, custom_config) # check the final, assembled initial node configuration to apply # self.personality.check_config(self.personality, config) self._config = config self.log.debug( 'Master node config after (effective after merge):\n{config}', config=pformat(config)) return config_source, config_path
parser.add_argument( '--gateway', dest='gateway', type=str, default=None, help= 'Ethereum HTTP gateway URL or None for auto-select (default: -, means let web3 auto-select).' ) args = parser.parse_args() if args.gateway: w3 = web3.Web3(web3.Web3.HTTPProvider(args.gateway)) else: # using automatic provider detection: from web3.auto import w3 # check we are connected, and check network ID if not w3.isConnected(): print('could not connect to Web3/Ethereum at "{}"'.format(args.gateway or 'auto')) sys.exit(1) else: print('connected via provider "{}"'.format(args.gateway or 'auto')) # set new provider on XBR library xbr.setProvider(w3) # now enter main .. main(w3.eth.accounts)
def load_config(self, configfile=None): """ Load the node configuration of CFC itself. The base node configuration is built into CFC, but can be overridden (partially) and extended by providing a regular, local node configuration file. When such a file exists: - and it contains a controller section, these take precedence over the builtin values. - and it contains a workers section (a list of workers), these are _added_ to the builtin workers. """ config_source = Node.CONFIG_SOURCE_EMPTY # 1/4: load builtin master node configuration as default # config_path = pkg_resources.resource_filename('crossbar', self.DEFAULT_CONFIG_PATH) with open(config_path) as f: config = json.load(f) # no need to check the builtin config (at run-time) # self.personality.check_config(self.personality, config) # remember config source config_source += Node.CONFIG_SOURCE_DEFAULT self.log.info('Built-in master node configuration loaded') # 2/4: allow extending/overriding the node configuration # with a local master node configuration file (eg for TLS setup) if configfile: config_path = os.path.abspath(os.path.join(self._cbdir, configfile)) with open(config_path) as f: custom_config = json.load(f) # as an overriding config file does not need to be a fully valid config in itself, # do _not_ check it .. # self.personality.check_config(self.personality, custom_config) # .. instead, we merge the config from the local file into the already # loaded default config (see above) config = merge_config(config, custom_config) # remember config source config_source += Node.CONFIG_SOURCE_LOCALFILE self.log.info( 'Local master node configuration merged from "{config_path}"', config_path=hlval(config_path)) # 3/4: allow extending/overriding the node configuration # with a remote master node configuration file from blockchain/IPFS if config.get('controller', {}).get('blockchain', None): blockchain_config = config['controller']['blockchain'] gateway_config = blockchain_config['gateway'] # setup Web3 connection from blockchain gateway configuration self._w3 = make_w3(gateway_config) # configure new Web3 connection as provider for XBR xbr.setProvider(self._w3) if self._w3.isConnected(): self.log.info( 'Connected to Ethereum network {network} at gateway "{gateway_url}"', network=self._w3.net.version, gateway_url=gateway_config['http']) # try to find node by node public key on-chain xbr_node_id = xbr.xbrnetwork.functions.getNodeByKey( self.key.public_key()).call() if xbr_node_id != b'\x00' * 16: assert (len(xbr_node_id) == 16) # get node domain, type, configuration and license as stored on-chain xbr_node_domain = xbr.xbrnetwork.functions.getNodeDomain( xbr_node_id).call() xbr_node_type = xbr.xbrnetwork.functions.getNodeType( xbr_node_id).call() xbr_node_config = xbr.xbrnetwork.functions.getNodeConfig( xbr_node_id).call() # FIXME: for testing use hard-coded "trial license" (no. 20010) xbr_node_license = 20010 # xbr_node_license = xbr.xbrnetwork.functions.getNodeLicense(xbr_node_id).call() self.log.info( 'Node is configured for XBR (xbr_node_id="{xbr_node_id}", xbr_node_domain="{xbr_node_domain}", xbr_node_type="{xbr_node_type}", xbr_node_license="{xbr_node_license}", xbr_node_config="{xbr_node_config}")', xbr_node_id=hlid( '0x' + binascii.b2a_hex(xbr_node_id).decode()), xbr_node_domain=hlid( '0x' + binascii.b2a_hex(xbr_node_domain).decode()), xbr_node_type=hlid(xbr_node_type), xbr_node_config=hlid(xbr_node_config), xbr_node_license=hlid(xbr_node_license)) self._license = License(xbr_node_license) self.log.info( 'Node is registered in the XBR network with license type={license}', license=self._license.type) # if a (hash of a) configuration is set on-chain for the master node, fetch the # configuration content for the hash from IPFS if xbr_node_config: if 'IPFS_GATEWAY_URL' in os.environ: ipfs_gateway_url = os.environ['IPFS_GATEWAY_URL'] self.log.info( 'Using explicit IPFS gateway URL {ipfs_gateway_url} from environment variable IPFS_GATEWAY_URL', ipfs_gateway_url=hlid(ipfs_gateway_url)) else: ipfs_gateway_url = 'https://ipfs.infura.io:5001' self.log.info( 'Using default IPFS Infura gateway URL {ipfs_gateway_url}', ipfs_gateway_url=hlid(ipfs_gateway_url)) ipfs_config_url = '{}/api/v0/cat?arg={}&encoding=json'.format( ipfs_gateway_url, xbr_node_config) resp = requests.get(ipfs_config_url) xbr_node_config_data = resp.json() from pprint import pprint pprint(xbr_node_config_data) self.personality.check_config(self.personality, xbr_node_config_data) if 'controller' not in xbr_node_config_data: xbr_node_config_data['controller'] = {} if 'id' not in xbr_node_config_data['controller']: xbr_node_config_data['controller']['id'] = str( uuid.UUID(bytes=xbr_node_id)) self.log.info( 'Deriving node ID {node_id} from XBR network node ID', node_id=hlid( xbr_node_config_data['controller']['id'])) else: self.log.info( 'Setting node ID {node_id} from XBR network node configuration', node_id=hlid( xbr_node_config_data['controller']['id'])) self._config = xbr_node_config_data self.log.info( 'Node configuration loaded from XBR network (xbr_node_id="{xbr_node_id}")', xbr_node_id=hlid( '0x' + binascii.b2a_hex(xbr_node_id).decode())) else: self.log.debug( 'There is no node configuration stored in XBR network (xbr_node_id="{xbr_node_id}")', xbr_node_id=hlid( '0x' + binascii.b2a_hex(xbr_node_id).decode())) config_source = self.CONFIG_SOURCE_XBRNETWORK else: self.log.warn( 'Could not find node public key on blockchain yet') else: self.log.warn('Could not connect to Ethereum blockchain') # 4/4: check and set the final merged master node configuration # self.personality.check_config(self.personality, config) self._config = config self.log.debug( 'Master node config after (effective after merge):\n{config}', config=pformat(config)) return config_source, config_path