From d9666f3a8834de0dc5176920ef8a36b97779e359 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 30 Dec 2025 18:13:03 +0100 Subject: [PATCH] move transaction link validUntil correction into database migration --- ...097-fix_production_data_for_blockchain2.ts | 78 +++++++++++++++++++ .../TransactionLinkFundingsSync.role.ts | 31 +------- .../db-v2.7.0_to_blockchain-v3.5/utils.ts | 4 - shared/src/const/index.ts | 3 + shared/src/logic/decay.ts | 13 +++- 5 files changed, 93 insertions(+), 36 deletions(-) diff --git a/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts b/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts index f8f2fdd57..f7c99561d 100644 --- a/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts +++ b/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts @@ -1,3 +1,10 @@ +import Decimal from 'decimal.js-light' +import { DECAY_FACTOR, reverseLegacyDecay } from 'shared' + +function calculateEffectiveSeconds(holdOriginal: Decimal, holdCorrected: Decimal): Decimal { + return holdOriginal.div(holdCorrected).ln().div(DECAY_FACTOR.ln()) +} + export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { /** * Migration: Correct historical inconsistencies in transactions, users, and contribution_links. @@ -34,6 +41,77 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis * ensuring blockchain consistency for contributions. */ + /** + * Fix 0: Update transaction links to match holdAvailableAmount with validUntil, because the old formula lead to incorrect values + */ + + let sumCount = 0 + let count = 0 + let lastProcessedId = 0 + const LIMIT = 200 + do { + const rows = await queryFn( + ` + SELECT id, amount, hold_available_amount, validUntil, createdAt, redeemedAt, deletedAt + FROM transaction_links + WHERE id > ? + ORDER BY id ASC + LIMIT ? + `, + [lastProcessedId, LIMIT], + ) + if (!rows.length) { + break + } + const updates: Array<{ id: number; newValidUntil: string }> = [] + for (const row of rows) { + const validUntil = new Date(row.validUntil) + const redeemedAt = row.redeemedAt ? new Date(row.redeemedAt) : null + const deletedAt = row.deletedAt ? new Date(row.deletedAt) : null + const createdAt = new Date(row.createdAt) + const amount = new Decimal(row.amount) + const duration = (validUntil.getTime() - createdAt.getTime()) / 1000 + const blockedAmountCorrected = reverseLegacyDecay(amount, duration) + // fix only if the difference is big enough to have an impact + if (blockedAmountCorrected.sub(amount).abs().lt(new Decimal('0.001'))) { + continue + } + const holdAvailableAmount = new Decimal(row.hold_available_amount) + const secondsDiff = calculateEffectiveSeconds( + new Decimal(holdAvailableAmount.toString()), + new Decimal(blockedAmountCorrected.toString()), + ) + const newValidUntil = new Date(validUntil.getTime() - secondsDiff.mul(1000).toNumber()) + if ( + (redeemedAt && redeemedAt.getTime() < validUntil.getTime()) || + (deletedAt && deletedAt.getTime() < validUntil.getTime()) + ) { + continue + } + updates.push({ + id: row.id, + newValidUntil: newValidUntil.toISOString().replace('T', ' ').replace('Z', ''), + }) + } + if (updates.length > 0) { + const caseStatements = updates.map((u) => `WHEN ${u.id} THEN '${u.newValidUntil}'`).join('\n') + + await queryFn( + ` + UPDATE transaction_links + SET validUntil = CASE id + ${caseStatements} + END + WHERE id IN (?) + `, + [updates.map((u) => u.id)], + ) + sumCount += updates.length + } + count = rows.length + lastProcessedId = rows[rows.length - 1].id + } while (count === LIMIT) + ///*/ /** * Fix 1: Remove self-signed contributions. * diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts index 6a28d4b7f..dc4032f68 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts @@ -127,32 +127,8 @@ export class TransactionLinkFundingsSyncRole extends AbstractSyncRole item.validUntil.getTime()) { - endDateTime = item.validUntil.getTime() - } - let duration = new DurationSeconds((endDateTime - item.createdAt.getTime()) / 1000) - const hourInSeconds = 60 * 60 - if (duration.getSeconds() < hourInSeconds) { - duration = new DurationSeconds(hourInSeconds) - } + let duration = new DurationSeconds((item.validUntil.getTime() - item.createdAt.getTime()) / 1000) let blockedAmount = GradidoUnit.fromString(reverseLegacyDecay(new Decimal(item.amount.toString()), duration.getSeconds()).toString()) - blockedAmount = blockedAmount.add(GradidoUnit.fromGradidoCent(1)) - // let blockedAmount = decayedAmount.calculateCompoundInterest(duration.getSeconds()) let accountBalances: AccountBalances try { accountBalances = this.calculateBalances(item, blockedAmount, communityContext, senderPublicKey, recipientPublicKey) @@ -171,11 +147,6 @@ export class TransactionLinkFundingsSyncRole extends AbstractSyncRole