raiden-network / raiden

Raiden Network
https://developer.raiden.network
Other
1.84k stars 378 forks source link

Add recipient metadata to message events #6894

Open fredo opened 3 years ago

fredo commented 3 years ago

Overview

The interface to the transport module has changed such that each message gets enqueued with an AddressMetadata object. This object is supposed to be passed along the state machine in the class SendMessageEvent. It has now a field called recipient_metadata.

For each message event we can now start to find out, if it is necessary and if yes, where these metadata should come from. It is possible to leave it None and the transport will still be able to process the message event. The fallback is sending it to all possible user_ids.

As we currently agreed, it should be noticed that AddressMetadata are typically bound to payments. Therefore we need to be cautious where to store the metadata in the state.

How to analyze the Message event

As a hint, I suggest the following mechanism. Each message event has also the field recipient. In general, it might make sense to have a look where the recipient address comes from upon instantiation. Maybe metadata should be stored in the state where the recipient address is stored. Note, that it might not make sense for every message event type!

I see three options how to get metadata:

Here is an example how metadata are passed with the recipient address in the case of LockedTransfer

Additional information

WithdrawRequest gets the recipient address from the NettingChannelState. This is an example where I think it does not make sense to store the metadata along the recipient address as NettingChannelState describes the current state of the channel and should not be mixed with payment bound information. Here it could make sense to request metadata from the PFS before the state change is applied (or created) and passed with it into the state machine or it might also make sense to leave it empty if it were too much effort to implement the former.

MessageEvents

ezdac commented 3 years ago

Some analysis to move this forward:

Role: Mediator

Phase 1: mediate / refund incoming LockedTransfer:

ActionInitMediator -> mediator.handle_init( ) -> MediatorTransferState event receiver address from? associated state
SendProcessed Initiator / prev. Hop ActionInitMediator /
SendLockedTransfer (forward) Target / next Hop ActionInitMediator MediationPairState
SendLockedTransfer (backward) Initiator / prev. Hop MediationPairState MediationPairState

Phase 2: unlock and reveal secret

ReceiveSecretReveal -> mediator.handle_offchain_secret_reveal( ) -> MediatorTransferState event receiver address from? associated state
SendSecretReveal Target / next Hop MediationPairState MediationPairState
SendUnlock Initiator / prev. Hop MediationPairState MediationPairState

Phase 3: process unlock

ReceiveUnlock -> mediator.handle_unlock( ) -> MediatorTransferState event receiver address from? associated state
SendProcessed Initiator / prev. Hop Hop MediationPairState MediationPairState

This suggests that the payer/payee address-metadata should be memorized with the MediationPairState.

Note that the overall metadata received with the lockedtransfer message is also attached in the MediatorTransferState.routes. The MediatorTransferState is present in all top-level handler functions mentioned above, so the metadata could also be passed down the call-chain from there. Therefore, another possibility would be to only store the address metadata there, and just pass a mapping of all address -> metadata to the functions in the layers below, where a lookup for the metadata can be performed on creation of SendMessageEvents.

ezdac commented 3 years ago

Suggestion / plan-to-action

To summarise some ideas and plan on how to move forward, I gathered some information / ideas below. Some of this is already implemented or was already discussed, but here might be a good place to collect this information for further discussion and later retrieval.

Individually query PFS / send to all possible user-ids

Use provided address metadata and keep state

Where is the metadata retrieved from initially

The initial metadata is only retrieved / fed to the state-machine once, depending on the node's role:

For the Initiator, it is retrieved from the PFS and fed to the state-machine with the ActionInitInitiator.

For the mediator, it is retrieved from a neighbouring nodes' LockedTransfer message as additional route-metadata and fed to the state-machine with theActionInitMediator.

For the target, it is retrieved from a neighbouring nodes' LockedTransfer message as additional route-metadata and fed to the state-machine with theActionInitTarget.

Where is the metadata stored for later retrieval ?

Since the address-metadata is bound to a payment, it would generally make sense to store the relevant metadata somewhere in the state that is bound to payments, namely:

In which sub-states (attributes of the above states) the metadata should be stored is a tradeoff between simplicity on the state-side and the number of handler/send functions that have to be modified with an additional argument on the other side. Especially the handler functions in the channel module all need to be passed the address-metadata information as arguments from the payment-based handlers, since metadata is not supposed to be channel-bound, and therefore not available in the states passed to those functions.

I suggest the following:

The route-state will be modified to keep all address-metadata as provided by the pfs/ locked-transfer messages. The hop-state will be modified to keep the address metadata of the neighbouring sender of locked-transfers.

@dataclass
class RouteState(State):
    route: List[Address]
    address_to_metadata: Dict[Address, AddressMetadata] = field(default_factory=dict)
    ...

@dataclass
class HopState(State):
    node_address: Address
    channel_identifier: ChannelID
    address_metadata: Optional[AddressMetadata] = None

Therefore the address-metadata will be persisted for the initiator in the InitiatorPaymentState.routes: List[RouteState], and for the mediator will be persisted in the MediatorTransferState.routes: List[RouteState].

For the target, TargetTransferState.from_hop.address_metadata will keep track of the neighbouring sender of the transfer, while TargetTransferState.initiator_address_metadata will keep track of the metadata of the initiator of the payment.

Since there can be some duplication of addresses in the metadata (the same hop/target can be part of multiple routes), the retrieval of neighbouring address-metadata (for the nodes own message sending) will be done by iterating over all address-metadata dictionaries and using the first metadata that is a key for the retrieved address.

ezdac commented 3 years ago

This was implemented (with a little bit different architecture than planned) in #6906.

Currently the aforementioned non-time-critical messages (SendWithdrawRequest) do not explicitly query the PFS for a user, but hand messages to the transport without metadata. This results in sending to all possible user-ids for that address.

@fredo - regarding that, can we close this issue nevertheless or should we leave it open until a definite decision on this is made?