Example #1
0
 def get_request_monitoring(
     self,
     privkey: str,
     reward_amount: TokenAmount,
     monitoring_service_contract_address: Address,
 ) -> RequestMonitoring:
     """Returns raiden client's RequestMonitoring object"""
     non_closing_signer = LocalSigner(decode_hex(privkey))
     partner_signed_self = SignedBlindedBalanceProof(
         channel_identifier=self.channel_identifier,
         token_network_address=self.token_network_address,
         nonce=self.nonce,
         additional_hash=decode_hex(self.additional_hash),
         chain_id=self.chain_id,
         signature=self.signature,
         balance_hash=decode_hex(self.balance_hash),
     )
     request_monitoring = RequestMonitoring(
         balance_proof=partner_signed_self,
         reward_amount=reward_amount,
         signature=EMPTY_SIGNATURE,
         monitoring_service_contract_address=
         monitoring_service_contract_address,
     )
     request_monitoring.sign(non_closing_signer)
     return request_monitoring
Example #2
0
    def f(chain_id=1, **kwargs):
        balance_proof = make_balance_proof(signer=signer, **kwargs)
        balance_proof.chain_id = chain_id
        partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state(
            balance_proof)
        request_monitoring = RequestMonitoring(
            onchain_balance_proof=partner_signed_balance_proof,
            reward_amount=TokenAmount(55))
        request_monitoring.sign(non_closing_signer)

        # usually not a property of RequestMonitoring, but added for convenience in these tests
        request_monitoring.non_closing_signer = to_checksum_address(  # type: ignore
            non_closing_signer.address)
        return request_monitoring
Example #3
0
 def f(amount=1, nonce=1):
     balance_proof = make_balance_proof(signer=signer,
                                        amount=amount,
                                        nonce=nonce)
     partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state(
         balance_proof, )
     request_monitoring = RequestMonitoring(
         onchain_balance_proof=partner_signed_balance_proof,
         reward_amount=55,
     )
     request_monitoring.sign(non_closing_signer)
     request_monitoring.non_closing_signer = to_checksum_address(
         non_closing_signer.address)
     return request_monitoring
Example #4
0
 def store_successful(**kwargs):
     rm_dict = request_monitoring.to_dict()
     for key, val in kwargs.items():
         rm_dict[key] = val
     request_collector.on_monitor_request(
         RequestMonitoring.from_dict(rm_dict), )
     return ms_database.monitor_request_count() == 1
Example #5
0
 def store_successful(reward_proof_signature=None, **kwargs):
     request_monitoring = build_request_monitoring(**kwargs)
     rm_dict = request_monitoring.to_dict()
     if reward_proof_signature:
         rm_dict['reward_proof_signature'] = reward_proof_signature
     request_collector.on_monitor_request(RequestMonitoring.from_dict(rm_dict))
     return ms_database.monitor_request_count() == 1
Example #6
0
def run_test_create_monitoring_request(raiden_network, token_addresses):
    app0, app1 = raiden_network
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    payment_network_id = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        chain_state=chain_state,
        payment_network_id=payment_network_id,
        token_address=token_address,
    )

    payment_identifier = create_default_identifier()
    transfer(
        initiator_app=app1,
        target_app=app0,
        token_address=token_address,
        amount=1,
        identifier=payment_identifier,
    )
    chain_state = views.state_from_raiden(app0.raiden)
    channel_state = views.get_channelstate_by_token_network_and_partner(
        chain_state,
        token_network_identifier,
        app1.raiden.address,
    )
    balance_proof = channel_state.partner_state.balance_proof
    api = RaidenAPI(app0.raiden)
    request = api.create_monitoring_request(
        balance_proof=balance_proof,
        reward_amount=1,
    )
    assert request
    as_dict = request.to_dict()
    from_dict = RequestMonitoring.from_dict(as_dict)
    assert from_dict.to_dict() == as_dict
