post-recoup-refresh.rst (9586B)
1 .. http:post:: /recoup-refresh 2 3 Demand that coins of revoked denominations, which originated from 4 one particular call to :http:post:`/melt </melt>` and 5 :http:post:`/reveal-melt </reveal-melt>`, be paid back to the old coin 6 they were refreshed from. 7 8 All coins in one request MUST originate from the same refresh operation. 9 The client identifies that operation by the public key of the old coin and 10 the refresh commitment ``rc`` of the original melt request. As with 11 :http:post:`/recoup-withdraw </recoup-withdraw>`, the client discloses the 12 secret material of the coins to be recouped and provides the envelope 13 hashes of the other coins of the same operation, so that the exchange can 14 recompute the hash over the batch of coins it signed and compare it with 15 the commitment it stored. 16 17 The residual value of each disclosed coin is credited to the old coin. 18 The old coin may then be spent or melted again, even if the deposit 19 expiration of its denomination has passed in the meantime (a "zombie" 20 coin). The refresh fee paid in the original operation is **not** 21 recouped. 22 23 The exchange only accepts this request for coins of denominations that 24 are listed in the ``recoup`` field of :http:get:`/keys </keys>`. 25 26 The base URL for this request may differ from the main base URL of the 27 exchange. The exchange MUST return a 307 or 308 redirection to the correct 28 base URL if this is the case. 29 30 This endpoint was introduced in protocol **vRECOUP** and replaces the 31 former ``/coins/$COIN_PUB/recoup-refresh`` endpoint. 32 33 **Request:** 34 35 The request body must be a `RecoupRefreshRequest` object. 36 37 **Response:** 38 39 :http:statuscode:`200 OK`: 40 The request was successful and the response is a 41 `RecoupRefreshResponse`. Repeating exactly the same request 42 yields the same response (the signature may differ if the exchange 43 has rotated its signing key in the meantime), so if the network goes 44 down before the client can commit the result to disk, the recoup is 45 not lost. 46 :http:statuscode:`400 Bad Request`: 47 The request body is malformed or a parameter is invalid. 48 This response comes with a standard `ErrorDetail` response. 49 Possible error codes include ``TALER_EC_GENERIC_PARAMETER_MALFORMED`` 50 (also used if ``coin_data`` does not contain at least one disclosed 51 coin) and ``TALER_EC_EXCHANGE_RECOUP_REFRESH_BATCH_SIZE_MISMATCH`` 52 (the number of entries in ``coin_data`` differs from the number of 53 coins the exchange signed in the original refresh operation). 54 :http:statuscode:`403 Forbidden`: 55 A signature is invalid. 56 This response comes with a standard `ErrorDetail` response. 57 Possible error codes include 58 ``TALER_EC_EXCHANGE_RECOUP_REFRESH_SIGNATURE_INVALID`` (a ``coin_sig``) 59 or ``TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID`` 60 (a ``denom_sig``). 61 :http:statuscode:`404 Not found`: 62 One of the following reasons occurred: 63 64 1. A denomination key is unknown. The response is a 65 `DenominationUnknownMessage` with error code 66 ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN``. 67 2. The exchange has no record of a refresh operation for the given 68 ``rc``, or the operation found was not a refresh of 69 ``old_coin_pub``. This response comes with a standard `ErrorDetail` 70 response with error code 71 ``TALER_EC_EXCHANGE_RECOUP_REFRESH_MELT_NOT_FOUND``. 72 :http:statuscode:`409 Conflict`: 73 One of the following reasons occurred: 74 75 1. The hash the exchange recomputed over the ``coin_data`` array does 76 not match the commitment of the refresh operation, so at least one 77 disclosed coin was not part of it. This response comes with a 78 standard `ErrorDetail` response with error code 79 ``TALER_EC_EXCHANGE_RECOUP_REFRESH_COMMITMENT_MISMATCH``. 80 2. The denomination of a disclosed coin differs from the denomination 81 recorded for that position of the refresh operation. This 82 response comes with a standard `ErrorDetail` response with error code 83 ``TALER_EC_EXCHANGE_RECOUP_REFRESH_DENOMINATION_MISMATCH``. 84 3. A disclosed coin has no residual value left. The response is a 85 `DepositDoubleSpendError` with error code 86 ``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS``. 87 4. The same coin public key was previously used with a different 88 denomination or age commitment. The response is a 89 `CoinDenominationConflictError` with error code 90 ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY`` 91 or a `CoinAgeCommitmentConflictError` with error code 92 ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH``. 93 94 In all of these cases nothing is credited, not even for the other 95 coins in the request. 96 :http:statuscode:`410 Gone`: 97 The denomination of a disclosed coin is not eligible for recoup. 98 The response is a `DenominationGoneMessage` with error code 99 ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED`` (past the deposit 100 expiration) or ``TALER_EC_EXCHANGE_RECOUP_REFRESH_NOT_ELIGIBLE`` (the 101 denomination was not revoked). 102 :http:statuscode:`412 Precondition Failed`: 103 The denomination of a disclosed coin is not yet valid. 104 The response is a `DenominationGoneMessage` with error code 105 ``TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE``. 106 :http:statuscode:`413 Request entity too large`: 107 The uploaded body is to long, it exceeds the size limit. 108 Returned with an error code of 109 ``TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT``. 110 :http:statuscode:`500 Internal Server Error`: 111 The exchange encountered an internal error. 112 This response comes with a standard `ErrorDetail` response. 113 Possible error codes include 114 ``TALER_EC_EXCHANGE_RECOUP_REFRESH_BLINDING_FAILED``, 115 ``TALER_EC_GENERIC_DB_FETCH_FAILED``, 116 ``TALER_EC_GENERIC_DB_COMMIT_FAILED``, or 117 ``TALER_EC_GENERIC_DB_INVARIANT_FAILURE``. 118 :http:statuscode:`502 Bad gateway`: 119 The exchange could not reach its signing helper to create 120 the confirmation signatures. Returned with an error code of 121 ``TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE``. 122 Wallets should retry the request (with some delay) at a later time. 123 :http:statuscode:`503 Service Unavailable`: 124 The exchange currently has no signing keys available. 125 This response comes with a standard `ErrorDetail` response with 126 a code of ``TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING``. 127 128 **Details:** 129 130 .. ts:def:: RecoupRefreshRequest 131 132 interface RecoupRefreshRequest { 133 // Public key of the old coin that was melted. 134 // The recouped value is credited to this coin. 135 old_coin_pub: CoinPublicKey; 136 137 // The refresh commitment of the original melt request, 138 // see `TALER_RefreshCommitmentP`. This identifies the 139 // refresh operation. 140 rc: HashCode; 141 142 // Exactly one entry per coin the exchange signed in the 143 // refresh operation, that is the ``n`` coins of the batch at 144 // the ``noreveal_index`` returned in the `MeltResponse`, in the 145 // order of the original request. 146 // At least one entry MUST be a `RecoupedCoin` and its 147 // ``coin_sig`` MUST be created with purpose 148 // ``TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH``. 149 coin_data: RecoupCoinData[]; 150 } 151 152 Note that for denominations of cipher type Clause-Schnorr the client 153 does not need to provide the session nonce or the R-value pair: the 154 exchange derives the nonce from the ``blinding_seed`` of the original 155 melt request and the coin's position in ``coin_data`` (exactly as the 156 wallet does for a melt), and it stored the R-values it returned in 157 :http:post:`/blinding-prepare </blinding-prepare>`. 158 159 The exchange processes the request as 160 :http:post:`/recoup-withdraw </recoup-withdraw>` does, with the refresh 161 operation looked up under ``rc``, the hash over ``coin_data`` compared 162 against the hash of the batch at the ``noreveal_index``, and the 163 residual value of every disclosed coin credited to ``old_coin_pub`` 164 in one database transaction. 165 166 .. ts:def:: RecoupRefreshResponse 167 168 interface RecoupRefreshResponse { 169 // Public key of the old coin that was credited. 170 old_coin_pub: CoinPublicKey; 171 172 // The refresh commitment of the refresh operation, as in the request. 173 rc: HashCode; 174 175 // Time when the exchange accepted the recoup. All coins 176 // of one request share this timestamp. 177 timestamp: Timestamp; 178 179 // Total amount credited to the old coin, that is the sum 180 // of the ``amount`` values in ``recoups``. 181 total_amount: Amount; 182 183 // One entry per `RecoupedCoin` in the request, in the same order. 184 recoups: RecoupedCoinResult[]; 185 186 // Signature over `TALER_RecoupRefreshBatchConfirmationPS` with 187 // purpose ``TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH_BATCH``, 188 // affirming the recoup of all coins in ``recoups``. 189 exchange_sig: EddsaSignature; 190 191 // Public key used to create ``exchange_sig``. 192 // Should match one of the exchange's signing keys from ``/keys``. 193 exchange_pub: EddsaPublicKey; 194 } 195 196 The coin histories report each recouped coin individually, see 197 `CoinRecoupRefreshTransaction` for the recouped coin and 198 `CoinRecoupRefreshReceiverTransaction` for the old coin. Those entries 199 carry a signature per coin over :ref:`TALER_RecoupRefreshConfirmationPS <TALER_RecoupRefreshConfirmationPS>`, 200 which the exchange creates when a history is requested; the batch 201 signature above is only part of the response to this request.