Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions database/migration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const run = async (command: string) => {
user: CONFIG.DB_USER,
password: CONFIG.DB_PASSWORD,
database: CONFIG.DB_DATABASE,
supportBigNumbers: true,
bigNumberStrings: true,
multipleStatements: true
Comment thread
einhornimmond marked this conversation as resolved.
Resolved
})
const migration = new Migration({
conn: pool,
Expand Down
76 changes: 76 additions & 0 deletions database/migration/migrations/0102-recalculate_balances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { DecayCalculationType, GradidoUnit } from 'shared'
import { calculateDecay } from 'shared-native'

export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
// Find all users & loop over them
const runningRequests: Promise<Array<any>>[] = []
Comment thread
einhornimmond marked this conversation as resolved.
Resolved
const users = await queryFn('SELECT id FROM users')
let countDiffs = 0
for (let u = 0; u < users.length; u++) {
process.stdout.write(`Recalculating balances for user ${u}/${users.length}\r`)
// find all transactions for a user
const transactions = await queryFn(
`
SELECT id, amount_gdd4, balance_gdd4, decay_gdd4, balance_date
FROM transactions
WHERE user_id = ?
ORDER BY balance_date ASC, id ASC
;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
`,
[users[u].id],
)

let previous = null
let balance = 0n
const transactionsToUpdate: string[] = []

for (let t = 0; t < transactions.length; t++) {
const transaction = transactions[t]
const amount = BigInt(transaction.amount_gdd4)
let decay = 0n
if (balance && previous) {
const decayedBalance = calculateDecay(
balance,
GradidoUnit.effectiveDecayDuration(previous.balance_date, transaction.balance_date)
.seconds,
)
decay = decayedBalance - balance
balance = decayedBalance
}
balance += amount
if (BigInt(transaction.balance_gdd4) !== balance) {
countDiffs++
transactionsToUpdate.push(
`UPDATE transactions
SET balance_gdd4 = '${balance.toString()}',
decay_gdd4 = '${decay.toString()}'
WHERE id = ${transaction.id}
;
`,
)
}
previous = transaction
}
if (transactionsToUpdate.length) {
runningRequests.push(queryFn(transactionsToUpdate.join('\n')))
// await queryFn(transactionsToUpdate.join('\n'))
}
}
await Promise.all(runningRequests)
await queryFn(`UPDATE transactions set decay_calculation_type = ?`, [
DecayCalculationType.NATIVE_C_FIXED_FACTOR_INTEGER,
])
process.stdout.write(`\n`)
// biome-ignore lint/suspicious/noConsole: no logger present
console.log(`${countDiffs} updated transactions`)
}
Comment thread
einhornimmond marked this conversation as resolved.
Resolved

export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(`
UPDATE transactions
SET balance_gdd4 = CAST(ROUND(balance_legacy * 10000) AS SIGNED),
decay_gdd4 = CAST(ROUND(decay_legacy * 10000) AS SIGNED); `)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
await queryFn(
`UPDATE transactions set decay_calculation_type = ${DecayCalculationType.DECIMAL_JS_FIXED_FACTOR}`,
)
}
3 changes: 0 additions & 3 deletions dlt-connector/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion dlt-connector/bunfig.toml

This file was deleted.

