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)
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
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
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
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)
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, )
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
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)
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