wallet-core: compute residual amount for recoup properly

This commit is contained in:
Florian Dold 2022-11-02 13:40:03 +01:00
parent 87bc4a6fcd
commit fe011321a4
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
7 changed files with 30 additions and 9 deletions

View File

@ -534,6 +534,8 @@ export interface BackupRefreshCoinSource {
* Public key of the coin that was refreshed into this coin. * Public key of the coin that was refreshed into this coin.
*/ */
old_coin_pub: string; old_coin_pub: string;
refresh_group_id: string;
} }
/** /**

View File

@ -181,6 +181,7 @@ export async function runRevocationTest(t: GlobalTestState) {
await makeTestPayment(t, { wallet, merchant, order }); await makeTestPayment(t, { wallet, merchant, order });
wallet.deleteDatabase(); wallet.deleteDatabase();
await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:15" }); await withdrawViaBank(t, { wallet, bank, exchange, amount: "TESTKUDOS:15" });
const coinDump = await wallet.client.call(WalletApiOperation.DumpCoins, {}); const coinDump = await wallet.client.call(WalletApiOperation.DumpCoins, {});

View File

@ -640,6 +640,7 @@ export interface WithdrawCoinSource {
export interface RefreshCoinSource { export interface RefreshCoinSource {
type: CoinSourceType.Refresh; type: CoinSourceType.Refresh;
refreshGroupId: string;
oldCoinPub: string; oldCoinPub: string;
} }

View File

@ -240,6 +240,7 @@ export async function exportBackup(
bcs = { bcs = {
type: BackupCoinSourceType.Refresh, type: BackupCoinSourceType.Refresh,
old_coin_pub: coin.coinSource.oldCoinPub, old_coin_pub: coin.coinSource.oldCoinPub,
refresh_group_id: coin.coinSource.refreshGroupId,
}; };
break; break;
case CoinSourceType.Tip: case CoinSourceType.Tip:

View File

@ -250,6 +250,7 @@ export async function importCoin(
coinSource = { coinSource = {
type: CoinSourceType.Refresh, type: CoinSourceType.Refresh,
oldCoinPub: backupCoin.coin_source.old_coin_pub, oldCoinPub: backupCoin.coin_source.old_coin_pub,
refreshGroupId: backupCoin.coin_source.refresh_group_id,
}; };
break; break;
case BackupCoinSourceType.Tip: case BackupCoinSourceType.Tip:

View File

@ -279,11 +279,21 @@ async function recoupRefreshCoin(
checkDbInvariant(!!oldCoinDenom); checkDbInvariant(!!oldCoinDenom);
checkDbInvariant(!!revokedCoinDenom); checkDbInvariant(!!revokedCoinDenom);
revokedCoin.status = CoinStatus.Dormant; revokedCoin.status = CoinStatus.Dormant;
recoupGroup.scheduleRefreshCoins.push({ if (!revokedCoin.spendAllocation) {
coinPub: oldCoin.coinPub, // We don't know what happened to this coin
//amount: Amounts.sub(oldCoinDenom.value, revokedCoinDenom.value).amount, logger.error(
amount: revokedCoinDenom.value, `can't refresh-recoup coin ${revokedCoin.coinPub}, no spendAllocation known`,
}); );
} else {
let residualAmount = Amounts.sub(
revokedCoinDenom.value,
revokedCoin.spendAllocation.amount,
).amount;
recoupGroup.scheduleRefreshCoins.push({
coinPub: oldCoin.coinPub,
amount: residualAmount,
});
}
await tx.coins.put(revokedCoin); await tx.coins.put(revokedCoin);
await tx.coins.put(oldCoin); await tx.coins.put(oldCoin);
await putGroupAsFinished(ws, tx, recoupGroup, coinIdx); await putGroupAsFinished(ws, tx, recoupGroup, coinIdx);

View File

@ -687,6 +687,7 @@ async function refreshReveal(
status: CoinStatus.Fresh, status: CoinStatus.Fresh,
coinSource: { coinSource: {
type: CoinSourceType.Refresh, type: CoinSourceType.Refresh,
refreshGroupId,
oldCoinPub: refreshGroup.oldCoinPubs[coinIndex], oldCoinPub: refreshGroup.oldCoinPubs[coinIndex],
}, },
coinEvHash: pc.coinEvHash, coinEvHash: pc.coinEvHash,
@ -838,10 +839,6 @@ async function processRefreshSession(
* Refreshes the remaining amount on the coin, effectively capturing the remaining * Refreshes the remaining amount on the coin, effectively capturing the remaining
* value in the refresh group. * value in the refresh group.
* *
* The caller must ensure that
* the remaining amount was updated correctly before the coin was deposited or
* credited.
*
* The caller must also ensure that the coins that should be refreshed exist * The caller must also ensure that the coins that should be refreshed exist
* in the current database transaction. * in the current database transaction.
*/ */
@ -893,6 +890,10 @@ export async function createRefreshGroup(
); );
switch (coin.status) { switch (coin.status) {
case CoinStatus.Dormant: case CoinStatus.Dormant:
coin.spendAllocation = {
amount: Amounts.stringify(ocp.amount),
id: `txn:refresh:${refreshGroupId}`,
};
break; break;
case CoinStatus.Fresh: { case CoinStatus.Fresh: {
coin.status = CoinStatus.Dormant; coin.status = CoinStatus.Dormant;
@ -911,6 +912,10 @@ export async function createRefreshGroup(
// For suspended coins, we don't have to adjust coin // For suspended coins, we don't have to adjust coin
// availability, as they are not counted as available. // availability, as they are not counted as available.
coin.status = CoinStatus.Dormant; coin.status = CoinStatus.Dormant;
coin.spendAllocation = {
amount: Amounts.stringify(ocp.amount),
id: `txn:refresh:${refreshGroupId}`,
};
break; break;
} }
default: default: