예제 #1
0
def make_from_route_from_counter(counter):
    from_channel = factories.create(
        factories.NettingChannelStateProperties(
            canonical_identifier=factories.make_canonical_identifier(),
            token_address=factories.make_token_address(),
            partner_state=factories.NettingChannelEndStateProperties(
                balance=next(counter), address=factories.HOP1),
        ))
    from_hop = factories.make_hop_from_channel(from_channel)

    expiration = BlockExpiration(factories.UNIT_REVEAL_TIMEOUT + 1)

    from_transfer = factories.make_signed_transfer_for(
        from_channel,
        factories.LockedTransferSignedStateProperties(
            transferred_amount=TokenAmount(0),
            canonical_identifier=factories.make_canonical_identifier(
                token_network_address=from_channel.token_network_address),
            amount=TokenAmount(1),
            expiration=expiration,
            secret=sha3(factories.make_secret(next(counter))),
            initiator=factories.make_initiator_address(),
            target=factories.make_target_address(),
            payment_identifier=next(counter),
            sender=factories.HOP1,
            pkey=factories.HOP1_KEY,
        ),
    )
    return from_hop, from_transfer
예제 #2
0
def test_restore_queueids_to_queues(chain_state, netting_channel_state):
    """Test that withdraw messages are restorable if they exist in
    chain_state.queueids_to_queues.
    """
    recipient = netting_channel_state.partner_state.address

    queue_identifier = QueueIdentifier(
        recipient=recipient,
        canonical_identifier=netting_channel_state.canonical_identifier)

    msg_args = dict(
        recipient=recipient,
        canonical_identifier=netting_channel_state.canonical_identifier,
        message_identifier=factories.make_message_identifier(),
        total_withdraw=WithdrawAmount(1),
        participant=recipient,
        expiration=BlockExpiration(10),
        nonce=Nonce(15),
    )
    messages = [
        SendWithdrawRequest(**msg_args),
        SendWithdrawConfirmation(**msg_args),
        SendWithdrawExpired(**msg_args),
    ]

    chain_state.queueids_to_queues[queue_identifier] = messages

    serialized_chain_state = JSONSerializer.serialize(chain_state)

    deserialized_chain_state = JSONSerializer.deserialize(
        serialized_chain_state)

    assert chain_state == deserialized_chain_state
예제 #3
0
def test_events_loaded_from_storage_should_deserialize(tmp_path):
    filename = Path(f"{tmp_path}/v{RAIDEN_DB_VERSION}_log.db")
    storage = SerializedSQLiteStorage(filename, serializer=JSONSerializer())

    # Satisfy the foreign-key constraint for state change ID
    ids = storage.write_state_changes([
        Block(
            block_number=BlockNumber(1),
            gas_limit=BlockGasLimit(1),
            block_hash=factories.make_block_hash(),
        )
    ])

    canonical_identifier = factories.make_canonical_identifier()
    recipient = factories.make_address()
    participant = factories.make_address()
    event = SendWithdrawRequest(
        recipient=recipient,
        canonical_identifier=canonical_identifier,
        message_identifier=factories.make_message_identifier(),
        total_withdraw=WithdrawAmount(1),
        participant=participant,
        expiration=BlockExpiration(10),
        nonce=Nonce(15),
    )
    storage.write_events([(ids[0], event)])

    stored_events = storage.get_events()
    assert stored_events[0] == event
예제 #4
0
    def from_dict(cls, data: Dict[str, Any]) -> 'ContractSendSecretReveal':
        restored = cls(
            expiration=BlockExpiration(int(data['expiration'])),
            secret=Secret(serialization.deserialize_bytes(data['secret'])),
        )

        return restored
예제 #5
0
    def from_dict(cls, data: Dict[str, Any]) -> 'ContractSendChannelUpdateTransfer':
        restored = cls(
            expiration=BlockExpiration(int(data['expiration'])),
            balance_proof=data['balance_proof'],
            triggered_by_block_hash=BlockHash(deserialize_bytes(data['triggered_by_block_hash'])),
        )

        return restored
예제 #6
0
파일: transfers.py 프로젝트: sekmet/raiden
 def from_bytes(cls, serialized: bytes) -> "Lock":
     return cls(
         expiration=BlockExpiration(
             int.from_bytes(serialized[:32], byteorder="big")),
         amount=PaymentWithFeeAmount(
             int.from_bytes(serialized[32:64], byteorder="big")),
         secrethash=SecretHash(serialized[64:]),
     )
