Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
    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'
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
    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'
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
    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)
Exemplo n.º 7
0
    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