コード例 #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=AdditionalHash(decode_hex(self.additional_hash)),
         chain_id=self.chain_id,
         signature=self.signature,
         balance_hash=BalanceHash(decode_hex(self.balance_hash)),
     )
     request_monitoring = RequestMonitoring(
         balance_proof=partner_signed_self,
         non_closing_participant=privatekey_to_address(decode_hex(privkey)),
         reward_amount=reward_amount,
         signature=EMPTY_SIGNATURE,
         monitoring_service_contract_address=
         monitoring_service_contract_address,
     )
     request_monitoring.sign(non_closing_signer)
     return request_monitoring
コード例 #2
0
ファイル: services.py プロジェクト: weilbith/raiden
def update_monitoring_service_from_balance_proof(
    raiden: "RaidenService",
    chain_state: ChainState,
    new_balance_proof: BalanceProofSignedState,
    non_closing_participant: Address,
) -> None:
    if raiden.config.services.monitoring_enabled is False:
        return

    msg = f"Monitoring is enabled but the default monitoring service address is None."
    assert raiden.default_msc_address is not None, msg

    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: {to_checksum_address(new_balance_proof.token_network_address)}."
    )
    assert channel_state, msg

    msg = f"Monitoring is enabled but the `UserDeposit` contract is None."
    assert raiden.user_deposit is not None, msg
    rei_balance = raiden.user_deposit.effective_balance(
        raiden.address, BLOCK_ID_LATEST)
    if rei_balance < MONITORING_REWARD:
        rdn_balance = to_rdn(rei_balance)
        rdn_reward = to_rdn(MONITORING_REWARD)
        log.warning(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.",
        node=to_checksum_address(raiden.address),
        balance_proof=new_balance_proof,
    )

    monitoring_message = RequestMonitoring.from_balance_proof_signed_state(
        balance_proof=new_balance_proof,
        non_closing_participant=non_closing_participant,
        reward_amount=MONITORING_REWARD,
        monitoring_service_contract_address=raiden.default_msc_address,
    )
    monitoring_message.sign(raiden.signer)
    raiden.transport.broadcast(constants.MONITORING_BROADCASTING_ROOM,
                               monitoring_message)