예제 #7
0
def test_locked_transfer_secret_registered_onchain(
    raiden_network, token_addresses, secret_registry_address, retry_timeout
):
    app0 = raiden_network[0]
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state, token_network_registry_address, token_address
    )

    amount = TokenAmount(1)
    target = factories.UNIT_TRANSFER_INITIATOR
    identifier = PaymentID(1)
    transfer_secret = make_secret()

    secret_registry_proxy = app0.raiden.proxy_manager.secret_registry(
        secret_registry_address, block_identifier=chain_state.block_hash
    )
    secret_registry_proxy.register_secret(secret=transfer_secret)

    # Wait until our node has processed the block that the secret registration was mined at
    block_number = app0.raiden.get_block_number()
    wait_for_block(
        raiden=app0.raiden,
        block_number=block_number + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
        retry_timeout=retry_timeout,
    )

    # Test that sending a transfer with a secret already registered on-chain fails
    with pytest.raises(RaidenUnrecoverableError):
        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=amount,
            target=target,
            identifier=identifier,
            secret=transfer_secret,
        )

    # Test that receiving a transfer with a secret already registered on chain fails
    expiration = BlockExpiration(9999)
    locked_transfer = factories.create(
        factories.LockedTransferProperties(
            amount=amount,
            target=app0.raiden.address,
            expiration=expiration,
            secret=transfer_secret,
        )
    )

    message_handler = MessageHandler()
    message_handler.handle_message_lockedtransfer(app0.raiden, locked_transfer)

    state_changes = app0.raiden.wal.storage.get_statechanges_by_range(RANGE_ALL_STATE_CHANGES)
    transfer_statechange_dispatched = search_for_item(
        state_changes, ActionInitMediator, {}
    ) or search_for_item(state_changes, ActionInitTarget, {})
    assert not transfer_statechange_dispatched
예제 #8
0
    def from_dict(cls, data: Dict[str, Any]) -> "ContractSendSecretReveal":
        restored = cls(
            expiration=BlockExpiration(int(data["expiration"])),
            secret=Secret(serialization.deserialize_bytes(data["secret"])),
            triggered_by_block_hash=BlockHash(
                deserialize_bytes(data["triggered_by_block_hash"])),
        )

        return restored
예제 #9
0
 def from_dict(cls, data: Dict[str, Any]) -> 'ReceiveSecretRequest':
     instance = cls(
         payment_identifier=PaymentID(int(data['payment_identifier'])),
         amount=PaymentAmount(int(data['amount'])),
         expiration=BlockExpiration(int(data['expiration'])),
         secrethash=SecretHash(deserialize_bytes(data['secrethash'])),
         sender=to_canonical_address(data['sender']),
     )
     instance.revealsecret = data['revealsecret']
     return instance
예제 #10
0
 def from_dict(cls, data: Dict[str, Any]) -> "ReceiveSecretRequest":
     instance = cls(
         payment_identifier=PaymentID(int(data["payment_identifier"])),
         amount=PaymentAmount(int(data["amount"])),
         expiration=BlockExpiration(int(data["expiration"])),
         secrethash=SecretHash(deserialize_bytes(data["secrethash"])),
         sender=to_canonical_address(data["sender"]),
     )
     instance.revealsecret = data["revealsecret"]
     return instance
예제 #11
0
파일: events.py 프로젝트: virrius/lumino
    def from_dict(
            cls, data: Dict[str,
                            Any]) -> "ContractSendChannelUpdateTransferLight":
        restored = cls(expiration=BlockExpiration(int(data["expiration"])),
                       balance_proof=data["balance_proof"],
                       triggered_by_block_hash=BlockHash(
                           deserialize_bytes(data["triggered_by_block_hash"])),
                       lc_bp_signature=data["lc_bp_signature"],
                       lc_address=to_canonical_address(data["lc_address"]))

        return restored
예제 #12
0
def make_message(sign: bool = True) -> Message:
    message = SecretRequest(
        message_identifier=make_message_identifier(),
        payment_identifier=PaymentID(1),
        secrethash=factories.UNIT_SECRETHASH,
        amount=PaymentAmount(1),
        expiration=BlockExpiration(10),
        signature=EMPTY_SIGNATURE,
    )
    if sign:
        message.sign(LocalSigner(factories.HOP1_KEY))
    return message
