def test_regression_revealsecret_after_secret(raiden_network, token_addresses): """ A RevealSecret message received after a Secret message must be cleanly handled. """ app0, app1, app2 = raiden_network token = token_addresses[0] identifier = 1 transfer = app0.raiden.mediated_transfer_async( token_address=token, amount=1, target=app2.raiden.address, identifier=identifier, ) assert transfer.wait() event = None for _, event in app1.raiden.wal.storage.get_events_by_block(0, 'latest'): if isinstance(event, SendRevealSecret): break assert event message_identifier = random.randint(0, UINT64_MAX) reveal_secret = RevealSecret( message_identifier, event.secret, ) app2.raiden.sign(reveal_secret) reveal_data = reveal_secret.encode() app1.raiden.protocol.receive(reveal_data)
def run_test_regression_revealsecret_after_secret(raiden_network, token_addresses, transport_protocol): app0, app1, app2 = raiden_network token = token_addresses[0] identifier = 1 payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token) payment_status = app0.raiden.mediated_transfer_async( token_network_identifier, amount=1, target=app2.raiden.address, identifier=identifier) assert payment_status.payment_done.wait() event = search_for_item(app1.raiden.wal.storage.get_events(), SendSecretReveal, {}) assert event message_identifier = random.randint(0, UINT64_MAX) reveal_secret = RevealSecret(message_identifier=message_identifier, secret=event.secret) app2.raiden.sign(reveal_secret) if transport_protocol is TransportProtocol.UDP: reveal_data = reveal_secret.encode() host_port = None app1.raiden.transport.receive(reveal_data, host_port) elif transport_protocol is TransportProtocol.MATRIX: app1.raiden.transport._receive_message(reveal_secret) # pylint: disable=protected-access else: raise TypeError("Unknown TransportProtocol")
def test_regression_revealsecret_after_secret(raiden_network, token_addresses): """ A RevealSecret message received after a Secret message must be cleanly handled. """ app0, app1, app2 = raiden_network token = token_addresses[0] identifier = 1 transfer = app0.raiden.mediated_transfer_async( token_address=token, amount=1, target=app2.raiden.address, identifier=identifier, ) assert transfer.wait() all_logs = app1.raiden.transaction_log.get_events_in_block_range( 0, app1.raiden.get_block_number(), ) secret = None for log in all_logs: event = log.event_object if isinstance(event, SendRevealSecret): secret = event.secret break assert secret reveal_secret = RevealSecret(secret) app2.raiden.sign(reveal_secret) reveal_data = reveal_secret.encode() app1.raiden.protocol.receive(reveal_data)
def test_reveal_secret_7(): print("Secret {} ".format(secret.hex())) print("SecretHash {} ".format(secrethash.hex())) message = RevealSecret(message_identifier=MessageID(2226977946511089099), secret=secret) message.sign(signer) data_was_signed = message._data_to_sign() print("Reveal Secret signature: " + message.signature.hex()) assert recover(data_was_signed, message.signature) == to_canonical_address( "0x7ca28d3d760b4aa2b79e8d42cbdc187c7df9af40")
def test_reveal_secret_9(): message = RevealSecret( message_identifier=MessageID(10945162236180065780), secret=Secret( decode_hex( "0xb8ed582d16853c82a9a9a384118fcd10889ab0a5a3224ec6008bd88582319fc3" ))) message.sign(signer) data_was_signed = message._data_to_sign() print("Reveal Secret signature 9: " + message.signature.hex()) assert recover(data_was_signed, message.signature) == to_canonical_address( "0x7ca28d3d760b4aa2b79e8d42cbdc187c7df9af40")
def run_test_automatic_secret_registration(raiden_chain, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = 100 identifier = 1 hold_event_handler = HoldOffChainSecretRequest() message_handler = WaitForMessage() app1.raiden.raiden_event_handler = hold_event_handler app1.raiden.message_handler = message_handler target = app1.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) locked_transfer_received = message_handler.wait_for_message( LockedTransfer, {}) app0.raiden.start_mediated_transfer_with_secret( token_network_identifier=token_network_identifier, amount=amount, fee=0, target=target, identifier=identifier, secret=secret, ) # Wait for app1 to receive the locked transfer. locked_transfer_received.wait() # Stop app0 to avoid sending the unlock, this must be done after the locked # transfer is sent. app0.raiden.transport.stop() reveal_secret = RevealSecret( message_identifier=random.randint(0, UINT64_MAX), secret=secret, ) app0.raiden.sign(reveal_secret) message_handler.on_message(app1.raiden, reveal_secret) chain_state = views.state_from_app(app1) secrethash = sha3(secret) target_task = chain_state.payment_mapping.secrethashes_to_task[secrethash] lock_expiration = target_task.target_state.transfer.lock.expiration app1.raiden.chain.wait_until_block(target_block_number=lock_expiration) assert app1.raiden.default_secret_registry.is_secret_registered( secrethash=secrethash, block_identifier='latest', )
def test_close_channel_lack_of_balance_proof(raiden_chain, deposit, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) amount = 100 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) # Stop app0 to avoid sending the unlock app0.raiden.transport.stop_and_wait() reveal_secret = RevealSecret( random.randint(0, UINT64_MAX), secret, ) app0.raiden.sign(reveal_secret) message_handler.on_message(app1.raiden, reveal_secret) RaidenAPI(app0.raiden).channel_close( app0.raiden.default_registry.address, token_address, app1.raiden.address, ) channel_state = get_channelstate(app0, app1, token_network_identifier) waiting.wait_for_settle( app0.raiden, app0.raiden.default_registry.address, token_address, [channel_state.identifier], app0.raiden.alarm.sleep_time, ) # wait for the node to call batch unlock with gevent.Timeout(10): wait_for_batch_unlock( app0, token_network_identifier, channel_state.partner_state.address, channel_state.our_state.address, ) expected_balance0 = initial_balance0 + deposit - amount expected_balance1 = initial_balance1 + deposit + amount assert token_proxy.balance_of(app0.raiden.address) == expected_balance0 assert token_proxy.balance_of(app1.raiden.address) == expected_balance1
def test_receive_hashlocktransfer_unknown(raiden_network): app0 = raiden_network[0] # pylint: disable=unbalanced-tuple-unpacking token_manager0 = app0.raiden.managers_by_token_address.values()[0] other_key = PrivateKey(HASH2, ctx=GLOBAL_CTX, raw=True) other_address = privatekey_to_address(other_key.private_key) amount = 10 lock = Lock(amount, 1, HASH) refund_transfer = RefundTransfer(identifier=1, nonce=1, token=token_manager0.token_address, transferred_amount=amount, recipient=app0.raiden.address, locksroot=HASH, lock=lock) sign_and_send(refund_transfer, other_key, other_address, app0) transfer_timeout = TransferTimeout(HASH, HASH) sign_and_send(transfer_timeout, other_key, other_address, app0) secret = Secret(1, HASH, token_manager0.token_address) sign_and_send(secret, other_key, other_address, app0) secret_request = SecretRequest(1, HASH, 1) sign_and_send(secret_request, other_key, other_address, app0) reveal_secret = RevealSecret(HASH) sign_and_send(reveal_secret, other_key, other_address, app0) # Whenever processing of ConfirmTransfer is implemented test it here # too by removing the expectation of an exception with pytest.raises(KeyError): confirm_transfer = ConfirmTransfer(HASH) sign_and_send(confirm_transfer, other_key, other_address, app0)
def reveal_secret(self, raiden, secret, last_node, exchange_node): """ Reveal the `secret` to both participants. The secret must be revealed backwards to get the incentives right (first mediator would not forward the secret and get the transfer to itself). With exchanges there is an additional failure point, if a node is mediating both asset transfers it can intercept the transfer (as in not revealing the secret to others), for this reason it is not sufficient to just send the Secret backwards, the Secret must also be sent to the exchange_node. """ # pylint: disable=no-self-use reveal_secret = RevealSecret(secret) raiden.sign(reveal_secret) # first reveal the secret to the last_node in the chain, proceed after # ack raiden.send_and_wait(last_node, reveal_secret, timeout=None) # XXX: wait for expiration # the last_node has acknowledged the Secret, so we know the exchange # has kicked-off, reveal the secret to the exchange_node to # avoid interceptions but dont wait raiden.send_async(exchange_node, reveal_secret)
def test_receive_hashlocktransfer_unknown(raiden_network, token_addresses): app0 = raiden_network[0] token_address = token_addresses[0] other_key = HOP1_KEY other_address = HOP1 amount = 10 refund_transfer_message = make_refund_transfer( identifier=1, nonce=1, token=token_address, channel=other_address, transferred_amount=amount, recipient=app0.raiden.address, locksroot=UNIT_HASHLOCK, amount=amount, hashlock=UNIT_HASHLOCK, ) sign_and_inject(refund_transfer_message, other_key, other_address, app0) secret = Secret( identifier=1, nonce=1, channel=make_address(), transferred_amount=amount, locksroot=UNIT_HASHLOCK, secret=UNIT_SECRET, ) sign_and_inject(secret, other_key, other_address, app0) secret_request_message = SecretRequest(1, UNIT_HASHLOCK, 1) sign_and_inject(secret_request_message, other_key, other_address, app0) reveal_secret_message = RevealSecret(UNIT_SECRET) sign_and_inject(reveal_secret_message, other_key, other_address, app0)
def register_secret(self, secret): """ Register the secret with any channel that has a hashlock on it. This must search through all channels registered for a given hashlock and ignoring the tokens. Useful for refund transfer, split transfer, and token swaps. """ hashlock = sha3(secret) revealsecret_message = RevealSecret(secret) self.sign(revealsecret_message) for hash_channel in self.token_to_hashlock_to_channels.itervalues(): for channel in hash_channel[hashlock]: try: channel.register_secret(secret) # This will potentially be executed multiple times and could suffer # from amplification, the protocol will ignore messages that were # already registered and send it only until a first Ack is # received. self.send_async( channel.partner_state.address, revealsecret_message, ) except: # pylint: disable=bare-except # Only channels that care about the given secret can be # registered and channels that have claimed the lock must # be removed, so an exception should not happen at this # point, nevertheless handle it because we dont want an # error in a channel to mess the state from others. log.error('programming error')
def test_receive_hashlocktransfer_unknown(raiden_network): app0 = raiden_network[0] # pylint: disable=unbalanced-tuple-unpacking graph0 = app0.raiden.channelgraphs.values()[0] other_key = PrivateKey(HASH2) other_address = privatekey_to_address(HASH2) amount = 10 lock = Lock(amount, 1, HASH) refund_transfer = RefundTransfer( identifier=1, nonce=1, token=graph0.token_address, transferred_amount=amount, recipient=app0.raiden.address, locksroot=HASH, lock=lock ) sign_and_send(refund_transfer, other_key, other_address, app0) secret = Secret(1, HASH, graph0.token_address) sign_and_send(secret, other_key, other_address, app0) secret_request = SecretRequest(1, HASH, 1) sign_and_send(secret_request, other_key, other_address, app0) reveal_secret = RevealSecret(HASH) sign_and_send(reveal_secret, other_key, other_address, app0)
def register_secret(self, secret: bytes): """ Register the secret with any channel that has a hashlock on it. This must search through all channels registered for a given hashlock and ignoring the tokens. Useful for refund transfer, split transfer, and token swaps. Raises: TypeError: If secret is unicode data. """ if not isinstance(secret, bytes): raise TypeError('secret must be bytes') hashlock = sha3(secret) revealsecret_message = RevealSecret(secret) self.sign(revealsecret_message) for hash_channel in self.token_to_hashlock_to_channels.values(): for channel in hash_channel[hashlock]: channel.register_secret(secret) # The protocol ignores duplicated messages. self.send_async( channel.partner_state.address, revealsecret_message, )
def test_receive_hashlocktransfer_unknown(raiden_network): app0 = raiden_network[0] # pylint: disable=unbalanced-tuple-unpacking token_manager0 = app0.raiden.managers_by_token_address.values()[0] other_key = PrivateKey(HASH2, ctx=GLOBAL_CTX, raw=True) other_address = privatekey_to_address(other_key.private_key) amount = 10 lock = Lock(amount, 1, HASH) refund_transfer = RefundTransfer(identifier=1, nonce=1, token=token_manager0.token_address, transferred_amount=amount, recipient=app0.raiden.address, locksroot=HASH, lock=lock) sign_and_send(refund_transfer, other_key, other_address, app0) secret = Secret(1, HASH, token_manager0.token_address) sign_and_send(secret, other_key, other_address, app0) secret_request = SecretRequest(1, HASH, 1) sign_and_send(secret_request, other_key, other_address, app0) reveal_secret = RevealSecret(HASH) sign_and_send(reveal_secret, other_key, other_address, app0)
def run_test_receive_secrethashtransfer_unknown(raiden_network, token_addresses): app0 = raiden_network[0] token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) other_key = HOP1_KEY other_signer = LocalSigner(other_key) channel_identifier = make_channel_identifier() amount = 10 refund_transfer_message = make_refund_transfer( payment_identifier=1, nonce=1, token_network_address=token_network_identifier, token=token_address, channel_identifier=channel_identifier, transferred_amount=amount, recipient=app0.raiden.address, locksroot=UNIT_SECRETHASH, amount=amount, secrethash=UNIT_SECRETHASH, ) sign_and_inject(refund_transfer_message, other_signer, app0) unlock = Unlock( chain_id=UNIT_CHAIN_ID, message_identifier=random.randint(0, UINT64_MAX), payment_identifier=1, nonce=1, channel_identifier=channel_identifier, token_network_address=token_network_identifier, transferred_amount=amount, locked_amount=0, locksroot=UNIT_SECRETHASH, secret=UNIT_SECRET, ) sign_and_inject(unlock, other_signer, app0) secret_request_message = SecretRequest( message_identifier=random.randint(0, UINT64_MAX), payment_identifier=1, secrethash=UNIT_SECRETHASH, amount=1, expiration=refund_transfer_message.lock.expiration, ) sign_and_inject(secret_request_message, other_signer, app0) reveal_secret_message = RevealSecret( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, ) sign_and_inject(reveal_secret_message, other_signer, app0)
def test_regression_revealsecret_after_secret(raiden_network, token_addresses, transport_config): """ A RevealSecret message received after a Secret message must be cleanly handled. """ app0, app1, app2 = raiden_network token = token_addresses[0] identifier = 1 payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token, ) transfer = app0.raiden.mediated_transfer_async( token_network_identifier, amount=1, target=app2.raiden.address, identifier=identifier, ) assert transfer.wait() event = must_contain_entry( app1.raiden.wal.storage.get_events(), SendSecretReveal, {}, ) assert event message_identifier = random.randint(0, UINT64_MAX) reveal_secret = RevealSecret( message_identifier, event.secret, ) app2.raiden.sign(reveal_secret) if transport_config.protocol is TransportProtocol.UDP: reveal_data = reveal_secret.encode() host_port = None app1.raiden.transport.receive(reveal_data, host_port) elif transport_config.protocol is TransportProtocol.MATRIX: app1.raiden.transport._receive_message(reveal_secret) # pylint: disable=protected-access else: raise TypeError('Unknown TransportProtocol')
def on_event(self, event): if isinstance(event, SendMediatedTransfer): receiver = event.receiver fee = 0 graph = self.raiden.channelgraphs[event.token] channel = graph.partneraddress_channel[receiver] mediated_transfer = channel.create_mediatedtransfer( event.initiator, event.target, fee, event.amount, event.identifier, event.expiration, event.hashlock, ) self.raiden.sign(mediated_transfer) channel.register_transfer(mediated_transfer) self.raiden.send_async(receiver, mediated_transfer) elif isinstance(event, SendRevealSecret): reveal_message = RevealSecret(event.secret) self.raiden.sign(reveal_message) self.raiden.send_async(event.receiver, reveal_message) elif isinstance(event, SendBalanceProof): # TODO: issue #189 # unlock and update remotely (send the Secret message) self.raiden.handle_secret( event.identifier, event.token, event.secret, None, sha3(event.secret), ) elif isinstance(event, SendSecretRequest): secret_request = SecretRequest( event.identifier, event.hashlock, event.amount, ) self.raiden.sign(secret_request) self.raiden.send_async(event.receiver, secret_request) elif isinstance(event, SendRefundTransfer): pass elif isinstance(event, EventTransferCompleted): for result in self.raiden.identifier_result[event.identifier]: result.set(True) elif isinstance(event, EventTransferFailed): for result in self.raiden.identifier_result[event.identifier]: result.set(True)
def handle_send_revealsecret( raiden: 'RaidenService', reveal_secret_event: SendRevealSecret): reveal_secret_message = RevealSecret.from_event(reveal_secret_event) raiden.sign(reveal_secret_message) raiden.send_async( reveal_secret_event.receiver, reveal_secret_message, )
def test_regression_revealsecret_after_secret(raiden_network, token_addresses, transport_protocol): """ A RevealSecret message received after a Secret message must be cleanly handled. """ app0, app1, app2 = raiden_network token = token_addresses[0] identifier = 1 payment_network_identifier = app0.raiden.default_registry.address token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), payment_network_identifier, token, ) transfer = app0.raiden.mediated_transfer_async( token_network_identifier, amount=1, target=app2.raiden.address, identifier=identifier, ) assert transfer.wait() event = must_contain_entry( app1.raiden.wal.storage.get_events(), SendSecretReveal, {}, ) assert event message_identifier = random.randint(0, UINT64_MAX) reveal_secret = RevealSecret( message_identifier, event.secret, ) app2.raiden.sign(reveal_secret) if transport_protocol is TransportProtocol.UDP: reveal_data = reveal_secret.encode() host_port = None app1.raiden.transport.receive(reveal_data, host_port) elif transport_protocol is TransportProtocol.MATRIX: app1.raiden.transport._receive_message(reveal_secret) # pylint: disable=protected-access else: raise TypeError('Unknown TransportProtocol')
def handle_send_revealsecret( raiden: 'RaidenService', reveal_secret_event: SendRevealSecret, ): reveal_secret_message = RevealSecret.from_event(reveal_secret_event) raiden.sign(reveal_secret_message) raiden.protocol.send_async( reveal_secret_event.queue_name, reveal_secret_event.recipient, reveal_secret_message, )
def from_dict(cls, data: Dict[str, Any]) -> "SendSecretRevealLight": restored = cls( sender=to_canonical_address(data["sender"]), recipient=to_canonical_address(data["recipient"]), channel_identifier=ChannelID(int(data["channel_identifier"])), message_identifier=MessageID(int(data["message_identifier"])), secret=deserialize_secret(data["secret"]), signed_secret_reveal=RevealSecret.from_dict( data["signed_secret_reveal"])) return restored
def test_receive_secrethashtransfer_unknown(raiden_network, token_addresses): app0 = raiden_network[0] token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) other_key = HOP1_KEY other_address = HOP1 amount = 10 refund_transfer_message = make_refund_transfer( payment_identifier=1, nonce=1, token_network_address=token_network_identifier, token=token_address, channel=other_address, transferred_amount=amount, recipient=app0.raiden.address, locksroot=UNIT_SECRETHASH, amount=amount, secrethash=UNIT_SECRETHASH, ) sign_and_inject(refund_transfer_message, other_key, other_address, app0) secret = Secret( message_identifier=random.randint(0, UINT64_MAX), payment_identifier=1, nonce=1, channel=make_address(), token_network_address=token_network_identifier, transferred_amount=amount, locked_amount=0, locksroot=UNIT_SECRETHASH, secret=UNIT_SECRET, ) sign_and_inject(secret, other_key, other_address, app0) secret_request_message = SecretRequest( message_identifier=random.randint(0, UINT64_MAX), payment_identifier=1, secrethash=UNIT_SECRETHASH, amount=1, ) sign_and_inject(secret_request_message, other_key, other_address, app0) reveal_secret_message = RevealSecret( message_identifier=random.randint(0, UINT64_MAX), secret=UNIT_SECRET, ) sign_and_inject(reveal_secret_message, other_key, other_address, app0)
def test_automatic_secret_registration(raiden_chain, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = 100 identifier = 1 hold_event_handler = HoldOffChainSecretRequest() app1.raiden.raiden_event_handler = hold_event_handler target = app1.raiden.address secret = sha3(target) secrethash = sha3(secret) hold_event_handler.hold_secretrequest_for(secrethash=secrethash) app0.raiden.start_mediated_transfer_with_secret( token_network_identifier, amount, target, identifier, secret, ) gevent.sleep(1) # wait for the messages to be exchanged # Stop app0 to avoid sending the unlock app0.raiden.transport.stop() reveal_secret = RevealSecret( message_identifier=random.randint(0, UINT64_MAX), secret=secret, ) app0.raiden.sign(reveal_secret) message_handler.MessageHandler().on_message(app1.raiden, reveal_secret) chain_state = views.state_from_app(app1) secrethash = sha3(secret) target_task = chain_state.payment_mapping.secrethashes_to_task[secrethash] lock_expiration = target_task.target_state.transfer.lock.expiration app1.raiden.chain.wait_until_block(target_block_number=lock_expiration) assert app1.raiden.default_secret_registry.check_registered( secrethash=secrethash, block_identifier='latest', )
def test_close_channel_lack_of_balance_proof( raiden_chain, reveal_timeout, settle_timeout, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] channel01 = channel(app0, app1, token_address) secret = sha3('test_close_channel_lack_of_balance_proof') hashlock = sha3(secret) fee = 0 amount = 100 identifier = 1 expiration = app0.raiden.get_block_number() + reveal_timeout * 2 transfer = channel01.create_mediatedtransfer( app0.raiden.address, app1.raiden.address, fee, amount, identifier, expiration, hashlock, ) app0.raiden.sign(transfer) async_result = app0.raiden.send_async(app1.raiden.address, transfer) assert async_result.wait() reveal_secret = RevealSecret(secret) app0.raiden.sign(reveal_secret) async_result = app0.raiden.send_async(app1.raiden.address, reveal_secret) assert async_result.wait() wait_until = app0.raiden.get_block_number() + settle_timeout + 2 wait_until_block(app0.raiden.chain, wait_until) # required for tester blockchain: let the alarm task run gevent.sleep(1) assert channel01.state != CHANNEL_STATE_OPENED
def test_close_channel_lack_of_balance_proof(raiden_chain, deposit, token_addresses): app0, app1 = raiden_chain token_address = token_addresses[0] token_proxy = app0.raiden.chain.token(token_address) initial_balance0 = token_proxy.balance_of(app0.raiden.address) initial_balance1 = token_proxy.balance_of(app1.raiden.address) amount = 100 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_address, amount, identifier, ) # Stop app0 to avoid sending the unlock app0.raiden.protocol.stop_and_wait() reveal_secret = RevealSecret( random.randint(0, UINT64_MAX), secret, ) app0.raiden.sign(reveal_secret) udp_message_handler.on_udp_message(app1.raiden, reveal_secret) channel_state = get_channelstate(app0, app1, token_address) waiting.wait_for_settle( app0.raiden, app0.raiden.default_registry.address, token_address, [channel_state.identifier], app0.raiden.alarm.wait_time, ) expected_balance0 = initial_balance0 + deposit - amount expected_balance1 = initial_balance1 + deposit + amount assert token_proxy.balance_of(app0.raiden.address) == expected_balance0 assert token_proxy.balance_of(app1.raiden.address) == expected_balance1
def message_from_sendevent(send_event: SendMessageEvent) -> Message: if type(send_event) == SendLockedTransfer: assert isinstance(send_event, SendLockedTransfer), MYPY_ANNOTATION message = LockedTransfer.from_event(send_event) elif type(send_event) == SendLockedTransferLight: assert isinstance(send_event, SendLockedTransferLight), MYPY_ANNOTATION message = send_event.signed_locked_transfer elif type(send_event) == SendSecretReveal: assert isinstance(send_event, SendSecretReveal), MYPY_ANNOTATION message = RevealSecret.from_event(send_event) elif type(send_event) == SendSecretRevealLight: assert isinstance(send_event, SendSecretRevealLight), MYPY_ANNOTATION message = send_event.signed_secret_reveal elif type(send_event) == SendBalanceProof: assert isinstance(send_event, SendBalanceProof), MYPY_ANNOTATION message = Unlock.from_event(send_event) elif type(send_event) == SendBalanceProofLight: assert isinstance(send_event, SendBalanceProofLight), MYPY_ANNOTATION message = send_event.signed_balance_proof elif type(send_event) == SendSecretRequest: assert isinstance(send_event, SendSecretRequest), MYPY_ANNOTATION message = SecretRequest.from_event(send_event) elif type(send_event) == SendSecretRequestLight: assert isinstance(send_event, SendSecretRequestLight), MYPY_ANNOTATION message = send_event.signed_secret_request elif type(send_event) == SendRefundTransfer: assert isinstance(send_event, SendRefundTransfer), MYPY_ANNOTATION message = RefundTransfer.from_event(send_event) elif type(send_event) == SendLockExpired: assert isinstance(send_event, SendLockExpired), MYPY_ANNOTATION message = LockExpired.from_event(send_event) elif type(send_event) == SendProcessed: assert isinstance(send_event, SendProcessed), MYPY_ANNOTATION message = Processed.from_event(send_event) else: raise ValueError(f"Unknown event type {send_event}") return message
def register_secret(self, secret): """ Register the secret with the interested channels. Note: The channel needs to be registered with `register_channel_for_hashlock`. """ hashlock = sha3(secret) revealsecret_message = RevealSecret(secret) self.raiden.sign(revealsecret_message) channels_list = self.hashlock_channel[hashlock] for channel in channels_list: channel.register_secret(secret) # This will potentially be executed multiple times and could suffer # from amplification, the protocol will ignore messages that were # already registered and send it only until a first Ack is # received. self.raiden.send_async( channel.partner_state.address, revealsecret_message, )
def test_automatic_secret_registration(raiden_chain, deposit, token_addresses, reveal_timeout): app0, app1 = raiden_chain token_address = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token_address, ) amount = 100 identifier = 1 secret = pending_mediated_transfer( raiden_chain, token_network_identifier, amount, identifier, ) # Stop app0 to avoid sending the unlock app0.raiden.transport.stop() reveal_secret = RevealSecret( random.randint(0, UINT64_MAX), secret, ) app0.raiden.sign(reveal_secret) message_handler.on_message(app1.raiden, reveal_secret) chain_state = views.state_from_app(app1) secrethash = sha3(secret) target_task = chain_state.payment_mapping.secrethashes_to_task[secrethash] lock_expiration = target_task.target_state.transfer.lock.expiration wait_until_block(app1.raiden.chain, lock_expiration) assert app1.raiden.default_secret_registry.check_registered(secrethash)
def test_receive_hashlocktransfer_unknown(raiden_network): app0 = raiden_network[0] # pylint: disable=unbalanced-tuple-unpacking graph0 = app0.raiden.token_to_channelgraph.values()[0] other_key = PrivateKey(HASH2) other_address = privatekey_to_address(HASH2) amount = 10 refund_transfer = make_refund_transfer( identifier=1, nonce=1, token=graph0.token_address, channel=other_address, transferred_amount=amount, recipient=app0.raiden.address, locksroot=UNIT_HASHLOCK, amount=amount, hashlock=UNIT_HASHLOCK, ) sign_and_send(refund_transfer, other_key, other_address, app0) secret = Secret( identifier=1, nonce=1, channel=make_address(), transferred_amount=amount, locksroot=UNIT_HASHLOCK, secret=UNIT_SECRET, ) sign_and_send(secret, other_key, other_address, app0) secret_request = SecretRequest(1, UNIT_HASHLOCK, 1) sign_and_send(secret_request, other_key, other_address, app0) reveal_secret = RevealSecret(UNIT_SECRET) sign_and_send(reveal_secret, other_key, other_address, app0)
def handle_secret( # pylint: disable=too-many-arguments self, identifier, token_address, secret, partner_secret_message, hashlock): """ Unlock/Witdraws locks, register the secret, and send Secret messages as necessary. This function will: - Unlock the locks created by this node and send a Secret message to the corresponding partner so that she can withdraw the token. - Withdraw the lock from sender. - Register the secret for the locks received and reveal the secret to the senders Note: The channel needs to be registered with `raiden.register_channel_for_hashlock`. """ # handling the secret needs to: # - unlock the token for all `forward_channel` (the current one # and the ones that failed with a refund) # - send a message to each of the forward nodes allowing them # to withdraw the token # - register the secret for the `originating_channel` so that a # proof can be made, if necessary # - reveal the secret to the `sender` node (otherwise we # cannot withdraw the token) channels_list = self.token_to_hashlock_to_channels[token_address][ hashlock] channels_to_remove = list() revealsecret_message = RevealSecret(secret) self.sign(revealsecret_message) messages_to_send = [] for channel in channels_list: # unlock a pending lock if channel.our_state.is_known(hashlock): secret = channel.create_secret(identifier, secret) self.sign(secret) channel.register_transfer( self.get_block_number(), secret, ) messages_to_send.append(( channel.partner_state.address, secret, )) channels_to_remove.append(channel) # withdraw a pending lock elif channel.partner_state.is_known(hashlock): if partner_secret_message: is_balance_proof = (partner_secret_message.sender == channel.partner_state.address and partner_secret_message.channel == channel.channel_address) if is_balance_proof: channel.register_transfer( self.get_block_number(), partner_secret_message, ) channels_to_remove.append(channel) else: channel.register_secret(secret) messages_to_send.append(( channel.partner_state.address, revealsecret_message, )) else: channel.register_secret(secret) messages_to_send.append(( channel.partner_state.address, revealsecret_message, )) else: log.error( 'Channel is registered for a given lock but the lock is not contained in it.' ) for channel in channels_to_remove: channels_list.remove(channel) if not channels_list: del self.token_to_hashlock_to_channels[token_address][hashlock] # send the messages last to avoid races for recipient, message in messages_to_send: self.send_async( recipient, message, )
def _secret(self, identifier, secret, partner_secret_message, hashlock): channels_list = self.hashlock_channel[hashlock] channels_to_remove = list() # Dont use the partner_secret_message.token since it might not match with the # current token manager our_secret_message = Secret(identifier, secret, self.token_address) self.raiden.sign(our_secret_message) revealsecret_message = RevealSecret(secret) self.raiden.sign(revealsecret_message) for channel in channels_list: # critical read/write section # - the `release_lock` might raise if the `balance_proof` changes # after the check # - a message created before the lock is release must be added in # the message queue before `our_secret_message` # We are relying on the GIL and non-blocking apis instead of an # explicit lock. if channel.partner_state.balance_proof.is_unclaimed(hashlock): # we are the sender, so we can release the lock once the secret # is known and add the update message into the end of the # message queue, all the messages will remain consistent # (including the messages in-transit and the ones that are # already in the queue) channel.release_lock(secret) # notify our partner that our state is updated and it can # withdraw the token self.raiden.send_async(channel.partner_state.address, our_secret_message) channels_to_remove.append(channel) # we are the recipient, we can only withdraw the token if a secret # message is received from the correct sender and token address, so # withdraw if a valid message is received otherwise register the # secret and reveal the secret to channel patner. if channel.our_state.balance_proof.is_unclaimed(hashlock): # partner_secret_message might be None if partner_secret_message: valid_sender = partner_secret_message.sender == channel.partner_state.address valid_token = partner_secret_message.token == channel.token_address if valid_sender and valid_token: channel.withdraw_lock(secret) channels_to_remove.append(channel) else: # assume our partner does not know the secret and reveal it channel.register_secret(secret) self.raiden.send_async(channel.partner_state.address, revealsecret_message) else: channel.register_secret(secret) self.raiden.send_async(channel.partner_state.address, revealsecret_message) # /critical read/write section for channel in channels_to_remove: channels_list.remove(channel) # delete the list from defaultdict, it wont be used again if len(channels_list) == 0: del self.hashlock_channel[hashlock]
def test_regression_multiple_revealsecret(raiden_network, token_addresses, transport_protocol): """ Multiple RevealSecret messages arriving at the same time must be handled properly. Secret handling followed these steps: The Secret message arrives The secret is registered The channel is updated and the correspoding lock is removed * A balance proof for the new channel state is created and sent to the payer The channel is unregistered for the given secrethash The step marked with an asterisk above introduced a context-switch. This allowed a second Reveal Secret message to be handled before the channel was unregistered. And because the channel was already updated an exception was raised for an unknown secret. """ app0, app1 = raiden_network token = token_addresses[0] token_network_identifier = views.get_token_network_identifier_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token, ) channelstate_0_1 = get_channelstate(app0, app1, token_network_identifier) payment_identifier = 1 secret = sha3(b'test_regression_multiple_revealsecret') secrethash = sha3(secret) expiration = app0.raiden.get_block_number() + 100 lock_amount = 10 lock = Lock( lock_amount, expiration, secrethash, ) nonce = 1 transferred_amount = 0 mediated_transfer = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=random.randint(0, UINT64_MAX), payment_identifier=payment_identifier, nonce=nonce, token_network_address=app0.raiden.default_registry.address, token=token, channel_identifier=channelstate_0_1.identifier, transferred_amount=transferred_amount, locked_amount=lock_amount, recipient=app1.raiden.address, locksroot=lock.secrethash, lock=lock, target=app1.raiden.address, initiator=app0.raiden.address, ) app0.raiden.sign(mediated_transfer) if transport_protocol is TransportProtocol.UDP: message_data = mediated_transfer.encode() host_port = None app1.raiden.transport.receive(message_data, host_port) elif transport_protocol is TransportProtocol.MATRIX: app1.raiden.transport._receive_message(mediated_transfer) else: raise TypeError('Unknown TransportProtocol') reveal_secret = RevealSecret( random.randint(0, UINT64_MAX), secret, ) app0.raiden.sign(reveal_secret) token_network_identifier = channelstate_0_1.token_network_identifier secret = Secret( chain_id=UNIT_CHAIN_ID, message_identifier=random.randint(0, UINT64_MAX), payment_identifier=payment_identifier, nonce=mediated_transfer.nonce + 1, token_network_address=token_network_identifier, channel_identifier=channelstate_0_1.identifier, transferred_amount=lock_amount, locked_amount=0, locksroot=EMPTY_MERKLE_ROOT, secret=secret, ) app0.raiden.sign(secret) if transport_protocol is TransportProtocol.UDP: messages = [ secret.encode(), reveal_secret.encode(), ] host_port = None receive_method = app1.raiden.transport.receive wait = [ gevent.spawn_later( .1, receive_method, data, host_port, ) for data in messages ] elif transport_protocol is TransportProtocol.MATRIX: messages = [ secret, reveal_secret, ] receive_method = app1.raiden.transport._receive_message wait = [ gevent.spawn_later( .1, receive_method, data, ) for data in messages ] else: raise TypeError('Unknown TransportProtocol') gevent.joinall(wait)
def test_regression_multiple_revealsecret(raiden_network, token_addresses): """ Multiple RevealSecret messages arriving at the same time must be handled properly. Secret handling followed these steps: The Secret message arrives The secret is registered The channel is updated and the correspoding lock is removed * A balance proof for the new channel state is created and sent to the payer The channel is unregistered for the given hashlock The step marked with an asterisk above introduced a context-switch, this allowed a second Reveal Secret message to be handled before the channel was unregistered, because the channel was already updated an exception was raised for an unknown secret. """ app0, app1 = raiden_network token = token_addresses[0] identifier = 1 secret = sha3(b'test_regression_multiple_revealsecret') hashlock = sha3(secret) expiration = app0.raiden.get_block_number() + 100 amount = 10 mediated_transfer = channel(app0, app1, token).create_mediatedtransfer( transfer_initiator=app0.raiden.address, transfer_target=app1.raiden.address, fee=0, amount=amount, identifier=identifier, expiration=expiration, hashlock=hashlock, ) app0.raiden.sign(mediated_transfer) message_data = mediated_transfer.encode() app1.raiden.protocol.receive(message_data) reveal_secret = RevealSecret(secret) app0.raiden.sign(reveal_secret) reveal_secret_data = reveal_secret.encode() secret = Secret( identifier=identifier, nonce=mediated_transfer.nonce + 1, channel=channel(app0, app1, token).channel_address, transferred_amount=amount, locksroot=EMPTY_MERKLE_ROOT, secret=secret, ) app0.raiden.sign(secret) secret_data = secret.encode() messages = [ secret_data, reveal_secret_data, ] wait = [ gevent.spawn_later( .1, app1.raiden.protocol.receive, data, ) for data in messages ] gevent.joinall(wait)