Skip to content

Commit

Permalink
feat(ApostilleHttp): Rewrite fetchALlTransactions to use RxJs
Browse files Browse the repository at this point in the history
  • Loading branch information
jontey committed Nov 30, 2018
1 parent c3cb86f commit cfb6a40
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 85 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@
],
"license": "MIT",
"dependencies": {
"@types/crypto-js": "^3.1.43",
"@types/lodash": "^4.14.113",
"commitizen": "3.0.4",
"crypto-js": "^3.1.9-1",
"js-sha3": "0.8.0",
"lodash": "^4.17.10",
Expand All @@ -57,9 +54,12 @@
"rxjs": "^6.2.2"
},
"devDependencies": {
"@types/crypto-js": "^3.1.43",
"@types/lodash": "^4.14.113",
"@types/jest": "^23.3.9",
"@types/sinon": "5.0.7",
"codecov": "^3.0.4",
"commitizen": "3.0.4",
"commitlint": "7.2.1",
"cz-conventional-changelog": "^2.1.0",
"ghooks": "^2.0.4",
Expand Down
132 changes: 63 additions & 69 deletions src/infrastructure/ApostilleHttp.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
import { sortBy } from 'lodash';
import { AccountHttp, Address, AggregateTransaction, Listener, PublicAccount, QueryParams, SignedTransaction, Transaction, TransactionAnnounceResponse, TransactionHttp, TransactionInfo, TransferTransaction } from 'nem2-sdk';
import { filter, mergeMap } from 'rxjs/operators';
import { EMPTY, Observable } from 'rxjs';
import { expand, filter, mergeMap } from 'rxjs/operators';
import { Errors } from '../types/Errors';
import { Initiator } from './Initiator';

export interface IReadyTransaction {
transaction: Transaction;
initiator?: Initiator;
}
export class ApostilleHttp {

private transactionHttp: TransactionHttp;
private accountHttp: AccountHttp;
private listener: Listener;

private unannouncedTransactions: IReadyTransaction[] = [];

public constructor(url: string) {
this.transactionHttp = new TransactionHttp(url);
this.accountHttp = new AccountHttp(url);
this.listener = new Listener(url);
}

public addTransaction(transaction: Transaction, initiator?: Initiator): void {
this.unannouncedTransactions.push({transaction, initiator});
}

public getIncompleteTransactions(): Transaction[] {
return this.unannouncedTransactions
.filter((readyTransaction) => {
return readyTransaction.initiator === undefined;
})
.map((readyTransaction) => {
return readyTransaction.transaction;
});
}

public hasIncompleteTransactions(): boolean {
return this.unannouncedTransactions.some((readyTransaction) => {
return readyTransaction.initiator === undefined;
});
}

/**
* @internal
* Generic announce method
*
* @param {SignedTransaction} signedTransaction
Expand Down Expand Up @@ -41,24 +72,25 @@ export class ApostilleHttp {
cosignatoryAccount: PublicAccount,
signedAggregateBondedTransaction: SignedTransaction,
signedLockFundsTransaction: SignedTransaction,
listener: Listener): Promise<TransactionAnnounceResponse> {
): Promise<TransactionAnnounceResponse> {

return new Promise<TransactionAnnounceResponse>((resolve, reject) => {
listener.open().then(() => {
this.listener.open().then(() => {

// Announce lock funds first
this.transactionHttp
.announce(signedLockFundsTransaction)
.subscribe((x) => console.log(x), (err) => reject(err));

// Watch for lock funds confirmation before announcing aggregate bonded
listener
this.listener
.confirmed(cosignatoryAccount.address)
.pipe(
filter((transaction) => transaction.transactionInfo !== undefined
&& transaction.transactionInfo.hash === signedLockFundsTransaction.hash),
mergeMap((ignored) => this.transactionHttp.announceAggregateBonded(
signedAggregateBondedTransaction)),
filter((transaction) => {
return transaction.transactionInfo !== undefined
&& transaction.transactionInfo.hash === signedLockFundsTransaction.hash;
}),
mergeMap((ignored) => this.transactionHttp.announceAggregateBonded(signedAggregateBondedTransaction)),
)
.subscribe((announcedAggregateBonded) => {
resolve(announcedAggregateBonded);
Expand All @@ -78,13 +110,13 @@ export class ApostilleHttp {
*/
public async isCreated(publicAccount: PublicAccount): Promise<boolean> {
try {
const unconfirmedTransactions = await this._unconfirmedTransactions(publicAccount);
const unconfirmedTransactions = await this._unconfirmedTransactions(publicAccount).toPromise();
if (unconfirmedTransactions.length) {
// the apostille has been sent to the network
return true;
} else {
// then check transactions
const transactions = await this._transactions(publicAccount);
const transactions = await this._transactions(publicAccount).toPromise();
if (transactions.length > 0) {
return true;
} else {
Expand Down Expand Up @@ -162,7 +194,7 @@ export class ApostilleHttp {
*/
public getCreationTransaction(publicAccount: PublicAccount): Promise<TransferTransaction> {
return new Promise((resolve, reject) => {
this._fetchAllTransactions(publicAccount).then((transactions: Transaction[]) => {
this.fetchAllTransactions(publicAccount).subscribe((transactions: Transaction[]) => {
if (transactions.length > 0) {
const firstTransaction = transactions[transactions.length - 1];
if (firstTransaction instanceof TransferTransaction) {
Expand All @@ -179,73 +211,35 @@ export class ApostilleHttp {
}
}
reject(Errors[Errors.CREATION_TRANSACTIONS_NOT_FOUND]);
}).catch((err) => {
reject(err);
});
});
}

/**
* Fetch all transactions pertaining to this publicAccount
*
* @returns {Promise<Transaction[]>}
* @memberof CertificateHistory
*/
public _fetchAllTransactions(publicAccount: PublicAccount): Promise <Transaction[]> {
return new Promise<Transaction[]>(async (resolve, reject) => {
let nextId: string = '';
const pageSize: number = 100;
let lastPageSize: number = 100;
const allTransactions: Transaction[] = [];
while (lastPageSize === pageSize) {
const queryParams = new QueryParams(pageSize, nextId !== '' ? nextId : undefined);
await this._transactions(publicAccount, queryParams).then((transactions) => {
lastPageSize = transactions.length;
if (lastPageSize < 1) { return; }
nextId = transactions[transactions.length - 1].transactionInfo!.id;
allTransactions.push(...transactions);
}).catch((err) => {
reject(err);
});
}
resolve(allTransactions);
});
public fetchAllTransactions(publicAccount: PublicAccount): Observable<Transaction[]> {
let nextId: string = '';
const pageSize: number = 100;
let lastPageSize: number = 100;
let queryParams = new QueryParams(pageSize);
return this._transactions(publicAccount, queryParams).pipe(
expand((transactions) => {
lastPageSize = transactions.length;
if (lastPageSize < pageSize) { return EMPTY; }
nextId = transactions[transactions.length - 1].transactionInfo!.id;
queryParams = new QueryParams(pageSize, nextId !== '' ? nextId : undefined);
return this._transactions(publicAccount, queryParams);
}),
);
}

private _unconfirmedTransactions(
public _transactions(
publicAccount: PublicAccount,
queryParams ?: QueryParams | undefined): Promise<Transaction[]> {

return new Promise<Transaction[]>((resolve, reject) => {
this.accountHttp.unconfirmedTransactions(
publicAccount,
queryParams,
).subscribe((unconfirmedTransactions) => {
resolve(unconfirmedTransactions);
}, (err) => {
// network or comunication problem
reject(err);
});
});

queryParams ?: QueryParams | undefined): Observable<Transaction[]> {
return this.accountHttp.transactions(publicAccount, queryParams);
}

private _transactions(
public _unconfirmedTransactions(
publicAccount: PublicAccount,
queryParams ?: QueryParams | undefined): Promise<Transaction[]> {

return new Promise<Transaction[]>((resolve, reject) => {
this.accountHttp.transactions(
publicAccount,
queryParams,
).subscribe((transactions) => {
resolve(transactions);
}, (err) => {
// network or comunication problem
reject(err);
});
});

queryParams ?: QueryParams | undefined): Observable<Transaction[]> {
return this.accountHttp.unconfirmedTransactions(publicAccount, queryParams);
}

}
3 changes: 3 additions & 0 deletions src/infrastructure/Initiator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class Initiator {

}
24 changes: 12 additions & 12 deletions src/model/apostille/ApostillePublicAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ export class ApostillePublicAccount {
* @description - modify ownership of the apostille account by modifying the multisig contract
* @param {PublicAccount[]} newOwners - array of owners to add
* @param {PublicAccount[]} OwnersToRemove - array of owners to remove
* @param {number} quorum - relative quorum (refer to http://bit.ly/2Jnff1r)
* @param {number} minRemoval - relative number of minimum owners necessary to agree to remove 1/n owners
* @param {number} quorumDelta - relative quorum (refer to http://bit.ly/2Jnff1r)
* @param {number} minRemovalDelta - relative number of minimum owners necessary to agree to remove 1/n owners
* @returns {ModifyMultisigAccountTransaction}
* @memberof ApostilleAccount
*/
public transfer(
newOwners: PublicAccount[],
ownersToRemove: PublicAccount[],
quorum: number,
minRemoval: number,
quorumDelta: number,
minRemovalDelta: number,
): ModifyMultisigAccountTransaction {
// the initiator must be a multisig account
const modifications: MultisigCosignatoryModification[] = [];
Expand All @@ -67,8 +67,8 @@ export class ApostillePublicAccount {

const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
quorum,
minRemoval,
quorumDelta,
minRemovalDelta,
modifications,
this.publicAccount.address.networkType,
);
Expand All @@ -94,17 +94,17 @@ export class ApostillePublicAccount {
}

/**
* @description sign normal transaction (can sign update(if normal transaction) and lockFundsTransaction)
* @description sign normal transaction (can sign update(if normal transaction) and lockFundsTransaction
* @param {TransferTransaction} transferTransaction
* @param {Account} initiatorAccount
* @param {HashFunction} [hashFunction] - only hash transfer transaction message
* @returns
* @returns {SignedTransaction}
* @memberof ApostillePublicAccount
*/
public sign(
transaction: TransferTransaction | Transaction,
initiatorAccount: Account,
hashFunction?: HashFunction) {
hashFunction?: HashFunction): SignedTransaction {
if (initiatorAccount.address.networkType !== this.publicAccount.address.networkType) {
throw new Error(Errors[Errors.NETWORK_TYPE_MISMATCHED]);
}
Expand Down Expand Up @@ -136,12 +136,12 @@ export class ApostillePublicAccount {
* @description signed aggregate transaction (can sign update(if multisig transaction) and transfer transaction)
* @param {Transaction} transaction
* @param {Account[]} signers
* @param {boolean} isCompleteCosignatories
* @param {boolean} isComplete
* @returns
* @memberof ApostillePublicAccount
*/
public signAggregate(transaction: Transaction, signers: Account[], isCompleteCosignatories: boolean) {
if (isCompleteCosignatories) {
public signAggregate(transaction: Transaction, signers: Account[], isComplete: boolean): SignedTransaction {
if (isComplete) {
return this._signTransferTransactionAgregateComplete(transaction, signers);
} else {
return this._signTransferTransactionAggregateBonded(transaction, signers);
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/PublicApostille/PublicApostille.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const hashFn = new SHA256();

describe('announce function should work properly', () => {
test('updating an public apostille should be allowed as many times as we want', async () => {
const sinkAddress = Address.createFromRawAddress( 'SCKPEZ-5ZAPYO-PXVF6U-YLHINF-CLYZHO-YCIO3P-KGVV');
const sinkAddress = Address.createFromRawAddress('SCKPEZ-5ZAPYO-PXVF6U-YLHINF-CLYZHO-YCIO3P-KGVV');
const publicApostille = new PublicApostille(fileName, sinkAddress);

let updateTransaction;
Expand Down

0 comments on commit cfb6a40

Please sign in to comment.