def verify_balance_proof(self, sender, open_block_number, balance,
                             signature):
        """Verify that a balance proof is valid and return the sender.

        Does not check the balance itself.

        :returns: the channel
        """
        if (sender, open_block_number) in self.unconfirmed_channels:
            raise InsufficientConfirmations(
                'Insufficient confirmations for the channel '
                '(sender=%s, open_block_number=%d)' %
                (sender, open_block_number))
        try:
            c = self.channels[sender, open_block_number]
        except KeyError:
            raise NoOpenChannel('Channel does not exist or has been closed'
                                '(sender=%s, open_block_number=%s)' %
                                (sender, open_block_number))
        if c.is_closed:
            raise NoOpenChannel('Channel closing has been requested already.')

        if not is_same_address(
                verify_balance_proof(self.receiver, open_block_number, balance,
                                     decode_hex(signature)), sender):
            raise InvalidBalanceProof(
                'Recovered signer does not match the sender')
        return c
Beispiel #2
0
    def on_invalid_amount(self, method: str, url: str, response: Response,
                          **kwargs) -> bool:
        log.debug('Server claims an invalid amount sent.')
        balance_sig = response.headers.get(HTTPHeaders.BALANCE_SIGNATURE)
        if balance_sig:
            balance_sig = decode_hex(balance_sig)
        last_balance = int(response.headers.get(HTTPHeaders.SENDER_BALANCE))

        channel = self.get_channel(url)
        verified = balance_sig and is_same_address(
            verify_balance_proof(
                channel.receiver, channel.block, last_balance, balance_sig,
                self.client.channel_manager_address), channel.sender)

        if verified:
            if last_balance == channel.balance:
                log.error(
                    'Server tried to disguise the last unconfirmed payment as a confirmed payment.'
                )
                return False
            else:
                log.debug(
                    'Server provided proof for a different channel balance ({}). Adopting.'
                    .format(last_balance))
                channel.update_balance(last_balance)
        else:
            log.debug(
                'Server did not provide proof for a different channel balance. Reverting to 0.'
            )
            channel.update_balance(0)

        return self.on_payment_requested(method, url, response, **kwargs)
Beispiel #3
0
def test_verify_balance_proof_v0(channel_manager_contract_address: str):
    sig = sign_balance_proof(SENDER_PRIVATE_KEY, RECEIVER_ADDR, 312524, 11,
                             channel_manager_contract_address)
    sig = sig[:-1] + b'\x00'
    assert verify_balance_proof(
        RECEIVER_ADDR, 312524, 11, sig,
        channel_manager_contract_address) == SENDER_ADDR
Beispiel #4
0
def test_verify_balance_proof_v27(channel_manager_contract_address: str):
    # Should be default but test anyway.
    sig = sign_balance_proof(SENDER_PRIVATE_KEY, RECEIVER_ADDR, 312524, 11,
                             channel_manager_contract_address)
    sig = sig[:-1] + b'\x1b'
    assert verify_balance_proof(
        RECEIVER_ADDR, 312524, 11, sig,
        channel_manager_contract_address) == SENDER_ADDR
    def _sync_balance(self, balance: int, balance_sig: bytes) -> bool:
        if not self.channel:
            # Nothing to verify or sync. Server does not know about a channel yet.
            return True
        elif not balance:
            # Server does know about the channel but cannot confirm its creation yet.
            log.info(
                'Server could not confirm new channel yet. Waiting for {} seconds.'
                .format(self.retry_interval))
            time.sleep(self.retry_interval)
            self.retry = True
            return False

        verified = balance_sig and is_same_address(
            verify_balance_proof(self.channel.receiver, self.channel.block,
                                 balance, balance_sig), self.channel.sender)

        if balance > self.channel.balance:
            if verified:
                log.info(
                    'Server proved a higher channel balance (server/local): {}/{}. Adopting.'
                    .format(balance, self.channel.balance))
                self.channel.balance = balance
            else:
                log.error(
                    'Server could not prove higher channel balance (server/local): {}/{}'
                    .format(balance, self.channel.balance))
                return False

        elif balance < self.channel.balance:
            if verified:
                log.info(
                    'Server sent older balance proof or rejected the last one (server/local): '
                    '{}/{}. Possibly because of an unconfirmed topup. Retrying in {} seconds.'
                    .format(balance, self.channel.balance,
                            self.retry_interval))
                self.channel.balance = balance

                time.sleep(self.retry_interval)
                self.retry = True
                return False
            else:
                log.info(
                    'Server sent lower balance without proof. Attempting to continue on lower '
                    'balance (server/local): {}.'.format(
                        balance, self.channel.balance))
                self.channel.balance = balance

        return True
    def close_cooperatively(self, closing_sig: bytes):
        """
        Attempts to close the channel immediately by providing a hash of the channel's balance
        proof signed by the receiver. This signature must correspond to the balance proof stored in
        the passed channel state.
        """
        if self.state == Channel.State.closed:
            log.error(
                'Channel must not be closed already to be closed cooperatively.'
            )
            return None
        log.info(
            'Attempting to cooperatively close channel to {} created at block #{}.'
            .format(self.receiver, self.block))
        current_block = self.client.web3.eth.blockNumber
        if not is_same_address(
                verify_balance_proof(self.receiver, self.block, self.balance,
                                     closing_sig), self.receiver):
            log.error('Invalid closing signature.')
            return None

        tx = self.client.channel_manager_proxy.create_signed_transaction(
            'close', [
                self.receiver, self.block, self.balance, self.balance_sig,
                closing_sig
            ])
        self.client.web3.eth.sendRawTransaction(tx)

        log.info('Waiting for settle confirmation event...')
        event = self.client.channel_manager_proxy.get_channel_settle_event_blocking(
            self.sender, self.receiver, self.block, current_block + 1)

        if event:
            log.info('Successfully closed channel in block {}.'.format(
                event['blockNumber']))
            self.state = Channel.State.closed
            self.client.store_channels()
            return event
        else:
            log.error('No event received.')
            return None
def test_verify_balance_proof():
    sig = sign_balance_proof(SENDER_PRIVATE_KEY, RECEIVER_ADDR, 315123, 8)
    assert verify_balance_proof(RECEIVER_ADDR, 315123, 8, sig) == SENDER_ADDR
def test_verify_balance_proof_v27():
    # Should be default but test anyway.
    sig = sign_balance_proof(SENDER_PRIVATE_KEY, RECEIVER_ADDR, 312524, 11)
    sig = sig[:-1] + b'\x1b'
    assert verify_balance_proof(RECEIVER_ADDR, 312524, 11, sig) == SENDER_ADDR
def test_verify_balance_proof_v0():
    sig = sign_balance_proof(SENDER_PRIVATE_KEY, RECEIVER_ADDR, 312524, 11)
    sig = sig[:-1] + b'\x00'
    assert verify_balance_proof(RECEIVER_ADDR, 312524, 11, sig) == SENDER_ADDR
Beispiel #10
0
def test_verify_balance_proof(channel_manager_contract_address: str):
    sig = sign_balance_proof(SENDER_PRIVATE_KEY, RECEIVER_ADDR, 315123, 8,
                             channel_manager_contract_address)
    assert verify_balance_proof(
        RECEIVER_ADDR, 315123, 8, sig,
        channel_manager_contract_address) == SENDER_ADDR