mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 01:46:07 +00:00
add test for transmitToIota context, move some test init code into seeding
This commit is contained in:
parent
d959fdfbd8
commit
8a135bd983
@ -6,7 +6,7 @@ module.exports = {
|
||||
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
lines: 66,
|
||||
lines: 71,
|
||||
},
|
||||
},
|
||||
setupFiles: ['<rootDir>/test/testSetup.ts'],
|
||||
|
||||
35
dlt-connector/src/data/Account.logic.ts
Normal file
35
dlt-connector/src/data/Account.logic.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Account } from '@entity/Account'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { KeyPair } from './KeyPair'
|
||||
import { UserLogic } from './User.logic'
|
||||
|
||||
export class AccountLogic {
|
||||
// eslint-disable-next-line no-useless-constructor
|
||||
public constructor(private self: Account) {}
|
||||
|
||||
/**
|
||||
* calculate account key pair starting from community key pair => derive user key pair => derive account key pair
|
||||
* @param communityKeyPair
|
||||
*/
|
||||
public calculateKeyPair(communityKeyPair: KeyPair): KeyPair {
|
||||
if (!this.self.user) {
|
||||
throw new LogError('missing user')
|
||||
}
|
||||
const userLogic = new UserLogic(this.self.user)
|
||||
const accountKeyPair = userLogic
|
||||
.calculateKeyPair(communityKeyPair)
|
||||
.derive([this.self.derivationIndex])
|
||||
|
||||
if (
|
||||
this.self.derive2Pubkey &&
|
||||
this.self.derive2Pubkey.compare(accountKeyPair.publicKey) !== 0
|
||||
) {
|
||||
throw new LogError(
|
||||
'The freshly derived public key does not correspond to the stored public key',
|
||||
)
|
||||
}
|
||||
return accountKeyPair
|
||||
}
|
||||
}
|
||||
@ -77,14 +77,14 @@ export class TransactionLogic {
|
||||
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
|
||||
this.self.createdAt.getTime() !== otherTransaction.createdAt.getTime()
|
||||
) {
|
||||
logger.debug('transaction a and b are not pairs', {
|
||||
a: new TransactionLoggingView(this.self),
|
||||
@ -135,6 +135,25 @@ export class TransactionLogic {
|
||||
logger.info(`TransactionType ${type} couldn't be a CrossGroup Transaction`)
|
||||
return false
|
||||
}
|
||||
if (
|
||||
[
|
||||
TransactionType.GRADIDO_CREATION,
|
||||
TransactionType.GRADIDO_TRANSFER,
|
||||
TransactionType.GRADIDO_DEFERRED_TRANSFER,
|
||||
].includes(type)
|
||||
) {
|
||||
if (!this.self.amount || !otherTransaction.amount) {
|
||||
logger.info('missing amount')
|
||||
return false
|
||||
}
|
||||
if (this.self.amount.cmp(otherTransaction.amount.toString())) {
|
||||
logger.info('amounts mismatch', {
|
||||
a: this.self.amount.toString(),
|
||||
b: otherTransaction.amount.toString(),
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (body.otherGroup === otherBody.otherGroup) {
|
||||
logger.info('otherGroups are the same', {
|
||||
a: new TransactionBodyLoggingView(body),
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
|
||||
import { isValidDateString } from '@validator/DateString'
|
||||
import { IsBoolean, IsUUID } from 'class-validator'
|
||||
import { Field, InputType } from 'type-graphql'
|
||||
|
||||
import { isValidDateString } from '@validator/DateString'
|
||||
|
||||
@InputType()
|
||||
export class CommunityDraft {
|
||||
@Field(() => String)
|
||||
|
||||
@ -1,33 +1,25 @@
|
||||
import 'reflect-metadata'
|
||||
import { Account } from '@entity/Account'
|
||||
import { Community } from '@entity/Community'
|
||||
import { User } from '@entity/User'
|
||||
import { TestDB } from '@test/TestDB'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { v4 } from 'uuid'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { AccountFactory } from '@/data/Account.factory'
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { Mnemonic } from '@/data/Mnemonic'
|
||||
import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType'
|
||||
import { TransactionType } from '@/data/proto/3_3/enum/TransactionType'
|
||||
import { TransactionBody } from '@/data/proto/3_3/TransactionBody'
|
||||
import { UserFactory } from '@/data/User.factory'
|
||||
import { UserLogic } from '@/data/User.logic'
|
||||
import { AccountType } from '@/graphql/enum/AccountType'
|
||||
import { InputTransactionType } from '@/graphql/enum/InputTransactionType'
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { UserAccountDraft } from '@/graphql/input/UserAccountDraft'
|
||||
import { UserIdentifier } from '@/graphql/input/UserIdentifier'
|
||||
import { TransactionBodyLoggingView } from '@/logging/TransactionBodyLogging.view'
|
||||
import { TransactionLoggingView } from '@/logging/TransactionLogging.view'
|
||||
|
||||
import { AddCommunityContext } from '../community/AddCommunity.context'
|
||||
import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter'
|
||||
|
||||
import { CreateTransactionRecipeContext } from './CreateTransationRecipe.context'
|
||||
import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter'
|
||||
|
||||
// eslint-disable-next-line import/order
|
||||
import { communitySeed } from '@test/seeding/Community.seed'
|
||||
// eslint-disable-next-line import/order
|
||||
import { createUserSet, UserSet } from '@test/seeding/UserSet.seed'
|
||||
|
||||
jest.mock('@typeorm/DataSource', () => ({
|
||||
getDataSource: jest.fn(() => TestDB.instance.dbConnect),
|
||||
@ -37,58 +29,11 @@ CONFIG.IOTA_HOME_COMMUNITY_SEED = '034b0229a2ba4e98e1cc5e8767dca886279b484303ffa
|
||||
const homeCommunityUuid = v4()
|
||||
const foreignCommunityUuid = v4()
|
||||
|
||||
type UserSet = {
|
||||
identifier: UserIdentifier
|
||||
user: User
|
||||
account: Account
|
||||
}
|
||||
|
||||
function createUserIdentifier(userUuid: string, communityUuid: string): UserIdentifier {
|
||||
const user = new UserIdentifier()
|
||||
user.uuid = userUuid
|
||||
user.communityUuid = communityUuid
|
||||
return user
|
||||
}
|
||||
|
||||
const keyPair = new KeyPair(new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED))
|
||||
const foreignKeyPair = new KeyPair(
|
||||
new Mnemonic('5d4e163c078cc6b51f5c88f8422bc8f21d1d59a284515ab1ea79e1c176ebec50'),
|
||||
)
|
||||
|
||||
function createUserAndAccount(userIdentifier: UserIdentifier): Account {
|
||||
const accountDraft = new UserAccountDraft()
|
||||
accountDraft.user = userIdentifier
|
||||
accountDraft.createdAt = new Date().toISOString()
|
||||
accountDraft.accountType = AccountType.COMMUNITY_HUMAN
|
||||
let _keyPair: KeyPair
|
||||
if (userIdentifier.communityUuid === homeCommunityUuid) {
|
||||
_keyPair = keyPair
|
||||
} else {
|
||||
_keyPair = foreignKeyPair
|
||||
}
|
||||
const user = UserFactory.create(accountDraft, _keyPair)
|
||||
const userLogic = new UserLogic(user)
|
||||
const account = AccountFactory.createAccountFromUserAccountDraft(
|
||||
accountDraft,
|
||||
userLogic.calculateKeyPair(_keyPair),
|
||||
)
|
||||
account.user = user
|
||||
return account
|
||||
}
|
||||
|
||||
function createUserSet(userUuid: string, communityUuid: string): UserSet {
|
||||
const identifier = createUserIdentifier(userUuid, communityUuid)
|
||||
const account = createUserAndAccount(identifier)
|
||||
if (!account.user) {
|
||||
throw Error('user missing')
|
||||
}
|
||||
return {
|
||||
identifier,
|
||||
account,
|
||||
user: account.user,
|
||||
}
|
||||
}
|
||||
|
||||
let moderator: UserSet
|
||||
let firstUser: UserSet
|
||||
let secondUser: UserSet
|
||||
@ -100,29 +45,13 @@ const foreignTopic = iotaTopicFromCommunityUUID(foreignCommunityUuid)
|
||||
describe('interactions/backendToDb/transaction/Create Transaction Recipe Context Test', () => {
|
||||
beforeAll(async () => {
|
||||
await TestDB.instance.setupTestDB()
|
||||
const homeCommunityDraft = new CommunityDraft()
|
||||
homeCommunityDraft.uuid = homeCommunityUuid
|
||||
homeCommunityDraft.foreign = false
|
||||
homeCommunityDraft.createdAt = '2024-01-25T13:09:55.339Z'
|
||||
let addCommunityContext = new AddCommunityContext(homeCommunityDraft)
|
||||
await addCommunityContext.run()
|
||||
await communitySeed(homeCommunityUuid, false)
|
||||
await communitySeed(foreignCommunityUuid, true, foreignKeyPair)
|
||||
|
||||
const foreignCommunityDraft = new CommunityDraft()
|
||||
foreignCommunityDraft.uuid = foreignCommunityUuid
|
||||
foreignCommunityDraft.foreign = true
|
||||
foreignCommunityDraft.createdAt = '2024-01-25T13:34:28.020Z'
|
||||
addCommunityContext = new AddCommunityContext(foreignCommunityDraft)
|
||||
await addCommunityContext.run()
|
||||
|
||||
const foreignCommunity = await Community.findOneOrFail({ where: { foreign: true } })
|
||||
// that isn't entirely correct, normally only the public key from foreign community is know, and will be come form blockchain
|
||||
foreignKeyPair.fillInCommunityKeys(foreignCommunity)
|
||||
foreignCommunity.save()
|
||||
|
||||
moderator = createUserSet('ff8bbdcb-fc8b-4b5d-98e3-8bd7e1afcdbb', homeCommunityUuid)
|
||||
firstUser = createUserSet('8e47e32e-0182-4099-b94d-0cac567d1392', homeCommunityUuid)
|
||||
secondUser = createUserSet('9c8611dd-ee93-4cdb-a600-396c2ca91cc7', homeCommunityUuid)
|
||||
foreignUser = createUserSet('b0155716-5219-4c50-b3d3-0757721ae0d2', foreignCommunityUuid)
|
||||
moderator = createUserSet(homeCommunityUuid, keyPair)
|
||||
firstUser = createUserSet(homeCommunityUuid, keyPair)
|
||||
secondUser = createUserSet(homeCommunityUuid, keyPair)
|
||||
foreignUser = createUserSet(foreignCommunityUuid, foreignKeyPair)
|
||||
|
||||
await Account.save([
|
||||
moderator.account,
|
||||
@ -197,7 +126,6 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context
|
||||
sendTransactionDraft.linkedUser = secondUser.identifier
|
||||
sendTransactionDraft.user = firstUser.identifier
|
||||
sendTransactionDraft.type = InputTransactionType.SEND
|
||||
sendTransactionDraft.targetDate = new Date().toISOString()
|
||||
const context = new CreateTransactionRecipeContext(sendTransactionDraft)
|
||||
await context.run()
|
||||
const transaction = context.getTransactionRecipe()
|
||||
@ -251,7 +179,6 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context
|
||||
recvTransactionDraft.linkedUser = firstUser.identifier
|
||||
recvTransactionDraft.user = secondUser.identifier
|
||||
recvTransactionDraft.type = InputTransactionType.RECEIVE
|
||||
recvTransactionDraft.targetDate = new Date().toISOString()
|
||||
const context = new CreateTransactionRecipeContext(recvTransactionDraft)
|
||||
await context.run()
|
||||
const transaction = context.getTransactionRecipe()
|
||||
@ -304,7 +231,6 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context
|
||||
crossGroupSendTransactionDraft.linkedUser = foreignUser.identifier
|
||||
crossGroupSendTransactionDraft.user = firstUser.identifier
|
||||
crossGroupSendTransactionDraft.type = InputTransactionType.SEND
|
||||
crossGroupSendTransactionDraft.targetDate = new Date().toISOString()
|
||||
const context = new CreateTransactionRecipeContext(crossGroupSendTransactionDraft)
|
||||
await context.run()
|
||||
const transaction = context.getTransactionRecipe()
|
||||
@ -361,7 +287,6 @@ describe('interactions/backendToDb/transaction/Create Transaction Recipe Context
|
||||
crossGroupRecvTransactionDraft.linkedUser = firstUser.identifier
|
||||
crossGroupRecvTransactionDraft.user = foreignUser.identifier
|
||||
crossGroupRecvTransactionDraft.type = InputTransactionType.RECEIVE
|
||||
crossGroupRecvTransactionDraft.targetDate = new Date().toISOString()
|
||||
const context = new CreateTransactionRecipeContext(crossGroupRecvTransactionDraft)
|
||||
await context.run()
|
||||
const transaction = context.getTransactionRecipe()
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { AccountLogic } from '@/data/Account.logic'
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { TransactionBodyBuilder } from '@/data/proto/TransactionBody.builder'
|
||||
import { TransactionBuilder } from '@/data/Transaction.builder'
|
||||
@ -57,9 +58,11 @@ export class TransactionRecipeRole {
|
||||
await this.transactionBuilder.setOtherCommunityFromRecipientUser(recipientUser)
|
||||
}
|
||||
const transaction = this.transactionBuilder.getTransaction()
|
||||
const communityKeyPair = new KeyPair(this.transactionBuilder.getCommunity())
|
||||
const accountLogic = new AccountLogic(signingAccount)
|
||||
// sign
|
||||
this.transactionBuilder.setSignature(
|
||||
new KeyPair(this.transactionBuilder.getCommunity()).sign(transaction.bodyBytes),
|
||||
accountLogic.calculateKeyPair(communityKeyPair).sign(transaction.bodyBytes),
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
@ -11,14 +11,14 @@ import { GradidoTransactionLoggingView } from '@/logging/GradidoTransactionLoggi
|
||||
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) {}
|
||||
protected transactionBody: TransactionBody
|
||||
public constructor(protected self: Transaction) {
|
||||
this.transactionBody = TransactionBody.fromBodyBytes(this.self.bodyBytes)
|
||||
}
|
||||
|
||||
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(
|
||||
|
||||
@ -0,0 +1,167 @@
|
||||
import 'reflect-metadata'
|
||||
import { Account } from '@entity/Account'
|
||||
import { TestDB } from '@test/TestDB'
|
||||
import { Decimal } from 'decimal.js-light'
|
||||
import { v4 } from 'uuid'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { Mnemonic } from '@/data/Mnemonic'
|
||||
import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType'
|
||||
import { TransactionBody } from '@/data/proto/3_3/TransactionBody'
|
||||
import { InputTransactionType } from '@/graphql/enum/InputTransactionType'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { logger } from '@/logging/logger'
|
||||
|
||||
import { CreateTransactionRecipeContext } from '../backendToDb/transaction/CreateTransationRecipe.context'
|
||||
|
||||
import { TransmitToIotaContext } from './TransmitToIota.context'
|
||||
|
||||
// eslint-disable-next-line import/order
|
||||
import { communitySeed } from '@test/seeding/Community.seed'
|
||||
// eslint-disable-next-line import/order
|
||||
import { createUserSet, UserSet } from '@test/seeding/UserSet.seed'
|
||||
|
||||
jest.mock('@typeorm/DataSource', () => ({
|
||||
getDataSource: jest.fn(() => TestDB.instance.dbConnect),
|
||||
}))
|
||||
|
||||
jest.mock('@/client/IotaClient', () => {
|
||||
return {
|
||||
sendMessage: jest.fn().mockReturnValue({
|
||||
messageId: '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710',
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
CONFIG.IOTA_HOME_COMMUNITY_SEED = '034b0229a2ba4e98e1cc5e8767dca886279b484303ffa73546bd5f5bf0b71285'
|
||||
const homeCommunityUuid = v4()
|
||||
const foreignCommunityUuid = v4()
|
||||
|
||||
const keyPair = new KeyPair(new Mnemonic(CONFIG.IOTA_HOME_COMMUNITY_SEED))
|
||||
const foreignKeyPair = new KeyPair(
|
||||
new Mnemonic('5d4e163c078cc6b51f5c88f8422bc8f21d1d59a284515ab1ea79e1c176ebec50'),
|
||||
)
|
||||
|
||||
let moderator: UserSet
|
||||
let firstUser: UserSet
|
||||
let secondUser: UserSet
|
||||
let foreignUser: UserSet
|
||||
|
||||
const now = new Date()
|
||||
|
||||
describe('interactions/transmitToIota/TransmitToIotaContext', () => {
|
||||
beforeAll(async () => {
|
||||
await TestDB.instance.setupTestDB()
|
||||
await communitySeed(homeCommunityUuid, false)
|
||||
await communitySeed(foreignCommunityUuid, true, foreignKeyPair)
|
||||
|
||||
moderator = createUserSet(homeCommunityUuid, keyPair)
|
||||
firstUser = createUserSet(homeCommunityUuid, keyPair)
|
||||
secondUser = createUserSet(homeCommunityUuid, keyPair)
|
||||
foreignUser = createUserSet(foreignCommunityUuid, foreignKeyPair)
|
||||
|
||||
await Account.save([
|
||||
moderator.account,
|
||||
firstUser.account,
|
||||
secondUser.account,
|
||||
foreignUser.account,
|
||||
])
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await TestDB.instance.teardownTestDB()
|
||||
})
|
||||
|
||||
it('LOCAL transaction', async () => {
|
||||
const creationTransactionDraft = new TransactionDraft()
|
||||
creationTransactionDraft.amount = new Decimal('2000')
|
||||
creationTransactionDraft.backendTransactionId = 1
|
||||
creationTransactionDraft.createdAt = new Date().toISOString()
|
||||
creationTransactionDraft.linkedUser = moderator.identifier
|
||||
creationTransactionDraft.user = firstUser.identifier
|
||||
creationTransactionDraft.type = InputTransactionType.CREATION
|
||||
creationTransactionDraft.targetDate = new Date().toISOString()
|
||||
const transactionRecipeContext = new CreateTransactionRecipeContext(creationTransactionDraft)
|
||||
await transactionRecipeContext.run()
|
||||
const transaction = transactionRecipeContext.getTransactionRecipe()
|
||||
|
||||
const context = new TransmitToIotaContext(transaction)
|
||||
const debugSpy = jest.spyOn(logger, 'debug')
|
||||
await context.run()
|
||||
expect(
|
||||
transaction.iotaMessageId?.compare(
|
||||
Buffer.from('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', 'hex'),
|
||||
),
|
||||
).toBe(0)
|
||||
expect(debugSpy).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
expect.stringContaining('transmit LOCAL transaction to iota'),
|
||||
expect.objectContaining({}),
|
||||
)
|
||||
})
|
||||
|
||||
it('OUTBOUND transaction', async () => {
|
||||
const crossGroupSendTransactionDraft = new TransactionDraft()
|
||||
crossGroupSendTransactionDraft.amount = new Decimal('100')
|
||||
crossGroupSendTransactionDraft.backendTransactionId = 4
|
||||
crossGroupSendTransactionDraft.createdAt = now.toISOString()
|
||||
crossGroupSendTransactionDraft.linkedUser = foreignUser.identifier
|
||||
crossGroupSendTransactionDraft.user = firstUser.identifier
|
||||
crossGroupSendTransactionDraft.type = InputTransactionType.SEND
|
||||
const transactionRecipeContext = new CreateTransactionRecipeContext(
|
||||
crossGroupSendTransactionDraft,
|
||||
)
|
||||
await transactionRecipeContext.run()
|
||||
const transaction = transactionRecipeContext.getTransactionRecipe()
|
||||
await transaction.save()
|
||||
const body = TransactionBody.fromBodyBytes(transaction.bodyBytes)
|
||||
expect(body.type).toBe(CrossGroupType.OUTBOUND)
|
||||
const context = new TransmitToIotaContext(transaction)
|
||||
const debugSpy = jest.spyOn(logger, 'debug')
|
||||
await context.run()
|
||||
expect(
|
||||
transaction.iotaMessageId?.compare(
|
||||
Buffer.from('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', 'hex'),
|
||||
),
|
||||
).toBe(0)
|
||||
expect(debugSpy).toHaveBeenNthCalledWith(
|
||||
5,
|
||||
expect.stringContaining('transmit OUTBOUND transaction to iota'),
|
||||
expect.objectContaining({}),
|
||||
)
|
||||
})
|
||||
|
||||
it('INBOUND transaction', async () => {
|
||||
const crossGroupRecvTransactionDraft = new TransactionDraft()
|
||||
crossGroupRecvTransactionDraft.amount = new Decimal('100')
|
||||
crossGroupRecvTransactionDraft.backendTransactionId = 5
|
||||
crossGroupRecvTransactionDraft.createdAt = now.toISOString()
|
||||
crossGroupRecvTransactionDraft.linkedUser = firstUser.identifier
|
||||
crossGroupRecvTransactionDraft.user = foreignUser.identifier
|
||||
crossGroupRecvTransactionDraft.type = InputTransactionType.RECEIVE
|
||||
const transactionRecipeContext = new CreateTransactionRecipeContext(
|
||||
crossGroupRecvTransactionDraft,
|
||||
)
|
||||
await transactionRecipeContext.run()
|
||||
const transaction = transactionRecipeContext.getTransactionRecipe()
|
||||
await transaction.save()
|
||||
// console.log(new TransactionLoggingView(transaction))
|
||||
const body = TransactionBody.fromBodyBytes(transaction.bodyBytes)
|
||||
expect(body.type).toBe(CrossGroupType.INBOUND)
|
||||
|
||||
const context = new TransmitToIotaContext(transaction)
|
||||
const debugSpy = jest.spyOn(logger, 'debug')
|
||||
await context.run()
|
||||
expect(
|
||||
transaction.iotaMessageId?.compare(
|
||||
Buffer.from('5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710', 'hex'),
|
||||
),
|
||||
).toBe(0)
|
||||
expect(debugSpy).toHaveBeenNthCalledWith(
|
||||
7,
|
||||
expect.stringContaining('transmit INBOUND transaction to iota'),
|
||||
expect.objectContaining({}),
|
||||
)
|
||||
})
|
||||
})
|
||||
@ -2,7 +2,10 @@ import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { CrossGroupType } from '@/data/proto/3_3/enum/CrossGroupType'
|
||||
import { TransactionBody } from '@/data/proto/3_3/TransactionBody'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { TransactionLoggingView } from '@/logging/TransactionLogging.view'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { getDataSource } from '@/typeorm/DataSource'
|
||||
|
||||
import { AbstractTransactionRecipeRole } from './AbstractTransactionRecipe.role'
|
||||
import { InboundTransactionRecipeRole } from './InboundTransactionRecipe.role'
|
||||
@ -36,7 +39,19 @@ export class TransmitToIotaContext {
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const transaction = await this.transactionRecipeRole.transmitToIota()
|
||||
logger.debug('transaction sended via iota', new TransactionLoggingView(transaction))
|
||||
// store changes in db
|
||||
await transaction.save()
|
||||
// prevent endless loop
|
||||
const paringTransaction = transaction.paringTransaction
|
||||
if (paringTransaction) {
|
||||
transaction.paringTransaction = undefined
|
||||
await getDataSource().transaction(async (transactionalEntityManager) => {
|
||||
await transactionalEntityManager.save(transaction)
|
||||
await transactionalEntityManager.save(paringTransaction)
|
||||
})
|
||||
} else {
|
||||
await transaction.save()
|
||||
}
|
||||
logger.info('sended transaction successfully updated in db')
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ export class TransactionLoggingView extends AbstractLoggingView {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public toJSON(showBackendTransactions = true): any {
|
||||
public toJSON(showBackendTransactions = true, deep = 1): any {
|
||||
return {
|
||||
id: this.self.id,
|
||||
nr: this.self.nr,
|
||||
@ -31,16 +31,23 @@ export class TransactionLoggingView extends AbstractLoggingView {
|
||||
community: new CommunityLoggingView(this.self.community).toJSON(),
|
||||
otherCommunity: this.self.otherCommunity
|
||||
? new CommunityLoggingView(this.self.otherCommunity)
|
||||
: undefined,
|
||||
: { id: this.self.otherCommunityId },
|
||||
iotaMessageId: this.self.iotaMessageId
|
||||
? this.self.iotaMessageId.toString(this.bufferStringFormat)
|
||||
: undefined,
|
||||
signingAccount: this.self.signingAccount
|
||||
? new AccountLoggingView(this.self.signingAccount)
|
||||
: undefined,
|
||||
: { id: this.self.signingAccountId },
|
||||
recipientAccount: this.self.recipientAccount
|
||||
? new AccountLoggingView(this.self.recipientAccount)
|
||||
: undefined,
|
||||
: { id: this.self.recipientAccountId },
|
||||
pairingTransaction:
|
||||
this.self.paringTransaction && deep === 1
|
||||
? new TransactionLoggingView(this.self.paringTransaction).toJSON(
|
||||
showBackendTransactions,
|
||||
deep + 1,
|
||||
)
|
||||
: { id: this.self.paringTransactionId },
|
||||
amount: this.decimalToString(this.self.amount),
|
||||
accountBalanceOnCreation: this.decimalToString(this.self.accountBalanceOnCreation),
|
||||
accountBalanceOnConfirmation: this.decimalToString(this.self.accountBalanceOnConfirmation),
|
||||
|
||||
28
dlt-connector/test/seeding/Community.seed.ts
Normal file
28
dlt-connector/test/seeding/Community.seed.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Community } from '@entity/Community'
|
||||
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context'
|
||||
import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter'
|
||||
|
||||
export const communitySeed = async (
|
||||
uuid: string,
|
||||
foreign: boolean,
|
||||
keyPair: KeyPair | undefined = undefined,
|
||||
): Promise<Community> => {
|
||||
const homeCommunityDraft = new CommunityDraft()
|
||||
homeCommunityDraft.uuid = uuid
|
||||
homeCommunityDraft.foreign = foreign
|
||||
homeCommunityDraft.createdAt = new Date().toISOString()
|
||||
const iotaTopic = iotaTopicFromCommunityUUID(uuid)
|
||||
const addCommunityContext = new AddCommunityContext(homeCommunityDraft, iotaTopic)
|
||||
await addCommunityContext.run()
|
||||
|
||||
const community = await Community.findOneOrFail({ where: { iotaTopic } })
|
||||
if (foreign && keyPair) {
|
||||
// that isn't entirely correct, normally only the public key from foreign community is know, and will be come form blockchain
|
||||
keyPair.fillInCommunityKeys(community)
|
||||
await community.save()
|
||||
}
|
||||
return community
|
||||
}
|
||||
55
dlt-connector/test/seeding/UserSet.seed.ts
Normal file
55
dlt-connector/test/seeding/UserSet.seed.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { Account } from '@entity/Account'
|
||||
import { User } from '@entity/User'
|
||||
import { v4 } from 'uuid'
|
||||
|
||||
import { AccountFactory } from '@/data/Account.factory'
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { UserFactory } from '@/data/User.factory'
|
||||
import { UserLogic } from '@/data/User.logic'
|
||||
import { AccountType } from '@/graphql/enum/AccountType'
|
||||
import { UserAccountDraft } from '@/graphql/input/UserAccountDraft'
|
||||
import { UserIdentifier } from '@/graphql/input/UserIdentifier'
|
||||
|
||||
export type UserSet = {
|
||||
identifier: UserIdentifier
|
||||
user: User
|
||||
account: Account
|
||||
}
|
||||
|
||||
export const createUserIdentifier = (userUuid: string, communityUuid: string): UserIdentifier => {
|
||||
const user = new UserIdentifier()
|
||||
user.uuid = userUuid
|
||||
user.communityUuid = communityUuid
|
||||
return user
|
||||
}
|
||||
|
||||
export const createUserAndAccount = (
|
||||
userIdentifier: UserIdentifier,
|
||||
communityKeyPair: KeyPair,
|
||||
): Account => {
|
||||
const accountDraft = new UserAccountDraft()
|
||||
accountDraft.user = userIdentifier
|
||||
accountDraft.createdAt = new Date().toISOString()
|
||||
accountDraft.accountType = AccountType.COMMUNITY_HUMAN
|
||||
const user = UserFactory.create(accountDraft, communityKeyPair)
|
||||
const userLogic = new UserLogic(user)
|
||||
const account = AccountFactory.createAccountFromUserAccountDraft(
|
||||
accountDraft,
|
||||
userLogic.calculateKeyPair(communityKeyPair),
|
||||
)
|
||||
account.user = user
|
||||
return account
|
||||
}
|
||||
|
||||
export const createUserSet = (communityUuid: string, communityKeyPair: KeyPair): UserSet => {
|
||||
const identifier = createUserIdentifier(v4(), communityUuid)
|
||||
const account = createUserAndAccount(identifier, communityKeyPair)
|
||||
if (!account.user) {
|
||||
throw Error('user missing')
|
||||
}
|
||||
return {
|
||||
identifier,
|
||||
account,
|
||||
user: account.user,
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user