Example #7
0
def update_monitoring_service_from_balance_proof(
    raiden: 'RaidenService',
    chain_state: 'ChainState',
    new_balance_proof: BalanceProofSignedState,
) -> None:
    if raiden.config['services']['monitoring_enabled'] is False:
        return

    channel_state = views.get_channelstate_by_canonical_identifier(
        chain_state=chain_state,
        canonical_identifier=new_balance_proof.canonical_identifier,
    )

    msg = (
        f'Failed to update monitoring service due to inability to find '
        f'channel: {new_balance_proof.channel_identifier} '
        f'token_network_address: {pex(new_balance_proof.token_network_identifier)}.'
    )
    assert channel_state, msg

    balance = channel.get_balance(
        sender=channel_state.our_state,
        receiver=channel_state.partner_state,
    )

    if balance < MONITORING_MIN_CAPACITY:
        log.warn(
            f'Skipping update to Monitoring service. '
            f'Available balance of {balance} is less than configured '
            f'minimum capacity of {MONITORING_MIN_CAPACITY}', )
        return

    rei_balance = raiden.user_deposit.effective_balance(
        raiden.address, 'latest')
    if rei_balance < MONITORING_REWARD:
        rdn_balance = to_rdn(rei_balance)
        rdn_reward = to_rdn(MONITORING_REWARD)
        log.warn(
            f'Skipping update to Monitoring service. '
            f'Your deposit balance {rdn_balance} is less than '
            f'the required monitoring service reward of {rdn_reward}', )
        return

    log.info(
        'Received new balance proof, creating message for Monitoring Service.',
        balance_proof=new_balance_proof,
    )

    monitoring_message = RequestMonitoring.from_balance_proof_signed_state(
        new_balance_proof,
        MONITORING_REWARD,
    )
    monitoring_message.sign(raiden.signer)
    raiden.transport.send_global(
        constants.MONITORING_BROADCASTING_ROOM,
        monitoring_message,
    )
Example #8
0
    def get_request_monitoring(
        self, balance_proof: HashedBalanceProof, reward_amount: TokenAmount
    ) -> RequestMonitoring:
        """Get RequestMonitoring (as sent by the client) message for a given balance proof."""
        assert balance_proof.signature

        non_closing_signer = LocalSigner(decode_hex(self.privkey))
        partner_signed_balance_proof = SignedBlindedBalanceProof(
            channel_identifier=balance_proof.channel_identifier,
            token_network_address=decode_hex(balance_proof.token_network_address),
            nonce=balance_proof.nonce,
            additional_hash=decode_hex(balance_proof.additional_hash),
            chain_id=balance_proof.chain_id,
            signature=decode_hex(balance_proof.signature),
            balance_hash=decode_hex(balance_proof.balance_hash),
        )
        request_monitoring = RequestMonitoring(
            onchain_balance_proof=partner_signed_balance_proof, reward_amount=reward_amount
        )
        request_monitoring.sign(non_closing_signer)
        return request_monitoring
Example #9
0
 def create_monitoring_request(
     self, balance_proof: BalanceProofSignedState, reward_amount: TokenAmount
 ) -> Optional[RequestMonitoring]:
     """ This method can be used to create a `RequestMonitoring` message.
     It will contain all data necessary for an external monitoring service to
     - send an updateNonClosingBalanceProof transaction to the TokenNetwork contract,
     for the `balance_proof` that we received from a channel partner.
     - claim the `reward_amount` from the UDC.
     """
     # create RequestMonitoring message from the above + `reward_amount`
     monitor_request = RequestMonitoring.from_balance_proof_signed_state(
         balance_proof=balance_proof, reward_amount=reward_amount
     )
     # sign RequestMonitoring and return
     monitor_request.sign(self.raiden.signer)
     return monitor_request
Example #10
0
 def handle_received_balance_proof(
     raiden: RaidenService,
     new_balance_proof_event: EventNewBalanceProofReceived,
 ):
     log.info(
         'Received balance proof, creating message for Monitoring Service',
         evt=new_balance_proof_event,
     )
     reward_amount = 0  # FIXME: default reward is 0, should come from elsewhere
     monitoring_message = RequestMonitoring.from_balance_proof_signed_state(
         new_balance_proof_event.balance_proof,
         reward_amount,
     )
     monitoring_message.sign(raiden.signer)
     raiden.transport.send_global(
         MONITORING_BROADCASTING_ROOM,
         monitoring_message,
     )
Example #11
0
def update_monitoring_service_from_balance_proof(
    raiden: RaidenService,
    new_balance_proof: BalanceProofSignedState,
):
    if raiden.config['services']['monitoring_enabled'] is False:
        return None
    log.info(
        'Received new balance proof, creating message for Monitoring Service.',
        balance_proof=new_balance_proof,
    )
    reward_amount = 0  # FIXME: default reward is 0, should come from elsewhere
    monitoring_message = RequestMonitoring.from_balance_proof_signed_state(
        new_balance_proof,
        reward_amount,
    )
    monitoring_message.sign(raiden.signer)
    raiden.transport.send_global(
        constants.MONITORING_BROADCASTING_ROOM,
        monitoring_message,
    )