3 changes: 1 addition & 2 deletions dlt-connector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"start": "cross-env TZ=UTC bun run src/index.ts",
"build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --minify",
"dev": "cross-env TZ=UTC bun run --watch src/index.ts",
"migrate": "cross-env TZ=UTC bun src/migrations/db-v2.7.0_to_blockchain-v3.7",
"migrate": "cross-env TZ=UTC bun src/migrations/db-v2.7.0_to_blockchain-v3.7 --use-only-legacy-ledger-anchor-ids",
"test": "cross-env TZ=UTC bun test",
"test:debug": "cross-env TZ=UTC bun test --inspect-brk",
"typecheck": "tsc --noEmit",
Expand All @@ -33,7 +33,6 @@
"@types/uuid": "^8.3.4",
"adm-zip": "^0.5.16",
"async-mutex": "^0.5.0",
"decimal.js-light": "^2.5.1",
"dotenv": "^10.0.0",
"drizzle-orm": "^0.44.7",
"elysia": "1.3.8",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class Context {
public communities: Map<string, CommunityContext>
public cache: KeyPairCacheManager
public nativeDecayCalculationStartDate: Date
public useOnlyLegacyLedgerAnchorIds: boolean = false
private timeUsed: MonotonicTimer

constructor(
Expand All @@ -35,6 +36,7 @@ export class Context {
this.communities = new Map<string, CommunityContext>()
this.nativeDecayCalculationStartDate = nativeDecayCalculationStartDate
this.timeUsed = new MonotonicTimer()
this.useOnlyLegacyLedgerAnchorIds = process.argv.includes('--use-only-legacy-ledger-anchor-ids')
}

static async create(): Promise<Context> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import Decimal from 'decimal.js-light'
import { AccountBalance, GradidoUnit, MemoryBlockPtr } from 'gradido-blockchain-js'
import { Amount } from '../../../schemas/typeGuard.schema'
import { NegativeBalanceError } from '../errors'
import { legacyCalculateDecay } from '../utils'

Decimal.set({
precision: 25,
rounding: Decimal.ROUND_HALF_UP,
})

export class Balance {
private balance: GradidoUnit
Expand Down Expand Up @@ -40,62 +32,6 @@ export class Balance {
return this.date
}

updateLegacyDecay(amount: GradidoUnit, date: Date, dbBalance?: Amount) {
// 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
} else {
const decayedBalance = legacyCalculateDecay(
new Decimal(this.balance.toString()),
this.date,
date,
).toDecimalPlaces(4, Decimal.ROUND_CEIL)
/*
if (!decayedBalance.equals(this.balance.toString())) {
console.log({
input: this.balance.toString(4),
decayed: decayedBalance.toString(),
amount: amount.toString(4),
date
})
// throw new Error("Test Exit")
}
// */

let newBalance = decayedBalance.add(new Decimal(amount.toString()))
// reduce small deviations between db decay and balance calculation with 25 decimal places vs gradido-blockchain with 4
if (
dbBalance &&
new Decimal(newBalance.toString()).minus(dbBalance).abs() < new Decimal(0.01)
) {
newBalance = new Decimal(dbBalance)
}
this.balance = GradidoUnit.fromString(newBalance.toString())
this.date = date
}
if (this.balance.lt(GradidoUnit.zero())) {
if (this.balance.lt(GradidoUnit.fromGradidoCent(100n).negated())) {
const previousDecayedBalance = legacyCalculateDecay(
new Decimal(previousBalanceString),
previousDate,
date,
)
throw new NegativeBalanceError(
`negative Gradido amount detected in Balance.updateLegacyDecay`,
previousBalanceString,
amount.toString(),
previousDecayedBalance.toString(),
)
} else {
this.balance = GradidoUnit.zero()
}
}
}

update(amount: GradidoUnit, date: Date) {
const previousBalance = GradidoUnit.fromGradidoCent(this.balance.getGradidoCent())
const previousDate = new Date(this.date.getTime())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
bigint,
char,
datetime,
decimal,
index,
int,
mysqlTable,
Expand Down Expand Up @@ -78,7 +77,6 @@ export const transactionsTable = mysqlTable(
transactionLinkId: int('transaction_link_id').default(sql`NULL`),
amount: bigint('amount_gdd4', { mode: 'bigint' }).default(sql`NULL`),
balance: bigint('balance_gdd4', { mode: 'bigint' }).default(sql`NULL`),
balanceFull: decimal('balance_legacy', { precision: 40, scale: 20 }).default(sql`NULL`),
balanceDate: datetime('balance_date', { mode: 'string', fsp: 3 })
.default(sql`current_timestamp(3)`)
.notNull(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ import {
AccountBalances,
Filter,
GradidoTransactionBuilder,
HieroTransactionId,
InMemoryBlockchain,
KeyPairEd25519,
LedgerAnchor,
LedgerAnchor_Type,
MemoryBlockPtr,
MonotonicTimer,
SearchDirection_DESC,
} from 'gradido-blockchain-js'
import { getLogger, Logger } from 'log4js'
import { LOG4JS_BASE_CATEGORY } from '../../../../config/const'
import { deriveFromKeyPairAndIndex, deriveFromKeyPairAndUuid } from '../../../../data/deriveKeyPair'
import { Uuidv4 } from '../../../../schemas/typeGuard.schema'
import { HieroTransactionIdString, Uuidv4 } from '../../../../schemas/typeGuard.schema'
import { Context } from '../../Context'
import { Balance } from '../../data/Balance'
import { CommunityContext } from '../../valibot.schema'
Expand All @@ -20,22 +23,31 @@ export type IndexType = {
date: Date
id: number
}
export interface SyncItem {
id: number
messageId?: HieroTransactionIdString | null | undefined
}
export let nanosBalanceForUser = 0
const lastBalanceOfUserTimeUsed = new MonotonicTimer()

export abstract class AbstractSyncRole<ItemType> {
export abstract class AbstractSyncRole<ItemType extends SyncItem> {
private items: ItemType[] = []
protected lastIndex: IndexType = { date: new Date(0), id: 0 }
protected logger: Logger
protected transactionBuilder: GradidoTransactionBuilder
protected accountBalances: AccountBalances
protected legacyAnchorType: LedgerAnchor_Type

constructor(protected readonly context: Context) {
constructor(
protected readonly context: Context,
legacyAnchorType: LedgerAnchor_Type,
) {
this.logger = getLogger(
`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5.interaction.syncDbWithBlockchain`,
)
this.transactionBuilder = new GradidoTransactionBuilder()
this.accountBalances = new AccountBalances()
this.legacyAnchorType = legacyAnchorType
}

getAccountKeyPair(communityContext: CommunityContext, gradidoId: Uuidv4): KeyPairEd25519 {
Expand Down Expand Up @@ -84,6 +96,14 @@ export abstract class AbstractSyncRole<ItemType> {
return result
}

getLedgerAnchor(item: ItemType): LedgerAnchor {
if (item.messageId && !this.context.useOnlyLegacyLedgerAnchorIds) {
return new LedgerAnchor(new HieroTransactionId(item.messageId))
} else {
return new LedgerAnchor(item.id, this.legacyAnchorType)
}
}

logLastBalanceChangingTransactions(
publicKey: MemoryBlockPtr,
blockchain: InMemoryBlockchain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
EncryptedMemo,
Filter,
GradidoTransactionBuilder,
HieroTransactionId,
KeyPairEd25519,
LedgerAnchor,
MemoryBlockPtr,
Expand All @@ -31,7 +30,7 @@ import { AbstractSyncRole, IndexType } from './AbstractSync.role'

export class CreationsSyncRole extends AbstractSyncRole<CreationTransactionDb> {
constructor(context: Context) {
super(context)
super(context, LedgerAnchor.Type_LEGACY_GRADIDO_DB_CONTRIBUTION_ID)
this.accountBalances.reserve(3n)
}

Expand Down Expand Up @@ -137,10 +136,10 @@ export class CreationsSyncRole extends AbstractSyncRole<CreationTransactionDb> {
communityContext.communityId,
)

// calculate decay since last balance with legacy calculation method
balance.updateLegacyDecay(item.amount, item.confirmedAt)
communityContext.aufBalance.updateLegacyDecay(item.amount, item.confirmedAt)
communityContext.gmwBalance.updateLegacyDecay(item.amount, item.confirmedAt)
// calculate decay since last balance
balance.update(item.amount, item.confirmedAt)
communityContext.aufBalance.update(item.amount, item.confirmedAt)
communityContext.gmwBalance.update(item.amount, item.confirmedAt)

this.accountBalances.add(balance.getAccountBalance())
this.accountBalances.add(communityContext.aufBalance.getAccountBalance())
Expand All @@ -165,22 +164,11 @@ export class CreationsSyncRole extends AbstractSyncRole<CreationTransactionDb> {
}

try {
let ledgerAnchor: LedgerAnchor | undefined
if (item.messageId) {
ledgerAnchor = new LedgerAnchor(new HieroTransactionId(item.messageId))
} else {
ledgerAnchor = new LedgerAnchor(
item.id,
LedgerAnchor.Type_LEGACY_GRADIDO_DB_CONTRIBUTION_ID,
)
}
addToBlockchain(
this.buildTransaction(item, communityContext, recipientKeyPair, signerKeyPair).build(),
blockchain,
ledgerAnchor,
!this.context.isDecayCalculationTypeChanged(item.confirmedAt)
? this.calculateAccountBalances(item, communityContext, recipientPublicKey)
: undefined,
this.getLedgerAnchor(item),
this.calculateAccountBalances(item, communityContext, recipientPublicKey),
)
} catch (e) {
const f = new Filter()
Expand Down
Loading
Loading