コード例 #3
0
ファイル: services.py プロジェクト: sekmet/raiden
def update_monitoring_service_from_balance_proof(
    raiden: "RaidenService",
    chain_state: ChainState,
    new_balance_proof: BalanceProofSignedState,
    non_closing_participant: Address,
) -> None:
    if raiden.config.services.monitoring_enabled is False:
        return

    msg = "Monitoring is enabled but the default monitoring service address is None."
    assert raiden.default_msc_address is not None, msg

    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: {to_checksum_address(new_balance_proof.token_network_address)}."
    )
    assert channel_state, msg

    msg = "Monitoring is enabled but the `UserDeposit` contract is None."
    assert raiden.default_user_deposit is not None, msg
    rei_balance = raiden.default_user_deposit.effective_balance(
        raiden.address, BLOCK_ID_LATEST)
    if rei_balance < MONITORING_REWARD:
        rdn_balance = to_rdn(rei_balance)
        rdn_reward = to_rdn(MONITORING_REWARD)
        log.warning(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

    # In production there should be no MonitoringRequest if
    # channel balance is below a certain threshold. This is
    # a naive approach that needs to be worked on in the future
    if raiden.config.environment_type == Environment.PRODUCTION:
        message = ("Skipping update to Monitoring service. "
                   "Your channel balance {channel_balance} is less than "
                   "the required minimum balance of {min_balance} ")

        dai_token_network_address = views.get_token_network_address_by_token_address(
            chain_state=chain_state,
            token_network_registry_address=raiden.default_registry.address,
            token_address=DAI_TOKEN_ADDRESS,
        )
        weth_token_network_address = views.get_token_network_address_by_token_address(
            chain_state=chain_state,
            token_network_registry_address=raiden.default_registry.address,
            token_address=WETH_TOKEN_ADDRESS,
        )
        channel_balance = get_balance(
            sender=channel_state.our_state,
            receiver=channel_state.partner_state,
        )

        if channel_state.canonical_identifier.token_network_address == dai_token_network_address:
            if channel_balance < MIN_MONITORING_AMOUNT_DAI:
                data = dict(
                    channel_balance=channel_balance,
                    min_balance=MIN_MONITORING_AMOUNT_DAI,
                    channel_id=channel_state.canonical_identifier.
                    channel_identifier,
                    token_address=to_checksum_address(DAI_TOKEN_ADDRESS),
                )
                log.warning(message.format(**data), **data)
                return
        if channel_state.canonical_identifier.token_network_address == weth_token_network_address:
            if channel_balance < MIN_MONITORING_AMOUNT_WETH:
                data = dict(
                    channel_balance=channel_balance,
                    min_balance=MIN_MONITORING_AMOUNT_WETH,
                    channel_id=channel_state.canonical_identifier.
                    channel_identifier,
                    token_address=to_checksum_address(WETH_TOKEN_ADDRESS),
                )
                log.warning(message.format(**data), **data)
                return

    log.info(
        "Received new balance proof, creating message for Monitoring Service.",
        node=to_checksum_address(raiden.address),
        balance_proof=new_balance_proof,
    )

    monitoring_message = RequestMonitoring.from_balance_proof_signed_state(
        balance_proof=new_balance_proof,
        non_closing_participant=non_closing_participant,
        reward_amount=MONITORING_REWARD,
        monitoring_service_contract_address=raiden.default_msc_address,
    )
    monitoring_message.sign(raiden.signer)
    raiden.transport.broadcast(constants.MONITORING_BROADCASTING_ROOM,
                               monitoring_message)
コード例 #4
0
def test_request_monitoring() -> None:
    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(
        balance_proof=partner_signed_balance_proof,
        non_closing_participant=ADDRESS,
        reward_amount=TokenAmount(55),
        signature=EMPTY_SIGNATURE,
        monitoring_service_contract_address=MSC_ADDRESS,
    )
    assert request_monitoring
    request_monitoring.sign(signer)
    as_dict = DictSerializer.serialize(request_monitoring)
    assert DictSerializer.deserialize(as_dict) == request_monitoring
    # RequestMonitoring can be created directly from BalanceProofSignedState
    direct_created = RequestMonitoring.from_balance_proof_signed_state(
        balance_proof=balance_proof,
        non_closing_participant=ADDRESS,
        reward_amount=TokenAmount(55),
        monitoring_service_contract_address=MSC_ADDRESS,
    )
    # `direct_created` is not signed while request_monitoring is
    assert DictSerializer().serialize(
        direct_created) != DictSerializer().serialize(request_monitoring)

    direct_created.sign(signer)
    # Instances created from same balance proof are equal
    assert direct_created == request_monitoring
    other_balance_proof = factories.create(
        factories.replace(properties, message_hash=keccak(b"2")))
    other_instance = RequestMonitoring.from_balance_proof_signed_state(
        balance_proof=other_balance_proof,
        non_closing_participant=ADDRESS,
        reward_amount=TokenAmount(55),
        monitoring_service_contract_address=MSC_ADDRESS,
    )
    other_instance.sign(signer)
    # different balance proof ==> non-equality
    assert other_instance != request_monitoring

    # test signature verification
    assert request_monitoring.non_closing_signature
    reward_proof_data = pack_reward_proof(
        token_network_address=request_monitoring.balance_proof.
        token_network_address,
        chain_id=request_monitoring.balance_proof.chain_id,
        reward_amount=request_monitoring.reward_amount,
        monitoring_service_contract_address=MSC_ADDRESS,
        non_closing_participant=ADDRESS,
        non_closing_signature=request_monitoring.non_closing_signature,
    )

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

    blinded_data = pack_signed_balance_proof(
        msg_type=MessageTypeId.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=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,
        ),
        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=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,
        ),
    )
    assert (recover(
        balance_proof_data,
        request_monitoring.balance_proof.signature) == PARTNER_ADDRESS)

    assert request_monitoring.verify_request_monitoring(
        PARTNER_ADDRESS, ADDRESS)
