mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
create context and roles for transmit to iota
This commit is contained in:
parent
f5f7e5fb63
commit
35be61a9c8
@ -50,7 +50,7 @@ jest.mock('@iota/client', () => {
|
||||
|
||||
describe('Iota Tests', () => {
|
||||
it('test mocked sendDataMessage', async () => {
|
||||
const result = await sendMessage('Test Message')
|
||||
const result = await sendMessage('Test Message', 'topic')
|
||||
expect(result).toBe('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710')
|
||||
})
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import { LogError } from '@/server/LogError'
|
||||
import { toPublic, derivePrivate, sign, verify, generateFromSeed } from 'bip32-ed25519'
|
||||
|
||||
import { Mnemonic } from './Mnemonic'
|
||||
import { SignaturePair } from './proto/3_3/SignaturePair'
|
||||
|
||||
/**
|
||||
* Class Managing Key Pair and also generate, sign and verify signature with it
|
||||
@ -81,7 +82,7 @@ export class KeyPair {
|
||||
return sign(message, this.getExtendPrivateKey())
|
||||
}
|
||||
|
||||
public verify(message: Buffer, signature: Buffer): boolean {
|
||||
return verify(message, signature, this.getExtendPublicKey())
|
||||
public static verify(message: Buffer, { signature, pubKey }: SignaturePair): boolean {
|
||||
return verify(message, signature, pubKey)
|
||||
}
|
||||
}
|
||||
|
||||
161
dlt-connector/src/data/Transaction.logic.ts
Normal file
161
dlt-connector/src/data/Transaction.logic.ts
Normal file
@ -0,0 +1,161 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { Not } from 'typeorm'
|
||||
|
||||
import { logger } from '@/logging/logger'
|
||||
import { TransactionBodyLoggingView } from '@/logging/TransactionBodyLogging.view'
|
||||
import { TransactionLoggingView } from '@/logging/TransactionLogging.view'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { CrossGroupType } from './proto/3_3/enum/CrossGroupType'
|
||||
import { TransactionType } from './proto/3_3/enum/TransactionType'
|
||||
import { TransactionBody } from './proto/3_3/TransactionBody'
|
||||
|
||||
export class TransactionLogic {
|
||||
protected transactionBody: TransactionBody | undefined
|
||||
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
public constructor(private self: Transaction) {}
|
||||
|
||||
/**
|
||||
* search for transaction pair for Cross Group Transaction
|
||||
* @returns
|
||||
*/
|
||||
public async findPairTransaction(): Promise<Transaction> {
|
||||
const type = this.getBody().type
|
||||
if (type === CrossGroupType.LOCAL) {
|
||||
throw new LogError("local transaction don't has a pairing transaction")
|
||||
}
|
||||
|
||||
// check if already on entity
|
||||
if (this.self.paringTransaction) {
|
||||
return this.self.paringTransaction
|
||||
}
|
||||
|
||||
if (this.self.paringTransactionId) {
|
||||
const pairingTransaction = await Transaction.findOneBy({ id: this.self.paringTransactionId })
|
||||
if (pairingTransaction) {
|
||||
return pairingTransaction
|
||||
}
|
||||
}
|
||||
// check if we find some in db
|
||||
const sameCreationDateTransactions = await Transaction.findBy({
|
||||
createdAt: this.self.createdAt,
|
||||
id: Not(this.self.id),
|
||||
})
|
||||
if (
|
||||
sameCreationDateTransactions.length === 1 &&
|
||||
this.isBelongTogether(sameCreationDateTransactions[0])
|
||||
) {
|
||||
return sameCreationDateTransactions[0]
|
||||
}
|
||||
// this approach only work if all entities get ids really incremented by one
|
||||
if (type === CrossGroupType.OUTBOUND) {
|
||||
const prevTransaction = await Transaction.findOneBy({ id: this.self.id - 1 })
|
||||
if (prevTransaction && this.isBelongTogether(prevTransaction)) {
|
||||
return prevTransaction
|
||||
}
|
||||
} else if (type === CrossGroupType.INBOUND) {
|
||||
const nextTransaction = await Transaction.findOneBy({ id: this.self.id + 1 })
|
||||
if (nextTransaction && this.isBelongTogether(nextTransaction)) {
|
||||
return nextTransaction
|
||||
}
|
||||
}
|
||||
throw new LogError("couldn't find valid paring transaction", {
|
||||
id: this.self.id,
|
||||
type: CrossGroupType[type],
|
||||
transactionCountWithSameCreatedAt: sameCreationDateTransactions.length,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* check if two transactions belong together
|
||||
* are they pairs for a cross group transaction
|
||||
* @param otherTransaction
|
||||
*/
|
||||
public isBelongTogether(otherTransaction: Transaction): boolean {
|
||||
if (this.self.id === otherTransaction.id) {
|
||||
logger.info('id is the same, it is the same transaction!')
|
||||
return false
|
||||
}
|
||||
if (
|
||||
this.self.signingAccountId !== otherTransaction.signingAccountId ||
|
||||
this.self.recipientAccountId !== otherTransaction.recipientAccountId ||
|
||||
this.self.communityId !== otherTransaction.communityId ||
|
||||
this.self.otherCommunityId !== otherTransaction.otherCommunityId ||
|
||||
this.self.amount !== otherTransaction.amount ||
|
||||
this.self.accountBalanceOnCreation !== otherTransaction.accountBalanceOnCreation ||
|
||||
this.self.createdAt !== otherTransaction.createdAt
|
||||
) {
|
||||
logger.debug('transaction a and b are not pairs', {
|
||||
a: new TransactionLoggingView(this.self),
|
||||
b: new TransactionLoggingView(otherTransaction),
|
||||
})
|
||||
return false
|
||||
}
|
||||
const body = this.getBody()
|
||||
const otherBody = TransactionBody.fromBodyBytes(otherTransaction.bodyBytes)
|
||||
/**
|
||||
* both can be Cross
|
||||
* one can be OUTBOUND and one can be INBOUND
|
||||
* no one can be LOCAL
|
||||
*/
|
||||
if (
|
||||
(body.type === otherBody.type && body.type !== CrossGroupType.CROSS) ||
|
||||
body.type === CrossGroupType.LOCAL ||
|
||||
otherBody.type === CrossGroupType.LOCAL
|
||||
) {
|
||||
logger.info("cross group types don't match", {
|
||||
a: new TransactionBodyLoggingView(body),
|
||||
b: new TransactionBodyLoggingView(otherBody),
|
||||
})
|
||||
return false
|
||||
}
|
||||
const type = body.getTransactionType()
|
||||
const otherType = otherBody.getTransactionType()
|
||||
if (!type || !otherType) {
|
||||
throw new LogError("couldn't determine transaction type", {
|
||||
a: new TransactionBodyLoggingView(body),
|
||||
b: new TransactionBodyLoggingView(otherBody),
|
||||
})
|
||||
}
|
||||
if (type !== otherType) {
|
||||
logger.info("transaction types don't match", {
|
||||
a: new TransactionBodyLoggingView(body),
|
||||
b: new TransactionBodyLoggingView(otherBody),
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (
|
||||
[
|
||||
TransactionType.COMMUNITY_ROOT,
|
||||
TransactionType.GRADIDO_CREATION,
|
||||
TransactionType.GRADIDO_DEFERRED_TRANSFER,
|
||||
].includes(type)
|
||||
) {
|
||||
logger.info(`TransactionType ${type} couldn't be a CrossGroup Transaction`)
|
||||
return false
|
||||
}
|
||||
if (body.otherGroup === otherBody.otherGroup) {
|
||||
logger.info('otherGroups are the same', {
|
||||
a: new TransactionBodyLoggingView(body),
|
||||
b: new TransactionBodyLoggingView(otherBody),
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (body.memo !== otherBody.memo) {
|
||||
logger.info('memo differ', {
|
||||
a: new TransactionBodyLoggingView(body),
|
||||
b: new TransactionBodyLoggingView(otherBody),
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public getBody(): TransactionBody {
|
||||
if (!this.transactionBody) {
|
||||
this.transactionBody = TransactionBody.fromBodyBytes(this.self.bodyBytes)
|
||||
}
|
||||
return this.transactionBody
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,5 @@
|
||||
import { Field, Message } from 'protobufjs'
|
||||
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { SignatureMap } from './SignatureMap'
|
||||
@ -46,14 +43,6 @@ export class GradidoTransaction extends Message<GradidoTransaction> {
|
||||
}
|
||||
|
||||
getTransactionBody(): TransactionBody {
|
||||
try {
|
||||
return TransactionBody.decode(new Uint8Array(this.bodyBytes))
|
||||
} catch (error) {
|
||||
logger.error('error decoding body from gradido transaction: %s', error)
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.PROTO_DECODE_ERROR,
|
||||
'cannot decode body from gradido transaction',
|
||||
)
|
||||
}
|
||||
return TransactionBody.fromBodyBytes(this.bodyBytes)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { Field, Message, OneOf } from 'protobufjs'
|
||||
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { timestampToDate } from '@/utils/typeConverter'
|
||||
|
||||
@ -36,6 +39,18 @@ export class TransactionBody extends Message<TransactionBody> {
|
||||
}
|
||||
}
|
||||
|
||||
public static fromBodyBytes(bodyBytes: Buffer) {
|
||||
try {
|
||||
return TransactionBody.decode(new Uint8Array(bodyBytes))
|
||||
} catch (error) {
|
||||
logger.error('error decoding body from gradido transaction: %s', error)
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.PROTO_DECODE_ERROR,
|
||||
'cannot decode body from gradido transaction',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Field.d(1, 'string')
|
||||
public memo: string
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { TransactionDraft } from '@input/TransactionDraft'
|
||||
import { Resolver, Arg, Mutation } from 'type-graphql'
|
||||
|
||||
import { TransactionDraft } from '@input/TransactionDraft'
|
||||
|
||||
import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const'
|
||||
import { TransactionRepository } from '@/data/Transaction.repository'
|
||||
import { CreateTransactionRecipeContext } from '@/interactions/backendToDb/transaction/CreateTransationRecipe.context'
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { logger } from '@/logging/logger'
|
||||
import { TransactionLoggingView } from '@/logging/TransactionLogging.view'
|
||||
|
||||
/**
|
||||
* @DCI-Context
|
||||
* Context for sending transaction recipe to iota
|
||||
* send every transaction only once to iota!
|
||||
*/
|
||||
export class TransmitToIotaContext {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
public constructor(private transaction: Transaction) {
|
||||
|
||||
}
|
||||
|
||||
public async run(): Promise<void> {
|
||||
logger.info('transmit to iota', new TransactionLoggingView(this.transaction))
|
||||
const recipeController = new TransactionRecipe(recipe)
|
||||
const { transaction, body } = recipeController.getGradidoTransaction()
|
||||
const messageBuffer = GradidoTransaction.encode(transaction).finish()
|
||||
|
||||
if (body.type === CrossGroupType.LOCAL) {
|
||||
const resultMessage = await iotaSendMessage(
|
||||
messageBuffer,
|
||||
Buffer.from(recipe.community.iotaTopic, 'hex'),
|
||||
)
|
||||
recipe.iotaMessageId = Buffer.from(resultMessage.messageId, 'hex')
|
||||
logger.info('transmitted Gradido Transaction to Iota', {
|
||||
id: recipe.id,
|
||||
messageId: resultMessage.messageId,
|
||||
})
|
||||
await getDataSource().manager.save(recipe)
|
||||
} else {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.NOT_IMPLEMENTED_YET,
|
||||
'other as crossGroupType Local not implemented yet',
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { sendMessage as iotaSendMessage } from '@/client/IotaClient'
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { GradidoTransaction } from '@/data/proto/3_3/GradidoTransaction'
|
||||
import { SignaturePair } from '@/data/proto/3_3/SignaturePair'
|
||||
import { TransactionBody } from '@/data/proto/3_3/TransactionBody'
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { GradidoTransactionLoggingView } from '@/logging/GradidoTransactionLogging.view'
|
||||
import { logger } from '@/logging/logger'
|
||||
|
||||
export abstract class AbstractTransactionRecipeRole {
|
||||
protected transactionBody: TransactionBody | undefined
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
public constructor(protected self: Transaction) {}
|
||||
|
||||
public abstract transmitToIota(): Promise<Transaction>
|
||||
|
||||
protected getGradidoTransaction(): GradidoTransaction {
|
||||
this.transactionBody = TransactionBody.fromBodyBytes(this.self.bodyBytes)
|
||||
const transaction = new GradidoTransaction(this.transactionBody)
|
||||
if (!this.self.signature) {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing signature in transaction recipe',
|
||||
)
|
||||
}
|
||||
const signaturePair = new SignaturePair()
|
||||
if (this.self.signature.length !== 64) {
|
||||
throw new TransactionError(TransactionErrorType.INVALID_SIGNATURE, "signature isn't 64 bytes")
|
||||
}
|
||||
signaturePair.signature = this.self.signature
|
||||
if (this.transactionBody.communityRoot) {
|
||||
const publicKey = this.self.community.rootPubkey
|
||||
if (!publicKey) {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing community public key for community root transaction',
|
||||
)
|
||||
}
|
||||
signaturePair.pubKey = publicKey
|
||||
} else if (this.self.signingAccount) {
|
||||
const publicKey = this.self.signingAccount.derive2Pubkey
|
||||
if (!publicKey) {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.MISSING_PARAMETER,
|
||||
'missing signing account public key for transaction',
|
||||
)
|
||||
}
|
||||
signaturePair.pubKey = publicKey
|
||||
} else {
|
||||
throw new TransactionError(
|
||||
TransactionErrorType.NOT_FOUND,
|
||||
"signingAccount not exist and it isn't a community root transaction",
|
||||
)
|
||||
}
|
||||
if (signaturePair.validate()) {
|
||||
transaction.sigMap.sigPair.push(signaturePair)
|
||||
}
|
||||
if (!KeyPair.verify(transaction.bodyBytes, signaturePair)) {
|
||||
logger.debug('invalid signature', new GradidoTransactionLoggingView(transaction))
|
||||
throw new TransactionError(TransactionErrorType.INVALID_SIGNATURE, 'signature is invalid')
|
||||
}
|
||||
return transaction
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param gradidoTransaction
|
||||
* @param topic
|
||||
* @return iota message id
|
||||
*/
|
||||
protected async sendViaIota(
|
||||
gradidoTransaction: GradidoTransaction,
|
||||
topic: string,
|
||||
): Promise<Buffer> {
|
||||
// protobuf serializing function
|
||||
const messageBuffer = GradidoTransaction.encode(gradidoTransaction).finish()
|
||||
const resultMessage = await iotaSendMessage(
|
||||
messageBuffer,
|
||||
Uint8Array.from(Buffer.from(topic, 'hex')),
|
||||
)
|
||||
logger.info('transmitted Gradido Transaction to Iota', {
|
||||
id: this.self.id,
|
||||
messageId: resultMessage.messageId,
|
||||
})
|
||||
return Buffer.from(resultMessage.messageId, 'hex')
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { TransactionLogic } from '@/data/Transaction.logic'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { TransactionLoggingView } from '@/logging/TransactionLogging.view'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role'
|
||||
|
||||
/**
|
||||
* Inbound Transaction on recipient community, mark the gradidos as received from another community
|
||||
* need to set gradido id from OUTBOUND transaction!
|
||||
*/
|
||||
export class InboundTransactionRecipeRole extends AbstractTransactionRecipeRole {
|
||||
public async transmitToIota(): Promise<Transaction> {
|
||||
logger.debug('transmit INBOUND transaction to iota', new TransactionLoggingView(this.self))
|
||||
const gradidoTransaction = this.getGradidoTransaction()
|
||||
const pairingTransaction = await new TransactionLogic(this.self).findPairTransaction()
|
||||
if (!pairingTransaction.iotaMessageId || pairingTransaction.iotaMessageId.length !== 32) {
|
||||
throw new LogError(
|
||||
'missing iota message id in pairing transaction, was it already send?',
|
||||
new TransactionLoggingView(pairingTransaction),
|
||||
)
|
||||
}
|
||||
gradidoTransaction.parentMessageId = pairingTransaction.iotaMessageId
|
||||
this.self.paringTransactionId = pairingTransaction.id
|
||||
this.self.paringTransaction = pairingTransaction
|
||||
pairingTransaction.paringTransactionId = this.self.id
|
||||
|
||||
if (!this.self.otherCommunity) {
|
||||
throw new LogError('missing other community')
|
||||
}
|
||||
|
||||
this.self.iotaMessageId = await this.sendViaIota(
|
||||
gradidoTransaction,
|
||||
this.self.otherCommunity.iotaTopic,
|
||||
)
|
||||
return this.self
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { TransactionLoggingView } from '@/logging/TransactionLogging.view'
|
||||
|
||||
import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role'
|
||||
|
||||
export class LocalTransactionRecipeRole extends AbstractTransactionRecipeRole {
|
||||
public async transmitToIota(): Promise<Transaction> {
|
||||
let transactionCrossGroupTypeName = 'LOCAL'
|
||||
if (this.transactionBody) {
|
||||
transactionCrossGroupTypeName = CrossGroupType[this.transactionBody.type]
|
||||
}
|
||||
logger.debug(
|
||||
`transmit ${transactionCrossGroupTypeName} transaction to iota`,
|
||||
new TransactionLoggingView(this.self),
|
||||
)
|
||||
this.self.iotaMessageId = await this.sendViaIota(
|
||||
this.getGradidoTransaction(),
|
||||
this.self.community.iotaTopic,
|
||||
)
|
||||
return this.self
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { LocalTransactionRecipeRole } from './LocalTransactionRecipe.role'
|
||||
|
||||
/**
|
||||
* Outbound Transaction on sender community, mark the gradidos as sended out of community
|
||||
*/
|
||||
export class OutboundTransactionRecipeRole extends LocalTransactionRecipeRole {}
|
||||
@ -0,0 +1,42 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType'
|
||||
import { TransactionBody } from '@/data/proto/3_3/TransactionBody'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role'
|
||||
import { InboundTransactionRecipeRole } from './InboundTransactionRecipe.role'
|
||||
import { LocalTransactionRecipeRole } from './LocalTransactionRecipe.role'
|
||||
import { OutboundTransactionRecipeRole } from './OutboundTransactionRecipeRole'
|
||||
|
||||
/**
|
||||
* @DCI-Context
|
||||
* Context for sending transaction recipe to iota
|
||||
* send every transaction only once to iota!
|
||||
*/
|
||||
export class TransmitToIotaContext {
|
||||
private transactionRecipeRole: AbstractTransactionRecipeRole
|
||||
|
||||
public constructor(transaction: Transaction) {
|
||||
const transactionBody = TransactionBody.fromBodyBytes(transaction.bodyBytes)
|
||||
switch (transactionBody.type) {
|
||||
case CrossGroupType.LOCAL:
|
||||
this.transactionRecipeRole = new LocalTransactionRecipeRole(transaction)
|
||||
break
|
||||
case CrossGroupType.INBOUND:
|
||||
this.transactionRecipeRole = new InboundTransactionRecipeRole(transaction)
|
||||
break
|
||||
case CrossGroupType.OUTBOUND:
|
||||
this.transactionRecipeRole = new OutboundTransactionRecipeRole(transaction)
|
||||
break
|
||||
default:
|
||||
throw new LogError('unknown cross group type', transactionBody.type)
|
||||
}
|
||||
}
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const transaction = await this.transactionRecipeRole.transmitToIota()
|
||||
// store changes in db
|
||||
await transaction.save()
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/data/const'
|
||||
import { TransactionRepository } from '@/data/Transaction.repository'
|
||||
import { TransmitToIotaContext } from '@/interactions/backendToDb/transmitToIota/TransmitToIota.context'
|
||||
import { TransmitToIotaContext } from '@/interactions/transmitToIota/TransmitToIota.context'
|
||||
import { InterruptiveSleepManager } from '@/manager/InterruptiveSleepManager'
|
||||
|
||||
import { logger } from '../logging/logger'
|
||||
@ -36,7 +36,6 @@ export const transmitToIota = async (): Promise<void> => {
|
||||
|
||||
await InterruptiveSleepManager.getInstance().sleep(
|
||||
TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY,
|
||||
// 1000,
|
||||
1000,
|
||||
)
|
||||
} catch (error) {
|
||||
@ -44,7 +43,7 @@ export const transmitToIota = async (): Promise<void> => {
|
||||
await sleep(10000)
|
||||
}
|
||||
}
|
||||
logger.info(
|
||||
logger.error(
|
||||
'end iota message transmitter, no further transaction will be transmitted. !!! Please restart Server !!!',
|
||||
)
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ export class Transaction extends BaseEntity {
|
||||
@Column({ name: 'iota_message_id', type: 'binary', length: 32, nullable: true })
|
||||
iotaMessageId?: Buffer
|
||||
|
||||
@OneToOne(() => Transaction)
|
||||
@OneToOne(() => Transaction, { cascade: ['update'] })
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
paringTransaction?: Transaction
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user