Conclusion
Thanks to all who contributed to this and joined the Community Call on 15 May to discuss. Here is my summary of the outcome (thanks @sappenin for your notes in Slack, they helped jog my memory):
Components
-
Connector Balance Logic:
Logic in the connector that decides whether or not to forward packets based on the Interledger balance of a peer.
Adjusts Interledger balance based on exchange of packets with peer.
-
Accounting System:
Tracks the Interledger balance and determines when to make a settlement.
Communicates with the settlement engine and adjusts the Interledger balance based on settlement events.
-
Settlement Engine:
Performs settlements on a settlement system.
Manages liquidity in the settlement system.
Communicates with the settlement engines at peers using a transport provided by the connector
Design Decisions
What is the Settlement Engine?
The terminology we came to consensus on is not exactly what was described earlier in this thread so take not of the differences. The reasons are less important than the results, it’s just terminology after all.
Notably we have agreed that the system that runs outside the connector and interfaces with the settlement system is called the Settlement Engine and this DOES NOT contain the logic for deciding WHEN to settle (which is in the accounting system).
In effect this consists of two components, a settlement system liquidity manager (manages the available liquidity for settlement) and a settlement system adaptor (interfaces with the settlement system to, primarily, perform settlements).
Liquidity management of Settlement System is handled in the Settlement Engine
We have settled (pun intended) on a design that does not attempt to abstract the liquidity management functions of the Settlement Engine out of that component as the majority view was that this is quite specific to the underlying settlement system and difficult to abstract.
As such, the Accounting System has no view of the connector’s liquidity in the settlement system. Instead the AS simply requests a settlement and assumes this will be done eventually if the request is acknowledged by the SE.
The AS adjusts its own records to this effect and, in the case that the SE is unable to complete the settlement, the connector may find that packets forwarded to the peer start to be rejected due to a lack of liquidity.
This was accepted as the lowest risk compromise for the sake of keeping the design simple and reducing the API surface between the AS and the SE.
Management of this scenario is then left to operators to ensure they can respond to this eventuality. In reality, this will manifest as failed settlements which should be handled with high priority by an operator anyway.
The alternative to this proposal was to include the liquidity management logic in the accounting system which has the benefit of allowing the accounting system to develop more sophisticated logic around management of liquidity in the settlement system and in the Interledger accounts however this comes at the cost of needing to abstract liquidity management functions.
In time, data from the settlement process (the time taken and rate of success performing settlements) may be useful to the AS in planning future settlements and we may extend the API to enable this.
REST
For simplicity we have agreed to use a REST and JSON based API
Architecture
We have agreed that the standard API we want to define is between the Accounting System (which will likely run inside most connectors for now) and the Settlement Engine.
Both sides must run an HTTP server to accept requests as the interface is bilateral.
All interactions follow a request/reply pattern however some replies will be responses and others will simply be ACKs.
Settlement Engines have an implicit asset code and scale (i.e. a different SE is required for different assets) so the AS must apply any scale conversions before calling the SE API or when receiving API calls from the SE.
The Accounting System (Connector) must host the following interface:
-
ReceiveSettlement(accountId, amount)
Notification from the settlement system that an incoming settlement has been received.
The response to this is an ACK.
The AS will ACK the request and adjust the Interledger balance of the peer accordingly.
The SE should retry until this is ACK’d so it needs to be idempotent.
-
SendRequest(accountId, message)
Deliver a message to the peer’s settlement system and return the response.
The response is the response from the peer’s settlement system.
If this is used for some form of RPC between settlement systems then they should define that protocol separately (i.e. how to handle failures and errors).
An error response from the other SE should not be carried in an error at the API level.
(i.e. The response is always a 2XX)
The SE should retry until it gets a response so this needs to be idempotent.
Both calls can return an “Unknown Account Id” response (Maybe a 404?)
The Settlement Engine must host the following interface:
-
CreateAccount(accountId)
Be prepared to send and receive settlements for this account.
Connector provides the accountId and SE .
-
SendSettlement(accountId, amount)
Perform an outgoing settlement on the underlying settlement system.
The response to this is an ACK.
The SE will ACK the request and then attempt to perform the settlement. It will continue attempting the settlement until it succeeds (i.e. There is no mechanism to notify the AS to reverse the balance change)
The AS should retry until it gets a response so this needs to be idempotent.
-
ReceiveRequest(accountId, message)
Accept a message from the peer’s settlement system and return a response.
The SE should never return an error response unless the accountId is unknown.
(i.e. The response is always a 2XX even if the response is carrying an error message back to the peer’s SE)
The AS should retry until it gets a response so this needs to be idempotent.
Discussion on how to spec this out is being done in the #settlement
channel on Slack
Kava have an implementation that is already pretty close to this: https://github.com/Kava-Labs/ilp-plugin-xrp-paychan
UPDATE: Added amount
as a param to ReceiveSettlement. This was a mistake in the original post.