def set_onchain_secret(state, channelidentifiers_to_channels, secret, secrethash, block_number): """ Set the secret to all mediated transfers. The secret should have been learned from the secret registry. """ state.secret = secret for pair in state.transfers_pair: payer_channel = channelidentifiers_to_channels[ pair.payer_transfer.balance_proof.channel_identifier] channel.register_onchain_secret( payer_channel, secret, secrethash, block_number, ) payee_channel = channelidentifiers_to_channels[ pair.payee_transfer.balance_proof.channel_identifier] channel.register_onchain_secret( channel_state=payee_channel, secret=secret, secrethash=secrethash, secret_reveal_block_number=block_number, )
def set_onchain_secret(state, channelidentifiers_to_channels, secret, secrethash): """ Set the secret to all mediated transfers. The secret should have been learned from the secret registry. """ state.secret = secret for pair in state.transfers_pair: payer_channel = channelidentifiers_to_channels[ pair.payer_transfer.balance_proof.channel_address ] channel.register_onchain_secret( payer_channel, secret, secrethash, ) payee_channel = channelidentifiers_to_channels[ pair.payee_transfer.balance_proof.channel_address ] channel.register_onchain_secret( payee_channel, secret, secrethash, )
def handle_onchain_secretreveal( initiator_state: InitiatorTransferState, state_change: ContractReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, block_number: BlockNumber, ) -> TransitionResult[Optional[InitiatorTransferState]]: """ When a secret is revealed on-chain all nodes learn the secret. This check the on-chain secret corresponds to the one used by the initiator, and if valid a new balance proof is sent to the next hop with the current lock removed from the pending locks and the transferred amount updated. """ iteration: TransitionResult[Optional[InitiatorTransferState]] secret = state_change.secret secrethash = initiator_state.transfer_description.secrethash is_valid_secret = is_valid_secret_reveal(state_change=state_change, transfer_secrethash=secrethash) is_channel_open = channel.get_status( channel_state) == ChannelState.STATE_OPENED is_lock_expired = state_change.block_number > initiator_state.transfer.lock.expiration is_lock_unlocked = is_valid_secret and not is_lock_expired if is_lock_unlocked: channel.register_onchain_secret( channel_state=channel_state, secret=secret, secrethash=secrethash, secret_reveal_block_number=state_change.block_number, ) lock = initiator_state.transfer.lock expired = channel.is_lock_expired( end_state=channel_state.our_state, lock=lock, block_number=block_number, lock_expiration_threshold=lock.expiration, ) if is_lock_unlocked and is_channel_open and not expired: events = events_for_unlock_lock( initiator_state, channel_state, state_change.secret, state_change.secrethash, pseudo_random_generator, block_number, ) iteration = TransitionResult(None, events) else: events = list() iteration = TransitionResult(initiator_state, events) return iteration
def test_target_transfer_invalid_if_lock_registered_onchain(): lock_amount = 7 block_number = 1 initiator = factories.HOP6 pseudo_random_generator = random.Random() our_balance = 100 our_address = factories.make_address() partner_balance = 130 from_channel = factories.make_channel( our_address=our_address, our_balance=our_balance, partner_address=UNIT_TRANSFER_SENDER, partner_balance=partner_balance, ) from_route = factories.route_from_channel(from_channel) expiration = block_number + from_channel.settle_timeout - from_channel.reveal_timeout from_transfer = factories.make_signed_transfer_for( from_channel, lock_amount, initiator, our_address, expiration, UNIT_SECRET, identifier=1, nonce=1, ) init = ActionInitTarget( from_route, from_transfer, ) secrethash = from_transfer.lock.secrethash # mock register secret on-chain from_channel.our_state.secrethashes_to_lockedlocks[ secrethash] = from_transfer.lock channel.register_onchain_secret( channel_state=from_channel, secret=UNIT_SECRET, secrethash=secrethash, secret_reveal_block_number=0, delete_lock=True, ) init_transition = target.state_transition( None, init, from_channel, pseudo_random_generator, block_number, ) assert init_transition.new_state is None
def handle_secretreveal( target_state: TargetTransferState, state_change: ReceiveSecretReveal, channel_state: NettingChannelState, pseudo_random_generator: random.Random, ): """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash waiting_for_secret = target_state.state == 'secret_request' if valid_secret and waiting_for_secret: if isinstance(state_change, ReceiveSecretReveal): channel.register_secret( channel_state, state_change.secret, state_change.secrethash, ) elif isinstance(state_change, ContractReceiveSecretReveal): channel.register_onchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, secret_reveal_block_number=state_change.block_number, ) else: assert False, 'Got unexpected StateChange' route = target_state.route message_identifier = message_identifier_from_prng( pseudo_random_generator) target_state.state = 'reveal_secret' target_state.secret = state_change.secret recipient = route.node_address # Send the secret reveal message only once, delivery is guaranteed by # the transport and not by the state machine reveal = SendSecretReveal( recipient=recipient, channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, secret=target_state.secret, ) iteration = TransitionResult(target_state, [reveal]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration
def handle_secretreveal( target_state, state_change, channel_state, pseudo_random_generator, ): """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash if valid_secret: if isinstance(state_change, ReceiveSecretReveal): channel.register_secret( channel_state, state_change.secret, state_change.secrethash, ) elif isinstance(state_change, ContractReceiveSecretReveal): channel.register_onchain_secret( channel_state, state_change.secret, state_change.secrethash, ) else: assert False, 'Got unexpected StateChange' route = target_state.route message_identifier = message_identifier_from_prng( pseudo_random_generator) target_state.state = 'reveal_secret' target_state.secret = state_change.secret recipient = route.node_address queue_name = b'global' reveal = SendRevealSecret( recipient, queue_name, message_identifier, target_state.secret, ) iteration = TransitionResult(target_state, [reveal]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration
def handle_secretreveal( target_state, state_change, channel_state, pseudo_random_generator, ): """ Validates and handles a ReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash if valid_secret: if isinstance(state_change, ReceiveSecretReveal): channel.register_secret( channel_state, state_change.secret, state_change.secrethash, ) elif isinstance(state_change, ContractReceiveSecretReveal): channel.register_onchain_secret( channel_state, state_change.secret, state_change.secrethash, ) else: assert False, 'Got unexpected StateChange' route = target_state.route message_identifier = message_identifier_from_prng(pseudo_random_generator) target_state.state = 'reveal_secret' target_state.secret = state_change.secret recipient = route.node_address queue_name = b'global' reveal = SendRevealSecret( recipient, queue_name, message_identifier, target_state.secret, ) iteration = TransitionResult(target_state, [reveal]) else: # TODO: event for byzantine behavior iteration = TransitionResult(target_state, list()) return iteration
def handle_onchain_secretreveal( target_state: TargetTransferState, state_change: ContractReceiveSecretReveal, channel_state: NettingChannelState, ): """ Validates and handles a ContractReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash if valid_secret: channel.register_onchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, secret_reveal_block_number=state_change.block_number, ) target_state.state = 'reveal_secret' target_state.secret = state_change.secret return TransitionResult(target_state, list())
def handle_onchain_secretreveal( initiator_state: InitiatorTransferState, state_change: ContractReceiveSecretReveal, channel_state: NettingChannelState, ) -> TransitionResult: """ Validates and handles a ContractReceiveSecretReveal state change. """ valid_secret = state_change.secrethash == initiator_state.transfer.lock.secrethash iteration = TransitionResult(initiator_state, list()) if valid_secret: # Register LockedTransfer in secrethashes_to_onchain_unlockedlocks # without removing the LockedTransfer from secrethashes_to_lockedlocks channel.register_onchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, delete_lock=False, ) iteration.new_state = initiator_state return iteration
def handle_onchain_secretreveal( target_state: TargetTransferState, state_change: ContractReceiveSecretReveal, channel_state: NettingChannelState, ): """ Validates and handles a ContractReceiveSecretReveal state change. """ valid_secret = is_valid_secret_reveal( state_change=state_change, transfer_secrethash=target_state.transfer.lock.secrethash, secret=state_change.secret, ) if valid_secret: channel.register_onchain_secret( channel_state=channel_state, secret=state_change.secret, secrethash=state_change.secrethash, secret_reveal_block_number=state_change.block_number, ) target_state.state = TargetTransferState.ONCHAIN_UNLOCK target_state.secret = state_change.secret return TransitionResult(target_state, list())
def set_onchain_secret( state: MediatorTransferState, channelidentifiers_to_channels: typing.ChannelMap, secret: typing.Secret, secrethash: typing.SecretHash, block_number: typing.BlockNumber, ) -> typing.List[Event]: """ Set the secret to all mediated transfers. The secret should have been learned from the secret registry. """ state.secret = secret for pair in state.transfers_pair: payer_channel = channelidentifiers_to_channels[ pair.payer_transfer.balance_proof.channel_identifier ] channel.register_onchain_secret( payer_channel, secret, secrethash, block_number, ) payee_channel = channelidentifiers_to_channels[ pair.payee_transfer.balance_proof.channel_identifier ] channel.register_onchain_secret( channel_state=payee_channel, secret=secret, secrethash=secrethash, secret_reveal_block_number=block_number, ) # Like the off-chain secret reveal, the secret should never be revealed # on-chain if there is a waiting transfer. if state.waiting_transfer: payer_channel = channelidentifiers_to_channels[ state.waiting_transfer.transfer.balance_proof.channel_identifier ] channel.register_onchain_secret( channel_state=payer_channel, secret=secret, secrethash=secrethash, secret_reveal_block_number=block_number, ) unexpected_reveal = EventUnexpectedSecretReveal( secrethash=secrethash, reason='The mediator has a waiting transfer.', ) return [unexpected_reveal] return list()