Skip to content

Commit fe4cff0

Browse files
rg911decentraliserfboucquez
authored
Pagination for Block, Mosaic and Transaction endpoints (#600)
* Catapult-rest pagination implemenation (#553) * updated openAPI code * Applied transaction pagination changes * Fixed unit tests * Added tests * lint fix * Return distinct cosignature count in aggregateTransactionService (#552) * Fixed #551 * improved coverage * added test in account service * updated openAPI code * Applied transaction pagination changes * Fixed unit tests * Added tests * lint fix * fix typo (#555) Co-authored-by: Steven Liu <xian.f.liu@gmail.com> * updated openAPI code * Applied transaction pagination changes * Fixed unit tests * Added tests * lint fix * updated openAPI code * removed console log * Refactored to use interface * removed old transaction filter * improved coverage Co-authored-by: Decentraliser <me@decentraliser.dev> * Fixed #580 - Added block and mosaic pagination * temp push * Added PaginationStreamer unit tests for transaction, block and mosaic Upgraded MosaicRepository and BlockRepository to be Searcher * Added integration tests * Removed debug code * PR feedbacks * Removed getter Co-authored-by: Decentraliser <me@decentraliser.dev> Co-authored-by: fernando <fboucquez@gmail.com>
1 parent 060749f commit fe4cff0

File tree

60 files changed

+8156
-7709
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+8156
-7709
lines changed

e2e/infrastructure/AccountHttp.spec.ts

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,10 @@
1616

1717
import { expect } from 'chai';
1818
import { AccountRepository } from '../../src/infrastructure/AccountRepository';
19-
import { TransactionFilter } from '../../src/infrastructure/infrastructure';
2019
import { MultisigRepository } from '../../src/infrastructure/MultisigRepository';
2120
import { NamespaceRepository } from '../../src/infrastructure/NamespaceRepository';
22-
import { QueryParams } from '../../src/infrastructure/QueryParams';
2321
import { Account } from '../../src/model/account/Account';
2422
import { Address } from '../../src/model/account/Address';
25-
import { PublicAccount } from '../../src/model/account/PublicAccount';
2623
import { PlainMessage } from '../../src/model/message/PlainMessage';
2724
import { AliasAction } from '../../src/model/namespace/AliasAction';
2825
import { NamespaceId } from '../../src/model/namespace/NamespaceId';
@@ -32,7 +29,6 @@ import { AggregateTransaction } from '../../src/model/transaction/AggregateTrans
3229
import { Deadline } from '../../src/model/transaction/Deadline';
3330
import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction';
3431
import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction';
35-
import { TransactionType } from '../../src/model/transaction/TransactionType';
3632
import { TransferTransaction } from '../../src/model/transaction/TransferTransaction';
3733
import { UInt64 } from '../../src/model/UInt64';
3834
import { IntegrationTestHelper } from './IntegrationTestHelper';
@@ -47,7 +43,6 @@ describe('AccountHttp', () => {
4743
let cosignAccount3: Account;
4844
let accountAddress: Address;
4945
let accountPublicKey: string;
50-
let publicAccount: PublicAccount;
5146
let accountRepository: AccountRepository;
5247
let multisigRepository: MultisigRepository;
5348
let namespaceRepository: NamespaceRepository;
@@ -65,7 +60,6 @@ describe('AccountHttp', () => {
6560
cosignAccount3 = helper.cosignAccount3;
6661
accountAddress = helper.account.address;
6762
accountPublicKey = helper.account.publicKey;
68-
publicAccount = helper.account.publicAccount;
6963
generationHash = helper.generationHash;
7064
networkType = helper.networkType;
7165
accountRepository = helper.repositoryFactory.createAccountRepository();
@@ -198,19 +192,6 @@ describe('AccountHttp', () => {
198192
});
199193
});
200194

201-
describe('outgoingTransactions', () => {
202-
it('should call outgoingTransactions successfully', async () => {
203-
const transactions = await accountRepository.getAccountOutgoingTransactions(publicAccount.address).toPromise();
204-
expect(transactions.length).to.be.greaterThan(0);
205-
});
206-
});
207-
208-
describe('aggregateBondedTransactions', () => {
209-
it('should call aggregateBondedTransactions successfully', async () => {
210-
await accountRepository.getAccountPartialTransactions(publicAccount.address).toPromise();
211-
});
212-
});
213-
214195
describe('transactions', () => {
215196
it('should not return accounts when account does not exist', () => {
216197
return accountRepository
@@ -230,38 +211,6 @@ describe('AccountHttp', () => {
230211
});
231212
});
232213

233-
describe('transactions', () => {
234-
it('should call transactions successfully by type', async () => {
235-
const transactions = await accountRepository
236-
.getAccountTransactions(
237-
publicAccount.address,
238-
new QueryParams(),
239-
new TransactionFilter({
240-
types: [TransactionType.TRANSFER, TransactionType.AGGREGATE_COMPLETE],
241-
}),
242-
)
243-
.toPromise();
244-
expect(transactions.length).to.be.greaterThan(0);
245-
transactions.forEach((t) => {
246-
expect(t.type === TransactionType.TRANSFER || t.type === TransactionType.AGGREGATE_COMPLETE).to.be.eq(true);
247-
});
248-
});
249-
});
250-
251-
describe('transactions', () => {
252-
it('should call transactions successfully', async () => {
253-
const transactions = await accountRepository.getAccountTransactions(publicAccount.address).toPromise();
254-
expect(transactions.length).to.be.greaterThan(0);
255-
});
256-
});
257-
258-
describe('unconfirmedTransactions', () => {
259-
it('should call unconfirmedTransactions successfully', async () => {
260-
const transactions = await accountRepository.getAccountUnconfirmedTransactions(publicAccount.address).toPromise();
261-
expect(transactions.length).to.be.equal(0);
262-
});
263-
});
264-
265214
describe('getAddressNames', () => {
266215
it('should call getAddressNames successfully', async () => {
267216
const addressNames = await namespaceRepository.getAccountsNames([accountAddress]).toPromise();

e2e/infrastructure/BlockHttp.spec.ts

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,19 @@
1515
*/
1616

1717
import { expect } from 'chai';
18-
import { mergeMap } from 'rxjs/operators';
18+
import { mergeMap, toArray } from 'rxjs/operators';
1919
import { BlockRepository } from '../../src/infrastructure/BlockRepository';
20-
import { QueryParams } from '../../src/infrastructure/QueryParams';
2120
import { ReceiptRepository } from '../../src/infrastructure/ReceiptRepository';
2221
import { Account } from '../../src/model/account/Account';
2322
import { PlainMessage } from '../../src/model/message/PlainMessage';
2423
import { NetworkType } from '../../src/model/network/NetworkType';
2524
import { Deadline } from '../../src/model/transaction/Deadline';
26-
import { TransactionInfo } from '../../src/model/transaction/TransactionInfo';
2725
import { TransferTransaction } from '../../src/model/transaction/TransferTransaction';
2826
import { UInt64 } from '../../src/model/UInt64';
2927
import { IntegrationTestHelper } from './IntegrationTestHelper';
28+
import { BlockPaginationStreamer } from '../../src/infrastructure/paginationStreamer/BlockPaginationStreamer';
29+
import { deepEqual } from 'assert';
30+
import { take } from 'rxjs/operators';
3031

3132
describe('BlockHttp', () => {
3233
const helper = new IntegrationTestHelper();
@@ -37,6 +38,7 @@ describe('BlockHttp', () => {
3738
let chainHeight;
3839
let generationHash: string;
3940
let networkType: NetworkType;
41+
let transactionHash;
4042

4143
before(() => {
4244
return helper.start().then(() => {
@@ -76,6 +78,7 @@ describe('BlockHttp', () => {
7678
const signedTransaction = transferTransaction.signWith(account, generationHash);
7779
return helper.announce(signedTransaction).then((transaction) => {
7880
chainHeight = transaction.transactionInfo!.height.toString();
81+
transactionHash = transaction.transactionInfo?.hash?.toString();
7982
return chainHeight;
8083
});
8184
});
@@ -93,32 +96,23 @@ describe('BlockHttp', () => {
9396
});
9497
});
9598

96-
describe('getBlockTransactions', () => {
97-
let nextId: string;
98-
let firstId: string;
99-
100-
it('should return block transactions data given height', async () => {
101-
const transactions = await blockRepository.getBlockTransactions(UInt64.fromUint(1)).toPromise();
102-
nextId = transactions[0].transactionInfo!.id;
103-
firstId = transactions[1].transactionInfo!.id;
104-
expect(transactions.length).to.be.greaterThan(0);
105-
});
106-
107-
it('should return block transactions data given height with paginated transactionId', async () => {
108-
const transactions = await blockRepository
109-
.getBlockTransactions(UInt64.fromUint(1), new QueryParams({ pageSize: 10, id: nextId }))
110-
.toPromise();
111-
expect(transactions[0].transactionInfo!.id).to.be.equal(firstId);
112-
expect(transactions.length).to.be.greaterThan(0);
99+
describe('searchBlock', () => {
100+
it('should return block info given height and limit', async () => {
101+
const blocksInfo = await blockRepository.search({}).toPromise();
102+
expect(blocksInfo.data.length).to.be.greaterThan(0);
113103
});
114104
});
115105

116-
describe('getBlocksByHeightWithLimit', () => {
106+
describe('searchBlock with streamer', () => {
117107
it('should return block info given height and limit', async () => {
118-
const blocksInfo = await blockRepository.getBlocksByHeightWithLimit(chainHeight, 50).toPromise();
119-
expect(blocksInfo.length).to.be.greaterThan(0);
108+
const streamer = new BlockPaginationStreamer(blockRepository);
109+
const blockInfoStreamer = await streamer.search({ pageSize: 20 }).pipe(take(20), toArray()).toPromise();
110+
const blocksInfo = await blockRepository.search({ pageSize: 20 }).toPromise();
111+
expect(blockInfoStreamer.length).to.be.greaterThan(0);
112+
deepEqual(blockInfoStreamer, blocksInfo.data);
120113
});
121114
});
115+
122116
describe('getMerkleReceipts', () => {
123117
it('should return Merkle Receipts', async () => {
124118
const merkleReceipts = await receiptRepository
@@ -134,19 +128,7 @@ describe('BlockHttp', () => {
134128
});
135129
describe('getMerkleTransaction', () => {
136130
it('should return Merkle Transaction', async () => {
137-
const merkleTransactionss = await blockRepository
138-
.getBlockTransactions(chainHeight)
139-
.pipe(
140-
mergeMap((_) => {
141-
const hash = (_[0].transactionInfo as TransactionInfo).hash;
142-
if (hash) {
143-
return blockRepository.getMerkleTransaction(chainHeight, hash);
144-
}
145-
// If reaching this line, something is not right
146-
throw new Error('Tansacation hash is undefined');
147-
}),
148-
)
149-
.toPromise();
131+
const merkleTransactionss = await blockRepository.getMerkleTransaction(chainHeight, transactionHash).toPromise();
150132
expect(merkleTransactionss.merklePath).not.to.be.null;
151133
});
152134
});

e2e/infrastructure/Listener.spec.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import { assert, expect } from 'chai';
1717
import { ChronoUnit } from 'js-joda';
1818
import { filter } from 'rxjs/operators';
19-
import { AccountRepository } from '../../src/infrastructure/AccountRepository';
2019
import { TransactionRepository } from '../../src/infrastructure/TransactionRepository';
2120
import { Account } from '../../src/model/account/Account';
2221
import { PlainMessage } from '../../src/model/message/PlainMessage';
@@ -29,6 +28,8 @@ import { Deadline } from '../../src/model/transaction/Deadline';
2928
import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction';
3029
import { TransferTransaction } from '../../src/model/transaction/TransferTransaction';
3130
import { IntegrationTestHelper } from './IntegrationTestHelper';
31+
import { TransactionSearchCriteria } from '../../src/infrastructure/searchCriteria/TransactionSearchCriteria';
32+
import { TransactionGroupSubsetEnum } from 'symbol-openapi-typescript-node-client';
3233

3334
describe('Listener', () => {
3435
const helper = new IntegrationTestHelper();
@@ -38,7 +39,6 @@ describe('Listener', () => {
3839
let cosignAccount1: Account;
3940
let cosignAccount2: Account;
4041
let cosignAccount3: Account;
41-
let accountRepository: AccountRepository;
4242
let generationHash: string;
4343
let networkType: NetworkType;
4444
const NetworkCurrencyLocalId: NamespaceId = helper.networkCurrencyNamespaceId;
@@ -54,7 +54,6 @@ describe('Listener', () => {
5454
cosignAccount3 = helper.cosignAccount3;
5555
generationHash = helper.generationHash;
5656
networkType = helper.networkType;
57-
accountRepository = helper.repositoryFactory.createAccountRepository();
5857
transactionRepository = helper.repositoryFactory.createTransactionRepository();
5958
});
6059
});
@@ -250,7 +249,11 @@ describe('Listener', () => {
250249
done();
251250
});
252251
helper.listener.aggregateBondedAdded(cosignAccount1.address).subscribe(() => {
253-
accountRepository.getAccountPartialTransactions(cosignAccount1.publicAccount.address).subscribe((transactions) => {
252+
const criteria: TransactionSearchCriteria = {
253+
address: cosignAccount1.publicAccount.address,
254+
group: TransactionGroupSubsetEnum.Partial,
255+
};
256+
transactionRepository.search(criteria).subscribe((transactions) => {
254257
const transactionToCosign = transactions[0];
255258
const cosignatureTransaction = CosignatureTransaction.create(transactionToCosign);
256259
const cosignatureSignedTransaction = cosignAccount2.signCosignatureTransaction(cosignatureTransaction);
@@ -281,7 +284,11 @@ describe('Listener', () => {
281284
done();
282285
});
283286
helper.listener.aggregateBondedAdded(cosignAccount1.address).subscribe(() => {
284-
accountRepository.getAccountPartialTransactions(cosignAccount1.publicAccount.address).subscribe((transactions) => {
287+
const criteria: TransactionSearchCriteria = {
288+
address: cosignAccount1.publicAccount.address,
289+
group: TransactionGroupSubsetEnum.Partial,
290+
};
291+
transactionRepository.search(criteria).subscribe((transactions) => {
285292
const transactionToCosign = transactions[0];
286293
const cosignatureTransaction = CosignatureTransaction.create(transactionToCosign);
287294
const cosignatureSignedTransaction = cosignAccount2.signCosignatureTransaction(cosignatureTransaction);

e2e/infrastructure/MosaicHttp.spec.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicD
2929
import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction';
3030
import { UInt64 } from '../../src/model/UInt64';
3131
import { IntegrationTestHelper } from './IntegrationTestHelper';
32+
import { MosaicPaginationStreamer } from '../../src/infrastructure/paginationStreamer/MosaicPaginationStreamer';
33+
import { toArray, take } from 'rxjs/operators';
34+
import { deepEqual } from 'assert';
3235

3336
describe('MosaicHttp', () => {
3437
let mosaicId: MosaicId;
@@ -158,19 +161,25 @@ describe('MosaicHttp', () => {
158161
});
159162
});
160163

161-
describe('getMosaicsFromAccount', () => {
162-
it('should call getMosaicsFromAccount successfully', async () => {
163-
const mosaics = await mosaicRepository.getMosaicsFromAccount(account.address).toPromise();
164-
expect(mosaics.length).to.be.greaterThan(0);
165-
expect(mosaics.find((m) => m.id.toHex() === mosaicId.toHex()) !== undefined).to.be.true;
164+
describe('searchMosaics', () => {
165+
it('should call searchMosaics successfully', async () => {
166+
const mosaics = await mosaicRepository.search({ ownerAddress: account.address }).toPromise();
167+
expect(mosaics.data.length).to.be.greaterThan(0);
168+
expect(mosaics.data.find((m) => m.id.toHex() === mosaicId.toHex()) !== undefined).to.be.true;
166169
});
167170
});
168171

169-
describe('getMosaicsFromAccounts', () => {
170-
it('should call getMosaicsFromAccounts successfully', async () => {
171-
const mosaics = await mosaicRepository.getMosaicsFromAccounts([account.address]).toPromise();
172-
expect(mosaics.length).to.be.greaterThan(0);
173-
expect(mosaics.find((m) => m.id.toHex() === mosaicId.toHex()) !== undefined).to.be.true;
172+
describe('searchMosaics with streamer', () => {
173+
it('should call searchMosaics successfully', async () => {
174+
const streamer = new MosaicPaginationStreamer(mosaicRepository);
175+
const mosaicsStreamer = await streamer
176+
.search({ ownerAddress: account.address, pageSize: 3 })
177+
.pipe(take(3), toArray())
178+
.toPromise();
179+
const mosaics = await mosaicRepository.search({ ownerAddress: account.address, pageSize: 3 }).toPromise();
180+
expect(mosaicsStreamer.length).to.be.greaterThan(0);
181+
expect(mosaicsStreamer.find((m) => m.id.toHex() === mosaicId.toHex()) !== undefined).to.be.true;
182+
deepEqual(mosaics.data, mosaicsStreamer);
174183
});
175184
});
176185

0 commit comments

Comments
 (0)