diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/data/Balance.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/data/Balance.ts index 718be3ff9..d9e36721f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/data/Balance.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/data/Balance.ts @@ -1,6 +1,7 @@ import Decimal from 'decimal.js-light' import { AccountBalance, GradidoUnit, MemoryBlockPtr } from 'gradido-blockchain-js' import { legacyCalculateDecay } from '../utils' +import { NegativeBalanceError } from '../errors' export class Balance { private balance: GradidoUnit @@ -25,8 +26,15 @@ export class Balance { return this.balance } + getDate(): Date { + return this.date + } + updateLegacyDecay(amount: GradidoUnit, date: Date) { + // make sure to copy instead of referencing const previousBalanceString = this.balance.toString() + const previousDate = new Date(this.date.getTime()) + if (this.balance.equal(GradidoUnit.zero())) { this.balance = amount this.date = date @@ -37,12 +45,20 @@ export class Balance { this.date = date } if (this.balance.lt(GradidoUnit.zero())) { - throw new Error(`negative Gradido amount detected in Balance.updateLegacyDecay, previous balance: ${previousBalanceString}, amount: ${amount.toString()}`) + const previousDecayedBalance = legacyCalculateDecay(new Decimal(previousBalanceString), previousDate, date) + throw new NegativeBalanceError( + `negative Gradido amount detected in Balance.updateLegacyDecay`, + previousBalanceString, + amount.toString(), + previousDecayedBalance.toString(), + ) } } update(amount: GradidoUnit, date: Date) { - const previousBalanceString = this.balance.toString() + const previousBalance = new GradidoUnit(this.balance.toString()) + const previousDate = new Date(this.date.getTime()) + if (this.balance.equal(GradidoUnit.zero())) { this.balance = amount this.date = date @@ -53,7 +69,13 @@ export class Balance { this.date = date } if (this.balance.lt(GradidoUnit.zero())) { - throw new Error(`negative Gradido amount detected in Balance.update, previous balance: ${previousBalanceString}, amount: ${amount.toString()}`) + const previousDecayedBalance = this.balance.calculateDecay(previousDate, date) + throw new NegativeBalanceError( + `negative Gradido amount detected in Balance.update`, + previousBalance.toString(), + amount.toString(), + previousDecayedBalance.toString(), + ) } } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/errors.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/errors.ts index 504ce76a4..64b3a28e7 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/errors.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/errors.ts @@ -3,6 +3,7 @@ import * as v from 'valibot' export class NotEnoughGradidoBalanceError extends Error { constructor(public needed: number, public exist: number) { super(`Not enough Gradido Balance for send coins, needed: ${needed} Gradido, exist: ${exist} Gradido`) + this.name = 'NotEnoughGradidoBalanceError' } } @@ -42,3 +43,14 @@ export class BlockchainError extends Error { this.stack = originalError.stack } } + +export class NegativeBalanceError extends Error { + constructor(message: string, previousBalanceString: string, amount: string, previousDecayedBalance: string) { + const parts: string[] = [`NegativeBalanceError in ${message}`] + parts.push(`Previous balance: ${previousBalanceString}`) + parts.push(`Amount: ${amount}`) + parts.push(`Previous decayed balance: ${previousDecayedBalance}`) + super(parts.join('\n')) + this.name = 'NegativeBalanceError' + } +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts index df6ba0f19..307b2933c 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts @@ -43,6 +43,21 @@ export abstract class AbstractSyncRole { return Balance.fromAccountBalance(senderLastAccountBalance, lastConfirmedTransaction.getConfirmedAt().getDate()) } + logLastBalanceChangingTransactions(publicKey: MemoryBlockPtr, blockchain: InMemoryBlockchain, transactionCount: number = 5) { + if (!this.context.logger.isDebugEnabled()) { + return + } + const f = new Filter() + f.updatedBalancePublicKey = publicKey + f.searchDirection = SearchDirection_DESC + f.pagination.size = transactionCount + const lastTransactions = blockchain.findAll(f) + for (let i = lastTransactions.size() - 1; i >= 0; i--) { + const tx = lastTransactions.get(i) + this.context.logger.debug(`${tx?.getConfirmedTransaction()!.toJson(true)}`) + } + } + abstract getDate(): Date abstract loadFromDb(offset: number, count: number): Promise abstract pushToBlockchain(item: T): void diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/LocalTransactionsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/LocalTransactionsSync.role.ts index 63b03ff36..6476d886b 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/LocalTransactionsSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/LocalTransactionsSync.role.ts @@ -15,7 +15,7 @@ import * as v from 'valibot' import { addToBlockchain } from '../../blockchain' import { TransactionTypeId } from '../../data/TransactionTypeId' import { transactionsTable, usersTable } from '../../drizzle.schema' -import { BlockchainError, DatabaseError } from '../../errors' +import { BlockchainError, DatabaseError, NegativeBalanceError, NotEnoughGradidoBalanceError } from '../../errors' import { CommunityContext, TransactionDb, transactionDbSchema } from '../../valibot.schema' import { AbstractSyncRole } from './AbstractSync.role' @@ -99,20 +99,14 @@ export class LocalTransactionsSyncRole extends AbstractSyncRole { const senderLastBalance = this.getLastBalanceForUser(senderPublicKey, communityContext.blockchain) const recipientLastBalance = this.getLastBalanceForUser(recipientPublicKey, communityContext.blockchain) - if (senderLastBalance.getAccountBalance().getBalance().lt(item.amount)) { - const f = new Filter() - f.updatedBalancePublicKey = senderPublicKey - f.searchDirection = SearchDirection_DESC - f.pagination.size = 5 - const lastTransactions = communityContext.blockchain.findAll(f) - for (let i = lastTransactions.size() - 1; i >= 0; i--) { - const tx = lastTransactions.get(i) - this.context.logger.error(`${tx?.getConfirmedTransaction()!.toJson(true)}`) + try { + senderLastBalance.updateLegacyDecay(item.amount.negated(), item.balanceDate) + } catch(e) { + if (e instanceof NegativeBalanceError) { + this.logLastBalanceChangingTransactions(senderPublicKey, communityContext.blockchain) + throw e } - throw new Error(`sender has not enough balance (${senderLastBalance.getAccountBalance().getBalance().toString()}) to send ${item.amount.toString()} to ${recipientPublicKey.convertToHex()}`) } - - senderLastBalance.updateLegacyDecay(item.amount.negated(), item.balanceDate) recipientLastBalance.updateLegacyDecay(item.amount, item.balanceDate) accountBalances.add(senderLastBalance.getAccountBalance()) @@ -145,6 +139,9 @@ export class LocalTransactionsSyncRole extends AbstractSyncRole { this.calculateBalances(item, communityContext, senderPublicKey, recipientPublicKey), ) } catch(e) { + if (e instanceof NotEnoughGradidoBalanceError) { + this.logLastBalanceChangingTransactions(senderPublicKey, blockchain) + } throw new BlockchainError(`Error adding ${this.itemTypeName()}`, item, e as Error) } } 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 a0dd98593..574c02235 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 @@ -17,10 +17,12 @@ import { import * as v from 'valibot' import { addToBlockchain } from '../../blockchain' import { transactionLinksTable, usersTable } from '../../drizzle.schema' -import { BlockchainError, DatabaseError } from '../../errors' +import { BlockchainError, DatabaseError, NegativeBalanceError } from '../../errors' import { CommunityContext, TransactionLinkDb, transactionLinkDbSchema } from '../../valibot.schema' import { AbstractSyncRole } from './AbstractSync.role' import { deriveFromCode } from '../../../../data/deriveKeyPair' +import { legacyCalculateDecay } from '../../utils' +import Decimal from 'decimal.js-light' export class TransactionLinkFundingsSyncRole extends AbstractSyncRole { getDate(): Date { @@ -87,22 +89,9 @@ export class TransactionLinkFundingsSyncRole extends AbstractSyncRole= 0; i--) { - const lastSenderTransaction = lastSenderTransactions.get(i) - this.context.logger.error(`${lastSenderTransaction?.getConfirmedTransaction()?.toJson(true)}`) - } - } + let senderLastBalance = this.getLastBalanceForUser(senderPublicKey, communityContext.blockchain) senderLastBalance.updateLegacyDecay(blockedAmount.negated(), item.createdAt) - + accountBalances.add(senderLastBalance.getAccountBalance()) accountBalances.add(new AccountBalance(recipientPublicKey, blockedAmount, '')) return accountBalances @@ -122,16 +111,39 @@ export class TransactionLinkFundingsSyncRole extends AbstractSyncRole