예제 #1
0
    def get_counter_signature(self, privkey: PrivateKey) -> Signature:
        """Get a signature of this balance proof by the other party

        Useful for `closing_signature` of `TokenNetwork.closeChannel`
        """
        signer = LocalSigner(privkey)
        return signer.sign(self.serialize_bin() + self.signature)
예제 #2
0
def test_waiting_messages(pathfinding_service_mock):
    participant1_privkey, participant1 = make_privkey_address()
    token_network_address = TokenNetworkAddress(b"1" * 20)
    channel_id = ChannelID(1)

    # register token network internally
    database = pathfinding_service_mock.database
    database.conn.execute(
        "INSERT INTO token_network(address) VALUES (?)",
        [to_checksum_address(token_network_address)],
    )

    fee_update = PFSFeeUpdate(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=ChainID(61),
            token_network_address=token_network_address,
            channel_identifier=channel_id,
        ),
        updating_participant=participant1,
        fee_schedule=FeeScheduleState(),
        timestamp=datetime.utcnow(),
        signature=EMPTY_SIGNATURE,
    )
    fee_update.sign(LocalSigner(participant1_privkey))

    capacity_update = PFSCapacityUpdate(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=ChainID(61),
            token_network_address=token_network_address,
            channel_identifier=channel_id,
        ),
        updating_participant=make_address(),
        other_participant=make_address(),
        updating_nonce=Nonce(1),
        other_nonce=Nonce(1),
        updating_capacity=TokenAmount(100),
        other_capacity=TokenAmount(111),
        reveal_timeout=BlockTimeout(50),
        signature=EMPTY_SIGNATURE,
    )
    capacity_update.sign(LocalSigner(participant1_privkey))

    for message in (fee_update, capacity_update):
        database.insert_waiting_message(message)

        recovered_messages = list(
            database.pop_waiting_messages(
                token_network_address=token_network_address,
                channel_id=channel_id))
        assert len(recovered_messages) == 1
        assert message == recovered_messages[0]

        recovered_messages2 = list(
            database.pop_waiting_messages(
                token_network_address=token_network_address,
                channel_id=channel_id))
        assert len(recovered_messages2) == 0
예제 #3
0
 def make_params(timestamp: str):
     params = {
         "sender": to_checksum_address(sender),
         "receiver": to_checksum_address(api_sut.pathfinding_service.address),
         "timestamp": timestamp,
     }
     local_signer = LocalSigner(private_key=privkey)
     params["signature"] = encode_hex(
         local_signer.sign(
             to_canonical_address(params["sender"])
             + to_canonical_address(params["receiver"])
             + params["timestamp"].encode("utf8")
         )
     )
     return params
def get_capacity_update_message(  # pylint: disable=too-many-arguments
    updating_participant: Address,
    other_participant: Address,
    chain_id=ChainID(61),
    channel_identifier=DEFAULT_CHANNEL_ID,
    token_network_address: TokenNetworkAddress = DEFAULT_TOKEN_NETWORK_ADDRESS,
    updating_nonce=Nonce(1),
    other_nonce=Nonce(0),
    updating_capacity=TA(90),
    other_capacity=TA(110),
    reveal_timeout: BlockTimeout = BlockTimeout(2),
    privkey_signer: bytes = PRIVATE_KEY_1,
) -> PFSCapacityUpdate:
    updatepfs_message = PFSCapacityUpdate(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=chain_id,
            channel_identifier=channel_identifier,
            token_network_address=token_network_address,
        ),
        updating_participant=updating_participant,
        other_participant=other_participant,
        updating_nonce=updating_nonce,
        other_nonce=other_nonce,
        updating_capacity=updating_capacity,
        other_capacity=other_capacity,
        reveal_timeout=reveal_timeout,
        signature=EMPTY_SIGNATURE,
    )

    updatepfs_message.sign(LocalSigner(privkey_signer))

    return updatepfs_message
