fix double transaction entry

This commit is contained in:
Einhornimmond 2021-10-10 13:24:50 +02:00
parent bfa0e9481c
commit 865403e0fa
3 changed files with 39 additions and 44 deletions

View File

@ -1,3 +1,4 @@
node_modules node_modules
**/*.min.js **/*.min.js
build build
src/proto/bundle.d.ts

View File

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Resolver, Query, Args, Authorized, Ctx, Mutation, Root } from 'type-graphql' import { Resolver, Query, Args, Authorized, Ctx, Mutation } from 'type-graphql'
import { getCustomRepository, getConnection, EntityManager, Connection, QueryRunner } from 'typeorm' import { getCustomRepository, getConnection, QueryRunner } from 'typeorm'
import { createTransport } from 'nodemailer' import { createTransport } from 'nodemailer'
import CONFIG from '../../config' import CONFIG from '../../config'
@ -24,10 +24,7 @@ import { User as dbUser } from '../../typeorm/entity/User'
import { UserTransaction as DbUserTransaction } from '../../typeorm/entity/UserTransaction' import { UserTransaction as DbUserTransaction } from '../../typeorm/entity/UserTransaction'
import { Transaction as DbTransaction } from '../../typeorm/entity/Transaction' import { Transaction as DbTransaction } from '../../typeorm/entity/Transaction'
import { TransactionSignature as DbTransactionSignature } from '../../typeorm/entity/TransactionSignature' import { TransactionSignature as DbTransactionSignature } from '../../typeorm/entity/TransactionSignature'
import { import { TransactionSendCoin as DbTransactionSendCoin } from '../../typeorm/entity/TransactionSendCoin'
TransactionSendCoin as DbTransactionSendCoin,
TransactionSendCoin,
} from '../../typeorm/entity/TransactionSendCoin'
import { Balance as DbBalance } from '../../typeorm/entity/Balance' import { Balance as DbBalance } from '../../typeorm/entity/Balance'
import { apiGet, apiPost } from '../../apis/HttpRequest' import { apiGet, apiPost } from '../../apis/HttpRequest'
@ -243,8 +240,11 @@ async function updateStateBalance(
balance.userId = user.id balance.userId = user.id
balance.amount = centAmount balance.amount = centAmount
} else { } else {
const decaiedBalance = calculateDecay(balance.amount, balance.recordDate, received) const decaiedBalance = calculateDecay(balance.amount, balance.recordDate, received).catch(
.catch(() => {throw new Error('error by calculating decay')}) () => {
throw new Error('error by calculating decay')
},
)
balance.amount = Number(await decaiedBalance) + centAmount balance.amount = Number(await decaiedBalance) + centAmount
} }
if (balance.amount <= 0) { if (balance.amount <= 0) {
@ -272,7 +272,9 @@ async function addUserTransaction(
Number(lastUserTransaction.balance), Number(lastUserTransaction.balance),
lastUserTransaction.balanceDate, lastUserTransaction.balanceDate,
transaction.received, transaction.received,
).catch(() => {throw new Error('error by calculating decay')}), ).catch(() => {
throw new Error('error by calculating decay')
}),
) )
} }
@ -367,6 +369,8 @@ async function sendCoins(
// process db updates as transaction to able to rollback if an error occure // process db updates as transaction to able to rollback if an error occure
const queryRunner = getConnection().createQueryRunner() const queryRunner = getConnection().createQueryRunner()
// belong to debugging mysql query / typeorm line
// const startTime = new Date()
await queryRunner.connect() await queryRunner.connect()
await queryRunner.startTransaction('READ UNCOMMITTED') await queryRunner.startTransaction('READ UNCOMMITTED')
try { try {
@ -375,13 +379,12 @@ async function sendCoins(
transaction.transactionTypeId = TransactionTypeId.SEND transaction.transactionTypeId = TransactionTypeId.SEND
transaction.memo = memo transaction.memo = memo
const transactionRepository = getCustomRepository(TransactionRepository) const transactionRepository = getCustomRepository(TransactionRepository)
queryRunner.manager.save(transaction).catch((error) => {
throw new Error('error saving transaction: ' + error)
})
const insertResult = await queryRunner.manager.insert(DbTransaction, transaction) const insertResult = await queryRunner.manager.insert(DbTransaction, transaction)
transaction = await queryRunner.manager.findOneOrFail(DbTransaction, insertResult.generatedMaps[0].id).catch((error) => { transaction = await queryRunner.manager
throw new Error('error loading saved transaction: ' + error) .findOneOrFail(DbTransaction, insertResult.generatedMaps[0].id)
}) .catch((error) => {
throw new Error('error loading saved transaction: ' + error)
})
if (!recipiantUser) { if (!recipiantUser) {
throw new Error('Cannot find recipiant user by local send coins transaction') throw new Error('Cannot find recipiant user by local send coins transaction')
@ -418,9 +421,7 @@ async function sendCoins(
if (senderStateBalance.amount !== senderUserTransactionBalance.balance) { if (senderStateBalance.amount !== senderUserTransactionBalance.balance) {
throw new Error('db data corrupted, sender') throw new Error('db data corrupted, sender')
} }
if ( if (recipiantStateBalance.amount !== recipiantUserTransactionBalance.balance) {
recipiantStateBalance.amount !== recipiantUserTransactionBalance.balance
) {
throw new Error('db data corrupted, recipiant') throw new Error('db data corrupted, recipiant')
} }
@ -432,7 +433,7 @@ async function sendCoins(
transactionSendCoin.recipiantUserId = recipiantUser.id transactionSendCoin.recipiantUserId = recipiantUser.id
transactionSendCoin.recipiantPublic = Buffer.from(fromHex(recipiantPublicKey)) transactionSendCoin.recipiantPublic = Buffer.from(fromHex(recipiantPublicKey))
transactionSendCoin.amount = centAmount transactionSendCoin.amount = centAmount
transactionSendCoin.senderFinalBalance = senderStateBalance.amount transactionSendCoin.senderFinalBalance = senderStateBalance.amount
await queryRunner.manager.save(transactionSendCoin).catch((error) => { await queryRunner.manager.save(transactionSendCoin).catch((error) => {
throw new Error('error saving transaction send coin: ' + error) throw new Error('error saving transaction send coin: ' + error)
}) })
@ -440,10 +441,12 @@ async function sendCoins(
// tx hash // tx hash
const state = cryptoGenerichashInit(null, cryptoGenericHashBytes) const state = cryptoGenerichashInit(null, cryptoGenericHashBytes)
if (transaction.id > 1) { if (transaction.id > 1) {
const previousTransaction = await transactionRepository.findOne({ id: transaction.id - 1 }) const previousTransaction = await transactionRepository.findOne({ id: transaction.id - 1 })
if (!previousTransaction) { if (!previousTransaction) {
throw new Error('Error previous transaction not found') throw new Error('Error previous transaction not found, please try again')
}
if (!previousTransaction.txHash) {
throw new Error('Previous tx hash is null')
} }
cryptoGenerichashUpdate(state, previousTransaction.txHash) cryptoGenerichashUpdate(state, previousTransaction.txHash)
} }
@ -456,7 +459,7 @@ async function sendCoins(
await queryRunner.manager.save(transaction).catch((error) => { await queryRunner.manager.save(transaction).catch((error) => {
throw new Error('error saving transaction with tx hash: ' + error) throw new Error('error saving transaction with tx hash: ' + error)
}) })
// save signature // save signature
const signature = new DbTransactionSignature() const signature = new DbTransactionSignature()
signature.transactionId = transaction.id signature.transactionId = transaction.id
@ -466,14 +469,20 @@ async function sendCoins(
throw new Error('error saving signature: ' + error) throw new Error('error saving signature: ' + error)
}) })
await queryRunner.commitTransaction() await queryRunner.commitTransaction()
// great way de debug mysql querys / typeorm
// const result = await queryRunner.query("SELECT * FROM mysql.general_log WHERE thread_id IN (SELECT ID FROM information_schema.processlist WHERE DB = 'gradido_community') AND event_time > ?; ", [startTime])
// console.log("start time: %o, transaction log: %o", startTime.getTime(), result)
} catch (e) { } catch (e) {
await queryRunner.rollbackTransaction() await queryRunner.rollbackTransaction()
const count = await queryRunner.manager.count(DbTransaction) const count = await queryRunner.manager.count(DbTransaction)
// fix autoincrement value which seems not effected from rollback // fix autoincrement value which seems not effected from rollback
await queryRunner.query('ALTER TABLE `transactions` auto_increment = ?', [ count ]).catch((error) => { await queryRunner
// eslint-disable-next-line no-console .query('ALTER TABLE `transactions` auto_increment = ?', [count])
console.log("problems with reset auto increment: %o", error) .catch((error) => {
}) // eslint-disable-next-line no-console
console.log('problems with reset auto increment: %o', error)
})
throw e throw e
} finally { } finally {
@ -524,8 +533,6 @@ async function sendCoins(
}) })
if (!info.messageId) { if (!info.messageId) {
throw new Error('error sending notification email, but transaction succeed') throw new Error('error sending notification email, but transaction succeed')
} else {
console.log('send email: %o', info)
} }
} }
} }
@ -610,19 +617,6 @@ export class TransactionResolver {
@Args() { email, amount, memo }: TransactionSendArgs, @Args() { email, amount, memo }: TransactionSendArgs,
@Ctx() context: any, @Ctx() context: any,
): Promise<string> { ): Promise<string> {
const payload = {
session_id: context.sessionId,
target_email: email,
amount: amount * 10000,
memo,
auto_sign: true,
transaction_type: 'transfer',
blockchain_type: 'mysql',
}
/* const result = await apiPost(CONFIG.LOGIN_API_URL + 'createTransaction', payload)
if (!result.success) {
throw new Error(result.data)
} */
const recipiantPublicKey = await getPublicKey(email, context.sessionId) const recipiantPublicKey = await getPublicKey(email, context.sessionId)
if (!recipiantPublicKey) { if (!recipiantPublicKey) {
throw new Error('recipiant not known') throw new Error('recipiant not known')

View File

@ -7,7 +7,7 @@ function decayFormula(amount: number, seconds: number): number {
} }
async function calculateDecay(amount: number, from: Date, to: Date): Promise<number> { async function calculateDecay(amount: number, from: Date, to: Date): Promise<number> {
if(amount === undefined || !from || !to) { if (amount === undefined || !from || !to) {
throw new Error('at least one parameter is undefined') throw new Error('at least one parameter is undefined')
} }
// load decay start block // load decay start block