コード例 #5
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."""
    msc_address = bytes([1] * 20)
    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(
        balance_proof=partner_signed_balance_proof,
        reward_amount=55,
        signature=EMPTY_SIGNATURE,
        monitoring_service_contract_address=msc_address,
        non_closing_participant=ADDRESS,
    )
    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(
        chain_id=request_monitoring.balance_proof.chain_id,
        token_network_address=request_monitoring.balance_proof.
        token_network_address,
        reward_amount=request_monitoring.reward_amount,
        monitoring_service_contract_address=msc_address,
        non_closing_participant=ADDRESS,
        non_closing_signature=request_monitoring.non_closing_signature,
    )

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

    tampered_balance_hash_request_monitoring = RequestMonitoring(
        balance_proof=partner_signed_balance_proof,
        reward_amount=55,
        non_closing_participant=ADDRESS,
        signature=EMPTY_SIGNATURE,
        monitoring_service_contract_address=MSC_ADDRESS,
    )

    tampered_bp = tampered_balance_hash_request_monitoring.balance_proof
    tampered_balance_hash_reward_proof_data = pack_reward_proof(
        chain_id=tampered_bp.chain_id,
        token_network_address=request_monitoring.balance_proof.
        token_network_address,
        reward_amount=tampered_balance_hash_request_monitoring.reward_amount,
        monitoring_service_contract_address=msc_address,
        non_closing_participant=ADDRESS,
        non_closing_signature=request_monitoring.non_closing_signature,
    )
    # 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(
        balance_proof=partner_signed_balance_proof,
        reward_amount=55,
        signature=EMPTY_SIGNATURE,
        monitoring_service_contract_address=MSC_ADDRESS,
        non_closing_participant=ADDRESS,
    )

    tampered_bp = tampered_additional_hash_request_monitoring.balance_proof
    tampered_additional_hash_reward_proof_data = pack_reward_proof(
        chain_id=tampered_bp.chain_id,
        token_network_address=(tampered_additional_hash_request_monitoring.
                               balance_proof.token_network_address),
        reward_amount=tampered_additional_hash_request_monitoring.
        reward_amount,
        monitoring_service_contract_address=msc_address,
        non_closing_participant=ADDRESS,
        non_closing_signature=request_monitoring.non_closing_signature,
    )

    # 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(
        balance_proof=partner_signed_balance_proof,
        reward_amount=55,
        signature=EMPTY_SIGNATURE,
        monitoring_service_contract_address=MSC_ADDRESS,
        non_closing_participant=ADDRESS,
    )

    tampered_bp = tampered_non_closing_signature_request_monitoring.balance_proof
    tampered_non_closing_signature_reward_proof_data = pack_reward_proof(
        chain_id=tampered_bp.chain_id,
        token_network_address=(
            tampered_non_closing_signature_request_monitoring.balance_proof.
            token_network_address),
        reward_amount=tampered_non_closing_signature_request_monitoring.
        reward_amount,
        monitoring_service_contract_address=msc_address,
        non_closing_participant=ADDRESS,
        non_closing_signature=request_monitoring.non_closing_signature,
    )

    # 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)
コード例 #6
0
def test_encoding_and_decoding():
    message_factories = (
        factories.LockedTransferProperties(),
        factories.RefundTransferProperties(),
        factories.LockExpiredProperties(),
        factories.UnlockProperties(),
    )
    messages = [factories.create(factory) for factory in message_factories]

    # TODO Handle these with factories once #5091 is implemented
    messages.append(
        Delivered(
            delivered_message_identifier=factories.make_message_identifier(),
            signature=factories.make_signature(),
        ))
    messages.append(
        Processed(
            message_identifier=factories.make_message_identifier(),
            signature=factories.make_signature(),
        ))
    messages.append(
        RevealSecret(
            message_identifier=factories.make_message_identifier(),
            secret=factories.make_secret(),
            signature=factories.make_signature(),
        ))
    messages.append(
        SecretRequest(
            message_identifier=factories.make_message_identifier(),
            payment_identifier=factories.make_payment_id(),
            secrethash=factories.make_secret_hash(),
            amount=factories.make_token_amount(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        WithdrawRequest(
            message_identifier=factories.make_message_identifier(),
            chain_id=factories.make_chain_id(),
            token_network_address=factories.make_token_network_address(),
            channel_identifier=factories.make_channel_identifier(),
            participant=factories.make_address(),
            total_withdraw=factories.make_token_amount(),
            nonce=factories.make_nonce(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        WithdrawConfirmation(
            message_identifier=factories.make_message_identifier(),
            chain_id=factories.make_chain_id(),
            token_network_address=factories.make_token_network_address(),
            channel_identifier=factories.make_channel_identifier(),
            participant=factories.make_address(),
            total_withdraw=factories.make_token_amount(),
            nonce=factories.make_nonce(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        WithdrawExpired(
            message_identifier=factories.make_message_identifier(),
            chain_id=factories.make_chain_id(),
            token_network_address=factories.make_token_network_address(),
            channel_identifier=factories.make_channel_identifier(),
            participant=factories.make_address(),
            total_withdraw=factories.make_token_amount(),
            nonce=factories.make_nonce(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        PFSCapacityUpdate(
            canonical_identifier=factories.make_canonical_identifier(),
            updating_participant=factories.make_address(),
            other_participant=factories.make_address(),
            updating_nonce=factories.make_nonce(),
            other_nonce=factories.make_nonce(),
            updating_capacity=factories.make_token_amount(),
            other_capacity=factories.make_token_amount(),
            reveal_timeout=factories.make_uint64(),
            signature=factories.make_signature(),
        ))
    messages.append(
        PFSFeeUpdate(
            canonical_identifier=factories.make_canonical_identifier(),
            updating_participant=factories.make_address(),
            fee_schedule=factories.create(
                factories.FeeScheduleStateProperties()),
            timestamp=datetime.now(),
            signature=factories.make_signature(),
        ))
    messages.append(
        RequestMonitoring(
            reward_amount=factories.make_token_amount(),
            balance_proof=SignedBlindedBalanceProof.
            from_balance_proof_signed_state(
                factories.create(
                    factories.BalanceProofSignedStateProperties())),
            monitoring_service_contract_address=factories.make_address(),
            non_closing_participant=factories.make_address(),
            non_closing_signature=factories.make_signature(),
            signature=factories.make_signature(),
        ))

    for message in messages:
        serialized = MessageSerializer.serialize(message)
        deserialized = MessageSerializer.deserialize(serialized)
        assert deserialized == message
コード例 #7
0
)
messages.append(
    PFSFeeUpdate(
        canonical_identifier=factories.make_canonical_identifier(),
        updating_participant=factories.make_address(),
        fee_schedule=factories.create(factories.FeeScheduleStateProperties()),
        timestamp=datetime(2000, 1, 1),
        signature=factories.make_signature(),
    )
)
messages.append(
    RequestMonitoring(
        reward_amount=factories.make_token_amount(),
        balance_proof=SignedBlindedBalanceProof.from_balance_proof_signed_state(
            factories.create(factories.BalanceProofSignedStateProperties())
        ),
        monitoring_service_contract_address=factories.make_monitoring_service_address(),
        non_closing_participant=factories.make_address(),
        non_closing_signature=factories.make_signature(),
        signature=factories.make_signature(),
    )
)


@dataclass
class ClassWithGraphObject:
    graph: Graph


@dataclass
class ClassWithInt:
    value: int