예제 #13
0
    def from_dict(cls, data: Dict[str, Any]) -> 'SendSecretRequest':
        restored = cls(
            recipient=to_canonical_address(data['recipient']),
            channel_identifier=ChannelID(int(data['channel_identifier'])),
            message_identifier=MessageID(int(data['message_identifier'])),
            payment_identifier=PaymentID(int(data['payment_identifier'])),
            amount=TokenAmount(int(data['amount'])),
            expiration=BlockExpiration(int(data['expiration'])),
            secrethash=SecretHash(serialization.deserialize_bytes(data['secrethash'])),
        )

        return restored
예제 #14
0
    def from_dict(cls, data: Dict[str, Any]) -> "SendSecretRequest":
        restored = cls(
            recipient=to_canonical_address(data["recipient"]),
            channel_identifier=ChannelID(int(data["channel_identifier"])),
            message_identifier=MessageID(int(data["message_identifier"])),
            payment_identifier=PaymentID(int(data["payment_identifier"])),
            amount=PaymentWithFeeAmount(int(data["amount"])),
            expiration=BlockExpiration(int(data["expiration"])),
            secrethash=deserialize_secret_hash(data["secrethash"]),
        )

        return restored
예제 #15
0
class UnlockPartialProofState(State):
    """ Stores the lock along with its unlocking secret. """

    lock: HashTimeLockState
    secret: Secret = field(repr=False)
    amount: PaymentWithFeeAmount = field(repr=False, default=PaymentWithFeeAmount(0))
    expiration: BlockExpiration = field(repr=False, default=BlockExpiration(0))
    secrethash: SecretHash = field(repr=False, default=EMPTY_SECRETHASH)
    encoded: EncodedData = field(init=False, repr=False)

    def __post_init__(self) -> None:
        typecheck(self.lock, HashTimeLockState)
        typecheck(self.secret, T_Secret)

        self.amount = self.lock.amount
        self.expiration = self.lock.expiration
        self.secrethash = self.lock.secrethash
        self.encoded = self.lock.encoded
예제 #16
0
def make_iou(
    pfs_config: PFSConfig,
    our_address: Address,
    one_to_n_address: OneToNAddress,
    privkey: PrivateKey,
    block_number: BlockNumber,
    chain_id: ChainID,
    offered_fee: TokenAmount,
) -> IOU:
    expiration = BlockExpiration(block_number + pfs_config.iou_timeout)

    iou = IOU(
        sender=our_address,
        receiver=pfs_config.info.payment_address,
        one_to_n_address=one_to_n_address,
        amount=offered_fee,
        expiration_block=expiration,
        chain_id=chain_id,
    )
    iou.sign(privkey)

    return iou
예제 #17
0
    def _new_mediator_transfer(self, initiator_address, target_address,
                               payment_id, amount, secret,
                               our_address) -> LockedTransferSignedState:
        initiator_pkey = self.address_to_privkey[initiator_address]
        balance_proof_data = self._update_balance_proof_data(
            initiator_address, amount, self.block_number + 10, secret,
            our_address)
        self.secrethash_to_secret[sha256_secrethash(secret)] = secret

        return factories.create(
            factories.LockedTransferSignedStateProperties(  # type: ignore
                **balance_proof_data.properties.__dict__,
                amount=amount,
                expiration=BlockExpiration(self.block_number + 10),
                payment_identifier=payment_id,
                secret=secret,
                initiator=initiator_address,
                target=target_address,
                token=self.token_id,
                sender=initiator_address,
                recipient=our_address,
                pkey=initiator_pkey,
                message_identifier=MessageID(1),
            ))
