def f(): contract_address = get_random_address() channel_identifier = get_random_identifier() balance_hash_data = '%d' % random.randint(0, UINT64_MAX) additional_hash_data = '%d' % random.randint(0, UINT64_MAX) balance_hash = encode_hex((balance_hash_data.encode())) nonce = random.randint(0, UINT64_MAX) additional_hash = encode_hex(keccak(additional_hash_data.encode())) chain_id = 1 privkey = get_random_privkey() privkey_non_closing = get_random_privkey() bp = HashedBalanceProof( # type: ignore channel_identifier=channel_identifier, token_network_address=contract_address, chain_id=chain_id, balance_hash=balance_hash, nonce=nonce, additional_hash=additional_hash, priv_key=privkey, ) monitor_request = UnsignedMonitorRequest.from_balance_proof( bp, reward_amount=TokenAmount(0)).sign(privkey_non_closing) return monitor_request, privkey, privkey_non_closing
def f( chain_id: ChainID = ChainID(1), amount: TokenAmount = TokenAmount(50), nonce: Nonce = Nonce(1), ) -> RequestMonitoring: balance_proof = HashedBalanceProof( channel_identifier=ChannelID(1), token_network_address=TokenNetworkAddress(b"1" * 20), chain_id=chain_id, nonce=nonce, additional_hash="", balance_hash=encode_hex(bytes([amount])), priv_key=get_random_privkey(), ) request_monitoring = balance_proof.get_request_monitoring( privkey=non_closing_privkey, reward_amount=TokenAmount(55), monitoring_service_contract_address=Address(bytes([11] * 20)), ) # 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_address ) return request_monitoring
def test_get_iou(api_sut: PFSApi, api_url: str, token_network_model: TokenNetwork, make_iou): privkey = PrivateKey(get_random_privkey()) sender = private_key_to_address(privkey) url = api_url + f"/v1/{to_checksum_address(token_network_model.address)}/payment/iou" 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 # Request without IOU in database params = make_params(datetime.utcnow().isoformat()) response = requests.get(url, params=params) assert response.status_code == 404, response.json() assert response.json() == {"last_iou": None} # Add IOU to database iou = make_iou( privkey, api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address ) iou.claimed = False api_sut.pathfinding_service.database.upsert_iou(iou) # Is returned IOU the one save into the db? response = requests.get(url, params=params) assert response.status_code == 200, response.json() iou_dict = IOU.Schema(exclude=["claimed"]).dump(iou) assert response.json()["last_iou"] == iou_dict # Invalid signatures must fail params["signature"] = encode_hex((int(params["signature"], 16) + 1).to_bytes(65, "big")) response = requests.get(url, params=params) assert response.status_code == 400, response.json() assert response.json()["error_code"] == exceptions.InvalidSignature.error_code # Timestamp must no be too old to prevent replay attacks old_timestamp = datetime.utcnow() - timedelta(days=1) params = make_params(old_timestamp.isoformat()) response = requests.get(url, params=params) assert response.status_code == 400, response.json() assert response.json()["error_code"] == exceptions.RequestOutdated.error_code # Timestamp with timezone info is invalid for timestamp in (datetime.now(tz=timezone.utc).isoformat(), "2019-11-07T12:52:25.079Z"): params = make_params(timestamp) response = requests.get(url, params=params) assert response.status_code == 400, response.json() assert response.json()["error_code"] == exceptions.InvalidRequest.error_code
def test_load_and_save_iou(pathfinding_service_mocked_listeners): pfs = pathfinding_service_mocked_listeners iou_dict = make_iou(get_random_privkey(), pfs.address) iou = IOU.Schema().load(iou_dict)[0] iou.claimed = False pfs.database.upsert_iou(iou) stored_iou = pfs.database.get_iou(iou.sender, iou.expiration_block) assert stored_iou == iou
def f(): pk = get_random_privkey() ethereum_tester.add_account(pk) c = MockRaidenNode(pk, token_network, custom_token) c.client_registry = client_registry client_registry[c.address] = c send_funds(c.address) return c
def test_get_iou(api_sut: ServiceApi, api_url: str, token_network_model: TokenNetwork, make_iou): privkey = get_random_privkey() sender = private_key_to_address(privkey) url = api_url + f"/{to_checksum_address(token_network_model.address)}/payment/iou" def make_params(timestamp: datetime): params = { "sender": to_checksum_address(sender), "receiver": to_checksum_address(api_sut.pathfinding_service.address), "timestamp": timestamp.isoformat(), } local_signer = LocalSigner(private_key=decode_hex(privkey)) params["signature"] = encode_hex( local_signer.sign( pack_data( (params["sender"], "address"), (params["receiver"], "address"), (params["timestamp"], "string"), ))) return params # Request without IOU in database params = make_params(datetime.utcnow()) response = requests.get(url, params=params) assert response.status_code == 404, response.json() assert response.json() == {"last_iou": None} # Add IOU to database iou = make_iou(privkey, api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address) iou.claimed = False api_sut.pathfinding_service.database.upsert_iou(iou) # Is returned IOU the one save into the db? response = requests.get(url, params=params) assert response.status_code == 200, response.json() iou_dict = IOU.Schema(exclude=["claimed"]).dump(iou) assert response.json()["last_iou"] == iou_dict # Invalid signatures must fail params["signature"] = encode_hex( (int(params["signature"], 16) + 1).to_bytes(65, "big")) response = requests.get(url, params=params) assert response.status_code == 400, response.json() assert response.json( )["error_code"] == exceptions.InvalidSignature.error_code # Timestamp must no be too old to prevent replay attacks params = make_params(datetime.utcnow() - timedelta(days=1)) response = requests.get(url, params=params) assert response.status_code == 400, response.json() assert response.json( )["error_code"] == exceptions.RequestOutdated.error_code
def test_mr_with_unknown_signatures(context: Context,): """ The signatures are valid but don't belong to the participants. """ context = setup_state_with_closed_channel(context) def assert_mr_is_ignored(mr): context.db.upsert_monitor_request(mr) event = ActionMonitoringTriggeredEvent( token_network_address=DEFAULT_TOKEN_NETWORK_ADDRESS, channel_identifier=DEFAULT_CHANNEL_IDENTIFIER, non_closing_participant=DEFAULT_PARTICIPANT2, ) action_monitoring_triggered_event_handler(event, context) assert not context.monitoring_service_contract.functions.monitor.called assert_mr_is_ignored(get_signed_monitor_request(closing_privkey=get_random_privkey())) assert_mr_is_ignored(get_signed_monitor_request(nonclosing_privkey=get_random_privkey()))
def test_get_iou( api_sut: ServiceApi, api_url: str, pathfinding_service_mock, token_network_model: TokenNetwork ): privkey = get_random_privkey() sender = private_key_to_address(privkey) url = api_url + f'/{token_network_model.address}/payment/iou' def make_params(timestamp: datetime): params = { 'sender': sender, 'receiver': api_sut.pathfinding_service.address, 'timestamp': timestamp.isoformat(), } local_signer = LocalSigner(private_key=decode_hex(privkey)) params['signature'] = encode_hex( local_signer.sign( pack_data( ['address', 'address', 'string'], [params['sender'], params['receiver'], params['timestamp']], ) ) ) return params # Request without IOU in database params = make_params(datetime.utcnow()) response = requests.get(url, params=params) assert response.status_code == 404, response.json() assert response.json() == {'last_iou': None} # Add IOU to database iou = make_iou(privkey, api_sut.pathfinding_service.address) iou.claimed = False api_sut.pathfinding_service.database.upsert_iou(iou) # Is returned IOU the one save into the db? response = requests.get(url, params=params) assert response.status_code == 200, response.json() iou_dict = IOU.Schema(exclude=['claimed']).dump(iou)[0] assert response.json()['last_iou'] == iou_dict # Invalid signatures must fail params['signature'] = encode_hex((int(params['signature'], 16) + 1).to_bytes(65, 'big')) response = requests.get(url, params=params) assert response.status_code == 400, response.json() assert response.json()['error_code'] == exceptions.InvalidSignature.error_code # Timestamp must no be too old to prevent replay attacks params = make_params(datetime.utcnow() - timedelta(days=1)) response = requests.get(url, params=params) assert response.status_code == 400, response.json() assert response.json()['error_code'] == exceptions.RequestOutdated.error_code # kill all running greenlets gevent.killall([obj for obj in gc.get_objects() if isinstance(obj, gevent.Greenlet)])
def build_request_monitoring(): signer = LocalSigner(decode_hex(get_random_privkey())) non_closing_signer = LocalSigner(decode_hex(get_random_privkey())) 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 return f
def build_request_monitoring(): signer = LocalSigner(decode_hex(get_random_privkey())) non_closing_signer = LocalSigner(decode_hex(get_random_privkey())) 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 return f
def test_payment_with_new_iou_rejected( # pylint: disable=too-many-locals api_sut, api_url: str, addresses: List[Address], token_network_model: TokenNetwork, make_iou: Callable, ): """ Regression test for https://github.com/raiden-network/raiden-services/issues/624 """ initiator_address = to_checksum_address(addresses[0]) target_address = to_checksum_address(addresses[1]) url = api_url + "/" + to_checksum_address( token_network_model.address) + "/paths" default_params = { "from": initiator_address, "to": target_address, "value": 5, "max_paths": 3 } def request_path_with(status_code=400, **kwargs): params = default_params.copy() params.update(kwargs) response = requests.post(url, json=params) assert response.status_code == status_code, response.json() return response # test with payment api_sut.service_fee = 100 sender = get_random_privkey() iou = make_iou( sender, api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address, amount=100, expiration_block=1_234_567, ) first_iou_dict = iou.Schema().dump(iou) second_iou = make_iou( sender, api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address, amount=200, expiration_block=1_234_568, ) second_iou_dict = second_iou.Schema().dump(second_iou) response = request_path_with(status_code=200, iou=first_iou_dict) assert response.status_code == 200 response = request_path_with(iou=second_iou_dict) assert response.json()["error_code"] == exceptions.UseThisIOU.error_code
def get(): privkey = get_random_privkey() address = private_key_to_address(privkey) ethereum_tester.add_account(privkey) for faucet in web3.eth.accounts[:10]: try: web3.eth.sendTransaction({ 'from': faucet, 'to': address, 'value': 1 * denoms.finney, # pylint: disable=E1101 }) break except TransactionFailed: continue return address
def test_deploy_script_token( web3, ): """ Run test token deployment function used in the deployment script This checks if deploy_token_contract() works correctly in the happy case, to make sure no code dependencies have been changed, affecting the deployment script. This does not check however that the cli command works correctly. """ # normal deployment token_type = 'CustomToken' gas_limit = 5860000 deployer = ContractDeployer( web3=web3, private_key=FAUCET_PRIVATE_KEY, gas_limit=gas_limit, gas_price=1, wait=10, ) deployed_token = deployer.deploy_token_contract( token_supply=10000000, token_decimals=18, token_name='TestToken', token_symbol='TTT', token_type=token_type, ) assert deployed_token[token_type] is not None assert isinstance(deployed_token[token_type], T_Address) # check that it fails if sender has no eth deployer = ContractDeployer( web3=web3, private_key=get_random_privkey(), gas_limit=gas_limit, gas_price=1, wait=10, ) with pytest.raises(ValidationError): deployer.deploy_token_contract( token_supply=10000000, token_decimals=18, token_name='TestToken', token_symbol='TTT', token_type='CustomToken', )
def get(privkey: Optional[str] = None) -> HexAddress: if not privkey: privkey = get_random_privkey() address = private_key_to_address(privkey) if not any((is_same_address(address, x) for x in ethereum_tester.get_accounts())): # account has not been added to ethereum_tester, yet ethereum_tester.add_account(privkey) for faucet in web3.eth.accounts[:10]: try: web3.eth.sendTransaction( {"from": faucet, "to": address, "value": 1 * int(units["finney"])} ) break except TransactionFailed: continue return address
def test_deploy_script_raiden( web3, version: Optional[str], max_num_of_token_networks: Optional[int], deployer, deployed_raiden_info, ): """ Run raiden contracts deployment function and tamper with deployed_contracts_info This checks if deploy_raiden_contracts() works correctly in the happy case, to make sure no code dependencies have been changed, affecting the deployment script. This does not check however that the cli command works correctly. This also tampers with deployed_contracts_info to make sure an error is raised in verify_deployed_contracts() """ deployed_contracts_info = deployed_raiden_info deployer._verify_deployment_data( deployment_data=deployed_contracts_info, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['contracts_version'] = '0.0.0' with pytest.raises(AssertionError): deployer._verify_deployment_data( deployment_data=deployed_contracts_info_fail, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['chain_id'] = 0 with pytest.raises(AssertionError): deployer._verify_deployment_data( deployment_data=deployed_contracts_info_fail, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['contracts'][ CONTRACT_ENDPOINT_REGISTRY ]['address'] = EMPTY_ADDRESS with pytest.raises(AssertionError): deployer._verify_deployment_data( deployed_contracts_info_fail, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['contracts'][CONTRACT_SECRET_REGISTRY]['address'] = EMPTY_ADDRESS with pytest.raises(AssertionError): deployer._verify_deployment_data( deployed_contracts_info_fail, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['contracts'][ CONTRACT_TOKEN_NETWORK_REGISTRY ]['address'] = EMPTY_ADDRESS with pytest.raises(AssertionError): deployer._verify_deployment_data( deployed_contracts_info_fail, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['contracts'][CONTRACT_ENDPOINT_REGISTRY]['block_number'] = 0 with pytest.raises(AssertionError): deployer._verify_deployment_data( deployed_contracts_info_fail, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['contracts'][CONTRACT_SECRET_REGISTRY]['block_number'] = 0 with pytest.raises(AssertionError): deployer._verify_deployment_data( deployed_contracts_info_fail, ) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail['contracts'][CONTRACT_TOKEN_NETWORK_REGISTRY]['block_number'] = 0 with pytest.raises(AssertionError): deployer._verify_deployment_data( deployed_contracts_info_fail, ) # check that it fails if sender has no eth deployer = ContractDeployer( web3=web3, private_key=get_random_privkey(), gas_limit=GAS_LIMIT, gas_price=1, wait=10, ) with pytest.raises(ValidationError): deploy_raiden_contracts(deployer, 1)
def test_get_paths_validation( api_sut: ServiceApi, api_url: str, initiator_address: str, target_address: str, token_network_model: TokenNetwork, ): url = api_url + f'/{token_network_model.address}/paths' default_params = { 'from': initiator_address, 'to': target_address, 'value': 5, 'max_paths': 3, } def request_path_with(status_code=400, **kwargs): params = default_params.copy() params.update(kwargs) response = requests.post(url, json=params) assert response.status_code == status_code, response.json() return response response = requests.post(url) assert response.status_code == 400 assert response.json()['errors'].startswith('Required parameters:') response = request_path_with(**{'from': 'notanaddress'}) assert response.json( )['errors'] == 'Invalid initiator address: notanaddress' response = request_path_with(to='notanaddress') assert response.json()['errors'] == 'Invalid target address: notanaddress' response = request_path_with( **{'from': to_normalized_address(initiator_address)}) assert response.json( )['errors'] == 'Initiator address not checksummed: {}'.format( to_normalized_address(initiator_address), ) response = request_path_with(to=to_normalized_address(target_address)) assert response.json( )['errors'] == 'Target address not checksummed: {}'.format( to_normalized_address(target_address), ) response = request_path_with(value=-10) assert response.json( )['errors'] == 'Payment value must be non-negative: -10' response = request_path_with(max_paths=-1) assert response.json()['errors'] == 'Number of paths must be positive: -1' # Exemplary test for payment errors. Different errors are serialized the # same way in the rest API. Checking for specific errors is tested in # payment_tests. api_sut.pathfinding_service.service_fee = 1 response = request_path_with() assert response.json()['error_code'] == exceptions.MissingIOU.error_code # with successful payment iou = make_iou(get_random_privkey(), api_sut.pathfinding_service.address) response = request_path_with(iou=iou, status_code=200) # kill all running greenlets gevent.killall( [obj for obj in gc.get_objects() if isinstance(obj, gevent.Greenlet)], )
def test_crash(tmpdir, mockchain): # pylint: disable=too-many-locals """Process blocks and compare results with/without crash A somewhat meaninful crash handling is simulated by not including the UpdatedHeadBlockEvent in every block. """ token_address = TokenAddress(bytes([1] * 20)) token_network_address = TokenNetworkAddress(bytes([2] * 20)) channel_id = ChannelID(1) p1 = Address(bytes([3] * 20)) p2 = Address(bytes([4] * 20)) events = [ [ ReceiveTokenNetworkCreatedEvent( token_address=token_address, token_network_address=token_network_address, settle_timeout=DEFAULT_TOKEN_NETWORK_SETTLE_TIMEOUT, block_number=BlockNumber(1), ) ], [UpdatedHeadBlockEvent(BlockNumber(2))], [ ReceiveChannelOpenedEvent( token_network_address=token_network_address, channel_identifier=channel_id, participant1=p1, participant2=p2, block_number=BlockNumber(3), ) ], [UpdatedHeadBlockEvent(BlockNumber(4))], ] mockchain(events) server_private_key = PrivateKey(get_random_privkey()) contracts = { CONTRACT_TOKEN_NETWORK_REGISTRY: ContractMock(), CONTRACT_USER_DEPOSIT: ContractMock(), } def new_service(filename): service = PathfindingService( web3=Web3Mock(), private_key=server_private_key, contracts=contracts, sync_start_block=BlockNumber(0), required_confirmations=BlockTimeout(0), poll_interval=0, db_filename=os.path.join(tmpdir, filename), ) return service # initialize stable service stable_service = new_service("stable.db") # process each block and compare results between crashy and stable service for to_block in range(len(events)): crashy_service = new_service("crashy.db") # new instance to simulate crash result_state: List[dict] = [] for service in [stable_service, crashy_service]: service._process_new_blocks(BlockNumber(to_block)) # pylint: disable=protected-access result_state.append(dict(db_dump=list(service.database.conn.iterdump()))) # both instances should have the same state after processing for stable_state, crashy_state in zip(result_state[0].values(), result_state[1].values()): if isinstance(stable_state, BlockchainState): assert stable_state.chain_id == crashy_state.chain_id assert ( stable_state.token_network_registry_address == crashy_state.token_network_registry_address ) assert stable_state.latest_committed_block == crashy_state.latest_committed_block assert ( stable_state.monitor_contract_address == crashy_state.monitor_contract_address ) # Do not compare `current_event_filter_interval`, this is allowed to be different else: assert stable_state == crashy_state crashy_service.database.conn.close() # close the db connection so we can access it again
def test_get_paths_validation( api_sut: ServiceApi, api_url: str, addresses: List[Address], token_network_model: TokenNetwork, make_iou, ): initiator_address = to_checksum_address(addresses[0]) target_address = to_checksum_address(addresses[1]) url = api_url + "/" + to_checksum_address(token_network_model.address) + "/paths" default_params = {"from": initiator_address, "to": target_address, "value": 5, "max_paths": 3} def request_path_with(status_code=400, **kwargs): params = default_params.copy() params.update(kwargs) response = requests.post(url, json=params) assert response.status_code == status_code, response.json() return response response = requests.post(url) assert response.status_code == 400 assert response.json()["errors"].startswith("JSON payload expected") for address in ["notanaddress", to_normalized_address(initiator_address)]: response = request_path_with(**{"from": address}) assert response.json()["error_code"] == exceptions.InvalidRequest.error_code assert "from" in response.json()["error_details"] response = request_path_with(to=address) assert response.json()["error_code"] == exceptions.InvalidRequest.error_code assert "to" in response.json()["error_details"] response = request_path_with(value=-10) assert response.json()["error_code"] == exceptions.InvalidRequest.error_code assert "value" in response.json()["error_details"] response = request_path_with(max_paths=-1) assert response.json()["error_code"] == exceptions.InvalidRequest.error_code assert "max_paths" in response.json()["error_details"] # successful request without payment request_path_with(status_code=200) # Exemplary test for payment errors. Different errors are serialized the # same way in the rest API. Checking for specific errors is tested in # payment_tests. api_sut.service_fee = TokenAmount(1) response = request_path_with() assert response.json()["error_code"] == exceptions.MissingIOU.error_code # prepare iou for payment tests iou = make_iou( get_random_privkey(), api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address, ) good_iou_dict = iou.Schema().dump(iou) # malformed iou bad_iou_dict = good_iou_dict.copy() del bad_iou_dict["amount"] response = request_path_with(iou=bad_iou_dict) assert response.json()["error_code"] == exceptions.InvalidRequest.error_code # bad signature bad_iou_dict = good_iou_dict.copy() bad_iou_dict["signature"] = "0x" + "1" * 130 response = request_path_with(iou=bad_iou_dict) assert response.json()["error_code"] == exceptions.InvalidSignature.error_code # with successful payment request_path_with(iou=good_iou_dict, status_code=200)
def test_get_paths_validation( api_sut: ServiceApi, api_url: str, addresses: List[Address], token_network_model: TokenNetwork, make_iou: Callable, ): initiator_address = to_checksum_address(addresses[0]) target_address = to_checksum_address(addresses[1]) url = api_url + "/" + to_checksum_address( token_network_model.address) + "/paths" default_params = { "from": initiator_address, "to": target_address, "value": 5, "max_paths": 3 } def request_path_with(status_code=400, **kwargs): params = default_params.copy() params.update(kwargs) response = requests.post(url, json=params) assert response.status_code == status_code, response.json() return response response = requests.post(url) assert response.status_code == 400 assert response.json()["errors"].startswith("JSON payload expected") for address in ["notanaddress", to_normalized_address(initiator_address)]: response = request_path_with(**{"from": address}) assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code assert "from" in response.json()["error_details"] response = request_path_with(to=address) assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code assert "to" in response.json()["error_details"] response = request_path_with(value=-10) assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code assert "value" in response.json()["error_details"] response = request_path_with(max_paths=-1) assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code assert "max_paths" in response.json()["error_details"] # successful request without payment request_path_with(status_code=200) # Exemplary test for payment errors. Different errors are serialized the # same way in the rest API. Checking for specific errors is tested in # payment_tests. api_sut.service_fee = TokenAmount(1) response = request_path_with() assert response.json()["error_code"] == exceptions.MissingIOU.error_code # prepare iou for payment tests iou = make_iou( get_random_privkey(), api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address, ) good_iou_dict = iou.Schema().dump(iou) # malformed iou bad_iou_dict = good_iou_dict.copy() del bad_iou_dict["amount"] response = request_path_with(iou=bad_iou_dict) assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code # malformed iou bad_iou_dict = { "amount": { "_hex": "0x64" }, "chain_id": { "_hex": "0x05" }, "expiration_block": { "_hex": "0x188cba" }, "one_to_n_address": "0x0000000000000000000000000000000000000000", "receiver": "0x94DEe8e391410A9ebbA791B187df2d993212c849", "sender": "0x2046F7341f15D0211ca1EBeFb19d029c4Bc4c4e7", "signature": ("0x0c3066e6a954d660028695f96dfe88cabaf0bc8a385e51781ac4d21003d0b6cd7a8b2" "a1134115845655d1a509061f48459cd401565b5df7845c913ed329cd2351b"), } response = request_path_with(iou=bad_iou_dict) assert response.json( )["error_code"] == exceptions.InvalidRequest.error_code # bad signature bad_iou_dict = good_iou_dict.copy() bad_iou_dict["signature"] = "0x" + "1" * 130 response = request_path_with(iou=bad_iou_dict) assert response.json( )["error_code"] == exceptions.InvalidSignature.error_code # with successful payment request_path_with(iou=good_iou_dict, status_code=200)
def test_get_paths_validation( api_sut: ServiceApi, api_url: str, initiator_address: str, target_address: str, token_network_model: TokenNetwork, ): url = api_url + f'/{token_network_model.address}/paths' default_params = {'from': initiator_address, 'to': target_address, 'value': 5, 'max_paths': 3} def request_path_with(status_code=400, **kwargs): params = default_params.copy() params.update(kwargs) response = requests.post(url, json=params) assert response.status_code == status_code, response.json() return response response = requests.post(url) assert response.status_code == 400 assert response.json()['errors'].startswith('JSON payload expected') for address in ['notanaddress', to_normalized_address(initiator_address)]: response = request_path_with(**{'from': address}) assert response.json()['error_code'] == exceptions.InvalidRequest.error_code assert 'from' in response.json()['error_details'] response = request_path_with(to=address) assert response.json()['error_code'] == exceptions.InvalidRequest.error_code assert 'to' in response.json()['error_details'] response = request_path_with(value=-10) assert response.json()['error_code'] == exceptions.InvalidRequest.error_code assert 'value' in response.json()['error_details'] response = request_path_with(max_paths=-1) assert response.json()['error_code'] == exceptions.InvalidRequest.error_code assert 'max_paths' in response.json()['error_details'] # Exemplary test for payment errors. Different errors are serialized the # same way in the rest API. Checking for specific errors is tested in # payment_tests. api_sut.pathfinding_service.service_fee = 1 response = request_path_with() assert response.json()['error_code'] == exceptions.MissingIOU.error_code # prepare iou for payment tests iou = make_iou(get_random_privkey(), api_sut.pathfinding_service.address) good_iou_dict = iou.Schema().dump(iou)[0] # malformed iou bad_iou_dict = good_iou_dict.copy() del bad_iou_dict['amount'] response = request_path_with(iou=bad_iou_dict) assert response.json()['error_code'] == exceptions.InvalidRequest.error_code # bad signature bad_iou_dict = good_iou_dict.copy() bad_iou_dict['signature'] = hex(int(bad_iou_dict['signature'], 16) + 1) response = request_path_with(iou=bad_iou_dict) assert response.json()['error_code'] == exceptions.InvalidSignature.error_code # with successful payment response = request_path_with(iou=good_iou_dict, status_code=200) # kill all running greenlets gevent.killall([obj for obj in gc.get_objects() if isinstance(obj, gevent.Greenlet)])
def test_deploy_script_raiden(web3: Web3, deployer: ContractDeployer, deployed_raiden_info: DeployedContracts) -> None: """ Run raiden contracts deployment function and tamper with deployed_contracts_info This checks if deploy_raiden_contracts() works correctly in the happy case, to make sure no code dependencies have been changed, affecting the deployment script. This does not check however that the cli command works correctly. This also tampers with deployed_contracts_info to make sure an error is raised in verify_deployed_contracts() """ deployed_contracts_info = deployed_raiden_info deployer.verify_deployment_data(deployment_data=deployed_contracts_info) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts_version"] = "0.0.0" with pytest.raises(RuntimeError): deployer.verify_deployment_data( deployment_data=deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["chain_id"] = 0 with pytest.raises(RuntimeError): deployer.verify_deployment_data( deployment_data=deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][ "address"] = EMPTY_ADDRESS with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][ "address"] = EMPTY_ADDRESS with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][ "address"] = EMPTY_ADDRESS with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][ "block_number"] = 0 with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][ "block_number"] = 0 with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][ "block_number"] = 0 with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][ "gas_cost"] = 0 with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][ "address"] = EMPTY_ADDRESS with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) deployed_contracts_info_fail = deepcopy(deployed_contracts_info) deployed_contracts_info_fail["contracts_version"] = "0.4.0" with pytest.raises(RuntimeError): deployer.verify_deployment_data(deployed_contracts_info_fail) # check that it fails if sender has no eth deployer = ContractDeployer(web3=web3, private_key=get_random_privkey(), gas_limit=GAS_LIMIT, gas_price=1, wait=10) with pytest.raises(ValidationError): deployer.deploy_raiden_contracts(1)
def test_crash(tmpdir, get_accounts, get_private_key, mockchain): # pylint: disable=too-many-locals """ Process blocks and compare results with/without crash A somewhat meaninful crash handling is simulated by not including the UpdatedHeadBlockEvent in every block. """ channel_identifier = ChannelID(3) c1, c2 = get_accounts(2) token_network_address = TokenNetworkAddress( to_canonical_address(get_random_address())) balance_proof = HashedBalanceProof( nonce=Nonce(1), transferred_amount=TokenAmount(2), priv_key=get_private_key(c1), channel_identifier=channel_identifier, token_network_address=token_network_address, chain_id=ChainID(1), additional_hash="0x%064x" % 0, locked_amount=0, locksroot=encode_hex(LOCKSROOT_OF_NO_LOCKS), ) monitor_request = balance_proof.get_monitor_request( get_private_key(c2), reward_amount=TokenAmount(0), msc_address=TEST_MSC_ADDRESS) events = [ [ ReceiveChannelOpenedEvent( token_network_address=token_network_address, channel_identifier=channel_identifier, participant1=c1, participant2=c2, settle_timeout=20, block_number=BlockNumber(0), ) ], [UpdatedHeadBlockEvent(BlockNumber(1))], [ ActionMonitoringTriggeredEvent( token_network_address=token_network_address, channel_identifier=channel_identifier, non_closing_participant=c2, ) ], [UpdatedHeadBlockEvent(BlockNumber(3))], ] mockchain(events) server_private_key = get_random_privkey() contracts = { CONTRACT_TOKEN_NETWORK_REGISTRY: ContractMock(), CONTRACT_MONITORING_SERVICE: ContractMock(), CONTRACT_USER_DEPOSIT: ContractMock(), CONTRACT_SERVICE_REGISTRY: ContractMock(), } def new_ms(filename): ms = MonitoringService( web3=Web3Mock(), private_key=server_private_key, contracts=contracts, db_filename=os.path.join(tmpdir, filename), ) msc = Mock() ms.context.monitoring_service_contract = msc ms.monitor_mock = msc.functions.monitor.return_value.transact # type: ignore ms.monitor_mock.return_value = bytes(0) # type: ignore return ms # initialize both monitoring services stable_ms = new_ms("stable.db") crashy_ms = new_ms("crashy.db") for ms in [stable_ms, crashy_ms]: ms.database.conn.execute( "INSERT INTO token_network(address) VALUES (?)", [to_checksum_address(token_network_address)], ) ms.context.ms_state.blockchain_state.token_network_addresses = [ token_network_address ] ms.database.upsert_monitor_request(monitor_request) ms.database.conn.commit() # process each block and compare results between crashy and stable ms for to_block in range(len(events)): crashy_ms = new_ms("crashy.db") # new instance to simulate crash stable_ms.monitor_mock.reset_mock() # clear calls from last block result_state: List[dict] = [] for ms in [stable_ms, crashy_ms]: ms._process_new_blocks(to_block) # pylint: disable=protected-access result_state.append( dict( blockchain_state=ms.context.ms_state.blockchain_state, db_dump=list(ms.database.conn.iterdump()), monitor_calls=ms.monitor_mock.mock_calls, )) # both instances should have the same state after processing for stable_state, crashy_state in zip(result_state[0].values(), result_state[1].values()): # do asserts for each key separately to get better error messages assert stable_state == crashy_state
def server_private_key(ethereum_tester): key = get_random_privkey() ethereum_tester.add_account(key) return key
def test_save_and_load_iou(pathfinding_service_mock, make_iou): pfs = pathfinding_service_mock iou = make_iou(get_random_privkey(), pfs.address) pfs.database.upsert_iou(iou) stored_iou = pfs.database.get_iou(iou.sender, iou.expiration_block) assert stored_iou == iou
def test_crash(tmpdir, mockchain): # pylint: disable=too-many-locals """ Process blocks and compare results with/without crash A somewhat meaninful crash handling is simulated by not including the UpdatedHeadBlockEvent in every block. """ token_address = Address("0x" + "1" * 40) token_network_address = TokenNetworkAddress("0x" + "2" * 40) channel_id = ChannelID(1) p1 = Address("0x" + "3" * 40) p2 = Address("0x" + "4" * 40) events = [ [ ReceiveTokenNetworkCreatedEvent( token_address=token_address, token_network_address=token_network_address, block_number=BlockNumber(1), ) ], [UpdatedHeadBlockEvent(BlockNumber(2))], [ ReceiveChannelOpenedEvent( token_network_address=token_network_address, channel_identifier=channel_id, participant1=p1, participant2=p2, settle_timeout=1000, block_number=BlockNumber(3), ) ], [UpdatedHeadBlockEvent(BlockNumber(4))], ] mockchain(events) server_private_key = get_random_privkey() contracts = { CONTRACT_TOKEN_NETWORK_REGISTRY: ContractMock(), CONTRACT_USER_DEPOSIT: ContractMock(), } def new_service(filename): service = PathfindingService( web3=Web3Mock(), private_key=server_private_key, contracts=contracts, db_filename=os.path.join(tmpdir, filename), ) return service # initialize stable service stable_service = new_service("stable.db") # process each block and compare results between crashy and stable service for to_block in range(len(events)): crashy_service = new_service( "crashy.db") # new instance to simulate crash result_state: List[dict] = [] for service in [stable_service, crashy_service]: service._process_new_blocks(BlockNumber(to_block)) # pylint: disable=protected-access result_state.append( dict(db_dump=list(service.database.conn.iterdump()))) # both instances should have the same state after processing for stable_state, crashy_state in zip(result_state[0].values(), result_state[1].values()): # do asserts for each key separately to get better error messages assert stable_state == crashy_state