Beispiel #1
0
 def __init__(self, wallet, deposit_amount=DEFAULT_DEPOSIT_AMOUNT, duration=DEFAULT_DURATION, close_amount=DEFAULT_CLOSE_AMOUNT):
     """Initialize the channel requests with a payment channel client."""
     super().__init__()
     from two1.lib.channels import PaymentChannelClient
     self._channelclient = PaymentChannelClient(wallet)
     self._deposit_amount = deposit_amount
     self._duration = duration
     self._close_amount = close_amount
Beispiel #2
0
    def __init__(self,
                 config_file=TWO1_CONFIG_FILE,
                 config=None,
                 create_wallet=True):
        if not os.path.exists(TWO1_USER_FOLDER):
            os.makedirs(TWO1_USER_FOLDER)
        self.file = path(config_file).expand().abspath()
        self.dir = self.file.parent
        self.defaults = {
        }  # TODO: Rename this var. Those are not the defaults but the actual values.
        self.json_output = False  # output in json
        #  actual config.
        self.load()
        # override config variables
        if config:
            if self.verbose:
                self.vlog("Applied manual config.")

            for k, v in config:
                self.defaults[k] = v
                if self.verbose:
                    self.vlog("\t{}={}".format(k, v))

        # add wallet object
        if self.defaults.get('testwallet', None) == 'y':
            self.wallet = test_wallet.TestWallet()
        elif create_wallet:
            dp = TwentyOneProvider(TWO1_PROVIDER_HOST)

            wallet_path = self.defaults.get('wallet_path')

            if not Two1Wallet.check_wallet_file(wallet_path):
                # configure wallet with default options
                click.pause(UxString.create_wallet)

                wallet_options = {
                    'data_provider': dp,
                    'wallet_path': wallet_path
                }

                if not Two1Wallet.configure(wallet_options):
                    raise click.ClickException(
                        UxString.Error.create_wallet_failed)

                # Display the wallet mnemonic and tell user to back it up.
                # Read the wallet JSON file and extract it.
                with open(wallet_path, 'r') as f:
                    wallet_config = json.load(f)
                    mnemonic = wallet_config['master_seed']

                click.pause(UxString.create_wallet_done % (mnemonic))

            # Start the daemon, if:
            # 1. It's not already started
            # 2. It's using the default wallet path
            # 3. We're not in a virtualenv
            try:
                d = daemonizer.get_daemonizer()

                if Two1Wallet.is_configured() and \
                   wallet_path == Two1Wallet.DEFAULT_WALLET_PATH and \
                   not os.environ.get("VIRTUAL_ENV") and \
                   not d.started():
                    d.start()
                    if d.started():
                        click.echo(UxString.wallet_daemon_started)
            except (OSError, DaemonizerError):
                pass

            self.wallet = Wallet(wallet_path=wallet_path, data_provider=dp)
            self.machine_auth = MachineAuthWallet(self.wallet)
            self.channel_client = PaymentChannelClient(self.wallet)
        else:
            # This branch is hit when '21 help' or '21 update' is invoked
            pass
Beispiel #3
0
class ChannelRequests(BitRequests):

    """BitRequests for making channel payments."""

    HTTP_BITCOIN_PRICE = 'price'
    HTTP_BITCOIN_MICROPAYMENT_SERVER = 'bitcoin-micropayment-server'
    HTTP_BITCOIN_MICROPAYMENT_TOKEN = 'bitcoin-micropayment-token'

    DEFAULT_DEPOSIT_AMOUNT = 100000
    DEFAULT_DURATION = 86400
    DEFAULT_CLOSE_AMOUNT = 1000

    def __init__(self, wallet, deposit_amount=DEFAULT_DEPOSIT_AMOUNT, duration=DEFAULT_DURATION, close_amount=DEFAULT_CLOSE_AMOUNT):
        """Initialize the channel requests with a payment channel client."""
        super().__init__()
        from two1.lib.channels import PaymentChannelClient
        self._channelclient = PaymentChannelClient(wallet)
        self._deposit_amount = deposit_amount
        self._duration = duration
        self._close_amount = close_amount

    def make_402_payment(self, response, max_price):
        """Make a channel payment."""

        # Retrieve payment headers
        price = response.headers.get(ChannelRequests.HTTP_BITCOIN_PRICE)
        server_url = response.headers.get(ChannelRequests.HTTP_BITCOIN_MICROPAYMENT_SERVER)

        # Verify that the payment method is supported
        if price is None or server_url is None:
            raise UnsupportedPaymentMethodError(
                'Resource does not support channels payment method.')

        # Convert string headers into correct data types
        price = int(price)

        # Verify resource cost against our budget
        if max_price and price > max_price:
            max_price_err = 'Resource price ({}) exceeds max price ({}).'
            raise ValueError(max_price_err.format(price, max_price))

        # Look up channel
        channel_urls = self._channelclient.list(server_url)
        channel_url = channel_urls[0] if channel_urls else None

        if channel_url:
            # Get channel status
            status = self._channelclient.status(channel_url)

            # Check if channel has expired
            if status.ready and status.expired:
                logger.debug("[ChannelRequests] Channel expired. Refreshing channel.")
                self._channelclient.sync(channel_url)
                channel_url = None

            # Check if the channel balance is sufficient
            elif status.ready and (status.balance - price) < self._close_amount:
                logger.debug("[ChannelRequests] Channel balance low. Refreshing channel.")
                self._channelclient.close(channel_url)
                status = self._channelclient.status(channel_url)
                logger.debug("[ChannelRequests] Channel spend txid is {}".format(status.spend_txid))
                channel_url = None

        # Open a new channel if we don't have a usable one
        if not channel_url or not status.ready:
            logger.debug("[ChannelRequests] Opening channel at {} with deposit {}.".format(channel_url, self._deposit_amount))
            channel_url = self._channelclient.open(server_url, self._deposit_amount, self._duration, zeroconf=True, use_unconfirmed=True)
            status = self._channelclient.status(channel_url)
            logger.debug("[ChannelRequests] Channel deposit txid is {}".format(status.deposit_txid))

        # Pay through the channel
        logger.debug("[ChannelRequests] Paying channel {} with amount {}.".format(channel_url, price))
        token = self._channelclient.pay(channel_url, price)

        return {ChannelRequests.HTTP_BITCOIN_MICROPAYMENT_TOKEN: token}

    def get_402_info(self, url):
        """Get channel payment information about the resource."""
        response = requests.get(url)
        price = response.headers.get(ChannelRequests.HTTP_BITCOIN_PRICE)
        channel_url = response.headers.get(ChannelRequests.HTTP_BITCOIN_MICROPAYMENT_SERVER)
        return {ChannelRequests.HTTP_BITCOIN_PRICE: price,
                ChannelRequests.HTTP_BITCOIN_MICROPAYMENT_SERVER: channel_url}