def test_event_operators(): a = EventTransferSentSuccess(2) b = EventTransferSentSuccess(2) c = EventTransferSentSuccess(3) assert a == b assert not a != b assert a != c assert not a == c a = EventTransferSentFailed(2, 'BECAUSE') b = EventTransferSentFailed(2, 'BECAUSE') c = EventTransferSentFailed(3, 'UNKNOWN') assert a == b assert not a != b assert a != c assert not a == c a = EventTransferReceivedSuccess(2, 5, sha3('initiator')) b = EventTransferReceivedSuccess(2, 5, sha3('initiator')) c = EventTransferReceivedSuccess(3, 5, sha3('initiator')) d = EventTransferReceivedSuccess(3, 5, sha3('other initiator')) assert a == b assert not a != b assert a != c assert not a == c assert c != d assert not c == d
def test_event_operators(): a = EventTransferSentSuccess(2) b = EventTransferSentSuccess(2) c = EventTransferSentSuccess(3) assert a == b assert not a != b assert a != c assert not a == c a = EventTransferSentFailed(2, 'BECAUSE') b = EventTransferSentFailed(2, 'BECAUSE') c = EventTransferSentFailed(3, 'UNKNOWN') assert a == b assert not a != b assert a != c assert not a == c a = EventTransferReceivedSuccess(2) b = EventTransferReceivedSuccess(2) c = EventTransferReceivedSuccess(3) assert a == b assert not a != b assert a != c assert not a == c
def test_event_operators(): a = EventTransferSentSuccess(2, 5, sha3(b'target')) b = EventTransferSentSuccess(2, 5, sha3(b'target')) c = EventTransferSentSuccess(3, 4, sha3(b'target')) d = EventTransferSentSuccess(3, 4, sha3(b'differenttarget')) # pylint: disable=unneeded-not assert a == b assert not a != b assert a != c assert not a == c assert not c == d a = EventTransferSentFailed(2, 'BECAUSE') b = EventTransferSentFailed(2, 'BECAUSE') c = EventTransferSentFailed(3, 'UNKNOWN') assert a == b assert not a != b assert a != c assert not a == c a = EventTransferReceivedSuccess(2, 5, sha3(b'initiator')) b = EventTransferReceivedSuccess(2, 5, sha3(b'initiator')) c = EventTransferReceivedSuccess(3, 5, sha3(b'initiator')) d = EventTransferReceivedSuccess(3, 5, sha3(b'other initiator')) assert a == b assert not a != b assert a != c assert not a == c assert c != d assert not c == d
def handle_secretreveal(state, state_change): """ Send a balance proof to the next hop with the current mediated transfer lock removed and the balance updated. """ if state_change.sender == state.route.node_address: # next hop learned the secret, unlock the token locally and send the # withdraw message to next hop transfer = state.transfer unlock_lock = SendBalanceProof( transfer.identifier, state.route.channel_address, transfer.token, state.route.node_address, transfer.secret, ) transfer_success = EventTransferSentSuccess( transfer.identifier, transfer.amount, transfer.target, ) unlock_success = EventUnlockSuccess( transfer.identifier, transfer.hashlock, ) iteration = TransitionResult(None, [unlock_lock, transfer_success, unlock_success]) else: iteration = TransitionResult(state, list()) return iteration
def test_initiator_log_directransfer_success( raiden_chain, token_addresses, deposit): token_address = token_addresses[0] amount = int(deposit / 2.) identifier = 7 app0, app1 = raiden_chain # pylint: disable=unbalanced-tuple-unpacking direct_transfer( app0, app1, token_address, amount, identifier, ) app0_events = get_all_state_events(app0.raiden.transaction_log) sucessful_transfers = [ event.event_object for event in app0_events if isinstance(event.event_object, EventTransferSentSuccess) ] assert sucessful_transfers[0] == EventTransferSentSuccess( identifier, )
def handle_processed( chain_state: ChainState, state_change: ReceiveProcessed, ) -> TransitionResult: # TODO: improve the complexity of this algorithm events = list() for queue in chain_state.queueids_to_queues.values(): remove = [] # TODO: ensure Processed message came from the correct peer for pos, message in enumerate(queue): if message.message_identifier == state_change.message_identifier: if type(message) == SendDirectTransfer: events.append( EventTransferSentSuccess( message.payment_identifier, message.balance_proof.transferred_amount, message.recipient, )) remove.append(pos) for removepos in reversed(remove): queue.pop(removepos) return TransitionResult(chain_state, events)
def handle_secretreveal( initiator_state: InitiatorTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, ) -> TransitionResult: """ Send a balance proof to the next hop with the current mediated transfer lock removed and the balance updated. """ is_valid_secret_reveal = ( state_change.sender == channel_state.partner_state.address and state_change.secrethash == initiator_state.transfer_description.secrethash) # If the channel is closed the balance proof must not be sent is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED if is_valid_secret_reveal and is_channel_open: # next hop learned the secret, unlock the token locally and send the # withdraw message to next hop transfer_description = initiator_state.transfer_description message_identifier = message_identifier_from_prng( pseudo_random_generator) unlock_lock = channel.send_unlock( channel_state, transfer_description.payment_identifier, message_identifier, state_change.secret, state_change.secrethash, ) # TODO: Emit these events after on-chain withdraw transfer_success = EventTransferSentSuccess( transfer_description.payment_identifier, transfer_description.amount, transfer_description.target, ) unlock_success = EventUnlockSuccess( transfer_description.payment_identifier, transfer_description.secrethash, ) iteration = TransitionResult( None, [transfer_success, unlock_success, unlock_lock]) else: iteration = TransitionResult(initiator_state, list()) return iteration
def handle_secretreveal2(initiator_state, state_change, channel_state): """ Send a balance proof to the next hop with the current mediated transfer lock removed and the balance updated. """ is_valid_secret_reveal = (state_change.sender == channel_state.partner_state.address and state_change.hashlock == initiator_state.transfer_description.hashlock) # If the channel is closed the balance proof must not be sent is_channel_open = channel.get_status(channel_state) == CHANNEL_STATE_OPENED if is_valid_secret_reveal and is_channel_open: # next hop learned the secret, unlock the token locally and send the # withdraw message to next hop transfer_description = initiator_state.transfer_description unlock_lock = channel.send_unlock( channel_state, transfer_description.identifier, state_change.secret, state_change.hashlock, ) # TODO: Emit these events after on-chain withdraw transfer_success = EventTransferSentSuccess( transfer_description.identifier, transfer_description.amount, transfer_description.target, ) unlock_success = EventUnlockSuccess( transfer_description.identifier, transfer_description.hashlock, ) iteration = TransitionResult( None, [transfer_success, unlock_success, unlock_lock]) else: iteration = TransitionResult(initiator_state, list()) return iteration
def direct_transfer_async(self, token_address, amount, target, identifier): """ Do a direct tranfer with target. Direct transfers are non cancellable and non expirable, since these transfers are a signed balance proof with the transferred amount incremented. Because the transfer is non cancellable, there is a level of trust with the target. After the message is sent the target is effectively paid and then it is not possible to revert. The async result will be set to False iff there is no direct channel with the target or the payer does not have balance to complete the transfer, otherwise because the transfer is non expirable the async result *will never be set to False* and if the message is sent it will hang until the target node acknowledge the message. This transfer should be used as an optimization, since only two packets are required to complete the transfer (from the payer's perspective), whereas the mediated transfer requires 6 messages. """ graph = self.token_to_channelgraph[token_address] direct_channel = graph.partneraddress_to_channel.get(target) direct_channel_with_capacity = (direct_channel and direct_channel.can_transfer and amount <= direct_channel.distributable) if direct_channel_with_capacity: direct_transfer = direct_channel.create_directtransfer( amount, identifier) self.sign(direct_transfer) direct_channel.register_transfer( self.get_block_number(), direct_transfer, ) direct_transfer_state_change = ActionTransferDirect( identifier, amount, token_address, direct_channel.partner_state.address, ) # TODO: add the transfer sent event state_change_id = self.transaction_log.log( direct_transfer_state_change) # TODO: This should be set once the direct transfer is acknowledged transfer_success = EventTransferSentSuccess( identifier, amount, target, ) self.transaction_log.log_events(state_change_id, [transfer_success], self.get_block_number()) async_result = self.protocol.send_async( direct_channel.partner_state.address, direct_transfer, ) else: async_result = AsyncResult() async_result.set(False) return async_result
def _direct_or_mediated_transfer(self, token_address, amount, identifier, direct_channel): """ Check the direct channel and if possible use it, otherwise start a mediated transfer. """ if not direct_channel.can_transfer: log.info( 'DIRECT CHANNEL %s > %s is closed or has no funding', pex(direct_channel.our_state.address), pex(direct_channel.partner_state.address), ) async_result = self._mediated_transfer( token_address, amount, identifier, direct_channel.partner_state.address, ) elif amount > direct_channel.distributable: log.info( 'DIRECT CHANNEL %s > %s doesnt have enough funds [%s]', pex(direct_channel.our_state.address), pex(direct_channel.partner_state.address), amount, ) async_result = self._mediated_transfer( token_address, amount, identifier, direct_channel.partner_state.address, ) else: direct_transfer = direct_channel.create_directtransfer(amount, identifier) self.sign(direct_transfer) direct_channel.register_transfer( self.get_block_number(), direct_transfer, ) direct_transfer_state_change = ActionTransferDirect( identifier, amount, token_address, direct_channel.partner_state.address, ) # TODO: add the transfer sent event state_change_id = self.transaction_log.log(direct_transfer_state_change) # TODO: This should be set once the direct transfer is acknowledged transfer_success = EventTransferSentSuccess( identifier, ) self.transaction_log.log_events( state_change_id, [transfer_success], self.get_block_number() ) async_result = self.protocol.send_async( direct_channel.partner_state.address, direct_transfer, ) return async_result