예제 #5
0
 def get_request_monitoring(
     self,
     privkey: PrivateKey,
     reward_amount: TokenAmount,
     monitoring_service_contract_address: MonitoringServiceAddress,
 ) -> RequestMonitoring:
     """Returns raiden client's RequestMonitoring object"""
     non_closing_signer = LocalSigner(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(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
def get_fee_update_message(  # pylint: disable=too-many-arguments
    updating_participant: Address,
    chain_id=ChainID(61),
    channel_identifier=DEFAULT_CHANNEL_ID,
    token_network_address: TokenNetworkAddress = DEFAULT_TOKEN_NETWORK_ADDRESS,
    fee_schedule: FeeScheduleState = FeeScheduleState(
        cap_fees=True,
        flat=FeeAmount(1),
        proportional=ProportionalFeeAmount(1)),
    timestamp: datetime = datetime.utcnow(),
    privkey_signer: bytes = PRIVATE_KEY_1,
) -> PFSFeeUpdate:
    fee_message = PFSFeeUpdate(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=chain_id,
            channel_identifier=channel_identifier,
            token_network_address=token_network_address,
        ),
        updating_participant=updating_participant,
        fee_schedule=fee_schedule,
        timestamp=timestamp,
        signature=EMPTY_SIGNATURE,
    )

    fee_message.sign(LocalSigner(privkey_signer))

    return fee_message
예제 #7
0
    def __init__(
        self,
        available_servers: Optional[List[str]],
        device_id: DeviceIDs,
        chain_id: ChainID,
        private_key: bytes,
        handle_matrix_sync: Callable[[List[MatrixMessage]], bool],
        enable_tracing: bool = False,
    ):
        self.user_manager: Optional[MultiClientUserAddressManager] = None
        self.local_signer = LocalSigner(private_key=private_key)
        self.device_id = device_id
        self.chain_id = chain_id
        self.stop_event = Event()
        self.stop_event.set()
        self._enable_tracing = enable_tracing

        try:
            matrix_known_servers_url = os.environ.get(
                "URL_KNOWN_FEDERATION_SERVERS",
                DEFAULT_MATRIX_KNOWN_SERVERS[Environment.PRODUCTION]
                if chain_id == 1
                else DEFAULT_MATRIX_KNOWN_SERVERS[Environment.DEVELOPMENT],
            )

            self.known_servers = (
                get_matrix_servers(matrix_known_servers_url)
                if chain_id
                in [
                    Networks.MAINNET.value,
                    Networks.ROPSTEN.value,
                    Networks.RINKEBY.value,
                    Networks.GOERLI.value,
                    Networks.KOVAN.value,
                ]
                else []
            )

        except RuntimeError:
            if available_servers is None:
                raise
            self.known_servers = []

        if available_servers:
            self.available_servers = available_servers
        else:
            self.available_servers = self.known_servers

        self.main_client = make_client(
            handle_messages_callback=handle_matrix_sync,
            servers=self.available_servers,
            http_pool_maxsize=4,
            http_retry_timeout=40,
            http_retry_delay=matrix_http_retry_delay,
        )
        if enable_tracing:
            matrix_client_enable_requests_tracing(self.main_client)
        self.server_url_to_other_clients: Dict[str, GMatrixClient] = {}
        self.connect_client_workers: Set[Greenlet] = set()
def test_metrics_iou(  # pylint: disable=too-many-locals
    pathfinding_service_web3_mock: PathfindingService,
    one_to_n_contract,
    web3: Web3,
    deposit_to_udc,
    get_accounts,
    get_private_key,
):
    pfs = pathfinding_service_web3_mock

    metrics_state = save_metrics_state(metrics.REGISTRY)
    # Prepare test data
    account = [decode_hex(acc) for acc in get_accounts(1)][0]
    local_signer = LocalSigner(private_key=get_private_key(account))
    iou = IOU(
        sender=account,
        receiver=pfs.address,
        amount=TokenAmount(100),
        claimable_until=web3.eth.get_block("latest").timestamp +
        100,  # type: ignore
        signature=Signature(bytes([1] * 64)),
        chain_id=ChainID(61),
        one_to_n_address=to_canonical_address(one_to_n_contract.address),
        claimed=False,
    )
    iou.signature = Signature(local_signer.sign(iou.packed_data()))
    pfs.database.upsert_iou(iou)
    deposit_to_udc(iou.sender, 300)

    # Claim IOUs
    skipped, failures = claim_ious(
        ious=[iou],
        claim_cost_rdn=TokenAmount(100),
        one_to_n_contract=one_to_n_contract,
        web3=web3,
        database=pfs.database,
    )
    assert (skipped, failures) == (0, 0)

    assert (metrics_state.get_delta(
        "economics_iou_claims_total",
        labels=metrics.IouStatus.SUCCESSFUL.to_label_dict()) == 1.0)
    assert (metrics_state.get_delta(
        "economics_iou_claims_token_total",
        labels=metrics.IouStatus.SUCCESSFUL.to_label_dict(),
    ) == 100.0)
예제 #9
0
 def sign(self, priv_key: PrivateKey) -> "MonitorRequest":
     local_signer = LocalSigner(private_key=priv_key)
     non_closing_signature = local_signer.sign(self.packed_non_closing_data())
     return MonitorRequest(
         channel_identifier=self.channel_identifier,
         token_network_address=self.token_network_address,
         chain_id=self.chain_id,
         balance_hash=self.balance_hash,
         nonce=self.nonce,
         additional_hash=self.additional_hash,
         closing_signature=self.closing_signature,
         non_closing_signature=non_closing_signature,
         reward_amount=self.reward_amount,
         non_closing_participant=self.non_closing_participant,
         reward_proof_signature=local_signer.sign(
             self.packed_reward_proof_data(non_closing_signature)
         ),
         msc_address=self.msc_address,
     )
예제 #10
0
    def __init__(  # pylint: disable=too-many-arguments
        self,
        channel_identifier: ChannelID,
        token_network_address: TokenNetworkAddress,
        chain_id: ChainID,
        nonce: Nonce,
        additional_hash: str,
        balance_hash: Optional[str] = None,
        signature: Optional[Signature] = None,
        # these three parameters can be passed instead of `balance_hash`
        transferred_amount: Optional[int] = None,
        locked_amount: Optional[int] = None,
        locksroot: Optional[str] = None,
        # can be used instead of passing `signature`
        priv_key: Optional[PrivateKey] = None,
    ) -> None:
        self.channel_identifier = channel_identifier
        self.token_network_address = token_network_address
        self.chain_id = chain_id
        self.nonce = nonce
        self.additional_hash = additional_hash

        if balance_hash is None:
            assert signature is None
            balance_hash_data = (transferred_amount, locked_amount, locksroot)
            assert all(x is not None for x in balance_hash_data)
            self.balance_hash = encode_hex(
                Web3.solidityKeccak(["uint256", "uint256", "bytes32"], balance_hash_data)
            )
        else:
            self.balance_hash = balance_hash

        if signature is None:
            assert priv_key
            local_signer = LocalSigner(private_key=priv_key)
            self.signature = local_signer.sign(self.serialize_bin())
        else:
            self.signature = signature
예제 #11
0
def test_update_fee(order, pathfinding_service_mock, token_network_model):
    metrics_state = save_metrics_state(metrics.REGISTRY)

    pathfinding_service_mock.database.insert(
        "token_network", dict(address=token_network_model.address)
    )
    if order == "normal":
        setup_channel(pathfinding_service_mock, token_network_model)
        exception_expected = False
    else:
        exception_expected = True

    fee_schedule = FeeScheduleState(
        flat=FeeAmount(1),
        proportional=ProportionalFeeAmount(int(0.1e9)),
        imbalance_penalty=[(TokenAmount(0), FeeAmount(0)), (TokenAmount(10), FeeAmount(10))],
    )
    fee_update = PFSFeeUpdate(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=ChainID(61),
            token_network_address=token_network_model.address,
            channel_identifier=ChannelID(1),
        ),
        updating_participant=PARTICIPANT1,
        fee_schedule=fee_schedule,
        timestamp=datetime.utcnow(),
        signature=EMPTY_SIGNATURE,
    )
    fee_update.sign(LocalSigner(PARTICIPANT1_PRIVKEY))
    pathfinding_service_mock.handle_message(fee_update)

    # Test for metrics having seen the processing of the message
    assert (
        metrics_state.get_delta(
            "messages_processing_duration_seconds_sum",
            labels={"message_type": "PFSFeeUpdate"},
        )
        > 0.0
    )
    assert metrics_state.get_delta(
        "messages_exceptions_total", labels={"message_type": "PFSFeeUpdate"}
    ) == float(exception_expected)

    if order == "fee_update_before_channel_open":
        setup_channel(pathfinding_service_mock, token_network_model)

    cv = token_network_model.G[PARTICIPANT1][PARTICIPANT2]["view"]
    for key in ("flat", "proportional", "imbalance_penalty"):
        assert getattr(cv.fee_schedule_sender, key) == getattr(fee_schedule, key)
