Skip to content

Commit

Permalink
feat: save commands even if they're rejected by aggregate (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
JonaszJestem authored Jul 28, 2022
1 parent 395cd6b commit 2511a46
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,7 @@ export class OffChainCertificateService<T = null> {
return;
}
await validateBatchClaimCommands(commands);
await this.validateBatchClaim(commands);
await this.handleBatch(commands);
await this.handleBatch(commands, (commands) => this.validateBatchClaim(commands));
}

public async batchTransfer(commands: ITransferCommand[]): Promise<void> {
Expand All @@ -227,14 +226,18 @@ export class OffChainCertificateService<T = null> {
}

await validateBatchTransferCommands(commands);
await this.validateBatchTransfer(commands);
await this.handleBatch(commands);
await this.handleBatch(commands, (commands) => this.validateBatchTransfer(commands));
}

private async handleBatch(commands: (IClaimCommand | ITransferCommand)[]) {
private async handleBatch<CommandType extends IClaimCommand | ITransferCommand>(
commands: CommandType[],
commandValidator: (commands: CommandType[]) => Promise<void>
) {
const savedCommands = await this.certCommandRepo.saveMany(
commands.map((command) => ({ payload: command }))
);

await commandValidator(commands);
const events = commands.map((command) => createEventFromCommand(command));

const eventsByCertificate = groupByInternalCertificateId(events);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class TransferCommandDto implements ITransferCommand {
@IsNumber()
@Min(0)
certificateId: number;
off;

@IsEthereumAddress()
fromAddress: string;
Expand Down
6 changes: 0 additions & 6 deletions packages/origin-247-certificate/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,3 @@ export interface IBatchClaimCommand {
export interface IBatchTransferCommand {
transfers: ITransferCommand[];
}

export interface IVolumeDistribution {
publicVolume: string;
privateVolume: string;
claimedVolume: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,24 @@ import {
} from '../../src';
import { CertificateEventType } from '../../src/offchain-certificate/events/Certificate.events';
import { CertificateEventRepository } from '../../src/offchain-certificate/repositories/CertificateEvent/CertificateEvent.repository';
import { CERTIFICATE_EVENT_REPOSITORY } from '../../src/offchain-certificate/repositories/repository.keys';
import {
CERTIFICATE_COMMAND_REPOSITORY,
CERTIFICATE_EVENT_REPOSITORY
} from '../../src/offchain-certificate/repositories/repository.keys';
import { CertificateForUnitTestsService } from '../../src/onchain-certificate/onchain-certificateForUnitTests.service';
import { CertificateErrors } from '../../src/offchain-certificate/errors';
import BatchError = CertificateErrors.BatchError;
import { CertificateCommandRepository } from '../../src/offchain-certificate/repositories/CertificateCommand/CertificateCommand.repository';
import { isEqual } from 'lodash';
import { ethers } from 'ethers';

describe('OffchainCertificateService + BlockchainSynchronizeService', () => {
let app: TestingModule;
let offChainCertificateService: OffChainCertificateService;
let synchronizeService: BlockchainSynchronizeService;
let onChainCertificateService: OnChainCertificateService;
let certificateEventRepository: CertificateEventRepository;
let certificateCommandRepository: CertificateCommandRepository;

describe('Working OnChain module', () => {
beforeEach(async () => {
Expand All @@ -32,6 +41,7 @@ describe('OffchainCertificateService + BlockchainSynchronizeService', () => {
synchronizeService = await app.resolve(BlockchainSynchronizeService);
onChainCertificateService = await app.resolve(ONCHAIN_CERTIFICATE_SERVICE_TOKEN);
certificateEventRepository = await app.resolve(CERTIFICATE_EVENT_REPOSITORY);
certificateCommandRepository = await app.resolve(CERTIFICATE_COMMAND_REPOSITORY);

await app.init();
});
Expand Down Expand Up @@ -65,6 +75,53 @@ describe('OffchainCertificateService + BlockchainSynchronizeService', () => {
expect(events).toHaveLength(6);
});

it('should issue certificate and then save transfer commands even when they are not further accepted by aggregate', async () => {
const [certificateId] = await offChainCertificateService.batchIssue([issueCommand]);
const expectedOriginalError = new Error(
`Transfer for: ${certificateId} failed. Address: ${transferAddress} has not enough balance.`
);
const expectedBatchError = new BatchError(expectedOriginalError);
const invalidTransferCommandPayload = {
certificateId,
...transferCommand,
fromAddress: transferAddress,
toAddress: issueAddress
};

await expect(() =>
offChainCertificateService.batchTransfer([invalidTransferCommandPayload])
).rejects.toEqual(expectedBatchError);

const commands = await certificateCommandRepository.getAll();
const savedTransferCommand = commands.find((c) =>
isEqual(invalidTransferCommandPayload, c.payload)
);
expect(savedTransferCommand).toBeDefined();
});

it('should issue certificate and then save claim commands even when they are not further accepted by aggregate', async () => {
const [certificateId] = await offChainCertificateService.batchIssue([issueCommand]);
const expectedOriginalError = new Error(
`Claim for internalCertificateId: ${certificateId} failed. Transfer is for zero address(0x0).`
);
const expectedBatchError = new BatchError(expectedOriginalError);
const invalidClaimCommandPayload = {
certificateId,
...claimCommand,
forAddress: ethers.constants.AddressZero
};

await expect(() =>
offChainCertificateService.batchClaim([invalidClaimCommandPayload])
).rejects.toEqual(expectedBatchError);

const commands = await certificateCommandRepository.getAll();
const savedClaimCommand = commands.find((c) =>
isEqual(invalidClaimCommandPayload, c.payload)
);
expect(savedClaimCommand).toBeDefined();
});

it('should batch issue, batch transfer, and batch claim certificates, and then synchronize it', async () => {
const [id1, id2] = await offChainCertificateService.batchIssue([
issueCommand,
Expand Down

0 comments on commit 2511a46

Please sign in to comment.