예제 #18
0
def test_regression_multiple_revealsecret(
        raiden_network: List[App],
        token_addresses: List[TokenAddress]) -> None:
    """ Multiple RevealSecret messages arriving at the same time must be
    handled properly.

    Unlock handling followed these steps:

        The Unlock 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 Unlock 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_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token)
    assert token_network_address
    channelstate_0_1 = get_channelstate(app0, app1, token_network_address)

    payment_identifier = PaymentID(1)
    secret, secrethash = make_secret_with_hash()
    expiration = BlockExpiration(app0.raiden.get_block_number() + 100)
    lock_amount = PaymentWithFeeAmount(10)
    lock = Lock(amount=lock_amount,
                expiration=expiration,
                secrethash=secrethash)

    nonce = Nonce(1)
    transferred_amount = TokenAmount(0)
    mediated_transfer = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=nonce,
        token_network_address=token_network_address,
        token=token,
        channel_identifier=channelstate_0_1.identifier,
        transferred_amount=transferred_amount,
        locked_amount=LockedAmount(lock_amount),
        recipient=app1.raiden.address,
        locksroot=Locksroot(lock.lockhash),
        lock=lock,
        target=TargetAddress(app1.raiden.address),
        initiator=InitiatorAddress(app0.raiden.address),
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[
            RouteMetadata(route=[app0.raiden.address, app1.raiden.address])
        ]),
    )
    app0.raiden.sign(mediated_transfer)
    app1.raiden.on_messages([mediated_transfer])

    reveal_secret = RevealSecret(message_identifier=make_message_identifier(),
                                 secret=secret,
                                 signature=EMPTY_SIGNATURE)
    app0.raiden.sign(reveal_secret)

    token_network_address = channelstate_0_1.token_network_address
    unlock = Unlock(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=Nonce(mediated_transfer.nonce + 1),
        token_network_address=token_network_address,
        channel_identifier=channelstate_0_1.identifier,
        transferred_amount=TokenAmount(lock_amount),
        locked_amount=LockedAmount(0),
        locksroot=LOCKSROOT_OF_NO_LOCKS,
        secret=secret,
        signature=EMPTY_SIGNATURE,
    )
    app0.raiden.sign(unlock)

    messages = [unlock, reveal_secret]
    receive_method = app1.raiden.on_messages
    wait = set(
        gevent.spawn_later(0.1, receive_method, [data]) for data in messages)

    gevent.joinall(wait, raise_error=True)
)
from raiden.transfer.mediated_transfer.state import MediatorTransferState
from raiden.transfer.mediated_transfer.state_change import (
    ActionInitMediator,
    ReceiveLockExpired,
    ReceiveSecretReveal,
    ReceiveTransferRefund,
)
from raiden.transfer.state import NetworkState, message_identifier_from_prng
from raiden.transfer.state_change import Block, ContractReceiveSecretReveal
from raiden.utils.signer import LocalSigner
from raiden.utils.typing import BlockExpiration

LONG_EXPIRATION = factories.create_properties(
    factories.LockedTransferSignedStateProperties(
        expiration=BlockExpiration(30)))


def test_payer_enter_danger_zone_with_transfer_payed():
    """ A mediator may have paid the next hop (payee), and didn't get paid by
    the previous hop (payer).

    When this happens, an assertion must not be hit, because it means the
    transfer must be unlocked on-chain.

    Issue: https://github.com/raiden-network/raiden/issues/1013
    """
    block_number = 5
    pseudo_random_generator = random.Random()

    channels = factories.mediator_make_channel_pair()
예제 #20
0
def make_hash_time_lock_state(amount) -> HashTimeLockState:
    return HashTimeLockState(amount=amount,
                             expiration=BlockExpiration(5),
                             secrethash=factories.UNIT_SECRETHASH)
예제 #21
0
def get_initial_lock_expiration(
    block_number: BlockNumber,
    reveal_timeout: BlockTimeout,
) -> BlockExpiration:
    """ Returns the expiration used for all hash-time-locks in transfer. """
    return BlockExpiration(block_number + reveal_timeout * 2)
예제 #22
0
def _withdraw_participant_left_capacity_from_channel(
    address_to_candidate: Dict[Address, ReclamationCandidate],
    channel: dict,
    token_network: TokenNetwork,
    current_confirmed_head: BlockIdentifier,
) -> None:
    """ Withdraw all tokens in channel to channel["participant1"] """
    assert token_network.client.address == channel["participant1"]

    # Check if channel still has deposits
    details = token_network.detail_participants(
        participant1=to_canonical_address(channel["participant1"]),
        participant2=to_canonical_address(channel["participant2"]),
        block_identifier=current_confirmed_head,
        channel_identifier=channel["channel_identifier"],
    )
    new_withdraw = WithdrawAmount(details.our_details.deposit -
                                  details.our_details.withdrawn +
                                  details.partner_details.deposit -
                                  details.partner_details.withdrawn)
    assert new_withdraw >= 0, "negative withdrawn should never happen."

    if new_withdraw == 0:
        log.info(
            "Participant has no left over capacity in the channel. Skipping channel.",
            channel=channel,
        )
        return

    partner_candidate = address_to_candidate.get(
        details.partner_details.address)
    if partner_candidate is None:
        log.error(
            "Both participants must be in list of reclamation_candidates. Skipping channel.",
            channel=channel,
        )
        return

    expiration_block = BlockExpiration(100000000000000)
    total_withdraw = WithdrawAmount(details.our_details.withdrawn +
                                    new_withdraw)
    packed_withdraw = pack_withdraw(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=token_network.chain_id(),
            token_network_address=token_network.address,
            channel_identifier=channel["channel_identifier"],
        ),
        participant=to_canonical_address(channel["participant1"]),
        total_withdraw=total_withdraw,
        expiration_block=expiration_block,
    )

    privkey = token_network.client.privkey
    try:
        token_network.set_total_withdraw(
            given_block_identifier=current_confirmed_head,
            channel_identifier=channel["channel_identifier"],
            total_withdraw=total_withdraw,
            expiration_block=expiration_block,
            participant=to_canonical_address(channel["participant1"]),
            partner=to_canonical_address(channel["participant2"]),
            participant_signature=LocalSigner(privkey).sign(packed_withdraw),
            partner_signature=LocalSigner(
                partner_candidate.privkey).sign(packed_withdraw),
        )
    except InsufficientEth:
        log.warning("Not enough ETH to withdraw", channel=channel)
    else:
        log.info("Withdraw successful", channel=channel, amount=new_withdraw)
예제 #23
0
def handle_block(
    initiator_state: InitiatorTransferState,
    state_change: Block,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
) -> TransitionResult[Optional[InitiatorTransferState]]:
    """ Checks if the lock has expired, and if it has sends a remove expired
    lock and emits the failing events.
    """
    secrethash = initiator_state.transfer.lock.secrethash
    locked_lock = channel_state.our_state.secrethashes_to_lockedlocks.get(
        secrethash)

    if not locked_lock:
        if channel_state.partner_state.secrethashes_to_lockedlocks.get(
                secrethash):
            return TransitionResult(initiator_state, list())
        else:
            # if lock is not in our or our partner's locked locks then the
            # task can go
            return TransitionResult(None, list())

    lock_expiration_threshold = BlockExpiration(
        locked_lock.expiration + DEFAULT_WAIT_BEFORE_LOCK_REMOVAL)
    lock_has_expired = channel.is_lock_expired(
        end_state=channel_state.our_state,
        lock=locked_lock,
        block_number=state_change.block_number,
        lock_expiration_threshold=lock_expiration_threshold,
    )

    events: List[Event] = list()

    if lock_has_expired and initiator_state.transfer_state != "transfer_expired":
        is_channel_open = channel.get_status(
            channel_state) == ChannelState.STATE_OPENED
        if is_channel_open:
            expired_lock_events = channel.send_lock_expired(
                channel_state=channel_state,
                locked_lock=locked_lock,
                pseudo_random_generator=pseudo_random_generator,
            )
            events.extend(expired_lock_events)

        if initiator_state.received_secret_request:
            reason = "bad secret request message from target"
        else:
            reason = "lock expired"

        transfer_description = initiator_state.transfer_description
        payment_identifier = transfer_description.payment_identifier
        # TODO: When we introduce multiple transfers per payment this needs to be
        #       reconsidered. As we would want to try other routes once a route
        #       has failed, and a transfer failing does not mean the entire payment
        #       would have to fail.
        #       Related issue: https://github.com/raiden-network/raiden/issues/2329
        payment_failed = EventPaymentSentFailed(
            token_network_registry_address=transfer_description.
            token_network_registry_address,
            token_network_address=transfer_description.token_network_address,
            identifier=payment_identifier,
            target=transfer_description.target,
            reason=reason,
        )
        route_failed = EventRouteFailed(
            secrethash=secrethash,
            route=initiator_state.route.route,
            token_network_address=transfer_description.token_network_address,
        )
        unlock_failed = EventUnlockFailed(
            identifier=payment_identifier,
            secrethash=initiator_state.transfer_description.secrethash,
            reason=reason,
        )

        lock_exists = channel.lock_exists_in_either_channel_side(
            channel_state=channel_state, secrethash=secrethash)
        initiator_state.transfer_state = "transfer_expired"

        return TransitionResult(
            # If the lock is either in our state or partner state we keep the
            # task around to wait for the LockExpired messages to sync.
            # Check https://github.com/raiden-network/raiden/issues/3183
            initiator_state if lock_exists else None,
            events + [payment_failed, route_failed, unlock_failed],
        )
    else:
        return TransitionResult(initiator_state, events)