Example #12
0
def test_request_monitoring():
    partner_signer = LocalSigner(PARTNER_PRIVKEY)
    balance_proof = make_balance_proof(signer=partner_signer, amount=1)
    partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state(
        balance_proof, )
    request_monitoring = RequestMonitoring(
        onchain_balance_proof=partner_signed_balance_proof,
        reward_amount=55,
    )
    assert request_monitoring
    with pytest.raises(ValueError):
        request_monitoring.to_dict()
    request_monitoring.sign(signer)
    as_dict = request_monitoring.to_dict()
    assert RequestMonitoring.from_dict(as_dict) == request_monitoring
    packed = request_monitoring.pack(request_monitoring.packed())
    assert RequestMonitoring.unpack(packed) == request_monitoring
    # RequestMonitoring can be created directly from BalanceProofSignedState
    direct_created = RequestMonitoring.from_balance_proof_signed_state(
        balance_proof,
        reward_amount=55,
    )
    with pytest.raises(ValueError):
        # equality test uses `validated` packed format
        assert direct_created == request_monitoring

    direct_created.sign(signer)
    # Instances created from same balance proof are equal
    assert direct_created == request_monitoring
    other_balance_proof = make_balance_proof(signer=partner_signer, amount=2)
    other_instance = RequestMonitoring.from_balance_proof_signed_state(
        other_balance_proof,
        reward_amount=55,
    )
    other_instance.sign(signer)
    # different balance proof ==> non-equality
    assert other_instance != request_monitoring

    # test signature verification
    reward_proof_data = pack_reward_proof(
        request_monitoring.balance_proof.channel_identifier,
        request_monitoring.reward_amount,
        request_monitoring.balance_proof.token_network_address,
        request_monitoring.balance_proof.chain_id,
        request_monitoring.balance_proof.nonce,
    )

    assert recover(reward_proof_data,
                   request_monitoring.reward_proof_signature) == ADDRESS

    blinded_data = pack_balance_proof_update(
        nonce=request_monitoring.balance_proof.nonce,
        balance_hash=request_monitoring.balance_proof.balance_hash,
        additional_hash=request_monitoring.balance_proof.additional_hash,
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=request_monitoring.balance_proof.chain_id,
            token_network_address=request_monitoring.balance_proof.
            token_network_address,
            channel_identifier=request_monitoring.balance_proof.
            channel_identifier,
        ),
        partner_signature=request_monitoring.balance_proof.signature,
    )
    assert recover(blinded_data,
                   request_monitoring.non_closing_signature) == ADDRESS

    balance_proof_data = pack_balance_proof(
        nonce=request_monitoring.balance_proof.nonce,
        balance_hash=request_monitoring.balance_proof.balance_hash,
        additional_hash=request_monitoring.balance_proof.additional_hash,
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=request_monitoring.balance_proof.chain_id,
            token_network_address=request_monitoring.balance_proof.
            token_network_address,
            channel_identifier=request_monitoring.balance_proof.
            channel_identifier,
        ),
    )
    assert recover(
        balance_proof_data,
        request_monitoring.balance_proof.signature,
    ) == PARTNER_ADDRESS

    assert request_monitoring.verify_request_monitoring(
        PARTNER_ADDRESS, ADDRESS)
