Request for comment on trade protocol domain design #938
Replies: 3 comments 1 reply
-
I looked through all classes and conceptually everything is fine. Good job! 👍 However, I have one question: What happens if two messages arrive out of order?As an example, imagine a Other small things
|
Beta Was this translation helpful? Give feedback.
-
Good point. At the current protocol there are no 2 messages for one side which could follow as there is a user action always between. But there could be such situations in other protocols (though the usual way would be a request/response pattern). Even with request/response pattern it could be that the messages are triggered by non user actions but e.g. blockchain events and then such critical situation could become more feasible as well. As all messages are mailbox messages and do not require the peer to be online the order of the processing of the mailbox messages is not defined, so that would be definitely a problematic situation in case of multiple messages. One approach could be to queue up messages which arrive at the wrong state (but would match a future state) and retry with the messages of that queue after the next state transition. That queue need to be persisted as well to avoid that those messages are lost in case if a restart. We likely will need also ACK messages for successfully processed messages (and/or when mailbox messages are processed). This might be another way how to deal with it to resend messages which do not got an ACK after a certain time, but that would only work if the sender is online. So the previous approach is probably better. Do you have some other idea how to deal with that?
Thanks! will apply those in the next PR.
Role is not persisted yet, but maybe better to persist that role instead the 2 booleans. |
Beta Was this translation helpful? Give feedback.
-
After discussion with @sqrrm how that protocol would work with more sophisticated trade protocols like the chained LN->Liquid->LN protocol idea we to the conclusion that it should work fine as a composition of 3 protocols and we could reuse the 3 single standalone protocols in the chained protocol. So the first would be a reverse submarine swap (RSMS) from LN-BTC to Liquid BTC. All those 3 protocols should be implemented as standalone protocols first. Once we have those in place we can chain them together so that for the user its just a LN-BTC to FIAT trade where they get back the security deposit as LN-BTC and they do not need to care about Liquid. To chain those 3 protocols we would first start the RSMS protocol. Once that is completed it triggers the start of the BMS protocol. Once that is completed it triggers the SMS protocol and once that is completed the trade is complete for the user. As there are not only 2 traders involved but potentially 4 (RSMS and SMS are done with some L-BTC liquidity providers) it might get a bit more complicated in case that there is not enough liquidity in the market to execute the swaps immediately, but I guess beside time delay it would not be a fundamental problem. We could also use centralized providers like Bolz as fallback in case the Bisq market lacks liquidity. We could also build hierarchical state machines, where for complex handlers a sub-fsm is used to execute those steps. But I guess more appropriate would be to split up those step into multiple state transitions. |
Beta Was this translation helpful? Give feedback.
-
I would like to give an overview about the trade protocol design and ask for feedback and comment
The
Protocol
class inherits from a finite state machine implementation (Fsm
) and holds a reference to aTrade
object.The
Trade
inherits from theFsmModel
which holds theState
. The state can only be set by theFsm
at a state transition.The
Trade
holds 2TradeParty
objects for maker and taker and theContract
. Fields for trade data inTradeParty
andTrade
are mutable and get filled during the protocol progress likeContractSignatureData
.TradeParty
holds immutable the usersNetworkId
The
Contract
contains theOffer
and data when the offer gets taken (e.g. amount, payment method,...).The
BisqEasyTradeService
(for BisqEasy protocol - there is no commonTradeService
base class yet) provides an API for triggering the events which trigger the state transition on theProtocol
. It also listens on network messages and use the messages the same way as user events are used for triggering a state transition.The definition of the state transistions is done in the concrete
Protocol
implementation for the relevant role:BisqEasyBuyerAsMakerProtocol
,BisqEasyBuyerAsTakerProtocol
,BisqEasySellerAsMakerProtocol
,BisqEasySellerAsTakerProtocol
in case for the BisqEasy domain.There is different handling dependent on the state in the protocol for maker and taker or for buyer and seller, thus we have 4 variants in total (2 pairs).
The transition config for
BisqEasySellerAsTakerProtocol
is for instance:The peers protocol is:
BisqEasyBuyerAsMakerProtocol
with following transition config:One can see the relevant role for the first transition is taker/maker but the following transitions are defined by seller/buyer role.
There might be more differences in other more complex protocols.
The event or message is defined by it's
Class
as well as the optional event handler. That way we avoid boilerplate enums.By convention we use the same name for the handler as the event with a "Handler" postfix.
The domain specific
State
is implemented as an enum.The
EventHander
gets theTradeModel
and aServiceProvider
(a collection of Bisq service classes) at the constructor.The
Event
gets the relevant data from the user event or message passed at creation. Thehandle
method in theEventHander
gets passed theEvent
and can take the specific data for processing.For messages we extend
TradeMessageHandler
which provides averifyMessage
method which should be used for message validation before the message gets processed.The changes to the model should be applied in the custom
commitToModel
method to avoid that an exception at processing would cause an invalid state in the model. The state transition is only performed if the eventHandler completed without exception, but if there would be changes to the model we would risk inconsistent state. There might get added more structure for enforcing that verify -> process -> commit patter. In the current BisqEasy handlers there is no complexity to justify that structural overhead but I guess for more complex protocols it will be useful.There is lack of generic support for the concrete event in the eventHandlers handle method. I tried to generify that but failed as the transition is in a map with different types and thus makes it difficult to apply generics. If any dev finds a solution it would be welcome. But the unsafe cast is not a real risk as the Event and Handler classes are tightly coupled by convention.
I added skeleton implementations for the Bisq multisig protocol and a potential LN submarine swap protocol. Beside the trade module its also supported in offer and contract. If any dev is interested to try to implement a prototype protocol for those trade protocols would be helpful to test the concept if it is flexible enough and if it works well.
There are no tests yet for the
BisqEasyProtocol
(only for theFsm
). It would be good to get a test suite for testing the whole protocol flow with potential failure modes. Help from other devs is very welcome.My next step is to integrate it to the UI and see if all works as expected.
Compared to Bisq 1 the
EventHander
does perform the function of theTask
classes. For more complex processing we can either break it up with multiple states (in case the processing cannot be done without irreversible changes like a commit of a tx) or to break inside theEventHander
the processing into more manageable chunks.What do you think about the concept?
Beta Was this translation helpful? Give feedback.
All reactions