exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit bbba167f12a002e30f603235946e031f225f85c9
parent 9dc093b153e95fc6050081afbbcb9ec57f61d04b
Author: Özgür Kesim <oec@codeblau.de>
Date:   Mon, 14 Sep 2026 21:13:23 +0200

exchange: allow melting zombie coins of revoked denominations

The melt handler rejected any melted coin whose denomination was
revoked.  Before the refactoring only the fresh denominations were
checked for revocation and an old coin past its deposit expiration
went through the zombie check; a coin credited by /recoup-refresh must
remain meltable (see the /recoup-refresh specification), also when
its denomination was revoked.  Treat a revoked denomination of the
melted coin like an expired one: the melt succeeds only if the coin
is a zombie.

Diffstat:
Msrc/exchange/taler-exchange-httpd_post-melt.c | 34+++++++++++++++++++++++++---------
1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_post-melt.c b/src/exchange/taler-exchange-httpd_post-melt.c @@ -705,7 +705,8 @@ phase_parse_request ( * @param denom_h Hash of the denomination key to check * @param[out] pdk denomination key found, might be NULL * @return #GNUNET_OK when denomation was found and valid, - * #GNUNET_NO when denomination is not valid at this time + * #GNUNET_NO when denomination is expired or revoked (error state + * set, but the caller may override it for a zombie coin), * #GNUNET_SYSERR otherwise (denomination invalid), with finish_loop called. */ static enum GNUNET_GenericReturnValue @@ -762,7 +763,13 @@ find_denomination ( { SET_ERROR (mc, MELT_ERROR_DENOMINATION_REVOKED); - return GNUNET_SYSERR; + /** + * Like for the expired denomination, we return GNUNET_NO here: a + * revoked denomination must not be used for fresh coins, but the + * melted coin may be a zombie (credited by /recoup-refresh), which + * phase_check_melt_valid checks. + */ + return GNUNET_NO; } /* In case of age melt, make sure that the denomination supports age restriction */ @@ -1042,10 +1049,12 @@ phase_check_melt_valid (struct MeltContext *mc) mc->error.code = MELT_ERROR_NONE; if (GNUNET_TIME_absolute_is_past ( - mc->melted_coin_denom->meta.expire_deposit.abs_time)) + mc->melted_coin_denom->meta.expire_deposit.abs_time) || + mc->melted_coin_denom->recoup_possible) { /** - * We are past deposit expiration time, but maybe this is a zombie? + * We are past deposit expiration time or the denomination was + * revoked, but maybe this is a zombie? */ struct TALER_DenominationHashP denom_hash; enum GNUNET_DB_QueryStatus qs; @@ -1068,11 +1077,18 @@ phase_check_melt_valid (struct MeltContext *mc) } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { - /* We never saw this coin before, so _this_ justification is not OK. */ - SET_ERROR_WITH_DETAIL (mc, - MELT_ERROR_DENOMINATION_EXPIRED, - denom_h, - mc->request.refresh.coin.denom_pub_hash); + /* We never saw this coin before, so _this_ justification is not + OK. Report the reason the denomination cannot be used for a + fresh coin: revoked, unless it is also past expiration. */ + if (GNUNET_TIME_absolute_is_past ( + mc->melted_coin_denom->meta.expire_deposit.abs_time)) + SET_ERROR_WITH_DETAIL (mc, + MELT_ERROR_DENOMINATION_EXPIRED, + denom_h, + mc->request.refresh.coin.denom_pub_hash); + else + SET_ERROR (mc, + MELT_ERROR_DENOMINATION_REVOKED); return; } /* sanity check */