Example #13
0
def test_tamper_request_monitoring():
    """ This test shows ways, how the current implementation of the RequestMonitoring's
    signature scheme might be used by an attacker to tamper with the BalanceProof that is
    incorporated in the RequestMonitoring message, if not all three signatures are verified."""
    properties = factories.BalanceProofSignedStateProperties(
        pkey=PARTNER_PRIVKEY)
    balance_proof = factories.create(properties)

    partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state(
        balance_proof)
    request_monitoring = RequestMonitoring(
        onchain_balance_proof=partner_signed_balance_proof, reward_amount=55)
    request_monitoring.sign(signer)

    # This is the signature, that is supposed to authenticate the message that a monitoring
    # service receives from a node. Note: It is generated on a valid Balance proof here and reused
    # to authenticate invalid messages throughout the rest of the test.
    exploited_signature = request_monitoring.reward_proof_signature

    reward_proof_data = pack_reward_proof(
        canonical_identifier=factories.make_canonical_identifier(
            chain_identifier=request_monitoring.balance_proof.chain_id,
            token_network_address=request_monitoring.balance_proof.
            token_network_address,
            channel_identifier=request_monitoring.balance_proof.
            channel_identifier,
        ),
        reward_amount=request_monitoring.reward_amount,
        nonce=request_monitoring.balance_proof.nonce,
    )

    # An attacker might change the balance hash
    partner_signed_balance_proof.balance_hash = "tampered".encode()

    tampered_balance_hash_request_monitoring = RequestMonitoring(
        onchain_balance_proof=partner_signed_balance_proof, reward_amount=55)

    tampered_bp = tampered_balance_hash_request_monitoring.balance_proof
    tampered_balance_hash_reward_proof_data = pack_reward_proof(
        canonical_identifier=factories.make_canonical_identifier(
            chain_identifier=tampered_bp.chain_id,
            token_network_address=tampered_bp.token_network_address,
            channel_identifier=tampered_bp.channel_identifier,
        ),
        reward_amount=tampered_balance_hash_request_monitoring.reward_amount,
        nonce=tampered_balance_hash_request_monitoring.balance_proof.nonce,
    )
    # The signature works/is unaffected by that change...
    recovered_address_tampered = recover(
        tampered_balance_hash_reward_proof_data, exploited_signature)

    assert recover(reward_proof_data,
                   exploited_signature) == recovered_address_tampered
    assert recover(tampered_balance_hash_reward_proof_data,
                   exploited_signature) == ADDRESS

    # ...but overall verification fails
    assert not tampered_balance_hash_request_monitoring.verify_request_monitoring(
        PARTNER_ADDRESS, ADDRESS)

    # An attacker might change the additional_hash
    partner_signed_balance_proof.additional_hash = "tampered".encode()

    tampered_additional_hash_request_monitoring = RequestMonitoring(
        onchain_balance_proof=partner_signed_balance_proof, reward_amount=55)

    tampered_bp = tampered_additional_hash_request_monitoring.balance_proof
    tampered_additional_hash_reward_proof_data = pack_reward_proof(
        canonical_identifier=factories.make_canonical_identifier(
            chain_identifier=tampered_bp.chain_id,
            token_network_address=tampered_bp.token_network_address,
            channel_identifier=tampered_bp.channel_identifier,
        ),
        reward_amount=tampered_additional_hash_request_monitoring.
        reward_amount,
        nonce=tampered_additional_hash_request_monitoring.balance_proof.nonce,
    )

    # The signature works/is unaffected by that change...

    recovered_address_tampered = recover(
        tampered_additional_hash_reward_proof_data, exploited_signature)

    assert recover(reward_proof_data,
                   exploited_signature) == recovered_address_tampered
    assert recovered_address_tampered == ADDRESS

    # ...but overall verification fails
    assert not tampered_balance_hash_request_monitoring.verify_request_monitoring(
        PARTNER_ADDRESS, ADDRESS)
    # An attacker can change the non_closing_signature
    partner_signed_balance_proof.non_closing_signature = "tampered".encode()

    tampered_non_closing_signature_request_monitoring = RequestMonitoring(
        onchain_balance_proof=partner_signed_balance_proof, reward_amount=55)

    tampered_bp = tampered_non_closing_signature_request_monitoring.balance_proof
    tampered_non_closing_signature_reward_proof_data = pack_reward_proof(
        canonical_identifier=factories.make_canonical_identifier(
            chain_identifier=tampered_bp.chain_id,
            token_network_address=tampered_bp.token_network_address,
            channel_identifier=tampered_bp.channel_identifier,
        ),
        reward_amount=tampered_non_closing_signature_request_monitoring.
        reward_amount,
        nonce=tampered_non_closing_signature_request_monitoring.balance_proof.
        nonce,
    )

    # The signature works/is unaffected by that change...

    recovered_address_tampered = recover(
        tampered_non_closing_signature_reward_proof_data, exploited_signature)
    assert recover(reward_proof_data,
                   exploited_signature) == recovered_address_tampered
    assert recovered_address_tampered == ADDRESS

    # ...but overall verification fails
    assert not tampered_non_closing_signature_request_monitoring.verify_request_monitoring(
        PARTNER_ADDRESS, ADDRESS)