예제 #12
0
def test_unhandled_message(pathfinding_service_mock, log):
    metrics_state = save_metrics_state(metrics.REGISTRY)

    unknown_message = Processed(MessageID(123), signature=EMPTY_SIGNATURE)
    unknown_message.sign(LocalSigner(PARTICIPANT1_PRIVKEY))

    pathfinding_service_mock.handle_message(unknown_message)

    # Although the message is unknown and will be ignored,
    # it is still logged under it's message type
    assert (
        metrics_state.get_delta(
            "messages_processing_duration_seconds_sum",
            labels={"message_type": "Processed"},
        )
        > 0.0
    )
    assert (
        metrics_state.get_delta("messages_exceptions_total", labels={"message_type": "Processed"})
        == 0.0
    )

    assert log.has("Ignoring message", unknown_message=unknown_message)
def test_claim_fees(  # pylint: disable=too-many-locals
    pathfinding_service_web3_mock: PathfindingService,
    one_to_n_contract,
    web3: Web3,
    deposit_to_udc,
    get_accounts,
    get_private_key,
):
    pfs = pathfinding_service_web3_mock

    # Prepare test data
    accounts = [decode_hex(acc) for acc in get_accounts(7)]
    iou_inputs: List[dict] = [
        dict(sender=accounts[0], amount=100, deposit=200),
        dict(sender=accounts[1], amount=200, deposit=100),
        dict(sender=accounts[2], amount=102,
             deposit=0),  # insufficient deposit
        dict(sender=accounts[3], amount=103,
             deposit=99),  # insufficient deposit
        dict(sender=accounts[4], amount=104, claimed=True),  # already claimed
        dict(sender=accounts[4], amount=99),  # too low amount
        dict(sender=accounts[5], claimable_until=100 * 15,
             amount=104),  # does not expire, yet
        dict(
            sender=accounts[6],
            claimable_until=web3.eth.get_block(web3.eth.block_number -
                                               1).timestamp,  # type: ignore
            amount=104,
        ),  # already expired
    ]

    # Create IOUs from `iou_inputs`
    ious: List[IOU] = []
    for iou_dict in iou_inputs:
        local_signer = LocalSigner(
            private_key=get_private_key(iou_dict["sender"]))
        iou = IOU(
            sender=iou_dict["sender"],
            receiver=pfs.address,
            amount=TokenAmount(iou_dict["amount"]),
            claimable_until=iou_dict.get(
                "claimable_until",
                web3.eth.get_block("latest").timestamp + 100  # type: ignore
            ),
            signature=Signature(bytes([1] * 64)),  # dummy, replaced below
            chain_id=ChainID(61),
            one_to_n_address=to_canonical_address(one_to_n_contract.address),
            claimed=iou_dict.get("claimed", False),
        )
        iou.signature = Signature(local_signer.sign(iou.packed_data()))
        ious.append(iou)
        pfs.database.upsert_iou(iou)
        if iou_dict.get("deposit", 0) > 0:
            deposit_to_udc(iou.sender, iou_dict["deposit"])

    # Check if the right IOUs are considered to be claimable
    expected_claimable = ious[:4]
    timestamp_now = web3.eth.get_block("latest").timestamp  # type: ignore

    claimable_ious = list(
        get_claimable_ious(
            database=pfs.database,
            claimable_until_after=timestamp_now,
            claimable_until_before=timestamp_now +
            10000,  # TODO: use proper boundaries
            claim_cost_rdn=TokenAmount(100),
        ))
    assert claimable_ious == expected_claimable

    # Claim IOUs
    skipped, failures = claim_ious(
        ious=claimable_ious,
        claim_cost_rdn=TokenAmount(100),
        one_to_n_contract=one_to_n_contract,
        web3=web3,
        database=pfs.database,
    )
    assert (skipped, failures) == (2, 0)

    # Those IOUs which have enough deposit should be marked as claimed
    # * in the blockchain
    # * in the database
    # All other IOUs must not be changed.
    claimable_with_enough_deposit = ious[:2]
    for iou in ious:
        expected_claimed = iou in claimable_with_enough_deposit

        iou_in_db = pfs.database.get_iou(sender=iou.sender,
                                         claimable_until=iou.claimable_until)
        assert iou_in_db
        assert iou_in_db.claimed == expected_claimed

        is_settled = bool(
            one_to_n_contract.functions.settled_sessions(
                iou.session_id).call())
        assert is_settled == expected_claimed