commit 6d3cc0987366cdccf8ef4d2b3dd905cd868781bd
parent 763366771f81553fc0590efbb69aa8fe7dfcf857
Author: Florian Dold <florian@dold.me>
Date: Tue, 8 Jul 2025 14:46:11 +0200
DD64: simplify and concretize steps
Diffstat:
1 file changed, 77 insertions(+), 102 deletions(-)
diff --git a/design-documents/064-kyc-operation-algo.rst b/design-documents/064-kyc-operation-algo.rst
@@ -24,120 +24,95 @@ Requirements
Proposed Solution
=================
+
Steps for processing operation of type ``op`` and amount ``amt``:
-0. Initialize ``last_op_attempt := null``, ``last_rule_gen := null``
- and ``last_aml_review := false`` and all back-off values to 0.
-1. Check if a zero limit for ``op`` is applicable.
+Initialization
+^^^^^^^^^^^^^^
+
+Initialize the following variables:
+
+* ``last_check_status := null``
+
+ * Last HTTP status of the kyc-check request.
+ A status of ``0`` indicates a network failure or request timeout
+ and is distinct from ``null``, which indicates that no check
+ request has been made.
+
+* ``last_check_code := null``
+
+ * Taler error code of the last kyc-check request or ``null`` if no such
+ request has been made or the last request didn't return an error code.
- * If the zero limit denies ``op``, proceed with step 3.
- * Proceed with step 2.
+* ``last_rule_gen := null``
+* ``last_aml_review := null``
+* ``last_op_deny := if isZeroLimited(op, amt) then now() else null``
+* ``account_keypair := getCurrentAccountKeyPair(op)``
-2. Attempt to make a request for ``op`` at the exchange. If the
- ``/kyc-check/`` result did not change since the last attempt,
- make sure to use exponential backoff on ``op`` requests with
- the frequency increasing up to once per day. The exponential
- backoff should be reset to 0 if the ``/kyc-check/`` result
- changed in any way.
- Set ``last_op_attempt`` to the current time.
+Processing
+^^^^^^^^^^
+
+1. If ``last_op_deny`` is ``null`` or more than ``1h`` ago,
+ make a request for ``op`` at the exchange. Let ``resp`` be the response.
* If the request succeeds, *halt*.
- * If ``last_aml_review`` was true, proceed with step 6.
- * If ``last_rule_gen`` is not ``null`` (Note 1), proceed with step 5.
- * Proceed with step 3.
-
-3. Request the ``/kyc-check/...`` endpoint applicable for ``op``
- (without long-polling!).
-
- * Handle response as detailed in step 7.
-
-4. Request the ``/kyc-check/...`` endpoint applicable for ``op``
- with long-polling for ``lpt=1``.
-
- * While waiting for the response, prompt the user to
- perform KYC auth wire transfer.
- * Handle response as detailed in step 7.
-
-5. Request the ``/kyc-check/...`` endpoint applicable for ``op``
- with long-polling for ``min_rule`` set to ``last_rule_gen``.
-
- * While waiting for the response, prompt the user to
- provide KYC information.
- * Handle response as detailed in step 7.
-
-6. Request the ``/kyc-check/...`` endpoint applicable for ``op``
- with long-polling for ``lpt=2`` and, additionally
- ``min_rule`` set to the last ``last_rule_gen`` (if the
- latter is not ``null``).
-
- * While waiting, indicate to the user that we are waiting on the
- provider's staff to review our account.
- * Handle response as detailed in step 7.
-
-7. General handling of ``/kyc-check`` responses:
-
- * If the request returns ``409 Conflict``, proceed with step 4.
- * If the request returns ``404 Not found``, proceed with
- step 8 applying the exposed default rules of the exchange.
- * If the request returns ``403 Forbidden``, check if the
- private key for the indicated public key is available, if
- so try again with that private key, otherwise
- proceed with step 4.
- * If the request returns ``204 No Content``:
- * Set ``last_aml_review := false``.
- * Proceed with step 2.
- * If the request returns ``202 Accepted``:
-
- * Set ``last_aml_review := response.aml_review``.
- * Set ``last_rule_gen := response.rule_gen``.
- * If the exposed limits do not explicitly deny ``op``,
- proceed with step 2.
- * Otherwise, proceed with step 5.
-
- * If the request returns ``200 Ok``:
-
- * Set ``last_aml_review := response.aml_review``.
- * Set ``last_rule_gen := response.rule_gen``.
- * Handle exposed limits returned in step 8.
-
- * If the response indicates no change in the status (including
- when there was no response because the connection was closed):
-
- * Repeat the request, using exponential back-off to reduce
- check frequency (without even long-polling) to eventually
- only check once per day.
- * Ensure the long-polling interval specified in the request
- works with the middleware. If we detect that a request timed
- out before the specified long-polling interval, use a shorter
- timeout argument in the HTTP request the next time
- (but do still keep exponentially
- backing off the actual request frequency).
- * Lower the back-off to zero if:
-
- * the user manually reviews the KYC auth wire transfer instructions, or
- * the user manually reviews KYC information page instructions, or
- * if ``op`` is a deposit and ``lpt=1`` and a withdraw succeeded
- from the same account
-
-8. Handle exposed limits applicable to the account:
-
- * If the exposed limits do not deny ``op``, proceed with step 2.
- * Otherwise (the exposed limits do deny ``op``), show an error message
+
+2. Request the ``/kyc-check/...`` endpoint applicable for ``op`` with ``account_keypair`` the following parameters:
+
+ * If ``last_check_status == null``: Make request without long-polling.
+ * If ``last_check_status in [403 Forbidden, 409 Conflict]``: Long-poll. Add query parameter ``lpt=1``
+ * If ``last_aml_review == true``: Long-poll. Add query parameter ``lpt=2``. If ``last_rule_gen != null``, add
+ query parameter ``min_rule=last_rule_gen``.
+ * If ``last_check_status == 402 Accepted``: Long-poll. If ``last_rule_gen != null``, add ``min_rule=last_rule_gen``
+ to the query parameters.
+
+3. Handle the ``/kyc-check/...`` response:
+
+ * Set ``same_resp := resp.status == last_check_status and resp.code == last_check_status and resp.rule_gen == last_rule_gen``.
+ * Set ``last_check_status := resp.status``, ``last_check_code := resp.code``, ``last_rule_gen := resp.rule_gen``
+ * If ``same_resp == true``: finish processing operation with result ``BACKOFF``.
+ * If ``resp.status == 204 No Content``: Set ``last_op_deny := null``. Finish processing operation with result ``PROGRESS`` (effectively
+ re-trying at step 1).
+ * If ``resp.status == 200 Ok``: Set ``last_op_deny := null``. Go to step 4.
+ * If ``resp.status == 202 Accepted``: Go to step 4.
+ * If ``resp.status == 403 Forbidden``: Check if the private key for the
+ indicated public key is available. If, set ``account_keypair`` to that key pair and finish with result ``PROGRESS``.
+ Otherwise, finish with result ``BACKOFF``.
+ * If ``resp.status == 404 Not Found``: Go to step 4, with exposed limits set to the default limits.
+ * Otherwise (unhandled status), finish processing operation with result ``BACKOFF``.
+
+4. Handle exposed limits applicable to the account:
+
+ * If the exposed limits do not deny ``op``, finish processing operation with result ``PROGRESS``.
+ * Otherwise (the exposed limits do deny ``op``), transition the transaction
+ to a ``failed`` state (Showing an error message
indicating that the operation is forbidden due to legal
- restrictions on the payment service provider.
+ restrictions on the payment service provider). Finish processing operation with result ``PROGRESS``.
* If merely a threshold over some timeframe is currently
- violated, compute the time when the operation may be allowed again,
- indicate that to the user, allowing them to "retry immediately"
- anyway, and also go to step 2 automatically at that time.
+ violated, compute the time ``t`` when the operation may be allowed again.
+ Finish processing operation with result ``AGAIN_AT(t)``.
+
+
+Additional Considerations
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* Ensure the long-polling interval specified in the request
+ works with the middleware. If we detect that a request timed
+ out before the specified long-polling interval, use a shorter
+ timeout argument in the HTTP request the next time
+ (but do still keep exponentially
+ backing off the actual request frequency).
+* Lower the retry back-off for the transaction to zero if:
-Notes:
-------
+ * the user manually reviews the KYC auth wire transfer instructions, or
+ * the user manually reviews KYC information page instructions, or
+ * if ``op`` is a deposit and ``lpt=1`` and a withdraw succeeded
+ from the same account
-* Note 1: We must long-poll for the next rule generation here,
- since we can assume that the current set of rules contains non-exposed
- rule that prevents the current operation.
+* Especially in step 4 (limit violated in timeframe),
+ the user should be offered the option to retry.
Definition of Done