commit daaa5f3d6e5a1594514fadffdd6e54ba8d7caba2
parent eadd86ae0dd44d4135a5ad020a73babe54963a7d
Author: Christian Grothoff <christian@grothoff.org>
Date: Fri, 20 Jun 2025 15:49:15 +0200
fix coin history implementation with new crypto-mas (#9975)
Diffstat:
4 files changed, 96 insertions(+), 21 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd_coins_get.c b/src/exchange/taler-exchange-httpd_coins_get.c
@@ -116,27 +116,46 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"DEPOSIT"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&deposit->amount_with_fee),
TALER_JSON_pack_amount ("deposit_fee",
&deposit->deposit_fee),
+ GNUNET_JSON_pack_data_auto ("merchant_pub",
+ &deposit->merchant_pub),
GNUNET_JSON_pack_timestamp ("timestamp",
deposit->timestamp),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_timestamp ("refund_deadline",
deposit->refund_deadline)),
- GNUNET_JSON_pack_data_auto ("merchant_pub",
- &deposit->merchant_pub),
GNUNET_JSON_pack_data_auto ("h_contract_terms",
&deposit->h_contract_terms),
GNUNET_JSON_pack_data_auto ("h_wire",
&h_wire),
+ GNUNET_JSON_pack_data_auto ("h_denom_pub",
+ &deposit->h_denom_pub),
GNUNET_JSON_pack_allow_null (
- deposit->no_age_commitment ?
- GNUNET_JSON_pack_string (
- "h_age_commitment", NULL) :
- GNUNET_JSON_pack_data_auto ("h_age_commitment",
- &deposit->h_age_commitment)),
+ deposit->has_policy
+ ? GNUNET_JSON_pack_data_auto ("h_policy",
+ &deposit->h_policy)
+ : GNUNET_JSON_pack_string (
+ "h_policy",
+ NULL)),
+ GNUNET_JSON_pack_allow_null (
+ deposit->no_wallet_data_hash
+ ? GNUNET_JSON_pack_string (
+ "wallet_data_hash",
+ NULL)
+ : GNUNET_JSON_pack_data_auto ("wallet_data_hash",
+ &deposit->wallet_data_hash)),
+ GNUNET_JSON_pack_allow_null (
+ deposit->no_age_commitment
+ ? GNUNET_JSON_pack_string (
+ "h_age_commitment",
+ NULL)
+ : GNUNET_JSON_pack_data_auto ("h_age_commitment",
+ &deposit->h_age_commitment)),
GNUNET_JSON_pack_data_auto ("coin_sig",
&deposit->csig))))
{
@@ -170,7 +189,6 @@ compile_transaction_history (
return NULL;
}
#endif
-
phac = (melt->no_age_commitment)
? NULL
: &melt->h_age_commitment;
@@ -183,12 +201,16 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"MELT"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&melt->amount_with_fee),
TALER_JSON_pack_amount ("melt_fee",
&melt->melt_fee),
GNUNET_JSON_pack_data_auto ("rc",
&melt->rc),
+ GNUNET_JSON_pack_data_auto ("h_denom_pub",
+ &melt->h_denom_pub),
GNUNET_JSON_pack_data_auto ("refresh_seed",
&melt->refresh_seed),
GNUNET_JSON_pack_allow_null (
@@ -243,6 +265,8 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"REFUND"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&value),
TALER_JSON_pack_amount ("refund_fee",
@@ -294,6 +318,8 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"OLD-COIN-RECOUP"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&pr->value),
GNUNET_JSON_pack_data_auto ("exchange_sig",
@@ -338,6 +364,8 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"RECOUP"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&recoup->value),
GNUNET_JSON_pack_data_auto ("exchange_sig",
@@ -348,8 +376,12 @@ compile_transaction_history (
&recoup->reserve_pub),
GNUNET_JSON_pack_data_auto ("coin_sig",
&recoup->coin_sig),
+ GNUNET_JSON_pack_data_auto ("h_denom_pub",
+ &recoup->h_denom_pub),
GNUNET_JSON_pack_data_auto ("coin_blind",
&recoup->coin_blind),
+ // FIXME-9828: spec says we should have h_commitment?
+ // FIXME-9828: spec says we should have coin_index?
GNUNET_JSON_pack_data_auto ("reserve_pub",
&recoup->reserve_pub),
GNUNET_JSON_pack_timestamp ("timestamp",
@@ -393,6 +425,8 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"RECOUP-REFRESH"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&pr->value),
GNUNET_JSON_pack_data_auto ("exchange_sig",
@@ -403,8 +437,13 @@ compile_transaction_history (
&pr->old_coin_pub),
GNUNET_JSON_pack_data_auto ("coin_sig",
&pr->coin_sig),
+ // FIXME-#9828: spec says to return h_denom_pub
GNUNET_JSON_pack_data_auto ("coin_blind",
&pr->coin_blind),
+ // FIXME-#9828: spec says to return h_commitment
+ // FIXME-#9828: spec says to return coin_index
+ // FIXME-#9828: spec says to return new_coin_blinding_secret
+ // FIXME-#9828: spec says to return new_coin_ev
GNUNET_JSON_pack_timestamp ("timestamp",
pr->timestamp))))
{
@@ -423,13 +462,14 @@ compile_transaction_history (
if (! pd->no_age_commitment)
phac = &pd->h_age_commitment;
-
if (0 !=
json_array_append_new (
history,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"PURSE-DEPOSIT"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&pd->amount),
GNUNET_JSON_pack_string ("exchange_base_url",
@@ -439,12 +479,16 @@ compile_transaction_history (
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_data_auto ("h_age_commitment",
phac)),
+ TALER_JSON_pack_amount ("deposit_fee",
+ &pd->deposit_fee),
GNUNET_JSON_pack_data_auto ("purse_pub",
&pd->purse_pub),
GNUNET_JSON_pack_bool ("refunded",
pd->refunded),
GNUNET_JSON_pack_data_auto ("coin_sig",
- &pd->coin_sig))))
+ &pd->coin_sig),
+ GNUNET_JSON_pack_data_auto ("h_denom_pub",
+ &pd->h_denom_pub))))
{
GNUNET_break (0);
json_decref (history);
@@ -491,6 +535,8 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"PURSE-REFUND"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("amount",
&value),
TALER_JSON_pack_amount ("refund_fee",
@@ -520,6 +566,8 @@ compile_transaction_history (
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("type",
"RESERVE-OPEN-DEPOSIT"),
+ GNUNET_JSON_pack_uint64 ("history_offset",
+ pos->coin_history_id),
TALER_JSON_pack_amount ("coin_contribution",
&role->coin_contribution),
GNUNET_JSON_pack_data_auto ("reserve_sig",
diff --git a/src/exchangedb/pg_get_coin_transactions.c b/src/exchangedb/pg_get_coin_transactions.c
@@ -58,6 +58,11 @@ struct CoinHistoryContext
struct PostgresClosure *pg;
/**
+ * Our current offset in the coin history.
+ */
+ uint64_t chid;
+
+ /**
* Set to 'true' if the transaction failed.
*/
bool failed;
@@ -144,6 +149,7 @@ add_coin_deposit (void *cls,
tl->type = TALER_EXCHANGEDB_TT_DEPOSIT;
tl->details.deposit = deposit;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -197,6 +203,8 @@ add_coin_purse_deposit (void *cls,
GNUNET_PQ_result_spec_bool ("refunded",
&deposit->refunded),
¬_finished),
+ GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+ &deposit->h_denom_pub),
GNUNET_PQ_result_spec_end
};
@@ -212,13 +220,17 @@ add_coin_purse_deposit (void *cls,
}
if (not_finished)
deposit->refunded = false;
- deposit->no_age_commitment = GNUNET_is_zero (&deposit->h_age_commitment);
+ /* double-check for all-zeros age commitment */
+ if (! deposit->no_age_commitment)
+ deposit->no_age_commitment
+ = GNUNET_is_zero (&deposit->h_age_commitment);
}
tl = GNUNET_new (struct TALER_EXCHANGEDB_TransactionList);
tl->next = chc->head;
tl->type = TALER_EXCHANGEDB_TT_PURSE_DEPOSIT;
tl->details.purse_deposit = deposit;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -291,6 +303,7 @@ add_coin_melt (void *cls,
tl->type = TALER_EXCHANGEDB_TT_MELT;
tl->details.melt = melt;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -354,6 +367,7 @@ add_coin_refund (void *cls,
tl->type = TALER_EXCHANGEDB_TT_REFUND;
tl->details.refund = refund;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -411,6 +425,7 @@ add_coin_purse_decision (void *cls,
tl->type = TALER_EXCHANGEDB_TT_PURSE_REFUND;
tl->details.purse_refund = prefund;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -477,6 +492,7 @@ add_old_coin_recoup (void *cls,
tl->type = TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP;
tl->details.old_coin_recoup = recoup;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -540,6 +556,7 @@ add_coin_recoup (void *cls,
tl->type = TALER_EXCHANGEDB_TT_RECOUP;
tl->details.recoup = recoup;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -606,6 +623,7 @@ add_coin_recoup_refresh (void *cls,
tl->type = TALER_EXCHANGEDB_TT_RECOUP_REFRESH;
tl->details.recoup_refresh = recoup;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -663,6 +681,7 @@ add_coin_reserve_open (void *cls,
tl->type = TALER_EXCHANGEDB_TT_RESERVE_OPEN;
tl->details.reserve_open = role;
tl->serial_id = serial_id;
+ tl->coin_history_id = chc->chid;
chc->head = tl;
}
}
@@ -751,6 +770,8 @@ handle_history_entry (void *cls,
&table_name),
GNUNET_PQ_result_spec_uint64 ("serial_id",
&serial_id),
+ GNUNET_PQ_result_spec_uint64 ("coin_history_serial_id",
+ &chc->chid),
GNUNET_PQ_result_spec_end
};
struct GNUNET_PQ_QueryParam params[] = {
@@ -862,6 +883,7 @@ TEH_PG_get_coin_transactions (
"SELECT"
" table_name"
",serial_id"
+ ",coin_history_serial_id"
" FROM coin_history"
" WHERE coin_pub=$1"
" AND coin_history_serial_id > $2"
@@ -920,6 +942,7 @@ TEH_PG_get_coin_transactions (
" partner_base_url"
",pd.amount_with_fee"
",denoms.fee_deposit"
+ ",denoms.denom_pub_hash"
",pd.purse_pub"
",kc.age_commitment_hash"
",pd.coin_sig"
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
@@ -2288,7 +2288,7 @@ struct TALER_EXCHANGEDB_MeltListEntry
struct TALER_AgeCommitmentHash h_age_commitment;
/**
- * true, if no h_age_commitment is applicable
+ * true, if no @e h_age_commitment is applicable
*/
bool no_age_commitment;
@@ -2318,7 +2318,6 @@ struct TALER_EXCHANGEDB_MeltListEntry
*/
struct TALER_PublicRefreshMasterSeedP refresh_seed;
-
/**
* If false, @e blinding_seed is present
*/
@@ -2372,6 +2371,11 @@ struct TALER_EXCHANGEDB_PurseDepositListEntry
struct TALER_AgeCommitmentHash h_age_commitment;
/**
+ * Hash of the public denomination key used to sign the coin.
+ */
+ struct TALER_DenominationHashP h_denom_pub;
+
+ /**
* Set to true if the coin was refunded.
*/
bool refunded;
@@ -2736,11 +2740,16 @@ struct TALER_EXCHANGEDB_TransactionList
enum TALER_EXCHANGEDB_TransactionType type;
/**
- * Serial ID of this entry in the database.
+ * Serial ID of this entry in the @e type-specific table.
*/
uint64_t serial_id;
/**
+ * Serial ID of this entry in the coin history table.
+ */
+ uint64_t coin_history_id;
+
+ /**
* Details about the transaction, depending on @e type.
*/
union
diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c
@@ -479,14 +479,11 @@ TALER_wallet_melt_sign (
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT),
.purpose.size = htonl (sizeof (melt)),
.rc = *rc,
- .h_denom_pub = *h_denom_pub,
- .h_age_commitment = {{{0}}},
+ .h_denom_pub = *h_denom_pub
};
if (NULL != h_age_commitment)
melt.h_age_commitment = *h_age_commitment;
-
-
TALER_amount_hton (&melt.amount_with_fee,
amount_with_fee);
TALER_amount_hton (&melt.melt_fee,
@@ -511,13 +508,11 @@ TALER_wallet_melt_verify (
.purpose.size = htonl (sizeof (melt)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT),
.rc = *rc,
- .h_denom_pub = *h_denom_pub,
- .h_age_commitment = {{{0}}},
+ .h_denom_pub = *h_denom_pub
};
if (NULL != h_age_commitment)
melt.h_age_commitment = *h_age_commitment;
-
TALER_amount_hton (&melt.amount_with_fee,
amount_with_fee);
TALER_amount_hton (&melt.melt_fee,