From 026d2faa29c78164c5e1c545ed0bbec5732db538 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 28 Nov 2019 19:50:39 +0000 Subject: [PATCH 01/50] added #357 transaction service for resolving alias --- .../transaction/CreateTransactionFromDTO.ts | 2 +- .../AccountAddressRestrictionTransaction.ts | 44 ++++++++++++++- .../transaction/AccountLinkTransaction.ts | 12 +++++ .../transaction/AccountMetadataTransaction.ts | 12 +++++ .../AccountMosaicRestrictionTransaction.ts | 41 ++++++++++++++ .../AccountOperationRestrictionTransaction.ts | 12 +++++ .../transaction/AddressAliasTransaction.ts | 12 +++++ src/model/transaction/AggregateTransaction.ts | 11 ++++ src/model/transaction/LockFundsTransaction.ts | 46 ++++++++++++++++ .../MosaicAddressRestrictionTransaction.ts | 36 +++++++++++++ .../transaction/MosaicAliasTransaction.ts | 12 +++++ .../MosaicDefinitionTransaction.ts | 12 +++++ .../MosaicGlobalRestrictionTransaction.ts | 37 +++++++++++++ .../transaction/MosaicMetadataTransaction.ts | 46 ++++++++++++++++ .../MosaicSupplyChangeTransaction.ts | 54 +++++++++++++++++-- .../MultisigAccountModificationTransaction.ts | 13 ++++- .../NamespaceMetadataTransaction.ts | 12 +++++ .../NamespaceRegistrationTransaction.ts | 12 +++++ .../transaction/SecretLockTransaction.ts | 36 ++++++++++++- .../transaction/SecretProofTransaction.ts | 44 +++++++++++++++ src/model/transaction/Transaction.ts | 8 +++ src/model/transaction/TransferTransaction.ts | 43 ++++++++++++++- src/service/TransactionService.ts | 50 +++++++++++++++++ test/model/transaction/Transaction.spec.ts | 7 ++- 24 files changed, 601 insertions(+), 13 deletions(-) create mode 100644 src/service/TransactionService.ts diff --git a/src/infrastructure/transaction/CreateTransactionFromDTO.ts b/src/infrastructure/transaction/CreateTransactionFromDTO.ts index ea6e1802c2..c7bada7ca1 100644 --- a/src/infrastructure/transaction/CreateTransactionFromDTO.ts +++ b/src/infrastructure/transaction/CreateTransactionFromDTO.ts @@ -175,7 +175,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr transactionDTO.version, Deadline.createFromDTO(transactionDTO.deadline), UInt64.fromNumericString(transactionDTO.maxFee || '0'), - new MosaicId(transactionDTO.mosaicId), + UnresolvedMapping.toUnresolvedMosaic(transactionDTO.mosaicId), transactionDTO.action, UInt64.fromNumericString(transactionDTO.delta), transactionDTO.signature, diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 90a513ee1a..0901889381 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { Convert, RawAddress } from '../../core/format'; +import { combineLatest, from, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { mergeMap, toArray } from 'rxjs/operators'; +import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountAddressRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountAddressRestrictionTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -25,13 +28,13 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; -import { AccountRestrictionModification } from './AccountRestrictionModification'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; import { Transaction } from './Transaction'; @@ -190,4 +193,41 @@ export class AccountAddressRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountAddressRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const restrictionAdditions = from(this.restrictionAdditions).pipe( + mergeMap((addition) => addition instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(addition) : + of(addition), + ), + toArray(), + ); + const restrictionDeletions = from(this.restrictionDeletions).pipe( + mergeMap((deletion) => deletion instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(deletion) : + of(deletion), + ), + toArray(), + ); + + return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { + return new AccountAddressRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.restrictionFlags, + additions, + deletions, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/AccountLinkTransaction.ts b/src/model/transaction/AccountLinkTransaction.ts index b5c2aa9308..d89d376c89 100644 --- a/src/model/transaction/AccountLinkTransaction.ts +++ b/src/model/transaction/AccountLinkTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountLinkTransactionBuilder } from '../../infrastructure/catbuffer/AccountLinkTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -21,6 +23,7 @@ import { EmbeddedAccountLinkTransactionBuilder } from '../../infrastructure/catb import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -163,4 +166,13 @@ export class AccountLinkTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountLinkTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AccountMetadataTransaction.ts b/src/model/transaction/AccountMetadataTransaction.ts index bbfc10c435..5f09acceb6 100644 --- a/src/model/transaction/AccountMetadataTransaction.ts +++ b/src/model/transaction/AccountMetadataTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountMetadataTransactionBuilder } from '../../infrastructure/catbuffer/AccountMetadataTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -21,6 +23,7 @@ import { EmbeddedAccountMetadataTransactionBuilder } from '../../infrastructure/ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -193,4 +196,13 @@ export class AccountMetadataTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountMetadataTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index 20bba4d76b..af134a61bb 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { combineLatest, from, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { mergeMap, toArray } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountMosaicRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountMosaicRestrictionTransactionBuilder'; @@ -25,6 +28,7 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -189,4 +193,41 @@ export class AccountMosaicRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountMosaicRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const restrictionAdditions = from(this.restrictionAdditions).pipe( + mergeMap((addition) => addition instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(addition) : + of(addition), + ), + toArray(), + ); + const restrictionDeletions = from(this.restrictionDeletions).pipe( + mergeMap((deletion) => deletion instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(deletion) : + of(deletion), + ), + toArray(), + ); + + return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { + return new AccountMosaicRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.restrictionFlags, + additions, + deletions, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/AccountOperationRestrictionTransaction.ts b/src/model/transaction/AccountOperationRestrictionTransaction.ts index 53661b6db4..a7a4181524 100644 --- a/src/model/transaction/AccountOperationRestrictionTransaction.ts +++ b/src/model/transaction/AccountOperationRestrictionTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountOperationRestrictionTransactionBuilder, @@ -25,6 +27,7 @@ import { import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; @@ -174,4 +177,13 @@ export class AccountOperationRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountOperationRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AddressAliasTransaction.ts b/src/model/transaction/AddressAliasTransaction.ts index 14b18f2c16..04bfd3df5c 100644 --- a/src/model/transaction/AddressAliasTransaction.ts +++ b/src/model/transaction/AddressAliasTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert, RawAddress } from '../../core/format'; import { AddressAliasTransactionBuilder } from '../../infrastructure/catbuffer/AddressAliasTransactionBuilder'; import { AddressDto } from '../../infrastructure/catbuffer/AddressDto'; @@ -23,6 +25,7 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -183,4 +186,13 @@ export class AddressAliasTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AddressAliasTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index a7ea36d201..391acbb95f 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -15,6 +15,7 @@ */ import { sha3_256 } from 'js-sha3'; +import { Observable } from 'rxjs/internal/Observable'; import {KeyPair, MerkleHashBuilder, SHA3Hasher, SignSchema} from '../../core/crypto'; import {Convert, RawArray} from '../../core/format'; import {AggregateBondedTransactionBuilder} from '../../infrastructure/catbuffer/AggregateBondedTransactionBuilder'; @@ -26,6 +27,7 @@ import { Hash256Dto } from '../../infrastructure/catbuffer/Hash256Dto'; import {KeyDto} from '../../infrastructure/catbuffer/KeyDto'; import {SignatureDto} from '../../infrastructure/catbuffer/SignatureDto'; import {TimestampDto} from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import {CreateTransactionFromPayload} from '../../infrastructure/transaction/CreateTransactionFromPayload'; import {Account} from '../account/Account'; import {PublicAccount} from '../account/PublicAccount'; @@ -400,4 +402,13 @@ export class AggregateTransaction extends Transaction { private getInnerTransactionPaddingSize(size: number, alignment: number): number { return 0 === size % alignment ? 0 : alignment - (size % alignment); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AggregateTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + throw new Error('Not implemented'); + } } diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index a772bd3e6e..52febc542a 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -14,6 +14,10 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; +import { map } from 'rxjs/internal/operators/map'; +import { mergeMap } from 'rxjs/internal/operators/mergeMap'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -25,10 +29,12 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; import { MosaicId } from '../mosaic/MosaicId'; +import { NamespaceId } from '../namespace/NamespaceId'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -50,6 +56,7 @@ export class LockFundsTransaction extends Transaction { * Aggregate bonded hash. */ public readonly hash: string; + signedTransaction: SignedTransaction; /** * Create a Lock funds transaction object @@ -108,6 +115,7 @@ export class LockFundsTransaction extends Transaction { transactionInfo?: TransactionInfo) { super(TransactionType.LOCK, networkType, version, deadline, maxFee, signature, signer, transactionInfo); this.hash = signedTransaction.hash; + this.signedTransaction = signedTransaction; if (signedTransaction.type !== TransactionType.AGGREGATE_BONDED) { throw new Error('Signed transaction must be Aggregate Bonded Transaction'); } @@ -200,4 +208,42 @@ export class LockFundsTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {LockFundsTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this.mosaic).pipe( + mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( + map((mosaicId) => new LockFundsTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + new Mosaic(mosaicId, mosaic.amount), + this.duration, + this.signedTransaction, + this.signature, + this.signer, + this.transactionInfo, + )), + ) : + of(new LockFundsTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaic, + this.duration, + this.signedTransaction, + this.signature, + this.signer, + this.transactionInfo, + )), + ), + ); + } } diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 11b25d3855..2c42f6052b 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { combineLatest } from 'rxjs/internal/observable/combineLatest'; +import { of } from 'rxjs/internal/observable/of'; import { Convert, RawAddress } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -26,6 +29,7 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -233,4 +237,36 @@ export class MosaicAddressRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicAddressRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedAddress = this.targetAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.targetAddress as NamespaceId) : + of(this.targetAddress); + + const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : + of(this.mosaicId); + + return combineLatest(resolvedAddress, resolvedMosaicId, (address, mosaicId) => { + return new MosaicAddressRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaicId, + this.restrictionKey, + address, + this.previousRestrictionValue, + this.newRestrictionValue, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/MosaicAliasTransaction.ts b/src/model/transaction/MosaicAliasTransaction.ts index 4fd81443ce..56457b20e8 100644 --- a/src/model/transaction/MosaicAliasTransaction.ts +++ b/src/model/transaction/MosaicAliasTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedMosaicAliasTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedMosaicAliasTransactionBuilder'; @@ -23,6 +25,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -178,4 +181,13 @@ export class MosaicAliasTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicAliasTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/MosaicDefinitionTransaction.ts b/src/model/transaction/MosaicDefinitionTransaction.ts index 179c37e0e7..79ffe963d8 100644 --- a/src/model/transaction/MosaicDefinitionTransaction.ts +++ b/src/model/transaction/MosaicDefinitionTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -25,6 +27,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { MosaicNonceDto } from '../../infrastructure/catbuffer/MosaicNonceDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicFlags } from '../mosaic/MosaicFlags'; @@ -221,4 +224,13 @@ export class MosaicDefinitionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicDefinitionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 404f14e63c..05bfcb57b5 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { combineLatest, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -25,6 +27,7 @@ import { MosaicGlobalRestrictionTransactionBuilder } from '../../infrastructure/ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -243,4 +246,38 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicGlobalRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : + of(this.mosaicId); + + const resolvedRefMosaicId = this.referenceMosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : + of(this.mosaicId); + + return combineLatest(resolvedMosaicId, resolvedRefMosaicId, (mosaicId, refMosaicId) => { + return new MosaicGlobalRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaicId, + refMosaicId, + this.restrictionKey, + this.previousRestrictionValue, + this.previousRestrictionType, + this.newRestrictionValue, + this.newRestrictionType, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index 6973af8283..b99fb4e61b 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -23,6 +26,7 @@ import { MosaicMetadataTransactionBuilder } from '../../infrastructure/catbuffer import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -209,4 +213,46 @@ export class MosaicMetadataTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicMetadataTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return this.targetMosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.targetMosaicId as NamespaceId).pipe( + map((mosaicId) => { + return new MosaicMetadataTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.targetPublicKey, + this.scopedMetadataKey, + mosaicId, + this.valueSizeDelta, + this.value, + this.signature, + this.signer, + this.transactionInfo, + ); + }), + ) : + of(new MosaicMetadataTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.targetPublicKey, + this.scopedMetadataKey, + this.targetMosaicId, + this.valueSizeDelta, + this.value, + this.signature, + this.signer, + this.transactionInfo, + ), + ); + } } diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index 5a3fea7dd5..348084157b 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +import { of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; +import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedMosaicSupplyChangeTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedMosaicSupplyChangeTransactionBuilder'; import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; @@ -22,10 +26,12 @@ import { MosaicSupplyChangeTransactionBuilder } from '../../infrastructure/catbu import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { MosaicSupplyChangeAction } from '../mosaic/MosaicSupplyChangeAction'; +import { NamespaceId } from '../namespace/NamespaceId'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -43,7 +49,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * Create a mosaic supply change transaction object * @param deadline - The deadline to include the transaction. - * @param mosaicId - The mosaic id. + * @param mosaicId - The unresolved mosaic id. * @param action - The supply change action (increase | decrease). * @param delta - The supply change in units for the mosaic. * @param networkType - The network type. @@ -51,7 +57,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { * @returns {MosaicSupplyChangeTransaction} */ public static create(deadline: Deadline, - mosaicId: MosaicId, + mosaicId: MosaicId | NamespaceId, action: MosaicSupplyChangeAction, delta: UInt64, networkType: NetworkType, @@ -83,9 +89,9 @@ export class MosaicSupplyChangeTransaction extends Transaction { deadline: Deadline, maxFee: UInt64, /** - * The mosaic id. + * The unresolved mosaic id. */ - public readonly mosaicId: MosaicId, + public readonly mosaicId: MosaicId | NamespaceId, /** * The supply type. */ @@ -115,7 +121,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { const transaction = MosaicSupplyChangeTransaction.create( isEmbedded ? Deadline.create() : Deadline.createFromDTO( (builder as MosaicSupplyChangeTransactionBuilder).getDeadline().timestamp), - new MosaicId(builder.getMosaicId().unresolvedMosaicId), + UnresolvedMapping.toUnresolvedMosaic(new UInt64(builder.getMosaicId().unresolvedMosaicId).toHex()), builder.getAction().valueOf(), new UInt64(builder.getDelta().amount), networkType, @@ -181,4 +187,42 @@ export class MosaicSupplyChangeTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicSupplyChangeTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return this.mosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId).pipe( + map((mosaicId) => { + return new MosaicSupplyChangeTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaicId, + this.action, + this.delta, + this.signature, + this.signer, + this.transactionInfo, + ); + }), + ) : + of(new MosaicSupplyChangeTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.mosaicId, + this.action, + this.delta, + this.signature, + this.signer, + this.transactionInfo, + ), + ); + } } diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index c2ecd6c9c8..1393b159a0 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { @@ -24,12 +26,12 @@ import {MultisigAccountModificationTransactionBuilder, } from '../../infrastructure/catbuffer/MultisigAccountModificationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; -import { MultisigCosignatoryModification } from './MultisigCosignatoryModification'; import { Transaction } from './Transaction'; import { TransactionInfo } from './TransactionInfo'; import { TransactionType } from './TransactionType'; @@ -213,4 +215,13 @@ export class MultisigAccountModificationTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MultisigAccountModificationTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/NamespaceMetadataTransaction.ts b/src/model/transaction/NamespaceMetadataTransaction.ts index b5dd3f8d11..3198791bca 100644 --- a/src/model/transaction/NamespaceMetadataTransaction.ts +++ b/src/model/transaction/NamespaceMetadataTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedNamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedNamespaceMetadataTransactionBuilder'; @@ -22,6 +24,7 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceMetadataTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; @@ -208,4 +211,13 @@ export class NamespaceMetadataTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {NamespaceMetadataTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/NamespaceRegistrationTransaction.ts b/src/model/transaction/NamespaceRegistrationTransaction.ts index b10a46714d..341d07ca74 100644 --- a/src/model/transaction/NamespaceRegistrationTransaction.ts +++ b/src/model/transaction/NamespaceRegistrationTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert, Convert as convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -25,6 +27,7 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceRegistrationTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceRegistrationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import {NamespaceMosaicIdGenerator} from '../../infrastructure/transaction/NamespaceMosaicIdGenerator'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -273,4 +276,13 @@ export class NamespaceRegistrationTransaction extends Transaction { } return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {NamespaceRegistrationTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index dfb1b9f41a..92a5f0d339 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Convert, Convert as convert, RawAddress } from '../../core/format'; +import { combineLatest, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; +import { Convert, Convert as convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -26,11 +29,11 @@ import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; -import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -231,4 +234,33 @@ export class SecretLockTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : + of(this.recipientAddress); + + const resolvedMosaic = this.mosaic instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.recipientAddress as NamespaceId).pipe( + map((mosaicId) => new Mosaic(mosaicId, this.mosaic.amount)), + ) : + of(this.mosaic); + + return combineLatest(resolvedRecipient, resolvedMosaic, (recipient, mosaic) => { + return new SecretLockTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaic, + this.duration, + this.hashType, + this.secret, + recipient, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 27a5d868e3..7bb2cd65cf 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; +import { map } from 'rxjs/operators'; import { Convert, Convert as convert, RawAddress } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -24,6 +27,7 @@ import { SecretProofTransactionBuilder } from '../../infrastructure/catbuffer/Se import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -207,4 +211,44 @@ export class SecretProofTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {SecretProofTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return this.recipientAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId).pipe( + map((recipient) => { + return new SecretProofTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.hashType, + this.secret, + recipient, + this.proof, + this.signature, + this.signer, + this.transactionInfo, + ); + }), + ) : + of(new SecretProofTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.hashType, + this.secret, + this.recipientAddress, + this.proof, + this.signature, + this.signer, + this.transactionInfo, + ), + ); + } } diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index f051d6ceeb..cdab1e54ef 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -14,8 +14,10 @@ * limitations under the License. */ +import { Observable } from 'rxjs'; import { KeyPair, SHA3Hasher, SignSchema } from '../../core/crypto'; import { Convert } from '../../core/format'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { SerializeTransactionToJSON } from '../../infrastructure/transaction/SerializeTransactionToJSON'; import { Account } from '../account/Account'; import { PublicAccount } from '../account/PublicAccount'; @@ -185,6 +187,12 @@ export abstract class Transaction { */ protected abstract generateEmbeddedBytes(): Uint8Array; + /** + * @internal + * @param namespaceHttp NamespaceHttp + */ + abstract resolveAliases(namespaceHttp: NamespaceHttp): Observable; + /** * @internal * Serialize and sign transaction creating a new SignedTransaction diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index 12c91e2241..cda3cc0e55 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -15,7 +15,10 @@ */ import * as Long from 'long'; -import {Convert, Convert as convert} from '../../core/format'; +import { combineLatest, from, Observable, of } from 'rxjs'; +import { map, toArray } from 'rxjs/operators'; +import { mergeMap} from 'rxjs/operators'; +import {Convert} from '../../core/format'; import {UnresolvedMapping} from '../../core/utils/UnresolvedMapping'; import {AmountDto} from '../../infrastructure/catbuffer/AmountDto'; import {EmbeddedTransferTransactionBuilder} from '../../infrastructure/catbuffer/EmbeddedTransferTransactionBuilder'; @@ -27,6 +30,7 @@ import {TransferTransactionBuilder} from '../../infrastructure/catbuffer/Transfe import {UnresolvedAddressDto} from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import {UnresolvedMosaicBuilder} from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import {UnresolvedMosaicIdDto} from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import {Address} from '../account/Address'; import {PublicAccount} from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; @@ -43,6 +47,7 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; +import { flatMap } from 'rxjs/operators'; /** * Transfer transactions contain data about transfers of mosaics and message to another account. @@ -272,4 +277,40 @@ export class TransferTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {TransferTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : + of(this.recipientAddress); + + const resolvedMosaics = from(this.mosaics).pipe( + mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( + map((mosaicId) => new Mosaic(mosaicId, mosaic.amount)), + ) : + of(mosaic), + ), + toArray(), + ); + + return combineLatest(resolvedRecipient, resolvedMosaics, (recipient, mosaics) => { + return new TransferTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + recipient, + mosaics, + this.message, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts new file mode 100644 index 0000000000..ad8f8e2e0c --- /dev/null +++ b/src/service/TransactionService.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Observable} from 'rxjs'; +import { flatMap, mergeMap, toArray} from 'rxjs/operators'; +import { NamespaceHttp } from '../infrastructure/NamespaceHttp'; +import { TransactionHttp } from '../infrastructure/TransactionHttp'; +import { Transaction } from '../model/transaction/Transaction'; + +/** + * Transaction Service + */ +export class TransactionService { + + private readonly transactionHttp: TransactionHttp; + private readonly namespaceHttp: NamespaceHttp; + /** + * Constructor + * @param url Base catapult-rest url + */ + constructor(url: string) { + this.transactionHttp = new TransactionHttp(url); + this.namespaceHttp = new NamespaceHttp(url); + } + + /** + * @param transationHashes List of transaction hashes. + * @returns Observable + */ + public resolveAliases(transationHashes: string[]): Observable { + return this.transactionHttp.getTransactions(transationHashes).pipe( + mergeMap((_) => _), + flatMap((transaction) => transaction.resolveAliases(this.namespaceHttp)), + toArray(), + ); + } +} diff --git a/test/model/transaction/Transaction.spec.ts b/test/model/transaction/Transaction.spec.ts index 5815da8f8b..c98bf76752 100644 --- a/test/model/transaction/Transaction.spec.ts +++ b/test/model/transaction/Transaction.spec.ts @@ -15,6 +15,9 @@ */ import { expect } from 'chai'; +import { Observable } from 'rxjs/internal/Observable'; +import { Convert } from '../../../src/core/format/Convert'; +import { NamespaceHttp } from '../../../src/infrastructure/NamespaceHttp'; import { Account } from '../../../src/model/account/Account'; import { Address } from '../../../src/model/account/Address'; import { NetworkType } from '../../../src/model/blockchain/NetworkType'; @@ -28,7 +31,6 @@ import { TransactionType } from '../../../src/model/transaction/TransactionType' import { TransferTransaction } from '../../../src/model/transaction/TransferTransaction'; import { UInt64 } from '../../../src/model/UInt64'; import { TestingAccount } from '../../conf/conf.spec'; -import { Convert } from '../../../src/core/format/Convert'; describe('Transaction', () => { let account: Account; @@ -403,4 +405,7 @@ class FakeTransaction extends Transaction { protected generateEmbeddedBytes(): Uint8Array { throw new Error('Not implemented'); } + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + throw new Error('Not implemented'); + } } From 96a75135b9632dbf7ef49d74c04a6a74f74c3e77 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 29 Nov 2019 14:18:02 +0000 Subject: [PATCH 02/50] restore missing tests --- e2e/service/TransactionService.spec.ts | 313 +++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 e2e/service/TransactionService.spec.ts diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts new file mode 100644 index 0000000000..b5c424ed6b --- /dev/null +++ b/e2e/service/TransactionService.spec.ts @@ -0,0 +1,313 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { assert } from 'chai'; +import { Listener } from '../../src/infrastructure/Listener'; +import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; +import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; +import { Account } from '../../src/model/account/Account'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction, Address } from '../../src/model/model'; +import { MosaicFlags } from '../../src/model/mosaic/MosaicFlags'; +import { MosaicId } from '../../src/model/mosaic/MosaicId'; +import { MosaicNonce } from '../../src/model/mosaic/MosaicNonce'; +import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { AliasAction } from '../../src/model/namespace/AliasAction'; +import { NamespaceId } from '../../src/model/namespace/NamespaceId'; +import { AddressAliasTransaction } from '../../src/model/transaction/AddressAliasTransaction'; +import { Deadline } from '../../src/model/transaction/Deadline'; +import { MosaicAliasTransaction } from '../../src/model/transaction/MosaicAliasTransaction'; +import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicDefinitionTransaction'; +import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; +import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { UInt64 } from '../../src/model/UInt64'; +import { TransactionService } from '../../src/service/TransactionService'; +import { expect } from 'chai'; + +describe('TransactionService', () => { + let account: Account; + let account2: Account; + let url: string; + let generationHash: string; + let namespaceHttp: NamespaceHttp; + let addressAlias: NamespaceId; + let mosaicAlias: NamespaceId; + let mosaicId: MosaicId; + let transactionHttp: TransactionHttp; + let config; + let transactionHashes: string[]; + + before((done) => { + const path = require('path'); + require('fs').readFile(path.resolve(__dirname, '../conf/network.conf'), (err, data) => { + if (err) { + throw err; + } + const json = JSON.parse(data); + config = json; + account = Account.createFromPrivateKey(json.testAccount.privateKey, NetworkType.MIJIN_TEST); + account2 = Account.createFromPrivateKey(json.testAccount2.privateKey, NetworkType.MIJIN_TEST); + url = json.apiUrl; + generationHash = json.generationHash; + namespaceHttp = new NamespaceHttp(json.apiUrl); + transactionHttp = new TransactionHttp(json.apiUrl); + transactionHashes = []; + done(); + }); + }); + + /** + * ========================= + * Setup test data + * ========================= + */ + describe('Create address alias NamespaceId', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce NamespaceRegistrationTransaction', (done) => { + const namespaceName = 'root-test-namespace-' + Math.floor(Math.random() * 10000); + const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( + Deadline.create(), + namespaceName, + UInt64.fromUint(9), + NetworkType.MIJIN_TEST, + ); + addressAlias = new NamespaceId(namespaceName); + const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Create mosaic alias NamespaceId', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce NamespaceRegistrationTransaction', (done) => { + const namespaceName = 'root-test-namespace-' + Math.floor(Math.random() * 10000); + const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( + Deadline.create(), + namespaceName, + UInt64.fromUint(9), + NetworkType.MIJIN_TEST, + ); + mosaicAlias = new NamespaceId(namespaceName); + const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Setup test AddressAlias', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + + it('Announce addressAliasTransaction', (done) => { + const addressAliasTransaction = AddressAliasTransaction.create( + Deadline.create(), + AliasAction.Link, + addressAlias, + account.address, + NetworkType.MIJIN_TEST, + ); + const signedTransaction = addressAliasTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Setup test MosaicId', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MosaicDefinitionTransaction', (done) => { + const nonce = MosaicNonce.createRandom(); + mosaicId = MosaicId.createFromNonce(nonce, account.publicAccount); + const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( + Deadline.create(), + nonce, + mosaicId, + MosaicFlags.create(true, true, false), + 3, + UInt64.fromUint(0), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = mosaicDefinitionTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('MosaicSupplyChangeTransaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('standalone', (done) => { + const mosaicSupplyChangeTransaction = MosaicSupplyChangeTransaction.create( + Deadline.create(), + mosaicId, + MosaicSupplyChangeAction.Increase, + UInt64.fromUint(10), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = mosaicSupplyChangeTransaction.signWith(account, generationHash); + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Setup MosaicAlias', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + + it('Announce MosaicAliasTransaction', (done) => { + const mosaicAliasTransaction = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Link, + mosaicAlias, + mosaicId, + NetworkType.MIJIN_TEST, + ); + const signedTransaction = mosaicAliasTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + describe('Create Transfer with alias', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + + it('Announce TransferTransaction', (done) => { + const transferTransaction = TransferTransaction.create( + Deadline.create(), + addressAlias, + [ + // NetworkCurrencyMosaic.createAbsolute(1), //Seems get banned on rest if passing multiple mosaic alias in + new Mosaic(mosaicAlias, UInt64.fromUint(1)), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = transferTransaction.signWith(account, generationHash); + + transactionHashes.push(signedTransaction.hash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + describe('should return resolved transaction', () => { + it('call transaction service', (done) => { + const transactionService = new TransactionService(url); + return transactionService.resolveAliases(transactionHashes).subscribe((transactions) => { + transactions.map((tx: TransferTransaction) => { + expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); + expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + }); + done(); + }); + }); + }); +}); From 01d48ee3a575d38f1d3e5bd352277ea9a281f9d5 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 21:14:28 +0000 Subject: [PATCH 03/50] Changed to resolve alias from receipts --- e2e/service/TransactionService.spec.ts | 4 +- src/core/utils/TransactionMapping.ts | 1 - src/core/utils/UnresolvedMapping.ts | 2 +- .../receipt/CreateReceiptFromDTO.ts | 32 ++- .../AccountAddressRestrictionTransaction.ts | 55 +++-- .../transaction/AccountLinkTransaction.ts | 8 +- .../transaction/AccountMetadataTransaction.ts | 8 +- .../AccountMosaicRestrictionTransaction.ts | 55 +++-- .../AccountOperationRestrictionTransaction.ts | 8 +- .../transaction/AddressAliasTransaction.ts | 8 +- src/model/transaction/AggregateTransaction.ts | 8 +- src/model/transaction/LockFundsTransaction.ts | 43 ++-- .../MosaicAddressRestrictionTransaction.ts | 44 +++- .../transaction/MosaicAliasTransaction.ts | 8 +- .../MosaicDefinitionTransaction.ts | 8 +- .../MosaicGlobalRestrictionTransaction.ts | 42 +++- .../transaction/MosaicMetadataTransaction.ts | 50 ++--- .../MosaicSupplyChangeTransaction.ts | 41 ++-- .../MultisigAccountModificationTransaction.ts | 7 +- .../NamespaceMetadataTransaction.ts | 7 +- .../NamespaceRegistrationTransaction.ts | 8 +- .../transaction/SecretLockTransaction.ts | 45 +++- .../transaction/SecretProofTransaction.ts | 67 +++--- src/model/transaction/Transaction.ts | 19 +- src/model/transaction/TransferTransaction.ts | 51 +++-- src/service/TransactionService.ts | 56 ++++- src/service/service.ts | 1 + .../receipt/CreateReceiptFromDTO.spec.ts | 8 +- test/model/receipt/Receipt.spec.ts | 4 +- test/model/transaction/Transaction.spec.ts | 5 +- test/service/TransactionService.spec.ts | 208 ++++++++++++++++++ 31 files changed, 657 insertions(+), 254 deletions(-) create mode 100644 test/service/TransactionService.spec.ts diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index b5c424ed6b..e6520cf0b1 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -15,13 +15,14 @@ */ import { assert } from 'chai'; +import { expect } from 'chai'; import { Listener } from '../../src/infrastructure/Listener'; import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; import { Account } from '../../src/model/account/Account'; import { NetworkType } from '../../src/model/blockchain/NetworkType'; import { PlainMessage } from '../../src/model/message/PlainMessage'; -import { Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction, Address } from '../../src/model/model'; +import { Address, Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction } from '../../src/model/model'; import { MosaicFlags } from '../../src/model/mosaic/MosaicFlags'; import { MosaicId } from '../../src/model/mosaic/MosaicId'; import { MosaicNonce } from '../../src/model/mosaic/MosaicNonce'; @@ -36,7 +37,6 @@ import { NamespaceRegistrationTransaction } from '../../src/model/transaction/Na import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; import { UInt64 } from '../../src/model/UInt64'; import { TransactionService } from '../../src/service/TransactionService'; -import { expect } from 'chai'; describe('TransactionService', () => { let account: Account; diff --git a/src/core/utils/TransactionMapping.ts b/src/core/utils/TransactionMapping.ts index 64a387c4d4..b579fd0cb6 100644 --- a/src/core/utils/TransactionMapping.ts +++ b/src/core/utils/TransactionMapping.ts @@ -18,7 +18,6 @@ import { CreateTransactionFromDTO } from '../../infrastructure/transaction/Creat import { CreateTransactionFromPayload } from '../../infrastructure/transaction/CreateTransactionFromPayload'; import { InnerTransaction } from '../../model/transaction/InnerTransaction'; import { Transaction } from '../../model/transaction/Transaction'; -import { SignSchema } from '../crypto/SignSchema'; export class TransactionMapping { diff --git a/src/core/utils/UnresolvedMapping.ts b/src/core/utils/UnresolvedMapping.ts index a77c4d33f8..1a8de4f376 100644 --- a/src/core/utils/UnresolvedMapping.ts +++ b/src/core/utils/UnresolvedMapping.ts @@ -14,11 +14,11 @@ * limitations under the License. */ import { Address } from '../../model/account/Address'; +import { NetworkType } from '../../model/blockchain/NetworkType'; import { MosaicId } from '../../model/mosaic/MosaicId'; import { NamespaceId } from '../../model/namespace/NamespaceId'; import { Convert } from '../format/Convert'; import { RawAddress } from '../format/RawAddress'; -import { NetworkType } from "../../model/blockchain/NetworkType"; /** * @internal diff --git a/src/infrastructure/receipt/CreateReceiptFromDTO.ts b/src/infrastructure/receipt/CreateReceiptFromDTO.ts index ee336b4e70..8eff4c9c87 100644 --- a/src/infrastructure/receipt/CreateReceiptFromDTO.ts +++ b/src/infrastructure/receipt/CreateReceiptFromDTO.ts @@ -14,12 +14,10 @@ * limitations under the License. */ +import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { Address } from '../../model/account/Address'; import {PublicAccount} from '../../model/account/PublicAccount'; import {MosaicId} from '../../model/mosaic/MosaicId'; -import { AddressAlias } from '../../model/namespace/AddressAlias'; -import { AliasType } from '../../model/namespace/AliasType'; -import { MosaicAlias } from '../../model/namespace/MosaicAlias'; import { NamespaceId } from '../../model/namespace/NamespaceId'; import { ArtifactExpiryReceipt } from '../../model/receipt/ArtifactExpiryReceipt'; import { BalanceChangeReceipt } from '../../model/receipt/BalanceChangeReceipt'; @@ -95,7 +93,7 @@ const createResolutionStatement = (statementDTO, resolutionType): ResolutionStat return new ResolutionStatement( ResolutionType.Address, UInt64.fromNumericString(statementDTO.height), - Address.createFromEncoded(statementDTO.unresolved), + extractUnresolvedAddress(statementDTO.unresolved), statementDTO.resolutionEntries.map((entry) => { return new ResolutionEntry(Address.createFromEncoded(entry.resolved), new ReceiptSource(entry.source.primaryId, entry.source.secondaryId)); @@ -105,7 +103,7 @@ const createResolutionStatement = (statementDTO, resolutionType): ResolutionStat return new ResolutionStatement( ResolutionType.Mosaic, UInt64.fromNumericString(statementDTO.height), - new MosaicId(statementDTO.unresolved), + UnresolvedMapping.toUnresolvedMosaic(statementDTO.unresolved), statementDTO.resolutionEntries.map((entry) => { return new ResolutionEntry(new MosaicId(entry.resolved), new ReceiptSource(entry.source.primaryId, entry.source.secondaryId)); @@ -197,6 +195,12 @@ const createInflationReceipt = (receiptDTO): Receipt => { ); }; +/** + * @internal + * @param receiptType receipt type + * @param id Artifact id + * @returns {MosaicId | NamespaceId} + */ const extractArtifactId = (receiptType: ReceiptType, id: string): MosaicId | NamespaceId => { switch (receiptType) { case ReceiptType.Mosaic_Expired: @@ -208,3 +212,21 @@ const extractArtifactId = (receiptType: ReceiptType, id: string): MosaicId | Nam throw new Error('Receipt type is not supported.'); } }; + +/** + * @interal + * @param unresolvedAddress unresolved address + * @returns {Address | NamespaceId} + */ +const extractUnresolvedAddress = (unresolvedAddress: any): Address | NamespaceId => { + if (typeof unresolvedAddress === 'string') { + return UnresolvedMapping.toUnresolvedAddress(unresolvedAddress); + } else if (typeof unresolvedAddress === 'object') { // Is JSON object + if (unresolvedAddress.hasOwnProperty('address')) { + return Address.createFromRawAddress(unresolvedAddress.address); + } else if (unresolvedAddress.hasOwnProperty('id')) { + return NamespaceId.createFromEncoded(unresolvedAddress.id); + } + } + throw new Error(`UnresolvedAddress: ${unresolvedAddress} type is not recognised`); +}; diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 0901889381..05960c8667 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { combineLatest, from, of } from 'rxjs'; +import { combineLatest, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; -import { mergeMap, toArray } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountAddressRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountAddressRestrictionTransactionBuilder'; @@ -28,11 +28,13 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -196,23 +198,40 @@ export class AccountAddressRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountAddressRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const restrictionAdditions = from(this.restrictionAdditions).pipe( - mergeMap((addition) => addition instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(addition) : - of(addition), - ), - toArray(), + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || + this.restrictionDeletions.find((address) => address instanceof NamespaceId) !== undefined; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + const restrictionAdditions = statementObservable.pipe( + map((statement) => { + return this.restrictionAdditions.map((addition) => { + return addition instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, addition as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + addition; + }); + }), ); - const restrictionDeletions = from(this.restrictionDeletions).pipe( - mergeMap((deletion) => deletion instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(deletion) : - of(deletion), - ), - toArray(), + + const restrictionDeletions = statementObservable.pipe( + map((statement) => { + return this.restrictionDeletions.map((deletion) => { + return deletion instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, deletion as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + deletion; + }); + }), ); return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { diff --git a/src/model/transaction/AccountLinkTransaction.ts b/src/model/transaction/AccountLinkTransaction.ts index d89d376c89..bbfa101882 100644 --- a/src/model/transaction/AccountLinkTransaction.ts +++ b/src/model/transaction/AccountLinkTransaction.ts @@ -23,7 +23,7 @@ import { EmbeddedAccountLinkTransactionBuilder } from '../../infrastructure/catb import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -169,10 +169,10 @@ export class AccountLinkTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountLinkTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AccountMetadataTransaction.ts b/src/model/transaction/AccountMetadataTransaction.ts index 5f09acceb6..2e41cde6ff 100644 --- a/src/model/transaction/AccountMetadataTransaction.ts +++ b/src/model/transaction/AccountMetadataTransaction.ts @@ -23,7 +23,7 @@ import { EmbeddedAccountMetadataTransactionBuilder } from '../../infrastructure/ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -199,10 +199,10 @@ export class AccountMetadataTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountMetadataTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index af134a61bb..0fa304b41c 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { combineLatest, from, of } from 'rxjs'; +import { combineLatest, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; -import { mergeMap, toArray } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountMosaicRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountMosaicRestrictionTransactionBuilder'; @@ -28,11 +28,13 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -196,23 +198,40 @@ export class AccountMosaicRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountMosaicRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const restrictionAdditions = from(this.restrictionAdditions).pipe( - mergeMap((addition) => addition instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(addition) : - of(addition), - ), - toArray(), + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || + this.restrictionDeletions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + const restrictionAdditions = statementObservable.pipe( + map((statement) => { + return this.restrictionAdditions.map((addition) => { + return addition instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, addition as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + addition; + }); + }), ); - const restrictionDeletions = from(this.restrictionDeletions).pipe( - mergeMap((deletion) => deletion instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(deletion) : - of(deletion), - ), - toArray(), + + const restrictionDeletions = statementObservable.pipe( + map((statement) => { + return this.restrictionDeletions.map((deletion) => { + return deletion instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, deletion as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + deletion; + }); + }), ); return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { diff --git a/src/model/transaction/AccountOperationRestrictionTransaction.ts b/src/model/transaction/AccountOperationRestrictionTransaction.ts index a7a4181524..e38165001e 100644 --- a/src/model/transaction/AccountOperationRestrictionTransaction.ts +++ b/src/model/transaction/AccountOperationRestrictionTransaction.ts @@ -27,7 +27,7 @@ import { import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; @@ -180,10 +180,10 @@ export class AccountOperationRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountOperationRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AddressAliasTransaction.ts b/src/model/transaction/AddressAliasTransaction.ts index 04bfd3df5c..ea8f874a27 100644 --- a/src/model/transaction/AddressAliasTransaction.ts +++ b/src/model/transaction/AddressAliasTransaction.ts @@ -25,7 +25,7 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -189,10 +189,10 @@ export class AddressAliasTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AddressAliasTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index 391acbb95f..63e844f8d4 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -27,7 +27,7 @@ import { Hash256Dto } from '../../infrastructure/catbuffer/Hash256Dto'; import {KeyDto} from '../../infrastructure/catbuffer/KeyDto'; import {SignatureDto} from '../../infrastructure/catbuffer/SignatureDto'; import {TimestampDto} from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import {CreateTransactionFromPayload} from '../../infrastructure/transaction/CreateTransactionFromPayload'; import {Account} from '../account/Account'; import {PublicAccount} from '../account/PublicAccount'; @@ -405,10 +405,10 @@ export class AggregateTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AggregateTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { throw new Error('Not implemented'); } } diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index 52febc542a..1464784e88 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -17,7 +17,6 @@ import { Observable } from 'rxjs/internal/Observable'; import { of } from 'rxjs/internal/observable/of'; import { map } from 'rxjs/internal/operators/map'; -import { mergeMap } from 'rxjs/internal/operators/mergeMap'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -29,12 +28,14 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -211,39 +212,33 @@ export class LockFundsTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {LockFundsTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return of(this.mosaic).pipe( - mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( - map((mosaicId) => new LockFundsTransaction( + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.mosaic.id instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + return statementObservable.pipe( + map((statement) => new LockFundsTransaction( this.networkType, this.version, this.deadline, this.maxFee, - new Mosaic(mosaicId, mosaic.amount), + new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaic.id as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount), this.duration, this.signedTransaction, this.signature, this.signer, this.transactionInfo, )), - ) : - of(new LockFundsTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - mosaic, - this.duration, - this.signedTransaction, - this.signature, - this.signer, - this.transactionInfo, - )), - ), ); } } diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 2c42f6052b..e4095cb413 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -17,7 +17,8 @@ import { Observable } from 'rxjs/internal/Observable'; import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { of } from 'rxjs/internal/observable/of'; -import { Convert, RawAddress } from '../../core/format'; +import { map } from 'rxjs/internal/operators/map'; +import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { @@ -29,12 +30,14 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -240,17 +243,36 @@ export class MosaicAddressRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicAddressRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedAddress = this.targetAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.targetAddress as NamespaceId) : - of(this.targetAddress); + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.targetAddress instanceof NamespaceId || + this.mosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); - const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : - of(this.mosaicId); + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + const resolvedAddress = statementObservable.pipe( + map((statement) => this.targetAddress instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.targetAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + this.targetAddress, + ), + ); + + const resolvedMosaicId = statementObservable.pipe( + map((statement) => this.mosaicId instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + this.mosaicId, + ), + ); return combineLatest(resolvedAddress, resolvedMosaicId, (address, mosaicId) => { return new MosaicAddressRestrictionTransaction( diff --git a/src/model/transaction/MosaicAliasTransaction.ts b/src/model/transaction/MosaicAliasTransaction.ts index 56457b20e8..f1c9dd186d 100644 --- a/src/model/transaction/MosaicAliasTransaction.ts +++ b/src/model/transaction/MosaicAliasTransaction.ts @@ -25,7 +25,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -184,10 +184,10 @@ export class MosaicAliasTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicAliasTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/MosaicDefinitionTransaction.ts b/src/model/transaction/MosaicDefinitionTransaction.ts index 79ffe963d8..257073c695 100644 --- a/src/model/transaction/MosaicDefinitionTransaction.ts +++ b/src/model/transaction/MosaicDefinitionTransaction.ts @@ -27,7 +27,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { MosaicNonceDto } from '../../infrastructure/catbuffer/MosaicNonceDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicFlags } from '../mosaic/MosaicFlags'; @@ -227,10 +227,10 @@ export class MosaicDefinitionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicDefinitionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 05bfcb57b5..c2546c2056 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -16,6 +16,7 @@ import { combineLatest, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -27,11 +28,13 @@ import { MosaicGlobalRestrictionTransactionBuilder } from '../../infrastructure/ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { MosaicRestrictionType } from '../restriction/MosaicRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -249,17 +252,36 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicGlobalRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : - of(this.mosaicId); + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.mosaicId instanceof NamespaceId || + this.referenceMosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - const resolvedRefMosaicId = this.referenceMosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : - of(this.mosaicId); + const resolvedMosaicId = statementObservable.pipe( + map((statement) => this.mosaicId instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + this.mosaicId, + ), + ); + + const resolvedRefMosaicId = statementObservable.pipe( + map((statement) => this.referenceMosaicId instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.referenceMosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + this.referenceMosaicId, + ), + ); return combineLatest(resolvedMosaicId, resolvedRefMosaicId, (mosaicId, refMosaicId) => { return new MosaicGlobalRestrictionTransaction( diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index b99fb4e61b..c48c020ebb 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -26,11 +26,13 @@ import { MosaicMetadataTransactionBuilder } from '../../infrastructure/catbuffer import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -216,43 +218,37 @@ export class MosaicMetadataTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicMetadataTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return this.targetMosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.targetMosaicId as NamespaceId).pipe( - map((mosaicId) => { - return new MosaicMetadataTransaction( + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.targetMosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + return statementObservable.pipe( + map((statement) => new MosaicMetadataTransaction( this.networkType, this.version, this.deadline, this.maxFee, this.targetPublicKey, this.scopedMetadataKey, - mosaicId, + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.targetMosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.valueSizeDelta, this.value, this.signature, this.signer, this.transactionInfo, - ); - }), - ) : - of(new MosaicMetadataTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.targetPublicKey, - this.scopedMetadataKey, - this.targetMosaicId, - this.valueSizeDelta, - this.value, - this.signature, - this.signer, - this.transactionInfo, - ), - ); + ), + ), + ); } } diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index 348084157b..f927b249c6 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -26,12 +26,14 @@ import { MosaicSupplyChangeTransactionBuilder } from '../../infrastructure/catbu import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { MosaicSupplyChangeAction } from '../mosaic/MosaicSupplyChangeAction'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -190,19 +192,29 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicSupplyChangeTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return this.mosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId).pipe( - map((mosaicId) => { + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.mosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + return statementObservable.pipe( + map((statement) => { return new MosaicSupplyChangeTransaction( this.networkType, this.version, this.deadline, this.maxFee, - mosaicId, + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.action, this.delta, this.signature, @@ -210,19 +222,6 @@ export class MosaicSupplyChangeTransaction extends Transaction { this.transactionInfo, ); }), - ) : - of(new MosaicSupplyChangeTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.mosaicId, - this.action, - this.delta, - this.signature, - this.signer, - this.transactionInfo, - ), ); } } diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index 1393b159a0..7dae91c99f 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -27,6 +27,7 @@ import {MultisigAccountModificationTransactionBuilder, import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -218,10 +219,10 @@ export class MultisigAccountModificationTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MultisigAccountModificationTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/NamespaceMetadataTransaction.ts b/src/model/transaction/NamespaceMetadataTransaction.ts index 3198791bca..5b2645f701 100644 --- a/src/model/transaction/NamespaceMetadataTransaction.ts +++ b/src/model/transaction/NamespaceMetadataTransaction.ts @@ -25,6 +25,7 @@ import { NamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuf import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; @@ -214,10 +215,10 @@ export class NamespaceMetadataTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {NamespaceMetadataTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/NamespaceRegistrationTransaction.ts b/src/model/transaction/NamespaceRegistrationTransaction.ts index 341d07ca74..9130fbe2c2 100644 --- a/src/model/transaction/NamespaceRegistrationTransaction.ts +++ b/src/model/transaction/NamespaceRegistrationTransaction.ts @@ -27,7 +27,7 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceRegistrationTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceRegistrationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import {NamespaceMosaicIdGenerator} from '../../infrastructure/transaction/NamespaceMosaicIdGenerator'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -279,10 +279,10 @@ export class NamespaceRegistrationTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {NamespaceRegistrationTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index 92a5f0d339..c9fd2455c0 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -29,12 +29,15 @@ import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; +import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { HashType, HashTypeLengthValidator } from './HashType'; @@ -235,16 +238,38 @@ export class SecretLockTransaction extends Transaction { return transactionBuilder.serialize(); } - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : - of(this.recipientAddress); + /** + * @internal + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} + */ + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.recipientAddress instanceof NamespaceId || + this.mosaic.id instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); - const resolvedMosaic = this.mosaic instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.recipientAddress as NamespaceId).pipe( - map((mosaicId) => new Mosaic(mosaicId, this.mosaic.amount)), - ) : - of(this.mosaic); + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + const resolvedRecipient = statementObservable.pipe( + map((statement) => this.recipientAddress instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + this.recipientAddress, + ), + ); + + const resolvedMosaic = statementObservable.pipe( + map((statement) => this.mosaic.id instanceof NamespaceId ? + new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount) : + this.mosaic, + ), + ); return combineLatest(resolvedRecipient, resolvedMosaic, (recipient, mosaic) => { return new SecretLockTransaction( diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 7bb2cd65cf..33cc84ab21 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -17,7 +17,7 @@ import { Observable } from 'rxjs/internal/Observable'; import { of } from 'rxjs/internal/observable/of'; import { map } from 'rxjs/operators'; -import { Convert, Convert as convert, RawAddress } from '../../core/format'; +import { Convert, Convert as convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedSecretProofTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedSecretProofTransactionBuilder'; @@ -27,11 +27,13 @@ import { SecretProofTransactionBuilder } from '../../infrastructure/catbuffer/Se import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { HashType, HashTypeLengthValidator } from './HashType'; @@ -214,40 +216,35 @@ export class SecretProofTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {SecretProofTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return this.recipientAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId).pipe( - map((recipient) => { - return new SecretProofTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.hashType, - this.secret, - recipient, - this.proof, - this.signature, - this.signer, - this.transactionInfo, - ); - }), - ) : - of(new SecretProofTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.hashType, - this.secret, - this.recipientAddress, - this.proof, - this.signature, - this.signer, - this.transactionInfo, + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.recipientAddress instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + return statementObservable.pipe( + map((statement) => new SecretProofTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.hashType, + this.secret, + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address, + this.proof, + this.signature, + this.signer, + this.transactionInfo, + ), ), ); } diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index cdab1e54ef..2f53db47af 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -18,6 +18,7 @@ import { Observable } from 'rxjs'; import { KeyPair, SHA3Hasher, SignSchema } from '../../core/crypto'; import { Convert } from '../../core/format'; import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { SerializeTransactionToJSON } from '../../infrastructure/transaction/SerializeTransactionToJSON'; import { Account } from '../account/Account'; import { PublicAccount } from '../account/PublicAccount'; @@ -189,9 +190,9 @@ export abstract class Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp + * @param receiptHttp ReceiptHttp */ - abstract resolveAliases(namespaceHttp: NamespaceHttp): Observable; + abstract resolveAliases(receiptHttp: ReceiptHttp): Observable; /** * @internal @@ -391,4 +392,18 @@ export abstract class Transaction { const childClassObject = SerializeTransactionToJSON(this); return {transaction: Object.assign(commonTransactionObject, childClassObject)}; } + + /** + * @internal + * Check if index and height exists in transactionInfo + * @returns TransactionInfo + */ + protected checkTransactionHeightAndIndex(): TransactionInfo { + if (this.transactionInfo === undefined || + this.transactionInfo.height === undefined || + this.transactionInfo.index === undefined) { + throw new Error('Transaction height or index undefined'); + } + return this.transactionInfo; + } } diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index cda3cc0e55..241b5ccd22 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -15,9 +15,8 @@ */ import * as Long from 'long'; -import { combineLatest, from, Observable, of } from 'rxjs'; -import { map, toArray } from 'rxjs/operators'; -import { mergeMap} from 'rxjs/operators'; +import { combineLatest, Observable, of } from 'rxjs'; +import { map } from 'rxjs/operators'; import {Convert} from '../../core/format'; import {UnresolvedMapping} from '../../core/utils/UnresolvedMapping'; import {AmountDto} from '../../infrastructure/catbuffer/AmountDto'; @@ -30,7 +29,8 @@ import {TransferTransactionBuilder} from '../../infrastructure/catbuffer/Transfe import {UnresolvedAddressDto} from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import {UnresolvedMosaicBuilder} from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import {UnresolvedMosaicIdDto} from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import {Address} from '../account/Address'; import {PublicAccount} from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; @@ -39,7 +39,9 @@ import {Message} from '../message/Message'; import {MessageType} from '../message/MessageType'; import {PlainMessage} from '../message/PlainMessage'; import {Mosaic} from '../mosaic/Mosaic'; +import { MosaicId } from '../mosaic/MosaicId'; import {NamespaceId} from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import {UInt64} from '../UInt64'; import {Deadline} from './Deadline'; import {InnerTransaction} from './InnerTransaction'; @@ -47,7 +49,6 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; -import { flatMap } from 'rxjs/operators'; /** * Transfer transactions contain data about transfers of mosaics and message to another account. @@ -280,22 +281,38 @@ export class TransferTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp + * @param receiptHttp ReceiptHttp * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : - of(this.recipientAddress); + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.recipientAddress instanceof NamespaceId || + this.mosaics.find((mosaic) => mosaic.id instanceof NamespaceId) !== undefined; - const resolvedMosaics = from(this.mosaics).pipe( - mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( - map((mosaicId) => new Mosaic(mosaicId, mosaic.amount)), - ) : - of(mosaic), + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + const resolvedRecipient = statementObservable.pipe( + map((statement) => this.recipientAddress instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + this.recipientAddress, + ), + ); + + const resolvedMosaics = statementObservable.pipe( + map((statement) => + this.mosaics.map((mosaic) => + mosaic.id instanceof NamespaceId ? + new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, mosaic.id as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, mosaic.amount) : + mosaic, + ), ), - toArray(), ); return combineLatest(resolvedRecipient, resolvedMosaics, (recipient, mosaics) => { diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index ad8f8e2e0c..d657fe594d 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -15,9 +15,15 @@ */ import {Observable} from 'rxjs'; -import { flatMap, mergeMap, toArray} from 'rxjs/operators'; -import { NamespaceHttp } from '../infrastructure/NamespaceHttp'; +import { mergeMap, toArray} from 'rxjs/operators'; +import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; +import { Address } from '../model/account/Address'; +import { MosaicId } from '../model/mosaic/MosaicId'; +import { NamespaceId } from '../model/namespace/NamespaceId'; +import { ReceiptType } from '../model/receipt/ReceiptType'; +import { ResolutionType } from '../model/receipt/ResolutionType'; +import { Statement } from '../model/receipt/Statement'; import { Transaction } from '../model/transaction/Transaction'; /** @@ -26,14 +32,54 @@ import { Transaction } from '../model/transaction/Transaction'; export class TransactionService { private readonly transactionHttp: TransactionHttp; - private readonly namespaceHttp: NamespaceHttp; + private readonly receiptHttp: ReceiptHttp; /** * Constructor * @param url Base catapult-rest url */ constructor(url: string) { this.transactionHttp = new TransactionHttp(url); - this.namespaceHttp = new NamespaceHttp(url); + this.receiptHttp = new ReceiptHttp(url); + } + + /** + * @internal + * Extract resolved address | mosaic from block receipt + * @param resolutionType Resolution type: Address / Mosaic + * @param unresolved Unresolved address / mosaicId + * @param statement Block receipt statement + * @param transactionIndex Transaction index + * @param height Transaction height + * @returns {MosaicId | Address} + */ + public static getResolvedFromReceipt(resolutionType: ResolutionType, + unresolved: NamespaceId, + statement: Statement, + transactionIndex: number, + height: string): MosaicId | Address { + // Check if Harvest_Fee receipt exists on the block as it always takes the index 0. + const hasHarvestStatement = statement.transactionStatements + .find((transactionStatements) => transactionStatements.source.primaryId === 0 && + transactionStatements.receipts.find((receipt) => receipt.type === ReceiptType.Harvest_Fee) !== undefined) !== undefined; + + // Transaction index can be different if Harvest_Fee transaction exists. + transactionIndex = hasHarvestStatement ? transactionIndex + 1 : transactionIndex; + + const resolutionStatement = (resolutionType === ResolutionType.Address ? statement.addressResolutionStatements : + statement.mosaicResolutionStatements).find((resolution) => resolution.height.toString() === height && + (resolution.unresolved as NamespaceId).equals(unresolved)); + + if (!resolutionStatement) { + throw new Error('No resolution statement found'); + } + + const resolutionEntry = resolutionStatement.resolutionEntries.find((entry) => entry.source.primaryId === transactionIndex); + + if (!resolutionEntry) { + throw new Error('No resolution entry found'); + } + + return resolutionEntry.resolved; } /** @@ -43,7 +89,7 @@ export class TransactionService { public resolveAliases(transationHashes: string[]): Observable { return this.transactionHttp.getTransactions(transationHashes).pipe( mergeMap((_) => _), - flatMap((transaction) => transaction.resolveAliases(this.namespaceHttp)), + mergeMap((transaction) => transaction.resolveAliases(this.receiptHttp)), toArray(), ); } diff --git a/src/service/service.ts b/src/service/service.ts index 03554176a9..fd6074d5c4 100644 --- a/src/service/service.ts +++ b/src/service/service.ts @@ -19,3 +19,4 @@ export * from './MosaicService'; export * from './AggregateTransactionService'; export * from './MetadataTransactionService'; export * from './MosaicRestrictionTransactionService'; +export * from './TransactionService'; diff --git a/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts b/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts index 4152778bb0..8c38aa5651 100644 --- a/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts +++ b/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts @@ -23,6 +23,7 @@ import { NetworkType } from '../../../src/model/blockchain/NetworkType'; import { MosaicId } from '../../../src/model/mosaic/MosaicId'; import { AddressAlias } from '../../../src/model/namespace/AddressAlias'; import { MosaicAlias } from '../../../src/model/namespace/MosaicAlias'; +import { NamespaceId } from '../../../src/model/namespace/NamespaceId'; import { ReceiptType } from '../../../src/model/receipt/ReceiptType'; import { UInt64 } from '../../../src/model/UInt64'; @@ -122,8 +123,8 @@ describe('Receipt - CreateStatementFromDTO', () => { }); it('should create Statement', () => { const statement = CreateStatementFromDTO(statementDto, netWorkType); - const unresolvedAddress = statement.addressResolutionStatements[0].unresolved as Address; - const unresolvedMosaicId = statement.mosaicResolutionStatements[0].unresolved as MosaicId; + const unresolvedAddress = statement.addressResolutionStatements[0].unresolved as NamespaceId; + const unresolvedMosaicId = statement.mosaicResolutionStatements[0].unresolved as NamespaceId; expect(statement.transactionStatements.length).to.be.equal(1); expect(statement.addressResolutionStatements.length).to.be.equal(2); @@ -136,8 +137,7 @@ describe('Receipt - CreateStatementFromDTO', () => { expect(statement.transactionStatements[0].receipts[0].type).to.be.equal(ReceiptType.Harvest_Fee); deepEqual(statement.addressResolutionStatements[0].height, UInt64.fromNumericString('1488')); - deepEqual(unresolvedAddress.plain(), - Address.createFromEncoded('9103B60AAF2762688300000000000000000000000000000000').plain()); + deepEqual(unresolvedAddress.toHex(), '83686227AF0AB603'); expect(statement.addressResolutionStatements[0].resolutionEntries.length).to.be.equal(1); expect((statement.addressResolutionStatements[0].resolutionEntries[0].resolved as Address).plain()) .to.be.equal(Address.createFromEncoded('917E7E29A01014C2F300000000000000000000000000000000').plain()); diff --git a/test/model/receipt/Receipt.spec.ts b/test/model/receipt/Receipt.spec.ts index d689180a17..2b0bb8ca00 100644 --- a/test/model/receipt/Receipt.spec.ts +++ b/test/model/receipt/Receipt.spec.ts @@ -18,7 +18,7 @@ import { deepEqual } from 'assert'; import { expect } from 'chai'; import { CreateReceiptFromDTO, - CreateStatementFromDTO + CreateStatementFromDTO, } from '../../../src/infrastructure/receipt/CreateReceiptFromDTO'; import { Account } from '../../../src/model/account/Account'; import { Address } from '../../../src/model/account/Address'; @@ -354,7 +354,7 @@ describe('Receipt', () => { const statement = CreateStatementFromDTO(statementDTO, netWorkType); const receipt = statement.addressResolutionStatements[0]; const hash = receipt.generateHash(NetworkType.MAIN_NET); - expect(hash).to.be.equal('6967470641BC527768CDC29998F4A3350813FDF2E40D1C97AB0BBA36B9AF649E'); + expect(hash).to.be.equal('952225717E26295B97F9A35E719CA1319114CCF23C927BCBD14E7A7AA4BAC617'); }); it('should generate hash for TransactionStatement', () => { diff --git a/test/model/transaction/Transaction.spec.ts b/test/model/transaction/Transaction.spec.ts index c98bf76752..8395f95189 100644 --- a/test/model/transaction/Transaction.spec.ts +++ b/test/model/transaction/Transaction.spec.ts @@ -17,7 +17,7 @@ import { expect } from 'chai'; import { Observable } from 'rxjs/internal/Observable'; import { Convert } from '../../../src/core/format/Convert'; -import { NamespaceHttp } from '../../../src/infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../../src/infrastructure/ReceiptHttp'; import { Account } from '../../../src/model/account/Account'; import { Address } from '../../../src/model/account/Address'; import { NetworkType } from '../../../src/model/blockchain/NetworkType'; @@ -256,7 +256,6 @@ describe('Transaction', () => { // expected values const knownHash_sha3 = '709373248659274C5933BEA2920942D6C7B48B9C2DA4BAEE233510E71495931F'; - const knownHash_keccak = '787423372BEC0CB2BE3EEA58E773074E121989AF29E5E5BD9EE660C1E3A0AF93'; const generationHashBytes = Array.from(Convert.hexToUint8('988C4CDCE4D188013C13DE7914C7FD4D626169EF256722F61C52EFBE06BD5A2C')); const generationHashBytes_mt = Array.from(Convert.hexToUint8('17FA4747F5014B50413CCF968749604D728D7065DC504291EEE556899A534CBB')); @@ -405,7 +404,7 @@ class FakeTransaction extends Transaction { protected generateEmbeddedBytes(): Uint8Array { throw new Error('Not implemented'); } - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { throw new Error('Not implemented'); } } diff --git a/test/service/TransactionService.spec.ts b/test/service/TransactionService.spec.ts new file mode 100644 index 0000000000..30a8d1534c --- /dev/null +++ b/test/service/TransactionService.spec.ts @@ -0,0 +1,208 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { UnresolvedMapping } from '../../src/core/utils/UnresolvedMapping'; +import { CreateStatementFromDTO } from '../../src/infrastructure/receipt/CreateReceiptFromDTO'; +import { Account } from '../../src/model/account/Account'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { Address, MosaicId, NamespaceId, ResolutionType } from '../../src/model/model'; +import { TransactionService } from '../../src/service/TransactionService'; + +describe('TransactionService', () => { + let account: Account; + let transactionStatementsDTO; + let addressResolutionStatementsDTO; + let mosaicResolutionStatementsDTO; + let statementDTO; + + before(() => { + account = Account.createFromPrivateKey('81C18245507F9C15B61BDEDAFA2C10D9DC2C4E401E573A10935D45AA2A461FD5', NetworkType.MIJIN_TEST); + transactionStatementsDTO = [ + { + statement: { + height: '1473', + source: { + primaryId: 0, + secondaryId: 0, + }, + receipts: [ + { + version: 1, + type: 8515, + targetPublicKey: 'B2708D49C46F8AB5CDBD7A09C959EEA12E4A782592F3D1D3D17D54622E655D7F', + mosaicId: '504677C3281108DB', + amount: '0', + }, + ], + }, + }, + ]; + addressResolutionStatementsDTO = [ + { + statement: { + height: '1473', + unresolved: '9156258DE356F030A500000000000000000000000000000000', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '901D8D4741F80299E66BF7FEEB4F30943DA7B68E068B182319', + }, + ], + }, + }, + ]; + mosaicResolutionStatementsDTO = [ + { + statement: { + height: '1473', + unresolved: '85BBEA6CC462B244', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '504677C3281108DB', + }, + ], + }, + }, + { + statement: { + height: '1473', + unresolved: 'E81F622A5B11A340', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '756482FB80FD406C', + }, + ], + }, + }, + ]; + + statementDTO = { + transactionStatements: transactionStatementsDTO, + addressResolutionStatements: addressResolutionStatementsDTO, + mosaicResolutionStatements: mosaicResolutionStatementsDTO, + }; + }); + + it('should get reolved address from receipt', () => { + const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof Address).to.be.true; + expect((resolved as Address).equals(account.address)).to.be.true; + }); + + it('should get reolved address from receipt without Harvesting_Fee', () => { + const statementWithoutHarvesting = { + transactionStatements: [], + addressResolutionStatements: [ + { + statement: { + height: '1473', + unresolved: '9156258DE356F030A500000000000000000000000000000000', + resolutionEntries: [ + { + source: { + primaryId: 0, + secondaryId: 0, + }, + resolved: '901D8D4741F80299E66BF7FEEB4F30943DA7B68E068B182319', + }, + ], + }, + }, + ], + mosaicResolutionStatements: [], + }; + const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); + const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof Address).to.be.true; + expect((resolved as Address).equals(account.address)).to.be.true; + }); + + it('should get reolved mosaic from receipt', () => { + const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof MosaicId).to.be.true; + expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; + }); + + it('should get reolved mosaic from receipt without Harvesting_Fee', () => { + const statementWithoutHarvesting = { + transactionStatements: [], + addressResolutionStatements: [], + mosaicResolutionStatements: [ + { + statement: { + height: '1473', + unresolved: '85BBEA6CC462B244', + resolutionEntries: [ + { + source: { + primaryId: 0, + secondaryId: 0, + }, + resolved: '504677C3281108DB', + }, + ], + }, + }, + { + statement: { + height: '1473', + unresolved: 'E81F622A5B11A340', + resolutionEntries: [ + { + source: { + primaryId: 0, + secondaryId: 0, + }, + resolved: '756482FB80FD406C', + }, + ], + }, + }, + ], + }; + const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); + const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof MosaicId).to.be.true; + expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; + }); + +}); From 865bb0b651a0ec43cc12e7fc046ccbbc0a5a7d67 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 21:36:08 +0000 Subject: [PATCH 04/50] Added resolveAliases for AggregateTransaction --- src/model/transaction/AggregateTransaction.ts | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index 63e844f8d4..f79c447689 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { sha3_256 } from 'js-sha3'; import { Observable } from 'rxjs/internal/Observable'; import {KeyPair, MerkleHashBuilder, SHA3Hasher, SignSchema} from '../../core/crypto'; -import {Convert, RawArray} from '../../core/format'; +import {Convert} from '../../core/format'; import {AggregateBondedTransactionBuilder} from '../../infrastructure/catbuffer/AggregateBondedTransactionBuilder'; import {AggregateCompleteTransactionBuilder} from '../../infrastructure/catbuffer/AggregateCompleteTransactionBuilder'; import {AmountDto} from '../../infrastructure/catbuffer/AmountDto'; @@ -42,6 +41,8 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; +import { of, from } from 'rxjs'; +import { map, mergeMap, toArray } from 'rxjs/operators'; /** * Aggregate innerTransactions contain multiple innerTransactions that can be initiated by different accounts. @@ -409,6 +410,24 @@ export class AggregateTransaction extends Transaction { * @returns {TransferTransaction} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { - throw new Error('Not implemented'); + return from(this.innerTransactions).pipe( + mergeMap((transaction) => transaction.resolveAliases(receiptHttp)), + map((transaction) => transaction as InnerTransaction), + toArray(), + ).pipe( + map((innerTransactions) => new AggregateTransaction( + this.networkType, + this.type, + this.version, + this.deadline, + this.maxFee, + innerTransactions, + this.cosignatures, + this.signature, + this.signer, + this.transactionInfo, + ), + ), + ); } } From 638f14331e2a8a93d148917a2d55145e75be9f8b Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 22:02:02 +0000 Subject: [PATCH 05/50] Updated e2e tests with aggregated tx --- e2e/service/TransactionService.spec.ts | 72 ++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index e6520cf0b1..17b9fc19de 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -20,19 +20,23 @@ import { Listener } from '../../src/infrastructure/Listener'; import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; import { Account } from '../../src/model/account/Account'; +import { Address } from '../../src/model/account/Address'; import { NetworkType } from '../../src/model/blockchain/NetworkType'; import { PlainMessage } from '../../src/model/message/PlainMessage'; -import { Address, Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction } from '../../src/model/model'; +import { Mosaic } from '../../src/model/mosaic/Mosaic'; import { MosaicFlags } from '../../src/model/mosaic/MosaicFlags'; import { MosaicId } from '../../src/model/mosaic/MosaicId'; import { MosaicNonce } from '../../src/model/mosaic/MosaicNonce'; +import { MosaicSupplyChangeAction } from '../../src/model/mosaic/MosaicSupplyChangeAction'; import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; import { AliasAction } from '../../src/model/namespace/AliasAction'; import { NamespaceId } from '../../src/model/namespace/NamespaceId'; import { AddressAliasTransaction } from '../../src/model/transaction/AddressAliasTransaction'; +import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; import { Deadline } from '../../src/model/transaction/Deadline'; import { MosaicAliasTransaction } from '../../src/model/transaction/MosaicAliasTransaction'; import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicDefinitionTransaction'; +import { MosaicSupplyChangeTransaction } from '../../src/model/transaction/MosaicSupplyChangeTransaction'; import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; import { UInt64 } from '../../src/model/UInt64'; @@ -94,7 +98,7 @@ describe('TransactionService', () => { ); addressAlias = new NamespaceId(namespaceName); const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -126,7 +130,7 @@ describe('TransactionService', () => { ); mosaicAlias = new NamespaceId(namespaceName); const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -158,7 +162,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = addressAliasTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -193,7 +197,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicDefinitionTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -219,6 +223,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicSupplyChangeTransaction.signWith(account, generationHash); + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -250,7 +255,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicAliasTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -277,7 +282,7 @@ describe('TransactionService', () => { Deadline.create(), addressAlias, [ - // NetworkCurrencyMosaic.createAbsolute(1), //Seems get banned on rest if passing multiple mosaic alias in + NetworkCurrencyMosaic.createAbsolute(1), new Mosaic(mosaicAlias, UInt64.fromUint(1)), ], PlainMessage.create('test-message'), @@ -298,13 +303,60 @@ describe('TransactionService', () => { transactionHttp.announce(signedTransaction); }); }); + + describe('Create Aggreate TransferTransaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('aggregate', (done) => { + const transferTransaction = TransferTransaction.create( + Deadline.create(), + addressAlias, + [ + NetworkCurrencyMosaic.createAbsolute(1), + new Mosaic(mosaicAlias, UInt64.fromUint(1)), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [transferTransaction.toAggregate(account.publicAccount)], + NetworkType.MIJIN_TEST, + [], + ); + const signedTransaction = aggregateTransaction.signWith(account, generationHash); + transactionHashes.push(signedTransaction.hash); + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); describe('should return resolved transaction', () => { it('call transaction service', (done) => { const transactionService = new TransactionService(url); return transactionService.resolveAliases(transactionHashes).subscribe((transactions) => { - transactions.map((tx: TransferTransaction) => { - expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); - expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + expect(transactions.length).to.be.equal(8); + transactions.map((tx) => { + if (tx instanceof TransferTransaction) { + expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); + expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + } else if (tx instanceof AggregateTransaction) { + expect(((tx.innerTransactions[0] as TransferTransaction).recipientAddress as Address) + .plain()).to.be.equal(account.address.plain()); + expect((tx.innerTransactions[0] as TransferTransaction).mosaics + .find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + } }); done(); }); From b5b20e127180b404cfc6b2ec349d35a3bc7b2ceb Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 22:20:22 +0000 Subject: [PATCH 06/50] Fixed jsdoc issues --- e2e/service/TransactionService.spec.ts | 7 +++++++ .../transaction/AccountAddressRestrictionTransaction.ts | 2 +- src/model/transaction/AccountLinkTransaction.ts | 2 +- src/model/transaction/AccountMetadataTransaction.ts | 2 +- .../transaction/AccountMosaicRestrictionTransaction.ts | 2 +- .../transaction/AccountOperationRestrictionTransaction.ts | 2 +- src/model/transaction/AddressAliasTransaction.ts | 2 +- src/model/transaction/AggregateTransaction.ts | 2 +- src/model/transaction/LockFundsTransaction.ts | 2 +- .../transaction/MosaicAddressRestrictionTransaction.ts | 2 +- src/model/transaction/MosaicAliasTransaction.ts | 2 +- src/model/transaction/MosaicDefinitionTransaction.ts | 2 +- .../transaction/MosaicGlobalRestrictionTransaction.ts | 2 +- src/model/transaction/MosaicMetadataTransaction.ts | 2 +- src/model/transaction/MosaicSupplyChangeTransaction.ts | 2 +- .../transaction/MultisigAccountModificationTransaction.ts | 2 +- src/model/transaction/NamespaceMetadataTransaction.ts | 2 +- src/model/transaction/NamespaceRegistrationTransaction.ts | 2 +- src/model/transaction/SecretLockTransaction.ts | 2 +- src/model/transaction/SecretProofTransaction.ts | 2 +- src/model/transaction/Transaction.ts | 1 + src/model/transaction/TransferTransaction.ts | 2 +- 22 files changed, 28 insertions(+), 20 deletions(-) diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index 17b9fc19de..6669cf162d 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -342,6 +342,13 @@ describe('TransactionService', () => { transactionHttp.announce(signedTransaction); }); }); + + /** + * ========================= + * Test + * ========================= + */ + describe('should return resolved transaction', () => { it('call transaction service', (done) => { const transactionService = new TransactionService(url); diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 05960c8667..5c8d3886ae 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -199,7 +199,7 @@ export class AccountAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || diff --git a/src/model/transaction/AccountLinkTransaction.ts b/src/model/transaction/AccountLinkTransaction.ts index bbfa101882..e1cb514b44 100644 --- a/src/model/transaction/AccountLinkTransaction.ts +++ b/src/model/transaction/AccountLinkTransaction.ts @@ -170,7 +170,7 @@ export class AccountLinkTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AccountMetadataTransaction.ts b/src/model/transaction/AccountMetadataTransaction.ts index 2e41cde6ff..b5e4a40558 100644 --- a/src/model/transaction/AccountMetadataTransaction.ts +++ b/src/model/transaction/AccountMetadataTransaction.ts @@ -200,7 +200,7 @@ export class AccountMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index 0fa304b41c..d0f3a63e19 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -199,7 +199,7 @@ export class AccountMosaicRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || diff --git a/src/model/transaction/AccountOperationRestrictionTransaction.ts b/src/model/transaction/AccountOperationRestrictionTransaction.ts index e38165001e..b8086f56b0 100644 --- a/src/model/transaction/AccountOperationRestrictionTransaction.ts +++ b/src/model/transaction/AccountOperationRestrictionTransaction.ts @@ -181,7 +181,7 @@ export class AccountOperationRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AddressAliasTransaction.ts b/src/model/transaction/AddressAliasTransaction.ts index ea8f874a27..20696aa65f 100644 --- a/src/model/transaction/AddressAliasTransaction.ts +++ b/src/model/transaction/AddressAliasTransaction.ts @@ -190,7 +190,7 @@ export class AddressAliasTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index f79c447689..f89904787f 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -407,7 +407,7 @@ export class AggregateTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return from(this.innerTransactions).pipe( diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index 1464784e88..4a6ede77b2 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -213,7 +213,7 @@ export class LockFundsTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.mosaic.id instanceof NamespaceId; diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index e4095cb413..13f7935918 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -244,7 +244,7 @@ export class MosaicAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.targetAddress instanceof NamespaceId || diff --git a/src/model/transaction/MosaicAliasTransaction.ts b/src/model/transaction/MosaicAliasTransaction.ts index f1c9dd186d..50ef6548c3 100644 --- a/src/model/transaction/MosaicAliasTransaction.ts +++ b/src/model/transaction/MosaicAliasTransaction.ts @@ -185,7 +185,7 @@ export class MosaicAliasTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/MosaicDefinitionTransaction.ts b/src/model/transaction/MosaicDefinitionTransaction.ts index 257073c695..69eb9782c2 100644 --- a/src/model/transaction/MosaicDefinitionTransaction.ts +++ b/src/model/transaction/MosaicDefinitionTransaction.ts @@ -228,7 +228,7 @@ export class MosaicDefinitionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index c2546c2056..4542567cc2 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -253,7 +253,7 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId || diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index c48c020ebb..952870a23c 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -219,7 +219,7 @@ export class MosaicMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.targetMosaicId instanceof NamespaceId; diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index f927b249c6..1f27366824 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -193,7 +193,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId; diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index 7dae91c99f..2d7a64d866 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -220,7 +220,7 @@ export class MultisigAccountModificationTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/NamespaceMetadataTransaction.ts b/src/model/transaction/NamespaceMetadataTransaction.ts index 5b2645f701..29ee8a8948 100644 --- a/src/model/transaction/NamespaceMetadataTransaction.ts +++ b/src/model/transaction/NamespaceMetadataTransaction.ts @@ -216,7 +216,7 @@ export class NamespaceMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/NamespaceRegistrationTransaction.ts b/src/model/transaction/NamespaceRegistrationTransaction.ts index 9130fbe2c2..ed631a043c 100644 --- a/src/model/transaction/NamespaceRegistrationTransaction.ts +++ b/src/model/transaction/NamespaceRegistrationTransaction.ts @@ -280,7 +280,7 @@ export class NamespaceRegistrationTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index c9fd2455c0..66a47b877d 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -241,7 +241,7 @@ export class SecretLockTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 33cc84ab21..99dcb374fc 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -217,7 +217,7 @@ export class SecretProofTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId; diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index 2f53db47af..c83ed25e3d 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -191,6 +191,7 @@ export abstract class Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @returns {Observable} */ abstract resolveAliases(receiptHttp: ReceiptHttp): Observable; diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index 241b5ccd22..dfa4aa66d8 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -282,7 +282,7 @@ export class TransferTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || From 903db08e6f00506f82375ba983d1038457bd4f79 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 2 Dec 2019 09:41:31 +0000 Subject: [PATCH 07/50] - Fixed primary source id as confirmed by Jag - Updated aggregate transaction handler with secondary source id --- .../AccountAddressRestrictionTransaction.ts | 7 ++++--- .../AccountMosaicRestrictionTransaction.ts | 7 ++++--- src/model/transaction/AggregateTransaction.ts | 7 ++++--- src/model/transaction/LockFundsTransaction.ts | 6 ++++-- .../MosaicAddressRestrictionTransaction.ts | 7 ++++--- .../MosaicGlobalRestrictionTransaction.ts | 7 ++++--- .../transaction/MosaicMetadataTransaction.ts | 5 +++-- .../MosaicSupplyChangeTransaction.ts | 5 +++-- .../MultisigAccountModificationTransaction.ts | 2 +- src/model/transaction/SecretLockTransaction.ts | 8 +++++--- src/model/transaction/SecretProofTransaction.ts | 5 +++-- src/model/transaction/Transaction.ts | 3 ++- src/model/transaction/TransferTransaction.ts | 8 +++++--- src/service/TransactionService.ts | 17 ++++++++--------- test/model/transaction/Transaction.spec.ts | 2 +- test/service/TransactionService.spec.ts | 6 +++--- 16 files changed, 58 insertions(+), 44 deletions(-) diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 5c8d3886ae..4566a36068 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -199,9 +199,10 @@ export class AccountAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || this.restrictionDeletions.find((address) => address instanceof NamespaceId) !== undefined; @@ -217,7 +218,7 @@ export class AccountAddressRestrictionTransaction extends Transaction { return this.restrictionAdditions.map((addition) => { return addition instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, addition as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : addition; }); }), @@ -228,7 +229,7 @@ export class AccountAddressRestrictionTransaction extends Transaction { return this.restrictionDeletions.map((deletion) => { return deletion instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, deletion as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : deletion; }); }), diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index d0f3a63e19..cbfab8525c 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -199,9 +199,10 @@ export class AccountMosaicRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || this.restrictionDeletions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined; @@ -217,7 +218,7 @@ export class AccountMosaicRestrictionTransaction extends Transaction { return this.restrictionAdditions.map((addition) => { return addition instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, addition as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : addition; }); }), @@ -228,7 +229,7 @@ export class AccountMosaicRestrictionTransaction extends Transaction { return this.restrictionDeletions.map((deletion) => { return deletion instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, deletion as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : deletion; }); }), diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index f89904787f..90c069e093 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -14,7 +14,9 @@ * limitations under the License. */ +import { from, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; +import { map, mergeMap, toArray } from 'rxjs/operators'; import {KeyPair, MerkleHashBuilder, SHA3Hasher, SignSchema} from '../../core/crypto'; import {Convert} from '../../core/format'; import {AggregateBondedTransactionBuilder} from '../../infrastructure/catbuffer/AggregateBondedTransactionBuilder'; @@ -41,8 +43,6 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; -import { of, from } from 'rxjs'; -import { map, mergeMap, toArray } from 'rxjs/operators'; /** * Aggregate innerTransactions contain multiple innerTransactions that can be initiated by different accounts. @@ -410,8 +410,9 @@ export class AggregateTransaction extends Transaction { * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { + const transactionInfo = this.checkTransactionHeightAndIndex(); return from(this.innerTransactions).pipe( - mergeMap((transaction) => transaction.resolveAliases(receiptHttp)), + mergeMap((transaction) => transaction.resolveAliases(receiptHttp, transactionInfo.index)), map((transaction) => transaction as InnerTransaction), toArray(), ).pipe( diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index 4a6ede77b2..e902ccf86f 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -213,9 +213,10 @@ export class LockFundsTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.mosaic.id instanceof NamespaceId; if (!hasUnresolved) { @@ -232,7 +233,8 @@ export class LockFundsTransaction extends Transaction { this.deadline, this.maxFee, new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaic.id as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount), + statement, transactionInfo.index, transactionInfo.height.toString(), + aggregateTransactionIndex) as MosaicId, this.mosaic.amount), this.duration, this.signedTransaction, this.signature, diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 13f7935918..57c6213344 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -244,9 +244,10 @@ export class MosaicAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.targetAddress instanceof NamespaceId || this.mosaicId instanceof NamespaceId; @@ -261,7 +262,7 @@ export class MosaicAddressRestrictionTransaction extends Transaction { const resolvedAddress = statementObservable.pipe( map((statement) => this.targetAddress instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.targetAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.targetAddress, ), ); @@ -269,7 +270,7 @@ export class MosaicAddressRestrictionTransaction extends Transaction { const resolvedMosaicId = statementObservable.pipe( map((statement) => this.mosaicId instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.mosaicId, ), ); diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 4542567cc2..39b5078252 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -253,9 +253,10 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId || this.referenceMosaicId instanceof NamespaceId; @@ -270,7 +271,7 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { const resolvedMosaicId = statementObservable.pipe( map((statement) => this.mosaicId instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.mosaicId, ), ); @@ -278,7 +279,7 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { const resolvedRefMosaicId = statementObservable.pipe( map((statement) => this.referenceMosaicId instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.referenceMosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.referenceMosaicId, ), ); diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index 952870a23c..8cc77ba69d 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -219,9 +219,10 @@ export class MosaicMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.targetMosaicId instanceof NamespaceId; if (!hasUnresolved) { @@ -241,7 +242,7 @@ export class MosaicMetadataTransaction extends Transaction { this.targetPublicKey, this.scopedMetadataKey, TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.targetMosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.valueSizeDelta, this.value, this.signature, diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index 1f27366824..db17c7ce2f 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -193,9 +193,10 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId; if (!hasUnresolved) { @@ -214,7 +215,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { this.deadline, this.maxFee, TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.action, this.delta, this.signature, diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index 2d7a64d866..cce5c9f6e0 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -220,7 +220,7 @@ export class MultisigAccountModificationTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {Observable + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index 66a47b877d..6fb5c0de90 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -241,9 +241,10 @@ export class SecretLockTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || this.mosaic.id instanceof NamespaceId; @@ -258,7 +259,7 @@ export class SecretLockTransaction extends Transaction { const resolvedRecipient = statementObservable.pipe( map((statement) => this.recipientAddress instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.recipientAddress, ), ); @@ -266,7 +267,8 @@ export class SecretLockTransaction extends Transaction { const resolvedMosaic = statementObservable.pipe( map((statement) => this.mosaic.id instanceof NamespaceId ? new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount) : + statement, transactionInfo.index, transactionInfo.height.toString(), + aggregateTransactionIndex) as MosaicId, this.mosaic.amount) : this.mosaic, ), ); diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 99dcb374fc..f97fca4d30 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -217,9 +217,10 @@ export class SecretProofTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId; if (!hasUnresolved) { @@ -239,7 +240,7 @@ export class SecretProofTransaction extends Transaction { this.hashType, this.secret, TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address, + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address, this.proof, this.signature, this.signer, diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index c83ed25e3d..0af948d992 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -191,9 +191,10 @@ export abstract class Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param AggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - abstract resolveAliases(receiptHttp: ReceiptHttp): Observable; + abstract resolveAliases(receiptHttp: ReceiptHttp, AggregateTransactionIndex?: number): Observable; /** * @internal diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index dfa4aa66d8..7c3181f31e 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -282,9 +282,10 @@ export class TransferTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || this.mosaics.find((mosaic) => mosaic.id instanceof NamespaceId) !== undefined; @@ -299,7 +300,7 @@ export class TransferTransaction extends Transaction { const resolvedRecipient = statementObservable.pipe( map((statement) => this.recipientAddress instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.recipientAddress, ), ); @@ -309,7 +310,8 @@ export class TransferTransaction extends Transaction { this.mosaics.map((mosaic) => mosaic.id instanceof NamespaceId ? new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, mosaic.id as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, mosaic.amount) : + statement, transactionInfo.index, transactionInfo.height.toString(), + aggregateTransactionIndex) as MosaicId, mosaic.amount) : mosaic, ), ), diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index d657fe594d..f733c58405 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -50,20 +50,15 @@ export class TransactionService { * @param statement Block receipt statement * @param transactionIndex Transaction index * @param height Transaction height + * @param aggregateTransactionIndex Transaction index for aggregate * @returns {MosaicId | Address} */ public static getResolvedFromReceipt(resolutionType: ResolutionType, unresolved: NamespaceId, statement: Statement, transactionIndex: number, - height: string): MosaicId | Address { - // Check if Harvest_Fee receipt exists on the block as it always takes the index 0. - const hasHarvestStatement = statement.transactionStatements - .find((transactionStatements) => transactionStatements.source.primaryId === 0 && - transactionStatements.receipts.find((receipt) => receipt.type === ReceiptType.Harvest_Fee) !== undefined) !== undefined; - - // Transaction index can be different if Harvest_Fee transaction exists. - transactionIndex = hasHarvestStatement ? transactionIndex + 1 : transactionIndex; + height: string, + aggregateTransactionIndex?: number): MosaicId | Address { const resolutionStatement = (resolutionType === ResolutionType.Address ? statement.addressResolutionStatements : statement.mosaicResolutionStatements).find((resolution) => resolution.height.toString() === height && @@ -73,7 +68,11 @@ export class TransactionService { throw new Error('No resolution statement found'); } - const resolutionEntry = resolutionStatement.resolutionEntries.find((entry) => entry.source.primaryId === transactionIndex); + // source (0,0) is reserved for blocks, source (n, 0) is for txes, where n is 1-based index + const resolutionEntry = resolutionStatement.resolutionEntries + .find((entry) => entry.source.primaryId === + (aggregateTransactionIndex ? aggregateTransactionIndex + 1 : transactionIndex + 1) && + entry.source.secondaryId === (aggregateTransactionIndex ? transactionIndex : 0)); if (!resolutionEntry) { throw new Error('No resolution entry found'); diff --git a/test/model/transaction/Transaction.spec.ts b/test/model/transaction/Transaction.spec.ts index 8395f95189..b86267517f 100644 --- a/test/model/transaction/Transaction.spec.ts +++ b/test/model/transaction/Transaction.spec.ts @@ -404,7 +404,7 @@ class FakeTransaction extends Transaction { protected generateEmbeddedBytes(): Uint8Array { throw new Error('Not implemented'); } - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { throw new Error('Not implemented'); } } diff --git a/test/service/TransactionService.spec.ts b/test/service/TransactionService.spec.ts index 30a8d1534c..d4071b43b7 100644 --- a/test/service/TransactionService.spec.ts +++ b/test/service/TransactionService.spec.ts @@ -129,7 +129,7 @@ describe('TransactionService', () => { resolutionEntries: [ { source: { - primaryId: 0, + primaryId: 1, secondaryId: 0, }, resolved: '901D8D4741F80299E66BF7FEEB4F30943DA7B68E068B182319', @@ -171,7 +171,7 @@ describe('TransactionService', () => { resolutionEntries: [ { source: { - primaryId: 0, + primaryId: 1, secondaryId: 0, }, resolved: '504677C3281108DB', @@ -186,7 +186,7 @@ describe('TransactionService', () => { resolutionEntries: [ { source: { - primaryId: 0, + primaryId: 1, secondaryId: 0, }, resolved: '756482FB80FD406C', From 404e0165fdebee541a8f1a6a0bd577d0dcfa5e37 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 2 Dec 2019 10:15:46 +0000 Subject: [PATCH 08/50] Fixed bug in transaction service --- src/service/TransactionService.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index f733c58405..952e78b6b0 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -67,12 +67,11 @@ export class TransactionService { if (!resolutionStatement) { throw new Error('No resolution statement found'); } - // source (0,0) is reserved for blocks, source (n, 0) is for txes, where n is 1-based index const resolutionEntry = resolutionStatement.resolutionEntries .find((entry) => entry.source.primaryId === - (aggregateTransactionIndex ? aggregateTransactionIndex + 1 : transactionIndex + 1) && - entry.source.secondaryId === (aggregateTransactionIndex ? transactionIndex : 0)); + (aggregateTransactionIndex !== undefined ? aggregateTransactionIndex + 1 : transactionIndex + 1) && + entry.source.secondaryId === (aggregateTransactionIndex !== undefined ? transactionIndex + 1 : 0)); if (!resolutionEntry) { throw new Error('No resolution entry found'); From c9415f93856deea959151b6adc97b898a66e6afa Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 2 Dec 2019 12:19:13 +0000 Subject: [PATCH 09/50] Sort aggregate inner transactions to original order --- e2e/service/TransactionService.spec.ts | 67 ++++++++++++++++++- src/model/transaction/AggregateTransaction.ts | 2 +- src/service/TransactionService.ts | 1 - 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index 6669cf162d..1812a12cad 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -16,6 +16,7 @@ import { assert } from 'chai'; import { expect } from 'chai'; +import { Convert } from '../../src/core/format/Convert'; import { Listener } from '../../src/infrastructure/Listener'; import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; @@ -36,6 +37,7 @@ import { AggregateTransaction } from '../../src/model/transaction/AggregateTrans import { Deadline } from '../../src/model/transaction/Deadline'; import { MosaicAliasTransaction } from '../../src/model/transaction/MosaicAliasTransaction'; import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicDefinitionTransaction'; +import { MosaicMetadataTransaction } from '../../src/model/transaction/MosaicMetadataTransaction'; import { MosaicSupplyChangeTransaction } from '../../src/model/transaction/MosaicSupplyChangeTransaction'; import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; @@ -51,6 +53,7 @@ describe('TransactionService', () => { let addressAlias: NamespaceId; let mosaicAlias: NamespaceId; let mosaicId: MosaicId; + let newMosaicId: MosaicId; let transactionHttp: TransactionHttp; let config; let transactionHashes: string[]; @@ -125,7 +128,7 @@ describe('TransactionService', () => { const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( Deadline.create(), namespaceName, - UInt64.fromUint(9), + UInt64.fromUint(20), NetworkType.MIJIN_TEST, ); mosaicAlias = new NamespaceId(namespaceName); @@ -304,6 +307,12 @@ describe('TransactionService', () => { }); }); + /** + * ===================================== + * Setup test aggregate transaction data + * ===================================== + */ + describe('Create Aggreate TransferTransaction', () => { let listener: Listener; before (() => { @@ -324,8 +333,56 @@ describe('TransactionService', () => { PlainMessage.create('test-message'), NetworkType.MIJIN_TEST, ); + // Unlink MosaicAlias + const mosaicAliasTransactionUnlink = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Unlink, + mosaicAlias, + mosaicId, + NetworkType.MIJIN_TEST, + ); + + // Create a new Mosaic + const nonce = MosaicNonce.createRandom(); + newMosaicId = MosaicId.createFromNonce(nonce, account.publicAccount); + const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( + Deadline.create(), + nonce, + newMosaicId, + MosaicFlags.create(true, true, false), + 3, + UInt64.fromUint(0), + NetworkType.MIJIN_TEST, + ); + + // Link namespace with new MosaicId + const mosaicAliasTransactionRelink = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Link, + mosaicAlias, + newMosaicId, + NetworkType.MIJIN_TEST, + ); + + // Use new mosaicAlias in metadata + const mosaicMetadataTransaction = MosaicMetadataTransaction.create( + Deadline.create(), + account.publicKey, + UInt64.fromUint(5), + mosaicAlias, + 10, + Convert.uint8ToUtf8(new Uint8Array(10)), + NetworkType.MIJIN_TEST, + ); const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), - [transferTransaction.toAggregate(account.publicAccount)], + [ + transferTransaction.toAggregate(account.publicAccount), + mosaicAliasTransactionUnlink.toAggregate(account.publicAccount), + mosaicDefinitionTransaction.toAggregate(account.publicAccount), + mosaicAliasTransactionRelink.toAggregate(account.publicAccount), + mosaicMetadataTransaction.toAggregate(account.publicAccount), + + ], NetworkType.MIJIN_TEST, [], ); @@ -359,13 +416,17 @@ describe('TransactionService', () => { expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); } else if (tx instanceof AggregateTransaction) { + expect(tx.innerTransactions.length).to.be.equal(5); + // Assert Transfer expect(((tx.innerTransactions[0] as TransferTransaction).recipientAddress as Address) .plain()).to.be.equal(account.address.plain()); expect((tx.innerTransactions[0] as TransferTransaction).mosaics .find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + // Assert MosaicMeta + expect((tx.innerTransactions[4] as MosaicMetadataTransaction) + .targetMosaicId.toHex() === newMosaicId.toHex()).to.be.true; } }); - done(); }); }); }); diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index 90c069e093..98e6874626 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -422,7 +422,7 @@ export class AggregateTransaction extends Transaction { this.version, this.deadline, this.maxFee, - innerTransactions, + innerTransactions.sort((a, b) => a.transactionInfo!.index - b.transactionInfo!.index), this.cosignatures, this.signature, this.signer, diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 952e78b6b0..46fd5d84a9 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -21,7 +21,6 @@ import { TransactionHttp } from '../infrastructure/TransactionHttp'; import { Address } from '../model/account/Address'; import { MosaicId } from '../model/mosaic/MosaicId'; import { NamespaceId } from '../model/namespace/NamespaceId'; -import { ReceiptType } from '../model/receipt/ReceiptType'; import { ResolutionType } from '../model/receipt/ResolutionType'; import { Statement } from '../model/receipt/Statement'; import { Transaction } from '../model/transaction/Transaction'; From 7aa54cb805d1adcb7da707769e7c2febc3588c8d Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 28 Nov 2019 19:50:39 +0000 Subject: [PATCH 10/50] added #357 transaction service for resolving alias --- .../transaction/CreateTransactionFromDTO.ts | 2 +- .../AccountAddressRestrictionTransaction.ts | 44 ++++++++++++++- .../transaction/AccountLinkTransaction.ts | 12 +++++ .../transaction/AccountMetadataTransaction.ts | 12 +++++ .../AccountMosaicRestrictionTransaction.ts | 41 ++++++++++++++ .../AccountOperationRestrictionTransaction.ts | 12 +++++ .../transaction/AddressAliasTransaction.ts | 12 +++++ src/model/transaction/AggregateTransaction.ts | 11 ++++ src/model/transaction/LockFundsTransaction.ts | 46 ++++++++++++++++ .../MosaicAddressRestrictionTransaction.ts | 36 +++++++++++++ .../transaction/MosaicAliasTransaction.ts | 12 +++++ .../MosaicDefinitionTransaction.ts | 12 +++++ .../MosaicGlobalRestrictionTransaction.ts | 37 +++++++++++++ .../transaction/MosaicMetadataTransaction.ts | 46 ++++++++++++++++ .../MosaicSupplyChangeTransaction.ts | 54 +++++++++++++++++-- .../MultisigAccountModificationTransaction.ts | 13 ++++- .../NamespaceMetadataTransaction.ts | 12 +++++ .../NamespaceRegistrationTransaction.ts | 12 +++++ .../transaction/SecretLockTransaction.ts | 36 ++++++++++++- .../transaction/SecretProofTransaction.ts | 44 +++++++++++++++ src/model/transaction/Transaction.ts | 8 +++ src/model/transaction/TransferTransaction.ts | 43 ++++++++++++++- src/service/TransactionService.ts | 50 +++++++++++++++++ test/model/transaction/Transaction.spec.ts | 7 ++- 24 files changed, 601 insertions(+), 13 deletions(-) create mode 100644 src/service/TransactionService.ts diff --git a/src/infrastructure/transaction/CreateTransactionFromDTO.ts b/src/infrastructure/transaction/CreateTransactionFromDTO.ts index ea6e1802c2..c7bada7ca1 100644 --- a/src/infrastructure/transaction/CreateTransactionFromDTO.ts +++ b/src/infrastructure/transaction/CreateTransactionFromDTO.ts @@ -175,7 +175,7 @@ const CreateStandaloneTransactionFromDTO = (transactionDTO, transactionInfo): Tr transactionDTO.version, Deadline.createFromDTO(transactionDTO.deadline), UInt64.fromNumericString(transactionDTO.maxFee || '0'), - new MosaicId(transactionDTO.mosaicId), + UnresolvedMapping.toUnresolvedMosaic(transactionDTO.mosaicId), transactionDTO.action, UInt64.fromNumericString(transactionDTO.delta), transactionDTO.signature, diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 90a513ee1a..0901889381 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { Convert, RawAddress } from '../../core/format'; +import { combineLatest, from, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { mergeMap, toArray } from 'rxjs/operators'; +import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountAddressRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountAddressRestrictionTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -25,13 +28,13 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; -import { AccountRestrictionModification } from './AccountRestrictionModification'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; import { Transaction } from './Transaction'; @@ -190,4 +193,41 @@ export class AccountAddressRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountAddressRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const restrictionAdditions = from(this.restrictionAdditions).pipe( + mergeMap((addition) => addition instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(addition) : + of(addition), + ), + toArray(), + ); + const restrictionDeletions = from(this.restrictionDeletions).pipe( + mergeMap((deletion) => deletion instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(deletion) : + of(deletion), + ), + toArray(), + ); + + return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { + return new AccountAddressRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.restrictionFlags, + additions, + deletions, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/AccountLinkTransaction.ts b/src/model/transaction/AccountLinkTransaction.ts index b5c2aa9308..d89d376c89 100644 --- a/src/model/transaction/AccountLinkTransaction.ts +++ b/src/model/transaction/AccountLinkTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountLinkTransactionBuilder } from '../../infrastructure/catbuffer/AccountLinkTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -21,6 +23,7 @@ import { EmbeddedAccountLinkTransactionBuilder } from '../../infrastructure/catb import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -163,4 +166,13 @@ export class AccountLinkTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountLinkTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AccountMetadataTransaction.ts b/src/model/transaction/AccountMetadataTransaction.ts index bbfc10c435..5f09acceb6 100644 --- a/src/model/transaction/AccountMetadataTransaction.ts +++ b/src/model/transaction/AccountMetadataTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountMetadataTransactionBuilder } from '../../infrastructure/catbuffer/AccountMetadataTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -21,6 +23,7 @@ import { EmbeddedAccountMetadataTransactionBuilder } from '../../infrastructure/ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -193,4 +196,13 @@ export class AccountMetadataTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountMetadataTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index 20bba4d76b..af134a61bb 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { combineLatest, from, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { mergeMap, toArray } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountMosaicRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountMosaicRestrictionTransactionBuilder'; @@ -25,6 +28,7 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -189,4 +193,41 @@ export class AccountMosaicRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountMosaicRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const restrictionAdditions = from(this.restrictionAdditions).pipe( + mergeMap((addition) => addition instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(addition) : + of(addition), + ), + toArray(), + ); + const restrictionDeletions = from(this.restrictionDeletions).pipe( + mergeMap((deletion) => deletion instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(deletion) : + of(deletion), + ), + toArray(), + ); + + return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { + return new AccountMosaicRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.restrictionFlags, + additions, + deletions, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/AccountOperationRestrictionTransaction.ts b/src/model/transaction/AccountOperationRestrictionTransaction.ts index 53661b6db4..a7a4181524 100644 --- a/src/model/transaction/AccountOperationRestrictionTransaction.ts +++ b/src/model/transaction/AccountOperationRestrictionTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountOperationRestrictionTransactionBuilder, @@ -25,6 +27,7 @@ import { import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; @@ -174,4 +177,13 @@ export class AccountOperationRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AccountOperationRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AddressAliasTransaction.ts b/src/model/transaction/AddressAliasTransaction.ts index 14b18f2c16..04bfd3df5c 100644 --- a/src/model/transaction/AddressAliasTransaction.ts +++ b/src/model/transaction/AddressAliasTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert, RawAddress } from '../../core/format'; import { AddressAliasTransactionBuilder } from '../../infrastructure/catbuffer/AddressAliasTransactionBuilder'; import { AddressDto } from '../../infrastructure/catbuffer/AddressDto'; @@ -23,6 +25,7 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -183,4 +186,13 @@ export class AddressAliasTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AddressAliasTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index a7ea36d201..391acbb95f 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -15,6 +15,7 @@ */ import { sha3_256 } from 'js-sha3'; +import { Observable } from 'rxjs/internal/Observable'; import {KeyPair, MerkleHashBuilder, SHA3Hasher, SignSchema} from '../../core/crypto'; import {Convert, RawArray} from '../../core/format'; import {AggregateBondedTransactionBuilder} from '../../infrastructure/catbuffer/AggregateBondedTransactionBuilder'; @@ -26,6 +27,7 @@ import { Hash256Dto } from '../../infrastructure/catbuffer/Hash256Dto'; import {KeyDto} from '../../infrastructure/catbuffer/KeyDto'; import {SignatureDto} from '../../infrastructure/catbuffer/SignatureDto'; import {TimestampDto} from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import {CreateTransactionFromPayload} from '../../infrastructure/transaction/CreateTransactionFromPayload'; import {Account} from '../account/Account'; import {PublicAccount} from '../account/PublicAccount'; @@ -400,4 +402,13 @@ export class AggregateTransaction extends Transaction { private getInnerTransactionPaddingSize(size: number, alignment: number): number { return 0 === size % alignment ? 0 : alignment - (size % alignment); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {AggregateTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + throw new Error('Not implemented'); + } } diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index a772bd3e6e..52febc542a 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -14,6 +14,10 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; +import { map } from 'rxjs/internal/operators/map'; +import { mergeMap } from 'rxjs/internal/operators/mergeMap'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -25,10 +29,12 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; import { MosaicId } from '../mosaic/MosaicId'; +import { NamespaceId } from '../namespace/NamespaceId'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -50,6 +56,7 @@ export class LockFundsTransaction extends Transaction { * Aggregate bonded hash. */ public readonly hash: string; + signedTransaction: SignedTransaction; /** * Create a Lock funds transaction object @@ -108,6 +115,7 @@ export class LockFundsTransaction extends Transaction { transactionInfo?: TransactionInfo) { super(TransactionType.LOCK, networkType, version, deadline, maxFee, signature, signer, transactionInfo); this.hash = signedTransaction.hash; + this.signedTransaction = signedTransaction; if (signedTransaction.type !== TransactionType.AGGREGATE_BONDED) { throw new Error('Signed transaction must be Aggregate Bonded Transaction'); } @@ -200,4 +208,42 @@ export class LockFundsTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {LockFundsTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this.mosaic).pipe( + mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( + map((mosaicId) => new LockFundsTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + new Mosaic(mosaicId, mosaic.amount), + this.duration, + this.signedTransaction, + this.signature, + this.signer, + this.transactionInfo, + )), + ) : + of(new LockFundsTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaic, + this.duration, + this.signedTransaction, + this.signature, + this.signer, + this.transactionInfo, + )), + ), + ); + } } diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 11b25d3855..2c42f6052b 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { combineLatest } from 'rxjs/internal/observable/combineLatest'; +import { of } from 'rxjs/internal/observable/of'; import { Convert, RawAddress } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -26,6 +29,7 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -233,4 +237,36 @@ export class MosaicAddressRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicAddressRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedAddress = this.targetAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.targetAddress as NamespaceId) : + of(this.targetAddress); + + const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : + of(this.mosaicId); + + return combineLatest(resolvedAddress, resolvedMosaicId, (address, mosaicId) => { + return new MosaicAddressRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaicId, + this.restrictionKey, + address, + this.previousRestrictionValue, + this.newRestrictionValue, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/MosaicAliasTransaction.ts b/src/model/transaction/MosaicAliasTransaction.ts index 4fd81443ce..56457b20e8 100644 --- a/src/model/transaction/MosaicAliasTransaction.ts +++ b/src/model/transaction/MosaicAliasTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedMosaicAliasTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedMosaicAliasTransactionBuilder'; @@ -23,6 +25,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -178,4 +181,13 @@ export class MosaicAliasTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicAliasTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/MosaicDefinitionTransaction.ts b/src/model/transaction/MosaicDefinitionTransaction.ts index 179c37e0e7..79ffe963d8 100644 --- a/src/model/transaction/MosaicDefinitionTransaction.ts +++ b/src/model/transaction/MosaicDefinitionTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -25,6 +27,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { MosaicNonceDto } from '../../infrastructure/catbuffer/MosaicNonceDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicFlags } from '../mosaic/MosaicFlags'; @@ -221,4 +224,13 @@ export class MosaicDefinitionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicDefinitionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 404f14e63c..05bfcb57b5 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { combineLatest, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -25,6 +27,7 @@ import { MosaicGlobalRestrictionTransactionBuilder } from '../../infrastructure/ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -243,4 +246,38 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicGlobalRestrictionTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : + of(this.mosaicId); + + const resolvedRefMosaicId = this.referenceMosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : + of(this.mosaicId); + + return combineLatest(resolvedMosaicId, resolvedRefMosaicId, (mosaicId, refMosaicId) => { + return new MosaicGlobalRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaicId, + refMosaicId, + this.restrictionKey, + this.previousRestrictionValue, + this.previousRestrictionType, + this.newRestrictionValue, + this.newRestrictionType, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index 6973af8283..b99fb4e61b 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -23,6 +26,7 @@ import { MosaicMetadataTransactionBuilder } from '../../infrastructure/catbuffer import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -209,4 +213,46 @@ export class MosaicMetadataTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicMetadataTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return this.targetMosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.targetMosaicId as NamespaceId).pipe( + map((mosaicId) => { + return new MosaicMetadataTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.targetPublicKey, + this.scopedMetadataKey, + mosaicId, + this.valueSizeDelta, + this.value, + this.signature, + this.signer, + this.transactionInfo, + ); + }), + ) : + of(new MosaicMetadataTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.targetPublicKey, + this.scopedMetadataKey, + this.targetMosaicId, + this.valueSizeDelta, + this.value, + this.signature, + this.signer, + this.transactionInfo, + ), + ); + } } diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index 5a3fea7dd5..348084157b 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +import { of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; +import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedMosaicSupplyChangeTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedMosaicSupplyChangeTransactionBuilder'; import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; @@ -22,10 +26,12 @@ import { MosaicSupplyChangeTransactionBuilder } from '../../infrastructure/catbu import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { MosaicSupplyChangeAction } from '../mosaic/MosaicSupplyChangeAction'; +import { NamespaceId } from '../namespace/NamespaceId'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -43,7 +49,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * Create a mosaic supply change transaction object * @param deadline - The deadline to include the transaction. - * @param mosaicId - The mosaic id. + * @param mosaicId - The unresolved mosaic id. * @param action - The supply change action (increase | decrease). * @param delta - The supply change in units for the mosaic. * @param networkType - The network type. @@ -51,7 +57,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { * @returns {MosaicSupplyChangeTransaction} */ public static create(deadline: Deadline, - mosaicId: MosaicId, + mosaicId: MosaicId | NamespaceId, action: MosaicSupplyChangeAction, delta: UInt64, networkType: NetworkType, @@ -83,9 +89,9 @@ export class MosaicSupplyChangeTransaction extends Transaction { deadline: Deadline, maxFee: UInt64, /** - * The mosaic id. + * The unresolved mosaic id. */ - public readonly mosaicId: MosaicId, + public readonly mosaicId: MosaicId | NamespaceId, /** * The supply type. */ @@ -115,7 +121,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { const transaction = MosaicSupplyChangeTransaction.create( isEmbedded ? Deadline.create() : Deadline.createFromDTO( (builder as MosaicSupplyChangeTransactionBuilder).getDeadline().timestamp), - new MosaicId(builder.getMosaicId().unresolvedMosaicId), + UnresolvedMapping.toUnresolvedMosaic(new UInt64(builder.getMosaicId().unresolvedMosaicId).toHex()), builder.getAction().valueOf(), new UInt64(builder.getDelta().amount), networkType, @@ -181,4 +187,42 @@ export class MosaicSupplyChangeTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MosaicSupplyChangeTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return this.mosaicId instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId).pipe( + map((mosaicId) => { + return new MosaicSupplyChangeTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaicId, + this.action, + this.delta, + this.signature, + this.signer, + this.transactionInfo, + ); + }), + ) : + of(new MosaicSupplyChangeTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.mosaicId, + this.action, + this.delta, + this.signature, + this.signer, + this.transactionInfo, + ), + ); + } } diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index c2ecd6c9c8..1393b159a0 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { @@ -24,12 +26,12 @@ import {MultisigAccountModificationTransactionBuilder, } from '../../infrastructure/catbuffer/MultisigAccountModificationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; -import { MultisigCosignatoryModification } from './MultisigCosignatoryModification'; import { Transaction } from './Transaction'; import { TransactionInfo } from './TransactionInfo'; import { TransactionType } from './TransactionType'; @@ -213,4 +215,13 @@ export class MultisigAccountModificationTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {MultisigAccountModificationTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/NamespaceMetadataTransaction.ts b/src/model/transaction/NamespaceMetadataTransaction.ts index b5dd3f8d11..3198791bca 100644 --- a/src/model/transaction/NamespaceMetadataTransaction.ts +++ b/src/model/transaction/NamespaceMetadataTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedNamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedNamespaceMetadataTransactionBuilder'; @@ -22,6 +24,7 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceMetadataTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; @@ -208,4 +211,13 @@ export class NamespaceMetadataTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {NamespaceMetadataTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/NamespaceRegistrationTransaction.ts b/src/model/transaction/NamespaceRegistrationTransaction.ts index b10a46714d..341d07ca74 100644 --- a/src/model/transaction/NamespaceRegistrationTransaction.ts +++ b/src/model/transaction/NamespaceRegistrationTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; import { Convert, Convert as convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -25,6 +27,7 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceRegistrationTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceRegistrationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import {NamespaceMosaicIdGenerator} from '../../infrastructure/transaction/NamespaceMosaicIdGenerator'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -273,4 +276,13 @@ export class NamespaceRegistrationTransaction extends Transaction { } return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {NamespaceRegistrationTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return of(this); + } } diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index dfb1b9f41a..92a5f0d339 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Convert, Convert as convert, RawAddress } from '../../core/format'; +import { combineLatest, of } from 'rxjs'; +import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; +import { Convert, Convert as convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -26,11 +29,11 @@ import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; -import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -231,4 +234,33 @@ export class SecretLockTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : + of(this.recipientAddress); + + const resolvedMosaic = this.mosaic instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(this.recipientAddress as NamespaceId).pipe( + map((mosaicId) => new Mosaic(mosaicId, this.mosaic.amount)), + ) : + of(this.mosaic); + + return combineLatest(resolvedRecipient, resolvedMosaic, (recipient, mosaic) => { + return new SecretLockTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + mosaic, + this.duration, + this.hashType, + this.secret, + recipient, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 27a5d868e3..7bb2cd65cf 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -14,6 +14,9 @@ * limitations under the License. */ +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; +import { map } from 'rxjs/operators'; import { Convert, Convert as convert, RawAddress } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -24,6 +27,7 @@ import { SecretProofTransactionBuilder } from '../../infrastructure/catbuffer/Se import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -207,4 +211,44 @@ export class SecretProofTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {SecretProofTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + return this.recipientAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId).pipe( + map((recipient) => { + return new SecretProofTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.hashType, + this.secret, + recipient, + this.proof, + this.signature, + this.signer, + this.transactionInfo, + ); + }), + ) : + of(new SecretProofTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.hashType, + this.secret, + this.recipientAddress, + this.proof, + this.signature, + this.signer, + this.transactionInfo, + ), + ); + } } diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index f051d6ceeb..cdab1e54ef 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -14,8 +14,10 @@ * limitations under the License. */ +import { Observable } from 'rxjs'; import { KeyPair, SHA3Hasher, SignSchema } from '../../core/crypto'; import { Convert } from '../../core/format'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import { SerializeTransactionToJSON } from '../../infrastructure/transaction/SerializeTransactionToJSON'; import { Account } from '../account/Account'; import { PublicAccount } from '../account/PublicAccount'; @@ -185,6 +187,12 @@ export abstract class Transaction { */ protected abstract generateEmbeddedBytes(): Uint8Array; + /** + * @internal + * @param namespaceHttp NamespaceHttp + */ + abstract resolveAliases(namespaceHttp: NamespaceHttp): Observable; + /** * @internal * Serialize and sign transaction creating a new SignedTransaction diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index 12c91e2241..cda3cc0e55 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -15,7 +15,10 @@ */ import * as Long from 'long'; -import {Convert, Convert as convert} from '../../core/format'; +import { combineLatest, from, Observable, of } from 'rxjs'; +import { map, toArray } from 'rxjs/operators'; +import { mergeMap} from 'rxjs/operators'; +import {Convert} from '../../core/format'; import {UnresolvedMapping} from '../../core/utils/UnresolvedMapping'; import {AmountDto} from '../../infrastructure/catbuffer/AmountDto'; import {EmbeddedTransferTransactionBuilder} from '../../infrastructure/catbuffer/EmbeddedTransferTransactionBuilder'; @@ -27,6 +30,7 @@ import {TransferTransactionBuilder} from '../../infrastructure/catbuffer/Transfe import {UnresolvedAddressDto} from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import {UnresolvedMosaicBuilder} from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import {UnresolvedMosaicIdDto} from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; +import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; import {Address} from '../account/Address'; import {PublicAccount} from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; @@ -43,6 +47,7 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; +import { flatMap } from 'rxjs/operators'; /** * Transfer transactions contain data about transfers of mosaics and message to another account. @@ -272,4 +277,40 @@ export class TransferTransaction extends Transaction { ); return transactionBuilder.serialize(); } + + /** + * @internal + * @param namespaceHttp NamespaceHttp + * @returns {TransferTransaction} + */ + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? + namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : + of(this.recipientAddress); + + const resolvedMosaics = from(this.mosaics).pipe( + mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? + namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( + map((mosaicId) => new Mosaic(mosaicId, mosaic.amount)), + ) : + of(mosaic), + ), + toArray(), + ); + + return combineLatest(resolvedRecipient, resolvedMosaics, (recipient, mosaics) => { + return new TransferTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + recipient, + mosaics, + this.message, + this.signature, + this.signer, + this.transactionInfo, + ); + }); + } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts new file mode 100644 index 0000000000..ad8f8e2e0c --- /dev/null +++ b/src/service/TransactionService.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Observable} from 'rxjs'; +import { flatMap, mergeMap, toArray} from 'rxjs/operators'; +import { NamespaceHttp } from '../infrastructure/NamespaceHttp'; +import { TransactionHttp } from '../infrastructure/TransactionHttp'; +import { Transaction } from '../model/transaction/Transaction'; + +/** + * Transaction Service + */ +export class TransactionService { + + private readonly transactionHttp: TransactionHttp; + private readonly namespaceHttp: NamespaceHttp; + /** + * Constructor + * @param url Base catapult-rest url + */ + constructor(url: string) { + this.transactionHttp = new TransactionHttp(url); + this.namespaceHttp = new NamespaceHttp(url); + } + + /** + * @param transationHashes List of transaction hashes. + * @returns Observable + */ + public resolveAliases(transationHashes: string[]): Observable { + return this.transactionHttp.getTransactions(transationHashes).pipe( + mergeMap((_) => _), + flatMap((transaction) => transaction.resolveAliases(this.namespaceHttp)), + toArray(), + ); + } +} diff --git a/test/model/transaction/Transaction.spec.ts b/test/model/transaction/Transaction.spec.ts index 5815da8f8b..c98bf76752 100644 --- a/test/model/transaction/Transaction.spec.ts +++ b/test/model/transaction/Transaction.spec.ts @@ -15,6 +15,9 @@ */ import { expect } from 'chai'; +import { Observable } from 'rxjs/internal/Observable'; +import { Convert } from '../../../src/core/format/Convert'; +import { NamespaceHttp } from '../../../src/infrastructure/NamespaceHttp'; import { Account } from '../../../src/model/account/Account'; import { Address } from '../../../src/model/account/Address'; import { NetworkType } from '../../../src/model/blockchain/NetworkType'; @@ -28,7 +31,6 @@ import { TransactionType } from '../../../src/model/transaction/TransactionType' import { TransferTransaction } from '../../../src/model/transaction/TransferTransaction'; import { UInt64 } from '../../../src/model/UInt64'; import { TestingAccount } from '../../conf/conf.spec'; -import { Convert } from '../../../src/core/format/Convert'; describe('Transaction', () => { let account: Account; @@ -403,4 +405,7 @@ class FakeTransaction extends Transaction { protected generateEmbeddedBytes(): Uint8Array { throw new Error('Not implemented'); } + resolveAliases(namespaceHttp: NamespaceHttp): Observable { + throw new Error('Not implemented'); + } } From ffc558189fe3e564e512156b8ba8b5be68baf9d5 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 29 Nov 2019 14:18:02 +0000 Subject: [PATCH 11/50] restore missing tests --- e2e/service/TransactionService.spec.ts | 313 +++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 e2e/service/TransactionService.spec.ts diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts new file mode 100644 index 0000000000..b5c424ed6b --- /dev/null +++ b/e2e/service/TransactionService.spec.ts @@ -0,0 +1,313 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { assert } from 'chai'; +import { Listener } from '../../src/infrastructure/Listener'; +import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; +import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; +import { Account } from '../../src/model/account/Account'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction, Address } from '../../src/model/model'; +import { MosaicFlags } from '../../src/model/mosaic/MosaicFlags'; +import { MosaicId } from '../../src/model/mosaic/MosaicId'; +import { MosaicNonce } from '../../src/model/mosaic/MosaicNonce'; +import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { AliasAction } from '../../src/model/namespace/AliasAction'; +import { NamespaceId } from '../../src/model/namespace/NamespaceId'; +import { AddressAliasTransaction } from '../../src/model/transaction/AddressAliasTransaction'; +import { Deadline } from '../../src/model/transaction/Deadline'; +import { MosaicAliasTransaction } from '../../src/model/transaction/MosaicAliasTransaction'; +import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicDefinitionTransaction'; +import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; +import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { UInt64 } from '../../src/model/UInt64'; +import { TransactionService } from '../../src/service/TransactionService'; +import { expect } from 'chai'; + +describe('TransactionService', () => { + let account: Account; + let account2: Account; + let url: string; + let generationHash: string; + let namespaceHttp: NamespaceHttp; + let addressAlias: NamespaceId; + let mosaicAlias: NamespaceId; + let mosaicId: MosaicId; + let transactionHttp: TransactionHttp; + let config; + let transactionHashes: string[]; + + before((done) => { + const path = require('path'); + require('fs').readFile(path.resolve(__dirname, '../conf/network.conf'), (err, data) => { + if (err) { + throw err; + } + const json = JSON.parse(data); + config = json; + account = Account.createFromPrivateKey(json.testAccount.privateKey, NetworkType.MIJIN_TEST); + account2 = Account.createFromPrivateKey(json.testAccount2.privateKey, NetworkType.MIJIN_TEST); + url = json.apiUrl; + generationHash = json.generationHash; + namespaceHttp = new NamespaceHttp(json.apiUrl); + transactionHttp = new TransactionHttp(json.apiUrl); + transactionHashes = []; + done(); + }); + }); + + /** + * ========================= + * Setup test data + * ========================= + */ + describe('Create address alias NamespaceId', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce NamespaceRegistrationTransaction', (done) => { + const namespaceName = 'root-test-namespace-' + Math.floor(Math.random() * 10000); + const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( + Deadline.create(), + namespaceName, + UInt64.fromUint(9), + NetworkType.MIJIN_TEST, + ); + addressAlias = new NamespaceId(namespaceName); + const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Create mosaic alias NamespaceId', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce NamespaceRegistrationTransaction', (done) => { + const namespaceName = 'root-test-namespace-' + Math.floor(Math.random() * 10000); + const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( + Deadline.create(), + namespaceName, + UInt64.fromUint(9), + NetworkType.MIJIN_TEST, + ); + mosaicAlias = new NamespaceId(namespaceName); + const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Setup test AddressAlias', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + + it('Announce addressAliasTransaction', (done) => { + const addressAliasTransaction = AddressAliasTransaction.create( + Deadline.create(), + AliasAction.Link, + addressAlias, + account.address, + NetworkType.MIJIN_TEST, + ); + const signedTransaction = addressAliasTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Setup test MosaicId', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MosaicDefinitionTransaction', (done) => { + const nonce = MosaicNonce.createRandom(); + mosaicId = MosaicId.createFromNonce(nonce, account.publicAccount); + const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( + Deadline.create(), + nonce, + mosaicId, + MosaicFlags.create(true, true, false), + 3, + UInt64.fromUint(0), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = mosaicDefinitionTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('MosaicSupplyChangeTransaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('standalone', (done) => { + const mosaicSupplyChangeTransaction = MosaicSupplyChangeTransaction.create( + Deadline.create(), + mosaicId, + MosaicSupplyChangeAction.Increase, + UInt64.fromUint(10), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = mosaicSupplyChangeTransaction.signWith(account, generationHash); + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Setup MosaicAlias', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + + it('Announce MosaicAliasTransaction', (done) => { + const mosaicAliasTransaction = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Link, + mosaicAlias, + mosaicId, + NetworkType.MIJIN_TEST, + ); + const signedTransaction = mosaicAliasTransaction.signWith(account, generationHash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + describe('Create Transfer with alias', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + + it('Announce TransferTransaction', (done) => { + const transferTransaction = TransferTransaction.create( + Deadline.create(), + addressAlias, + [ + // NetworkCurrencyMosaic.createAbsolute(1), //Seems get banned on rest if passing multiple mosaic alias in + new Mosaic(mosaicAlias, UInt64.fromUint(1)), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = transferTransaction.signWith(account, generationHash); + + transactionHashes.push(signedTransaction.hash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + describe('should return resolved transaction', () => { + it('call transaction service', (done) => { + const transactionService = new TransactionService(url); + return transactionService.resolveAliases(transactionHashes).subscribe((transactions) => { + transactions.map((tx: TransferTransaction) => { + expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); + expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + }); + done(); + }); + }); + }); +}); From e0df5c2eae0b6bf1f8aeca1cb89a2eb7280098d5 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 21:14:28 +0000 Subject: [PATCH 12/50] Changed to resolve alias from receipts --- e2e/service/TransactionService.spec.ts | 4 +- src/core/utils/TransactionMapping.ts | 1 - src/core/utils/UnresolvedMapping.ts | 2 +- .../receipt/CreateReceiptFromDTO.ts | 32 ++- .../AccountAddressRestrictionTransaction.ts | 55 +++-- .../transaction/AccountLinkTransaction.ts | 8 +- .../transaction/AccountMetadataTransaction.ts | 8 +- .../AccountMosaicRestrictionTransaction.ts | 55 +++-- .../AccountOperationRestrictionTransaction.ts | 8 +- .../transaction/AddressAliasTransaction.ts | 8 +- src/model/transaction/AggregateTransaction.ts | 8 +- src/model/transaction/LockFundsTransaction.ts | 43 ++-- .../MosaicAddressRestrictionTransaction.ts | 44 +++- .../transaction/MosaicAliasTransaction.ts | 8 +- .../MosaicDefinitionTransaction.ts | 8 +- .../MosaicGlobalRestrictionTransaction.ts | 42 +++- .../transaction/MosaicMetadataTransaction.ts | 50 ++--- .../MosaicSupplyChangeTransaction.ts | 41 ++-- .../MultisigAccountModificationTransaction.ts | 7 +- .../NamespaceMetadataTransaction.ts | 7 +- .../NamespaceRegistrationTransaction.ts | 8 +- .../transaction/SecretLockTransaction.ts | 45 +++- .../transaction/SecretProofTransaction.ts | 67 +++--- src/model/transaction/Transaction.ts | 19 +- src/model/transaction/TransferTransaction.ts | 51 +++-- src/service/TransactionService.ts | 56 ++++- src/service/service.ts | 1 + .../receipt/CreateReceiptFromDTO.spec.ts | 8 +- test/model/receipt/Receipt.spec.ts | 4 +- test/model/transaction/Transaction.spec.ts | 5 +- test/service/TransactionService.spec.ts | 208 ++++++++++++++++++ 31 files changed, 657 insertions(+), 254 deletions(-) create mode 100644 test/service/TransactionService.spec.ts diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index b5c424ed6b..e6520cf0b1 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -15,13 +15,14 @@ */ import { assert } from 'chai'; +import { expect } from 'chai'; import { Listener } from '../../src/infrastructure/Listener'; import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; import { Account } from '../../src/model/account/Account'; import { NetworkType } from '../../src/model/blockchain/NetworkType'; import { PlainMessage } from '../../src/model/message/PlainMessage'; -import { Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction, Address } from '../../src/model/model'; +import { Address, Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction } from '../../src/model/model'; import { MosaicFlags } from '../../src/model/mosaic/MosaicFlags'; import { MosaicId } from '../../src/model/mosaic/MosaicId'; import { MosaicNonce } from '../../src/model/mosaic/MosaicNonce'; @@ -36,7 +37,6 @@ import { NamespaceRegistrationTransaction } from '../../src/model/transaction/Na import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; import { UInt64 } from '../../src/model/UInt64'; import { TransactionService } from '../../src/service/TransactionService'; -import { expect } from 'chai'; describe('TransactionService', () => { let account: Account; diff --git a/src/core/utils/TransactionMapping.ts b/src/core/utils/TransactionMapping.ts index 64a387c4d4..b579fd0cb6 100644 --- a/src/core/utils/TransactionMapping.ts +++ b/src/core/utils/TransactionMapping.ts @@ -18,7 +18,6 @@ import { CreateTransactionFromDTO } from '../../infrastructure/transaction/Creat import { CreateTransactionFromPayload } from '../../infrastructure/transaction/CreateTransactionFromPayload'; import { InnerTransaction } from '../../model/transaction/InnerTransaction'; import { Transaction } from '../../model/transaction/Transaction'; -import { SignSchema } from '../crypto/SignSchema'; export class TransactionMapping { diff --git a/src/core/utils/UnresolvedMapping.ts b/src/core/utils/UnresolvedMapping.ts index a77c4d33f8..1a8de4f376 100644 --- a/src/core/utils/UnresolvedMapping.ts +++ b/src/core/utils/UnresolvedMapping.ts @@ -14,11 +14,11 @@ * limitations under the License. */ import { Address } from '../../model/account/Address'; +import { NetworkType } from '../../model/blockchain/NetworkType'; import { MosaicId } from '../../model/mosaic/MosaicId'; import { NamespaceId } from '../../model/namespace/NamespaceId'; import { Convert } from '../format/Convert'; import { RawAddress } from '../format/RawAddress'; -import { NetworkType } from "../../model/blockchain/NetworkType"; /** * @internal diff --git a/src/infrastructure/receipt/CreateReceiptFromDTO.ts b/src/infrastructure/receipt/CreateReceiptFromDTO.ts index ee336b4e70..8eff4c9c87 100644 --- a/src/infrastructure/receipt/CreateReceiptFromDTO.ts +++ b/src/infrastructure/receipt/CreateReceiptFromDTO.ts @@ -14,12 +14,10 @@ * limitations under the License. */ +import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { Address } from '../../model/account/Address'; import {PublicAccount} from '../../model/account/PublicAccount'; import {MosaicId} from '../../model/mosaic/MosaicId'; -import { AddressAlias } from '../../model/namespace/AddressAlias'; -import { AliasType } from '../../model/namespace/AliasType'; -import { MosaicAlias } from '../../model/namespace/MosaicAlias'; import { NamespaceId } from '../../model/namespace/NamespaceId'; import { ArtifactExpiryReceipt } from '../../model/receipt/ArtifactExpiryReceipt'; import { BalanceChangeReceipt } from '../../model/receipt/BalanceChangeReceipt'; @@ -95,7 +93,7 @@ const createResolutionStatement = (statementDTO, resolutionType): ResolutionStat return new ResolutionStatement( ResolutionType.Address, UInt64.fromNumericString(statementDTO.height), - Address.createFromEncoded(statementDTO.unresolved), + extractUnresolvedAddress(statementDTO.unresolved), statementDTO.resolutionEntries.map((entry) => { return new ResolutionEntry(Address.createFromEncoded(entry.resolved), new ReceiptSource(entry.source.primaryId, entry.source.secondaryId)); @@ -105,7 +103,7 @@ const createResolutionStatement = (statementDTO, resolutionType): ResolutionStat return new ResolutionStatement( ResolutionType.Mosaic, UInt64.fromNumericString(statementDTO.height), - new MosaicId(statementDTO.unresolved), + UnresolvedMapping.toUnresolvedMosaic(statementDTO.unresolved), statementDTO.resolutionEntries.map((entry) => { return new ResolutionEntry(new MosaicId(entry.resolved), new ReceiptSource(entry.source.primaryId, entry.source.secondaryId)); @@ -197,6 +195,12 @@ const createInflationReceipt = (receiptDTO): Receipt => { ); }; +/** + * @internal + * @param receiptType receipt type + * @param id Artifact id + * @returns {MosaicId | NamespaceId} + */ const extractArtifactId = (receiptType: ReceiptType, id: string): MosaicId | NamespaceId => { switch (receiptType) { case ReceiptType.Mosaic_Expired: @@ -208,3 +212,21 @@ const extractArtifactId = (receiptType: ReceiptType, id: string): MosaicId | Nam throw new Error('Receipt type is not supported.'); } }; + +/** + * @interal + * @param unresolvedAddress unresolved address + * @returns {Address | NamespaceId} + */ +const extractUnresolvedAddress = (unresolvedAddress: any): Address | NamespaceId => { + if (typeof unresolvedAddress === 'string') { + return UnresolvedMapping.toUnresolvedAddress(unresolvedAddress); + } else if (typeof unresolvedAddress === 'object') { // Is JSON object + if (unresolvedAddress.hasOwnProperty('address')) { + return Address.createFromRawAddress(unresolvedAddress.address); + } else if (unresolvedAddress.hasOwnProperty('id')) { + return NamespaceId.createFromEncoded(unresolvedAddress.id); + } + } + throw new Error(`UnresolvedAddress: ${unresolvedAddress} type is not recognised`); +}; diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 0901889381..05960c8667 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { combineLatest, from, of } from 'rxjs'; +import { combineLatest, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; -import { mergeMap, toArray } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountAddressRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountAddressRestrictionTransactionBuilder'; @@ -28,11 +28,13 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -196,23 +198,40 @@ export class AccountAddressRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountAddressRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const restrictionAdditions = from(this.restrictionAdditions).pipe( - mergeMap((addition) => addition instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(addition) : - of(addition), - ), - toArray(), + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || + this.restrictionDeletions.find((address) => address instanceof NamespaceId) !== undefined; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + const restrictionAdditions = statementObservable.pipe( + map((statement) => { + return this.restrictionAdditions.map((addition) => { + return addition instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, addition as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + addition; + }); + }), ); - const restrictionDeletions = from(this.restrictionDeletions).pipe( - mergeMap((deletion) => deletion instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(deletion) : - of(deletion), - ), - toArray(), + + const restrictionDeletions = statementObservable.pipe( + map((statement) => { + return this.restrictionDeletions.map((deletion) => { + return deletion instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, deletion as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + deletion; + }); + }), ); return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { diff --git a/src/model/transaction/AccountLinkTransaction.ts b/src/model/transaction/AccountLinkTransaction.ts index d89d376c89..bbfa101882 100644 --- a/src/model/transaction/AccountLinkTransaction.ts +++ b/src/model/transaction/AccountLinkTransaction.ts @@ -23,7 +23,7 @@ import { EmbeddedAccountLinkTransactionBuilder } from '../../infrastructure/catb import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -169,10 +169,10 @@ export class AccountLinkTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountLinkTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AccountMetadataTransaction.ts b/src/model/transaction/AccountMetadataTransaction.ts index 5f09acceb6..2e41cde6ff 100644 --- a/src/model/transaction/AccountMetadataTransaction.ts +++ b/src/model/transaction/AccountMetadataTransaction.ts @@ -23,7 +23,7 @@ import { EmbeddedAccountMetadataTransactionBuilder } from '../../infrastructure/ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -199,10 +199,10 @@ export class AccountMetadataTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountMetadataTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index af134a61bb..0fa304b41c 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -14,9 +14,9 @@ * limitations under the License. */ -import { combineLatest, from, of } from 'rxjs'; +import { combineLatest, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; -import { mergeMap, toArray } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountMosaicRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountMosaicRestrictionTransactionBuilder'; @@ -28,11 +28,13 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -196,23 +198,40 @@ export class AccountMosaicRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountMosaicRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const restrictionAdditions = from(this.restrictionAdditions).pipe( - mergeMap((addition) => addition instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(addition) : - of(addition), - ), - toArray(), + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || + this.restrictionDeletions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + const restrictionAdditions = statementObservable.pipe( + map((statement) => { + return this.restrictionAdditions.map((addition) => { + return addition instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, addition as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + addition; + }); + }), ); - const restrictionDeletions = from(this.restrictionDeletions).pipe( - mergeMap((deletion) => deletion instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(deletion) : - of(deletion), - ), - toArray(), + + const restrictionDeletions = statementObservable.pipe( + map((statement) => { + return this.restrictionDeletions.map((deletion) => { + return deletion instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, deletion as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + deletion; + }); + }), ); return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { diff --git a/src/model/transaction/AccountOperationRestrictionTransaction.ts b/src/model/transaction/AccountOperationRestrictionTransaction.ts index a7a4181524..e38165001e 100644 --- a/src/model/transaction/AccountOperationRestrictionTransaction.ts +++ b/src/model/transaction/AccountOperationRestrictionTransaction.ts @@ -27,7 +27,7 @@ import { import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; @@ -180,10 +180,10 @@ export class AccountOperationRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AccountOperationRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AddressAliasTransaction.ts b/src/model/transaction/AddressAliasTransaction.ts index 04bfd3df5c..ea8f874a27 100644 --- a/src/model/transaction/AddressAliasTransaction.ts +++ b/src/model/transaction/AddressAliasTransaction.ts @@ -25,7 +25,7 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -189,10 +189,10 @@ export class AddressAliasTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AddressAliasTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index 391acbb95f..63e844f8d4 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -27,7 +27,7 @@ import { Hash256Dto } from '../../infrastructure/catbuffer/Hash256Dto'; import {KeyDto} from '../../infrastructure/catbuffer/KeyDto'; import {SignatureDto} from '../../infrastructure/catbuffer/SignatureDto'; import {TimestampDto} from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import {CreateTransactionFromPayload} from '../../infrastructure/transaction/CreateTransactionFromPayload'; import {Account} from '../account/Account'; import {PublicAccount} from '../account/PublicAccount'; @@ -405,10 +405,10 @@ export class AggregateTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {AggregateTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { throw new Error('Not implemented'); } } diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index 52febc542a..1464784e88 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -17,7 +17,6 @@ import { Observable } from 'rxjs/internal/Observable'; import { of } from 'rxjs/internal/observable/of'; import { map } from 'rxjs/internal/operators/map'; -import { mergeMap } from 'rxjs/internal/operators/mergeMap'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -29,12 +28,14 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -211,39 +212,33 @@ export class LockFundsTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {LockFundsTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return of(this.mosaic).pipe( - mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( - map((mosaicId) => new LockFundsTransaction( + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.mosaic.id instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + return statementObservable.pipe( + map((statement) => new LockFundsTransaction( this.networkType, this.version, this.deadline, this.maxFee, - new Mosaic(mosaicId, mosaic.amount), + new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaic.id as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount), this.duration, this.signedTransaction, this.signature, this.signer, this.transactionInfo, )), - ) : - of(new LockFundsTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - mosaic, - this.duration, - this.signedTransaction, - this.signature, - this.signer, - this.transactionInfo, - )), - ), ); } } diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 2c42f6052b..e4095cb413 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -17,7 +17,8 @@ import { Observable } from 'rxjs/internal/Observable'; import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { of } from 'rxjs/internal/observable/of'; -import { Convert, RawAddress } from '../../core/format'; +import { map } from 'rxjs/internal/operators/map'; +import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { @@ -29,12 +30,14 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -240,17 +243,36 @@ export class MosaicAddressRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicAddressRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedAddress = this.targetAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.targetAddress as NamespaceId) : - of(this.targetAddress); + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.targetAddress instanceof NamespaceId || + this.mosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); - const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : - of(this.mosaicId); + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + const resolvedAddress = statementObservable.pipe( + map((statement) => this.targetAddress instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.targetAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + this.targetAddress, + ), + ); + + const resolvedMosaicId = statementObservable.pipe( + map((statement) => this.mosaicId instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + this.mosaicId, + ), + ); return combineLatest(resolvedAddress, resolvedMosaicId, (address, mosaicId) => { return new MosaicAddressRestrictionTransaction( diff --git a/src/model/transaction/MosaicAliasTransaction.ts b/src/model/transaction/MosaicAliasTransaction.ts index 56457b20e8..f1c9dd186d 100644 --- a/src/model/transaction/MosaicAliasTransaction.ts +++ b/src/model/transaction/MosaicAliasTransaction.ts @@ -25,7 +25,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -184,10 +184,10 @@ export class MosaicAliasTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicAliasTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/MosaicDefinitionTransaction.ts b/src/model/transaction/MosaicDefinitionTransaction.ts index 79ffe963d8..257073c695 100644 --- a/src/model/transaction/MosaicDefinitionTransaction.ts +++ b/src/model/transaction/MosaicDefinitionTransaction.ts @@ -27,7 +27,7 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { MosaicNonceDto } from '../../infrastructure/catbuffer/MosaicNonceDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicFlags } from '../mosaic/MosaicFlags'; @@ -227,10 +227,10 @@ export class MosaicDefinitionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicDefinitionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 05bfcb57b5..c2546c2056 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -16,6 +16,7 @@ import { combineLatest, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; +import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -27,11 +28,13 @@ import { MosaicGlobalRestrictionTransactionBuilder } from '../../infrastructure/ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { MosaicRestrictionType } from '../restriction/MosaicRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -249,17 +252,36 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicGlobalRestrictionTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedMosaicId = this.mosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : - of(this.mosaicId); + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.mosaicId instanceof NamespaceId || + this.referenceMosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - const resolvedRefMosaicId = this.referenceMosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId) : - of(this.mosaicId); + const resolvedMosaicId = statementObservable.pipe( + map((statement) => this.mosaicId instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + this.mosaicId, + ), + ); + + const resolvedRefMosaicId = statementObservable.pipe( + map((statement) => this.referenceMosaicId instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.referenceMosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + this.referenceMosaicId, + ), + ); return combineLatest(resolvedMosaicId, resolvedRefMosaicId, (mosaicId, refMosaicId) => { return new MosaicGlobalRestrictionTransaction( diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index b99fb4e61b..c48c020ebb 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -26,11 +26,13 @@ import { MosaicMetadataTransactionBuilder } from '../../infrastructure/catbuffer import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -216,43 +218,37 @@ export class MosaicMetadataTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicMetadataTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return this.targetMosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.targetMosaicId as NamespaceId).pipe( - map((mosaicId) => { - return new MosaicMetadataTransaction( + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.targetMosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + return statementObservable.pipe( + map((statement) => new MosaicMetadataTransaction( this.networkType, this.version, this.deadline, this.maxFee, this.targetPublicKey, this.scopedMetadataKey, - mosaicId, + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.targetMosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.valueSizeDelta, this.value, this.signature, this.signer, this.transactionInfo, - ); - }), - ) : - of(new MosaicMetadataTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.targetPublicKey, - this.scopedMetadataKey, - this.targetMosaicId, - this.valueSizeDelta, - this.value, - this.signature, - this.signer, - this.transactionInfo, - ), - ); + ), + ), + ); } } diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index 348084157b..f927b249c6 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -26,12 +26,14 @@ import { MosaicSupplyChangeTransactionBuilder } from '../../infrastructure/catbu import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { MosaicSupplyChangeAction } from '../mosaic/MosaicSupplyChangeAction'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -190,19 +192,29 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MosaicSupplyChangeTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return this.mosaicId instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.mosaicId as NamespaceId).pipe( - map((mosaicId) => { + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.mosaicId instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + return statementObservable.pipe( + map((statement) => { return new MosaicSupplyChangeTransaction( this.networkType, this.version, this.deadline, this.maxFee, - mosaicId, + TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.action, this.delta, this.signature, @@ -210,19 +222,6 @@ export class MosaicSupplyChangeTransaction extends Transaction { this.transactionInfo, ); }), - ) : - of(new MosaicSupplyChangeTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.mosaicId, - this.action, - this.delta, - this.signature, - this.signer, - this.transactionInfo, - ), ); } } diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index 1393b159a0..7dae91c99f 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -27,6 +27,7 @@ import {MultisigAccountModificationTransactionBuilder, import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -218,10 +219,10 @@ export class MultisigAccountModificationTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {MultisigAccountModificationTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/NamespaceMetadataTransaction.ts b/src/model/transaction/NamespaceMetadataTransaction.ts index 3198791bca..5b2645f701 100644 --- a/src/model/transaction/NamespaceMetadataTransaction.ts +++ b/src/model/transaction/NamespaceMetadataTransaction.ts @@ -25,6 +25,7 @@ import { NamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuf import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; @@ -214,10 +215,10 @@ export class NamespaceMetadataTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {NamespaceMetadataTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/NamespaceRegistrationTransaction.ts b/src/model/transaction/NamespaceRegistrationTransaction.ts index 341d07ca74..9130fbe2c2 100644 --- a/src/model/transaction/NamespaceRegistrationTransaction.ts +++ b/src/model/transaction/NamespaceRegistrationTransaction.ts @@ -27,7 +27,7 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceRegistrationTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceRegistrationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import {NamespaceMosaicIdGenerator} from '../../infrastructure/transaction/NamespaceMosaicIdGenerator'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -279,10 +279,10 @@ export class NamespaceRegistrationTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {NamespaceRegistrationTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); } } diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index 92a5f0d339..c9fd2455c0 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -29,12 +29,15 @@ import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; +import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { HashType, HashTypeLengthValidator } from './HashType'; @@ -235,16 +238,38 @@ export class SecretLockTransaction extends Transaction { return transactionBuilder.serialize(); } - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : - of(this.recipientAddress); + /** + * @internal + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} + */ + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.recipientAddress instanceof NamespaceId || + this.mosaic.id instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); - const resolvedMosaic = this.mosaic instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(this.recipientAddress as NamespaceId).pipe( - map((mosaicId) => new Mosaic(mosaicId, this.mosaic.amount)), - ) : - of(this.mosaic); + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + const resolvedRecipient = statementObservable.pipe( + map((statement) => this.recipientAddress instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + this.recipientAddress, + ), + ); + + const resolvedMosaic = statementObservable.pipe( + map((statement) => this.mosaic.id instanceof NamespaceId ? + new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount) : + this.mosaic, + ), + ); return combineLatest(resolvedRecipient, resolvedMosaic, (recipient, mosaic) => { return new SecretLockTransaction( diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 7bb2cd65cf..33cc84ab21 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -17,7 +17,7 @@ import { Observable } from 'rxjs/internal/Observable'; import { of } from 'rxjs/internal/observable/of'; import { map } from 'rxjs/operators'; -import { Convert, Convert as convert, RawAddress } from '../../core/format'; +import { Convert, Convert as convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedSecretProofTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedSecretProofTransactionBuilder'; @@ -27,11 +27,13 @@ import { SecretProofTransactionBuilder } from '../../infrastructure/catbuffer/Se import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { HashType, HashTypeLengthValidator } from './HashType'; @@ -214,40 +216,35 @@ export class SecretProofTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp - * @returns {SecretProofTransaction} + * @param receiptHttp ReceiptHttp + * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - return this.recipientAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId).pipe( - map((recipient) => { - return new SecretProofTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.hashType, - this.secret, - recipient, - this.proof, - this.signature, - this.signer, - this.transactionInfo, - ); - }), - ) : - of(new SecretProofTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.hashType, - this.secret, - this.recipientAddress, - this.proof, - this.signature, - this.signer, - this.transactionInfo, + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.recipientAddress instanceof NamespaceId; + + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + return statementObservable.pipe( + map((statement) => new SecretProofTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.hashType, + this.secret, + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address, + this.proof, + this.signature, + this.signer, + this.transactionInfo, + ), ), ); } diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index cdab1e54ef..2f53db47af 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -18,6 +18,7 @@ import { Observable } from 'rxjs'; import { KeyPair, SHA3Hasher, SignSchema } from '../../core/crypto'; import { Convert } from '../../core/format'; import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { SerializeTransactionToJSON } from '../../infrastructure/transaction/SerializeTransactionToJSON'; import { Account } from '../account/Account'; import { PublicAccount } from '../account/PublicAccount'; @@ -189,9 +190,9 @@ export abstract class Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp + * @param receiptHttp ReceiptHttp */ - abstract resolveAliases(namespaceHttp: NamespaceHttp): Observable; + abstract resolveAliases(receiptHttp: ReceiptHttp): Observable; /** * @internal @@ -391,4 +392,18 @@ export abstract class Transaction { const childClassObject = SerializeTransactionToJSON(this); return {transaction: Object.assign(commonTransactionObject, childClassObject)}; } + + /** + * @internal + * Check if index and height exists in transactionInfo + * @returns TransactionInfo + */ + protected checkTransactionHeightAndIndex(): TransactionInfo { + if (this.transactionInfo === undefined || + this.transactionInfo.height === undefined || + this.transactionInfo.index === undefined) { + throw new Error('Transaction height or index undefined'); + } + return this.transactionInfo; + } } diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index cda3cc0e55..241b5ccd22 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -15,9 +15,8 @@ */ import * as Long from 'long'; -import { combineLatest, from, Observable, of } from 'rxjs'; -import { map, toArray } from 'rxjs/operators'; -import { mergeMap} from 'rxjs/operators'; +import { combineLatest, Observable, of } from 'rxjs'; +import { map } from 'rxjs/operators'; import {Convert} from '../../core/format'; import {UnresolvedMapping} from '../../core/utils/UnresolvedMapping'; import {AmountDto} from '../../infrastructure/catbuffer/AmountDto'; @@ -30,7 +29,8 @@ import {TransferTransactionBuilder} from '../../infrastructure/catbuffer/Transfe import {UnresolvedAddressDto} from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import {UnresolvedMosaicBuilder} from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import {UnresolvedMosaicIdDto} from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; +import { TransactionService } from '../../service/TransactionService'; import {Address} from '../account/Address'; import {PublicAccount} from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; @@ -39,7 +39,9 @@ import {Message} from '../message/Message'; import {MessageType} from '../message/MessageType'; import {PlainMessage} from '../message/PlainMessage'; import {Mosaic} from '../mosaic/Mosaic'; +import { MosaicId } from '../mosaic/MosaicId'; import {NamespaceId} from '../namespace/NamespaceId'; +import { ResolutionType } from '../receipt/ResolutionType'; import {UInt64} from '../UInt64'; import {Deadline} from './Deadline'; import {InnerTransaction} from './InnerTransaction'; @@ -47,7 +49,6 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; -import { flatMap } from 'rxjs/operators'; /** * Transfer transactions contain data about transfers of mosaics and message to another account. @@ -280,22 +281,38 @@ export class TransferTransaction extends Transaction { /** * @internal - * @param namespaceHttp NamespaceHttp + * @param receiptHttp ReceiptHttp * @returns {TransferTransaction} */ - resolveAliases(namespaceHttp: NamespaceHttp): Observable { - const resolvedRecipient = this.recipientAddress instanceof NamespaceId ? - namespaceHttp.getLinkedAddress(this.recipientAddress as NamespaceId) : - of(this.recipientAddress); + resolveAliases(receiptHttp: ReceiptHttp): Observable { + const hasUnresolved = this.recipientAddress instanceof NamespaceId || + this.mosaics.find((mosaic) => mosaic.id instanceof NamespaceId) !== undefined; - const resolvedMosaics = from(this.mosaics).pipe( - mergeMap((mosaic) => mosaic.id instanceof NamespaceId ? - namespaceHttp.getLinkedMosaicId(mosaic.id).pipe( - map((mosaicId) => new Mosaic(mosaicId, mosaic.amount)), - ) : - of(mosaic), + if (!hasUnresolved) { + return of(this); + } + + const transactionInfo = this.checkTransactionHeightAndIndex(); + + const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); + + const resolvedRecipient = statementObservable.pipe( + map((statement) => this.recipientAddress instanceof NamespaceId ? + TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + this.recipientAddress, + ), + ); + + const resolvedMosaics = statementObservable.pipe( + map((statement) => + this.mosaics.map((mosaic) => + mosaic.id instanceof NamespaceId ? + new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, mosaic.id as NamespaceId, + statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, mosaic.amount) : + mosaic, + ), ), - toArray(), ); return combineLatest(resolvedRecipient, resolvedMosaics, (recipient, mosaics) => { diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index ad8f8e2e0c..d657fe594d 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -15,9 +15,15 @@ */ import {Observable} from 'rxjs'; -import { flatMap, mergeMap, toArray} from 'rxjs/operators'; -import { NamespaceHttp } from '../infrastructure/NamespaceHttp'; +import { mergeMap, toArray} from 'rxjs/operators'; +import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; +import { Address } from '../model/account/Address'; +import { MosaicId } from '../model/mosaic/MosaicId'; +import { NamespaceId } from '../model/namespace/NamespaceId'; +import { ReceiptType } from '../model/receipt/ReceiptType'; +import { ResolutionType } from '../model/receipt/ResolutionType'; +import { Statement } from '../model/receipt/Statement'; import { Transaction } from '../model/transaction/Transaction'; /** @@ -26,14 +32,54 @@ import { Transaction } from '../model/transaction/Transaction'; export class TransactionService { private readonly transactionHttp: TransactionHttp; - private readonly namespaceHttp: NamespaceHttp; + private readonly receiptHttp: ReceiptHttp; /** * Constructor * @param url Base catapult-rest url */ constructor(url: string) { this.transactionHttp = new TransactionHttp(url); - this.namespaceHttp = new NamespaceHttp(url); + this.receiptHttp = new ReceiptHttp(url); + } + + /** + * @internal + * Extract resolved address | mosaic from block receipt + * @param resolutionType Resolution type: Address / Mosaic + * @param unresolved Unresolved address / mosaicId + * @param statement Block receipt statement + * @param transactionIndex Transaction index + * @param height Transaction height + * @returns {MosaicId | Address} + */ + public static getResolvedFromReceipt(resolutionType: ResolutionType, + unresolved: NamespaceId, + statement: Statement, + transactionIndex: number, + height: string): MosaicId | Address { + // Check if Harvest_Fee receipt exists on the block as it always takes the index 0. + const hasHarvestStatement = statement.transactionStatements + .find((transactionStatements) => transactionStatements.source.primaryId === 0 && + transactionStatements.receipts.find((receipt) => receipt.type === ReceiptType.Harvest_Fee) !== undefined) !== undefined; + + // Transaction index can be different if Harvest_Fee transaction exists. + transactionIndex = hasHarvestStatement ? transactionIndex + 1 : transactionIndex; + + const resolutionStatement = (resolutionType === ResolutionType.Address ? statement.addressResolutionStatements : + statement.mosaicResolutionStatements).find((resolution) => resolution.height.toString() === height && + (resolution.unresolved as NamespaceId).equals(unresolved)); + + if (!resolutionStatement) { + throw new Error('No resolution statement found'); + } + + const resolutionEntry = resolutionStatement.resolutionEntries.find((entry) => entry.source.primaryId === transactionIndex); + + if (!resolutionEntry) { + throw new Error('No resolution entry found'); + } + + return resolutionEntry.resolved; } /** @@ -43,7 +89,7 @@ export class TransactionService { public resolveAliases(transationHashes: string[]): Observable { return this.transactionHttp.getTransactions(transationHashes).pipe( mergeMap((_) => _), - flatMap((transaction) => transaction.resolveAliases(this.namespaceHttp)), + mergeMap((transaction) => transaction.resolveAliases(this.receiptHttp)), toArray(), ); } diff --git a/src/service/service.ts b/src/service/service.ts index 03554176a9..fd6074d5c4 100644 --- a/src/service/service.ts +++ b/src/service/service.ts @@ -19,3 +19,4 @@ export * from './MosaicService'; export * from './AggregateTransactionService'; export * from './MetadataTransactionService'; export * from './MosaicRestrictionTransactionService'; +export * from './TransactionService'; diff --git a/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts b/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts index 4152778bb0..8c38aa5651 100644 --- a/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts +++ b/test/infrastructure/receipt/CreateReceiptFromDTO.spec.ts @@ -23,6 +23,7 @@ import { NetworkType } from '../../../src/model/blockchain/NetworkType'; import { MosaicId } from '../../../src/model/mosaic/MosaicId'; import { AddressAlias } from '../../../src/model/namespace/AddressAlias'; import { MosaicAlias } from '../../../src/model/namespace/MosaicAlias'; +import { NamespaceId } from '../../../src/model/namespace/NamespaceId'; import { ReceiptType } from '../../../src/model/receipt/ReceiptType'; import { UInt64 } from '../../../src/model/UInt64'; @@ -122,8 +123,8 @@ describe('Receipt - CreateStatementFromDTO', () => { }); it('should create Statement', () => { const statement = CreateStatementFromDTO(statementDto, netWorkType); - const unresolvedAddress = statement.addressResolutionStatements[0].unresolved as Address; - const unresolvedMosaicId = statement.mosaicResolutionStatements[0].unresolved as MosaicId; + const unresolvedAddress = statement.addressResolutionStatements[0].unresolved as NamespaceId; + const unresolvedMosaicId = statement.mosaicResolutionStatements[0].unresolved as NamespaceId; expect(statement.transactionStatements.length).to.be.equal(1); expect(statement.addressResolutionStatements.length).to.be.equal(2); @@ -136,8 +137,7 @@ describe('Receipt - CreateStatementFromDTO', () => { expect(statement.transactionStatements[0].receipts[0].type).to.be.equal(ReceiptType.Harvest_Fee); deepEqual(statement.addressResolutionStatements[0].height, UInt64.fromNumericString('1488')); - deepEqual(unresolvedAddress.plain(), - Address.createFromEncoded('9103B60AAF2762688300000000000000000000000000000000').plain()); + deepEqual(unresolvedAddress.toHex(), '83686227AF0AB603'); expect(statement.addressResolutionStatements[0].resolutionEntries.length).to.be.equal(1); expect((statement.addressResolutionStatements[0].resolutionEntries[0].resolved as Address).plain()) .to.be.equal(Address.createFromEncoded('917E7E29A01014C2F300000000000000000000000000000000').plain()); diff --git a/test/model/receipt/Receipt.spec.ts b/test/model/receipt/Receipt.spec.ts index d689180a17..2b0bb8ca00 100644 --- a/test/model/receipt/Receipt.spec.ts +++ b/test/model/receipt/Receipt.spec.ts @@ -18,7 +18,7 @@ import { deepEqual } from 'assert'; import { expect } from 'chai'; import { CreateReceiptFromDTO, - CreateStatementFromDTO + CreateStatementFromDTO, } from '../../../src/infrastructure/receipt/CreateReceiptFromDTO'; import { Account } from '../../../src/model/account/Account'; import { Address } from '../../../src/model/account/Address'; @@ -354,7 +354,7 @@ describe('Receipt', () => { const statement = CreateStatementFromDTO(statementDTO, netWorkType); const receipt = statement.addressResolutionStatements[0]; const hash = receipt.generateHash(NetworkType.MAIN_NET); - expect(hash).to.be.equal('6967470641BC527768CDC29998F4A3350813FDF2E40D1C97AB0BBA36B9AF649E'); + expect(hash).to.be.equal('952225717E26295B97F9A35E719CA1319114CCF23C927BCBD14E7A7AA4BAC617'); }); it('should generate hash for TransactionStatement', () => { diff --git a/test/model/transaction/Transaction.spec.ts b/test/model/transaction/Transaction.spec.ts index c98bf76752..8395f95189 100644 --- a/test/model/transaction/Transaction.spec.ts +++ b/test/model/transaction/Transaction.spec.ts @@ -17,7 +17,7 @@ import { expect } from 'chai'; import { Observable } from 'rxjs/internal/Observable'; import { Convert } from '../../../src/core/format/Convert'; -import { NamespaceHttp } from '../../../src/infrastructure/NamespaceHttp'; +import { ReceiptHttp } from '../../../src/infrastructure/ReceiptHttp'; import { Account } from '../../../src/model/account/Account'; import { Address } from '../../../src/model/account/Address'; import { NetworkType } from '../../../src/model/blockchain/NetworkType'; @@ -256,7 +256,6 @@ describe('Transaction', () => { // expected values const knownHash_sha3 = '709373248659274C5933BEA2920942D6C7B48B9C2DA4BAEE233510E71495931F'; - const knownHash_keccak = '787423372BEC0CB2BE3EEA58E773074E121989AF29E5E5BD9EE660C1E3A0AF93'; const generationHashBytes = Array.from(Convert.hexToUint8('988C4CDCE4D188013C13DE7914C7FD4D626169EF256722F61C52EFBE06BD5A2C')); const generationHashBytes_mt = Array.from(Convert.hexToUint8('17FA4747F5014B50413CCF968749604D728D7065DC504291EEE556899A534CBB')); @@ -405,7 +404,7 @@ class FakeTransaction extends Transaction { protected generateEmbeddedBytes(): Uint8Array { throw new Error('Not implemented'); } - resolveAliases(namespaceHttp: NamespaceHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp): Observable { throw new Error('Not implemented'); } } diff --git a/test/service/TransactionService.spec.ts b/test/service/TransactionService.spec.ts new file mode 100644 index 0000000000..30a8d1534c --- /dev/null +++ b/test/service/TransactionService.spec.ts @@ -0,0 +1,208 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { UnresolvedMapping } from '../../src/core/utils/UnresolvedMapping'; +import { CreateStatementFromDTO } from '../../src/infrastructure/receipt/CreateReceiptFromDTO'; +import { Account } from '../../src/model/account/Account'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { Address, MosaicId, NamespaceId, ResolutionType } from '../../src/model/model'; +import { TransactionService } from '../../src/service/TransactionService'; + +describe('TransactionService', () => { + let account: Account; + let transactionStatementsDTO; + let addressResolutionStatementsDTO; + let mosaicResolutionStatementsDTO; + let statementDTO; + + before(() => { + account = Account.createFromPrivateKey('81C18245507F9C15B61BDEDAFA2C10D9DC2C4E401E573A10935D45AA2A461FD5', NetworkType.MIJIN_TEST); + transactionStatementsDTO = [ + { + statement: { + height: '1473', + source: { + primaryId: 0, + secondaryId: 0, + }, + receipts: [ + { + version: 1, + type: 8515, + targetPublicKey: 'B2708D49C46F8AB5CDBD7A09C959EEA12E4A782592F3D1D3D17D54622E655D7F', + mosaicId: '504677C3281108DB', + amount: '0', + }, + ], + }, + }, + ]; + addressResolutionStatementsDTO = [ + { + statement: { + height: '1473', + unresolved: '9156258DE356F030A500000000000000000000000000000000', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '901D8D4741F80299E66BF7FEEB4F30943DA7B68E068B182319', + }, + ], + }, + }, + ]; + mosaicResolutionStatementsDTO = [ + { + statement: { + height: '1473', + unresolved: '85BBEA6CC462B244', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '504677C3281108DB', + }, + ], + }, + }, + { + statement: { + height: '1473', + unresolved: 'E81F622A5B11A340', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '756482FB80FD406C', + }, + ], + }, + }, + ]; + + statementDTO = { + transactionStatements: transactionStatementsDTO, + addressResolutionStatements: addressResolutionStatementsDTO, + mosaicResolutionStatements: mosaicResolutionStatementsDTO, + }; + }); + + it('should get reolved address from receipt', () => { + const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof Address).to.be.true; + expect((resolved as Address).equals(account.address)).to.be.true; + }); + + it('should get reolved address from receipt without Harvesting_Fee', () => { + const statementWithoutHarvesting = { + transactionStatements: [], + addressResolutionStatements: [ + { + statement: { + height: '1473', + unresolved: '9156258DE356F030A500000000000000000000000000000000', + resolutionEntries: [ + { + source: { + primaryId: 0, + secondaryId: 0, + }, + resolved: '901D8D4741F80299E66BF7FEEB4F30943DA7B68E068B182319', + }, + ], + }, + }, + ], + mosaicResolutionStatements: [], + }; + const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); + const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof Address).to.be.true; + expect((resolved as Address).equals(account.address)).to.be.true; + }); + + it('should get reolved mosaic from receipt', () => { + const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof MosaicId).to.be.true; + expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; + }); + + it('should get reolved mosaic from receipt without Harvesting_Fee', () => { + const statementWithoutHarvesting = { + transactionStatements: [], + addressResolutionStatements: [], + mosaicResolutionStatements: [ + { + statement: { + height: '1473', + unresolved: '85BBEA6CC462B244', + resolutionEntries: [ + { + source: { + primaryId: 0, + secondaryId: 0, + }, + resolved: '504677C3281108DB', + }, + ], + }, + }, + { + statement: { + height: '1473', + unresolved: 'E81F622A5B11A340', + resolutionEntries: [ + { + source: { + primaryId: 0, + secondaryId: 0, + }, + resolved: '756482FB80FD406C', + }, + ], + }, + }, + ], + }; + const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); + const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); + const resolved = TransactionService + .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, statement, 0, '1473'); + + expect(resolved instanceof MosaicId).to.be.true; + expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; + }); + +}); From 8da588613c267f5c01e7f1558c29ec4e4d4a79ad Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 21:36:08 +0000 Subject: [PATCH 13/50] Added resolveAliases for AggregateTransaction --- src/model/transaction/AggregateTransaction.ts | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index 63e844f8d4..f79c447689 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { sha3_256 } from 'js-sha3'; import { Observable } from 'rxjs/internal/Observable'; import {KeyPair, MerkleHashBuilder, SHA3Hasher, SignSchema} from '../../core/crypto'; -import {Convert, RawArray} from '../../core/format'; +import {Convert} from '../../core/format'; import {AggregateBondedTransactionBuilder} from '../../infrastructure/catbuffer/AggregateBondedTransactionBuilder'; import {AggregateCompleteTransactionBuilder} from '../../infrastructure/catbuffer/AggregateCompleteTransactionBuilder'; import {AmountDto} from '../../infrastructure/catbuffer/AmountDto'; @@ -42,6 +41,8 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; +import { of, from } from 'rxjs'; +import { map, mergeMap, toArray } from 'rxjs/operators'; /** * Aggregate innerTransactions contain multiple innerTransactions that can be initiated by different accounts. @@ -409,6 +410,24 @@ export class AggregateTransaction extends Transaction { * @returns {TransferTransaction} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { - throw new Error('Not implemented'); + return from(this.innerTransactions).pipe( + mergeMap((transaction) => transaction.resolveAliases(receiptHttp)), + map((transaction) => transaction as InnerTransaction), + toArray(), + ).pipe( + map((innerTransactions) => new AggregateTransaction( + this.networkType, + this.type, + this.version, + this.deadline, + this.maxFee, + innerTransactions, + this.cosignatures, + this.signature, + this.signer, + this.transactionInfo, + ), + ), + ); } } From d1b4b1a0927396303e5e7988be3ef92ac3df58e3 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 22:02:02 +0000 Subject: [PATCH 14/50] Updated e2e tests with aggregated tx --- e2e/service/TransactionService.spec.ts | 72 ++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index e6520cf0b1..17b9fc19de 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -20,19 +20,23 @@ import { Listener } from '../../src/infrastructure/Listener'; import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; import { Account } from '../../src/model/account/Account'; +import { Address } from '../../src/model/account/Address'; import { NetworkType } from '../../src/model/blockchain/NetworkType'; import { PlainMessage } from '../../src/model/message/PlainMessage'; -import { Address, Mosaic, MosaicSupplyChangeAction, MosaicSupplyChangeTransaction } from '../../src/model/model'; +import { Mosaic } from '../../src/model/mosaic/Mosaic'; import { MosaicFlags } from '../../src/model/mosaic/MosaicFlags'; import { MosaicId } from '../../src/model/mosaic/MosaicId'; import { MosaicNonce } from '../../src/model/mosaic/MosaicNonce'; +import { MosaicSupplyChangeAction } from '../../src/model/mosaic/MosaicSupplyChangeAction'; import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; import { AliasAction } from '../../src/model/namespace/AliasAction'; import { NamespaceId } from '../../src/model/namespace/NamespaceId'; import { AddressAliasTransaction } from '../../src/model/transaction/AddressAliasTransaction'; +import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; import { Deadline } from '../../src/model/transaction/Deadline'; import { MosaicAliasTransaction } from '../../src/model/transaction/MosaicAliasTransaction'; import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicDefinitionTransaction'; +import { MosaicSupplyChangeTransaction } from '../../src/model/transaction/MosaicSupplyChangeTransaction'; import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; import { UInt64 } from '../../src/model/UInt64'; @@ -94,7 +98,7 @@ describe('TransactionService', () => { ); addressAlias = new NamespaceId(namespaceName); const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -126,7 +130,7 @@ describe('TransactionService', () => { ); mosaicAlias = new NamespaceId(namespaceName); const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -158,7 +162,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = addressAliasTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -193,7 +197,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicDefinitionTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -219,6 +223,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicSupplyChangeTransaction.signWith(account, generationHash); + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -250,7 +255,7 @@ describe('TransactionService', () => { NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicAliasTransaction.signWith(account, generationHash); - + transactionHashes.push(signedTransaction.hash); listener.confirmed(account.address).subscribe(() => { done(); }); @@ -277,7 +282,7 @@ describe('TransactionService', () => { Deadline.create(), addressAlias, [ - // NetworkCurrencyMosaic.createAbsolute(1), //Seems get banned on rest if passing multiple mosaic alias in + NetworkCurrencyMosaic.createAbsolute(1), new Mosaic(mosaicAlias, UInt64.fromUint(1)), ], PlainMessage.create('test-message'), @@ -298,13 +303,60 @@ describe('TransactionService', () => { transactionHttp.announce(signedTransaction); }); }); + + describe('Create Aggreate TransferTransaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('aggregate', (done) => { + const transferTransaction = TransferTransaction.create( + Deadline.create(), + addressAlias, + [ + NetworkCurrencyMosaic.createAbsolute(1), + new Mosaic(mosaicAlias, UInt64.fromUint(1)), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [transferTransaction.toAggregate(account.publicAccount)], + NetworkType.MIJIN_TEST, + [], + ); + const signedTransaction = aggregateTransaction.signWith(account, generationHash); + transactionHashes.push(signedTransaction.hash); + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); describe('should return resolved transaction', () => { it('call transaction service', (done) => { const transactionService = new TransactionService(url); return transactionService.resolveAliases(transactionHashes).subscribe((transactions) => { - transactions.map((tx: TransferTransaction) => { - expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); - expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + expect(transactions.length).to.be.equal(8); + transactions.map((tx) => { + if (tx instanceof TransferTransaction) { + expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); + expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + } else if (tx instanceof AggregateTransaction) { + expect(((tx.innerTransactions[0] as TransferTransaction).recipientAddress as Address) + .plain()).to.be.equal(account.address.plain()); + expect((tx.innerTransactions[0] as TransferTransaction).mosaics + .find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + } }); done(); }); From 7f3886b8fc0372d5d8f66f256d6a0748918ea918 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Sat, 30 Nov 2019 22:20:22 +0000 Subject: [PATCH 15/50] Fixed jsdoc issues --- e2e/service/TransactionService.spec.ts | 7 +++++++ .../transaction/AccountAddressRestrictionTransaction.ts | 2 +- src/model/transaction/AccountLinkTransaction.ts | 2 +- src/model/transaction/AccountMetadataTransaction.ts | 2 +- .../transaction/AccountMosaicRestrictionTransaction.ts | 2 +- .../transaction/AccountOperationRestrictionTransaction.ts | 2 +- src/model/transaction/AddressAliasTransaction.ts | 2 +- src/model/transaction/AggregateTransaction.ts | 2 +- src/model/transaction/LockFundsTransaction.ts | 2 +- .../transaction/MosaicAddressRestrictionTransaction.ts | 2 +- src/model/transaction/MosaicAliasTransaction.ts | 2 +- src/model/transaction/MosaicDefinitionTransaction.ts | 2 +- .../transaction/MosaicGlobalRestrictionTransaction.ts | 2 +- src/model/transaction/MosaicMetadataTransaction.ts | 2 +- src/model/transaction/MosaicSupplyChangeTransaction.ts | 2 +- .../transaction/MultisigAccountModificationTransaction.ts | 2 +- src/model/transaction/NamespaceMetadataTransaction.ts | 2 +- src/model/transaction/NamespaceRegistrationTransaction.ts | 2 +- src/model/transaction/SecretLockTransaction.ts | 2 +- src/model/transaction/SecretProofTransaction.ts | 2 +- src/model/transaction/Transaction.ts | 1 + src/model/transaction/TransferTransaction.ts | 2 +- 22 files changed, 28 insertions(+), 20 deletions(-) diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index 17b9fc19de..6669cf162d 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -342,6 +342,13 @@ describe('TransactionService', () => { transactionHttp.announce(signedTransaction); }); }); + + /** + * ========================= + * Test + * ========================= + */ + describe('should return resolved transaction', () => { it('call transaction service', (done) => { const transactionService = new TransactionService(url); diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 05960c8667..5c8d3886ae 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -199,7 +199,7 @@ export class AccountAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || diff --git a/src/model/transaction/AccountLinkTransaction.ts b/src/model/transaction/AccountLinkTransaction.ts index bbfa101882..e1cb514b44 100644 --- a/src/model/transaction/AccountLinkTransaction.ts +++ b/src/model/transaction/AccountLinkTransaction.ts @@ -170,7 +170,7 @@ export class AccountLinkTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AccountMetadataTransaction.ts b/src/model/transaction/AccountMetadataTransaction.ts index 2e41cde6ff..b5e4a40558 100644 --- a/src/model/transaction/AccountMetadataTransaction.ts +++ b/src/model/transaction/AccountMetadataTransaction.ts @@ -200,7 +200,7 @@ export class AccountMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index 0fa304b41c..d0f3a63e19 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -199,7 +199,7 @@ export class AccountMosaicRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || diff --git a/src/model/transaction/AccountOperationRestrictionTransaction.ts b/src/model/transaction/AccountOperationRestrictionTransaction.ts index e38165001e..b8086f56b0 100644 --- a/src/model/transaction/AccountOperationRestrictionTransaction.ts +++ b/src/model/transaction/AccountOperationRestrictionTransaction.ts @@ -181,7 +181,7 @@ export class AccountOperationRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AddressAliasTransaction.ts b/src/model/transaction/AddressAliasTransaction.ts index ea8f874a27..20696aa65f 100644 --- a/src/model/transaction/AddressAliasTransaction.ts +++ b/src/model/transaction/AddressAliasTransaction.ts @@ -190,7 +190,7 @@ export class AddressAliasTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index f79c447689..f89904787f 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -407,7 +407,7 @@ export class AggregateTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return from(this.innerTransactions).pipe( diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index 1464784e88..4a6ede77b2 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -213,7 +213,7 @@ export class LockFundsTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.mosaic.id instanceof NamespaceId; diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index e4095cb413..13f7935918 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -244,7 +244,7 @@ export class MosaicAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.targetAddress instanceof NamespaceId || diff --git a/src/model/transaction/MosaicAliasTransaction.ts b/src/model/transaction/MosaicAliasTransaction.ts index f1c9dd186d..50ef6548c3 100644 --- a/src/model/transaction/MosaicAliasTransaction.ts +++ b/src/model/transaction/MosaicAliasTransaction.ts @@ -185,7 +185,7 @@ export class MosaicAliasTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/MosaicDefinitionTransaction.ts b/src/model/transaction/MosaicDefinitionTransaction.ts index 257073c695..69eb9782c2 100644 --- a/src/model/transaction/MosaicDefinitionTransaction.ts +++ b/src/model/transaction/MosaicDefinitionTransaction.ts @@ -228,7 +228,7 @@ export class MosaicDefinitionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index c2546c2056..4542567cc2 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -253,7 +253,7 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId || diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index c48c020ebb..952870a23c 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -219,7 +219,7 @@ export class MosaicMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.targetMosaicId instanceof NamespaceId; diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index f927b249c6..1f27366824 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -193,7 +193,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId; diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index 7dae91c99f..2d7a64d866 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -220,7 +220,7 @@ export class MultisigAccountModificationTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/NamespaceMetadataTransaction.ts b/src/model/transaction/NamespaceMetadataTransaction.ts index 5b2645f701..29ee8a8948 100644 --- a/src/model/transaction/NamespaceMetadataTransaction.ts +++ b/src/model/transaction/NamespaceMetadataTransaction.ts @@ -216,7 +216,7 @@ export class NamespaceMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/NamespaceRegistrationTransaction.ts b/src/model/transaction/NamespaceRegistrationTransaction.ts index 9130fbe2c2..ed631a043c 100644 --- a/src/model/transaction/NamespaceRegistrationTransaction.ts +++ b/src/model/transaction/NamespaceRegistrationTransaction.ts @@ -280,7 +280,7 @@ export class NamespaceRegistrationTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index c9fd2455c0..66a47b877d 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -241,7 +241,7 @@ export class SecretLockTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 33cc84ab21..99dcb374fc 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -217,7 +217,7 @@ export class SecretProofTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId; diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index 2f53db47af..c83ed25e3d 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -191,6 +191,7 @@ export abstract class Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @returns {Observable} */ abstract resolveAliases(receiptHttp: ReceiptHttp): Observable; diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index 241b5ccd22..dfa4aa66d8 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -282,7 +282,7 @@ export class TransferTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {TransferTransaction} + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || From 4f497aedd8c4a4974fdaeba0ee75aedb8fa38575 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 2 Dec 2019 09:41:31 +0000 Subject: [PATCH 16/50] - Fixed primary source id as confirmed by Jag - Updated aggregate transaction handler with secondary source id --- .../AccountAddressRestrictionTransaction.ts | 7 ++++--- .../AccountMosaicRestrictionTransaction.ts | 7 ++++--- src/model/transaction/AggregateTransaction.ts | 7 ++++--- src/model/transaction/LockFundsTransaction.ts | 6 ++++-- .../MosaicAddressRestrictionTransaction.ts | 7 ++++--- .../MosaicGlobalRestrictionTransaction.ts | 7 ++++--- .../transaction/MosaicMetadataTransaction.ts | 5 +++-- .../MosaicSupplyChangeTransaction.ts | 5 +++-- .../MultisigAccountModificationTransaction.ts | 2 +- src/model/transaction/SecretLockTransaction.ts | 8 +++++--- src/model/transaction/SecretProofTransaction.ts | 5 +++-- src/model/transaction/Transaction.ts | 3 ++- src/model/transaction/TransferTransaction.ts | 8 +++++--- src/service/TransactionService.ts | 17 ++++++++--------- test/model/transaction/Transaction.spec.ts | 2 +- test/service/TransactionService.spec.ts | 6 +++--- 16 files changed, 58 insertions(+), 44 deletions(-) diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 5c8d3886ae..4566a36068 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -199,9 +199,10 @@ export class AccountAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || this.restrictionDeletions.find((address) => address instanceof NamespaceId) !== undefined; @@ -217,7 +218,7 @@ export class AccountAddressRestrictionTransaction extends Transaction { return this.restrictionAdditions.map((addition) => { return addition instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, addition as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : addition; }); }), @@ -228,7 +229,7 @@ export class AccountAddressRestrictionTransaction extends Transaction { return this.restrictionDeletions.map((deletion) => { return deletion instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, deletion as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : deletion; }); }), diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index d0f3a63e19..cbfab8525c 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -199,9 +199,10 @@ export class AccountMosaicRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || this.restrictionDeletions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined; @@ -217,7 +218,7 @@ export class AccountMosaicRestrictionTransaction extends Transaction { return this.restrictionAdditions.map((addition) => { return addition instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, addition as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : addition; }); }), @@ -228,7 +229,7 @@ export class AccountMosaicRestrictionTransaction extends Transaction { return this.restrictionDeletions.map((deletion) => { return deletion instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, deletion as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : deletion; }); }), diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index f89904787f..90c069e093 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -14,7 +14,9 @@ * limitations under the License. */ +import { from, of } from 'rxjs'; import { Observable } from 'rxjs/internal/Observable'; +import { map, mergeMap, toArray } from 'rxjs/operators'; import {KeyPair, MerkleHashBuilder, SHA3Hasher, SignSchema} from '../../core/crypto'; import {Convert} from '../../core/format'; import {AggregateBondedTransactionBuilder} from '../../infrastructure/catbuffer/AggregateBondedTransactionBuilder'; @@ -41,8 +43,6 @@ import {Transaction} from './Transaction'; import {TransactionInfo} from './TransactionInfo'; import {TransactionType} from './TransactionType'; import {TransactionVersion} from './TransactionVersion'; -import { of, from } from 'rxjs'; -import { map, mergeMap, toArray } from 'rxjs/operators'; /** * Aggregate innerTransactions contain multiple innerTransactions that can be initiated by different accounts. @@ -410,8 +410,9 @@ export class AggregateTransaction extends Transaction { * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { + const transactionInfo = this.checkTransactionHeightAndIndex(); return from(this.innerTransactions).pipe( - mergeMap((transaction) => transaction.resolveAliases(receiptHttp)), + mergeMap((transaction) => transaction.resolveAliases(receiptHttp, transactionInfo.index)), map((transaction) => transaction as InnerTransaction), toArray(), ).pipe( diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index 4a6ede77b2..e902ccf86f 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -213,9 +213,10 @@ export class LockFundsTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.mosaic.id instanceof NamespaceId; if (!hasUnresolved) { @@ -232,7 +233,8 @@ export class LockFundsTransaction extends Transaction { this.deadline, this.maxFee, new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaic.id as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount), + statement, transactionInfo.index, transactionInfo.height.toString(), + aggregateTransactionIndex) as MosaicId, this.mosaic.amount), this.duration, this.signedTransaction, this.signature, diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 13f7935918..57c6213344 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -244,9 +244,10 @@ export class MosaicAddressRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.targetAddress instanceof NamespaceId || this.mosaicId instanceof NamespaceId; @@ -261,7 +262,7 @@ export class MosaicAddressRestrictionTransaction extends Transaction { const resolvedAddress = statementObservable.pipe( map((statement) => this.targetAddress instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.targetAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.targetAddress, ), ); @@ -269,7 +270,7 @@ export class MosaicAddressRestrictionTransaction extends Transaction { const resolvedMosaicId = statementObservable.pipe( map((statement) => this.mosaicId instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.mosaicId, ), ); diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 4542567cc2..39b5078252 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -253,9 +253,10 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId || this.referenceMosaicId instanceof NamespaceId; @@ -270,7 +271,7 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { const resolvedMosaicId = statementObservable.pipe( map((statement) => this.mosaicId instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.mosaicId, ), ); @@ -278,7 +279,7 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { const resolvedRefMosaicId = statementObservable.pipe( map((statement) => this.referenceMosaicId instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.referenceMosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.referenceMosaicId, ), ); diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index 952870a23c..8cc77ba69d 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -219,9 +219,10 @@ export class MosaicMetadataTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.targetMosaicId instanceof NamespaceId; if (!hasUnresolved) { @@ -241,7 +242,7 @@ export class MosaicMetadataTransaction extends Transaction { this.targetPublicKey, this.scopedMetadataKey, TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.targetMosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.valueSizeDelta, this.value, this.signature, diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index 1f27366824..db17c7ce2f 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -193,9 +193,10 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.mosaicId instanceof NamespaceId; if (!hasUnresolved) { @@ -214,7 +215,7 @@ export class MosaicSupplyChangeTransaction extends Transaction { this.deadline, this.maxFee, TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.action, this.delta, this.signature, diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index 2d7a64d866..cce5c9f6e0 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -220,7 +220,7 @@ export class MultisigAccountModificationTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp - * @returns {Observable + * @returns {Observable} */ resolveAliases(receiptHttp: ReceiptHttp): Observable { return of(this); diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index 66a47b877d..6fb5c0de90 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -241,9 +241,10 @@ export class SecretLockTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || this.mosaic.id instanceof NamespaceId; @@ -258,7 +259,7 @@ export class SecretLockTransaction extends Transaction { const resolvedRecipient = statementObservable.pipe( map((statement) => this.recipientAddress instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.recipientAddress, ), ); @@ -266,7 +267,8 @@ export class SecretLockTransaction extends Transaction { const resolvedMosaic = statementObservable.pipe( map((statement) => this.mosaic.id instanceof NamespaceId ? new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, this.mosaic.amount) : + statement, transactionInfo.index, transactionInfo.height.toString(), + aggregateTransactionIndex) as MosaicId, this.mosaic.amount) : this.mosaic, ), ); diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 99dcb374fc..f97fca4d30 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -217,9 +217,10 @@ export class SecretProofTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId; if (!hasUnresolved) { @@ -239,7 +240,7 @@ export class SecretProofTransaction extends Transaction { this.hashType, this.secret, TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address, + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address, this.proof, this.signature, this.signer, diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index c83ed25e3d..0af948d992 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -191,9 +191,10 @@ export abstract class Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param AggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - abstract resolveAliases(receiptHttp: ReceiptHttp): Observable; + abstract resolveAliases(receiptHttp: ReceiptHttp, AggregateTransactionIndex?: number): Observable; /** * @internal diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index dfa4aa66d8..7c3181f31e 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -282,9 +282,10 @@ export class TransferTransaction extends Transaction { /** * @internal * @param receiptHttp ReceiptHttp + * @param aggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { const hasUnresolved = this.recipientAddress instanceof NamespaceId || this.mosaics.find((mosaic) => mosaic.id instanceof NamespaceId) !== undefined; @@ -299,7 +300,7 @@ export class TransferTransaction extends Transaction { const resolvedRecipient = statementObservable.pipe( map((statement) => this.recipientAddress instanceof NamespaceId ? TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as Address : + statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.recipientAddress, ), ); @@ -309,7 +310,8 @@ export class TransferTransaction extends Transaction { this.mosaics.map((mosaic) => mosaic.id instanceof NamespaceId ? new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, mosaic.id as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString()) as MosaicId, mosaic.amount) : + statement, transactionInfo.index, transactionInfo.height.toString(), + aggregateTransactionIndex) as MosaicId, mosaic.amount) : mosaic, ), ), diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index d657fe594d..f733c58405 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -50,20 +50,15 @@ export class TransactionService { * @param statement Block receipt statement * @param transactionIndex Transaction index * @param height Transaction height + * @param aggregateTransactionIndex Transaction index for aggregate * @returns {MosaicId | Address} */ public static getResolvedFromReceipt(resolutionType: ResolutionType, unresolved: NamespaceId, statement: Statement, transactionIndex: number, - height: string): MosaicId | Address { - // Check if Harvest_Fee receipt exists on the block as it always takes the index 0. - const hasHarvestStatement = statement.transactionStatements - .find((transactionStatements) => transactionStatements.source.primaryId === 0 && - transactionStatements.receipts.find((receipt) => receipt.type === ReceiptType.Harvest_Fee) !== undefined) !== undefined; - - // Transaction index can be different if Harvest_Fee transaction exists. - transactionIndex = hasHarvestStatement ? transactionIndex + 1 : transactionIndex; + height: string, + aggregateTransactionIndex?: number): MosaicId | Address { const resolutionStatement = (resolutionType === ResolutionType.Address ? statement.addressResolutionStatements : statement.mosaicResolutionStatements).find((resolution) => resolution.height.toString() === height && @@ -73,7 +68,11 @@ export class TransactionService { throw new Error('No resolution statement found'); } - const resolutionEntry = resolutionStatement.resolutionEntries.find((entry) => entry.source.primaryId === transactionIndex); + // source (0,0) is reserved for blocks, source (n, 0) is for txes, where n is 1-based index + const resolutionEntry = resolutionStatement.resolutionEntries + .find((entry) => entry.source.primaryId === + (aggregateTransactionIndex ? aggregateTransactionIndex + 1 : transactionIndex + 1) && + entry.source.secondaryId === (aggregateTransactionIndex ? transactionIndex : 0)); if (!resolutionEntry) { throw new Error('No resolution entry found'); diff --git a/test/model/transaction/Transaction.spec.ts b/test/model/transaction/Transaction.spec.ts index 8395f95189..b86267517f 100644 --- a/test/model/transaction/Transaction.spec.ts +++ b/test/model/transaction/Transaction.spec.ts @@ -404,7 +404,7 @@ class FakeTransaction extends Transaction { protected generateEmbeddedBytes(): Uint8Array { throw new Error('Not implemented'); } - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { throw new Error('Not implemented'); } } diff --git a/test/service/TransactionService.spec.ts b/test/service/TransactionService.spec.ts index 30a8d1534c..d4071b43b7 100644 --- a/test/service/TransactionService.spec.ts +++ b/test/service/TransactionService.spec.ts @@ -129,7 +129,7 @@ describe('TransactionService', () => { resolutionEntries: [ { source: { - primaryId: 0, + primaryId: 1, secondaryId: 0, }, resolved: '901D8D4741F80299E66BF7FEEB4F30943DA7B68E068B182319', @@ -171,7 +171,7 @@ describe('TransactionService', () => { resolutionEntries: [ { source: { - primaryId: 0, + primaryId: 1, secondaryId: 0, }, resolved: '504677C3281108DB', @@ -186,7 +186,7 @@ describe('TransactionService', () => { resolutionEntries: [ { source: { - primaryId: 0, + primaryId: 1, secondaryId: 0, }, resolved: '756482FB80FD406C', From 510a64884f55778d5d0fe2f8dceb07c357550dcc Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 2 Dec 2019 10:15:46 +0000 Subject: [PATCH 17/50] Fixed bug in transaction service --- src/service/TransactionService.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index f733c58405..952e78b6b0 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -67,12 +67,11 @@ export class TransactionService { if (!resolutionStatement) { throw new Error('No resolution statement found'); } - // source (0,0) is reserved for blocks, source (n, 0) is for txes, where n is 1-based index const resolutionEntry = resolutionStatement.resolutionEntries .find((entry) => entry.source.primaryId === - (aggregateTransactionIndex ? aggregateTransactionIndex + 1 : transactionIndex + 1) && - entry.source.secondaryId === (aggregateTransactionIndex ? transactionIndex : 0)); + (aggregateTransactionIndex !== undefined ? aggregateTransactionIndex + 1 : transactionIndex + 1) && + entry.source.secondaryId === (aggregateTransactionIndex !== undefined ? transactionIndex + 1 : 0)); if (!resolutionEntry) { throw new Error('No resolution entry found'); From e484c93ba1fde33f52f3d9cc9f172ede8ade7ab9 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Mon, 2 Dec 2019 12:19:13 +0000 Subject: [PATCH 18/50] Sort aggregate inner transactions to original order --- e2e/service/TransactionService.spec.ts | 67 ++++++++++++++++++- src/model/transaction/AggregateTransaction.ts | 2 +- src/service/TransactionService.ts | 1 - 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index 6669cf162d..1812a12cad 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -16,6 +16,7 @@ import { assert } from 'chai'; import { expect } from 'chai'; +import { Convert } from '../../src/core/format/Convert'; import { Listener } from '../../src/infrastructure/Listener'; import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; @@ -36,6 +37,7 @@ import { AggregateTransaction } from '../../src/model/transaction/AggregateTrans import { Deadline } from '../../src/model/transaction/Deadline'; import { MosaicAliasTransaction } from '../../src/model/transaction/MosaicAliasTransaction'; import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicDefinitionTransaction'; +import { MosaicMetadataTransaction } from '../../src/model/transaction/MosaicMetadataTransaction'; import { MosaicSupplyChangeTransaction } from '../../src/model/transaction/MosaicSupplyChangeTransaction'; import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; @@ -51,6 +53,7 @@ describe('TransactionService', () => { let addressAlias: NamespaceId; let mosaicAlias: NamespaceId; let mosaicId: MosaicId; + let newMosaicId: MosaicId; let transactionHttp: TransactionHttp; let config; let transactionHashes: string[]; @@ -125,7 +128,7 @@ describe('TransactionService', () => { const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( Deadline.create(), namespaceName, - UInt64.fromUint(9), + UInt64.fromUint(20), NetworkType.MIJIN_TEST, ); mosaicAlias = new NamespaceId(namespaceName); @@ -304,6 +307,12 @@ describe('TransactionService', () => { }); }); + /** + * ===================================== + * Setup test aggregate transaction data + * ===================================== + */ + describe('Create Aggreate TransferTransaction', () => { let listener: Listener; before (() => { @@ -324,8 +333,56 @@ describe('TransactionService', () => { PlainMessage.create('test-message'), NetworkType.MIJIN_TEST, ); + // Unlink MosaicAlias + const mosaicAliasTransactionUnlink = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Unlink, + mosaicAlias, + mosaicId, + NetworkType.MIJIN_TEST, + ); + + // Create a new Mosaic + const nonce = MosaicNonce.createRandom(); + newMosaicId = MosaicId.createFromNonce(nonce, account.publicAccount); + const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( + Deadline.create(), + nonce, + newMosaicId, + MosaicFlags.create(true, true, false), + 3, + UInt64.fromUint(0), + NetworkType.MIJIN_TEST, + ); + + // Link namespace with new MosaicId + const mosaicAliasTransactionRelink = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Link, + mosaicAlias, + newMosaicId, + NetworkType.MIJIN_TEST, + ); + + // Use new mosaicAlias in metadata + const mosaicMetadataTransaction = MosaicMetadataTransaction.create( + Deadline.create(), + account.publicKey, + UInt64.fromUint(5), + mosaicAlias, + 10, + Convert.uint8ToUtf8(new Uint8Array(10)), + NetworkType.MIJIN_TEST, + ); const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), - [transferTransaction.toAggregate(account.publicAccount)], + [ + transferTransaction.toAggregate(account.publicAccount), + mosaicAliasTransactionUnlink.toAggregate(account.publicAccount), + mosaicDefinitionTransaction.toAggregate(account.publicAccount), + mosaicAliasTransactionRelink.toAggregate(account.publicAccount), + mosaicMetadataTransaction.toAggregate(account.publicAccount), + + ], NetworkType.MIJIN_TEST, [], ); @@ -359,13 +416,17 @@ describe('TransactionService', () => { expect((tx.recipientAddress as Address).plain()).to.be.equal(account.address.plain()); expect(tx.mosaics.find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); } else if (tx instanceof AggregateTransaction) { + expect(tx.innerTransactions.length).to.be.equal(5); + // Assert Transfer expect(((tx.innerTransactions[0] as TransferTransaction).recipientAddress as Address) .plain()).to.be.equal(account.address.plain()); expect((tx.innerTransactions[0] as TransferTransaction).mosaics .find((m) => m.id.toHex() === mosaicId.toHex())).not.to.equal(undefined); + // Assert MosaicMeta + expect((tx.innerTransactions[4] as MosaicMetadataTransaction) + .targetMosaicId.toHex() === newMosaicId.toHex()).to.be.true; } }); - done(); }); }); }); diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index 90c069e093..98e6874626 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -422,7 +422,7 @@ export class AggregateTransaction extends Transaction { this.version, this.deadline, this.maxFee, - innerTransactions, + innerTransactions.sort((a, b) => a.transactionInfo!.index - b.transactionInfo!.index), this.cosignatures, this.signature, this.signer, diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 952e78b6b0..46fd5d84a9 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -21,7 +21,6 @@ import { TransactionHttp } from '../infrastructure/TransactionHttp'; import { Address } from '../model/account/Address'; import { MosaicId } from '../model/mosaic/MosaicId'; import { NamespaceId } from '../model/namespace/NamespaceId'; -import { ReceiptType } from '../model/receipt/ReceiptType'; import { ResolutionType } from '../model/receipt/ResolutionType'; import { Statement } from '../model/receipt/Statement'; import { Transaction } from '../model/transaction/Transaction'; From a2e0dd46dfb023356cd2eb9fb8435889b02c65c0 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 09:26:37 +0000 Subject: [PATCH 19/50] Added transactionService interface --- src/service/TransactionService.ts | 3 +- src/service/interfaces/ITransactionService.ts | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/service/interfaces/ITransactionService.ts diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 46fd5d84a9..089b035c91 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -24,11 +24,12 @@ import { NamespaceId } from '../model/namespace/NamespaceId'; import { ResolutionType } from '../model/receipt/ResolutionType'; import { Statement } from '../model/receipt/Statement'; import { Transaction } from '../model/transaction/Transaction'; +import { ITransactionService } from './interfaces/ITransactionService'; /** * Transaction Service */ -export class TransactionService { +export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts new file mode 100644 index 0000000000..6bbeb16160 --- /dev/null +++ b/src/service/interfaces/ITransactionService.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {Observable} from 'rxjs'; +import { Transaction } from '../../model/transaction/Transaction'; + +/** + * Transaction Service Interface + */ +export interface ITransactionService { + + /** + * @param transationHashes List of transaction hashes. + * @returns Observable + */ + resolveAliases(transationHashes: string[]): Observable; +} From 58dd436b21a02d1832d7ae50f2513c17ee34caf0 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 20/50] Added #352 aggregate bonded announcing --- src/infrastructure/Listener.ts | 14 ++++-- src/model/transaction/SignedTransaction.ts | 10 +++++ src/service/TransactionService.ts | 45 ++++++++++++++++++- src/service/interfaces/ITransactionService.ts | 26 ++++++++++- 4 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/infrastructure/Listener.ts b/src/infrastructure/Listener.ts index 582ef69ed2..f1778b29ed 100644 --- a/src/infrastructure/Listener.ts +++ b/src/infrastructure/Listener.ts @@ -239,15 +239,18 @@ export class Listener { * it emits a new Transaction in the event stream. * * @param address address we listen when a transaction is in confirmed state + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of Transaction with state confirmed */ - public confirmed(address: Address): Observable { + public confirmed(address: Address, transactionHash?: string): Observable { this.subscribeTo(`confirmedAdded/${address.plain()}`); return this.messageSubject.asObservable().pipe( filter((_) => _.channelName === ListenerChannelName.confirmedAdded), filter((_) => _.message instanceof Transaction), map((_) => _.message as Transaction), - filter((_) => this.transactionFromAddress(_, address))); + filter((_) => this.transactionFromAddress(_, address)), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), + ); } /** @@ -289,15 +292,18 @@ export class Listener { * it emits a new {@link AggregateTransaction} in the event stream. * * @param address address we listen when a transaction with missing signatures state + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of AggregateTransaction with missing signatures state */ - public aggregateBondedAdded(address: Address): Observable { + public aggregateBondedAdded(address: Address, transactionHash?: string): Observable { this.subscribeTo(`partialAdded/${address.plain()}`); return this.messageSubject.asObservable().pipe( filter((_) => _.channelName === ListenerChannelName.aggregateBondedAdded), filter((_) => _.message instanceof AggregateTransaction), map((_) => _.message as AggregateTransaction), - filter((_) => this.transactionFromAddress(_, address))); + filter((_) => this.transactionFromAddress(_, address)), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), + ); } /** diff --git a/src/model/transaction/SignedTransaction.ts b/src/model/transaction/SignedTransaction.ts index addc04c6a1..bc776b4eb6 100644 --- a/src/model/transaction/SignedTransaction.ts +++ b/src/model/transaction/SignedTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Address } from '../account/Address'; +import { PublicAccount } from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; /** @@ -65,4 +67,12 @@ export class SignedTransaction { networkType: this.networkType, }; } + + /** + * Return signer's address + * @returns {Address} + */ + getSignerAddress(): Address { + return PublicAccount.createFromPublicKey(this.signerPublicKey, this.networkType).address; + } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 089b035c91..31771cd7ab 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -16,6 +16,8 @@ import {Observable} from 'rxjs'; import { mergeMap, toArray} from 'rxjs/operators'; +import { flatMap } from 'rxjs/operators'; +import { Listener } from '../infrastructure/Listener'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; import { Address } from '../model/account/Address'; @@ -23,6 +25,8 @@ import { MosaicId } from '../model/mosaic/MosaicId'; import { NamespaceId } from '../model/namespace/NamespaceId'; import { ResolutionType } from '../model/receipt/ResolutionType'; import { Statement } from '../model/receipt/Statement'; +import { AggregateTransaction } from '../model/transaction/AggregateTransaction'; +import { SignedTransaction } from '../model/transaction/SignedTransaction'; import { Transaction } from '../model/transaction/Transaction'; import { ITransactionService } from './interfaces/ITransactionService'; @@ -33,6 +37,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -40,6 +45,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** @@ -65,7 +71,7 @@ export class TransactionService implements ITransactionService { (resolution.unresolved as NamespaceId).equals(unresolved)); if (!resolutionStatement) { - throw new Error('No resolution statement found'); + throw new Error(`No resolution statement found for unsolved value: ${unresolved.toHex()}`); } // source (0,0) is reserved for blocks, source (n, 0) is for txes, where n is 1-based index const resolutionEntry = resolutionStatement.resolutionEntries @@ -74,7 +80,7 @@ export class TransactionService implements ITransactionService { entry.source.secondaryId === (aggregateTransactionIndex !== undefined ? transactionIndex + 1 : 0)); if (!resolutionEntry) { - throw new Error('No resolution entry found'); + throw new Error(`No resolution entry found for unsolved value: ${unresolved.toHex()}`); } return resolutionEntry.resolved; @@ -91,4 +97,39 @@ export class TransactionService implements ITransactionService { toArray(), ); } + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable { + return this.announce(signedHashLockTransaction).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + ); + + } } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 6bbeb16160..37a0984911 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,8 @@ */ import {Observable} from 'rxjs'; +import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; +import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; /** @@ -24,7 +26,29 @@ export interface ITransactionService { /** * @param transationHashes List of transaction hashes. - * @returns Observable + * @returns {Observable} */ resolveAliases(transationHashes: string[]): Observable; + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + announce(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable; } From afb2be10c41a4115337afa9086d942b1c43df354 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 23:08:42 +0000 Subject: [PATCH 21/50] get most recent resolution entry --- e2e/service/TransactionService.spec.ts | 238 ++++++++++++++---- src/infrastructure/Listener.ts | 14 +- src/model/receipt/ResolutionStatement.ts | 74 +++++- src/model/receipt/Statement.ts | 45 ++++ .../AccountAddressRestrictionTransaction.ts | 8 +- .../AccountMosaicRestrictionTransaction.ts | 8 +- src/model/transaction/LockFundsTransaction.ts | 4 +- .../MosaicAddressRestrictionTransaction.ts | 8 +- .../MosaicGlobalRestrictionTransaction.ts | 8 +- .../transaction/MosaicMetadataTransaction.ts | 4 +- .../MosaicSupplyChangeTransaction.ts | 4 +- .../transaction/SecretLockTransaction.ts | 8 +- .../transaction/SecretProofTransaction.ts | 4 +- src/model/transaction/TransferTransaction.ts | 8 +- src/service/TransactionService.ts | 43 ---- .../receipt/Statement.spec.ts} | 29 ++- 16 files changed, 356 insertions(+), 151 deletions(-) rename test/{service/TransactionService.spec.ts => model/receipt/Statement.spec.ts} (90%) diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index 1812a12cad..060d3dfe5d 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -40,6 +40,7 @@ import { MosaicDefinitionTransaction } from '../../src/model/transaction/MosaicD import { MosaicMetadataTransaction } from '../../src/model/transaction/MosaicMetadataTransaction'; import { MosaicSupplyChangeTransaction } from '../../src/model/transaction/MosaicSupplyChangeTransaction'; import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; +import { SignedTransaction } from '../../src/model/transaction/SignedTransaction'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; import { UInt64 } from '../../src/model/UInt64'; import { TransactionService } from '../../src/service/TransactionService'; @@ -47,6 +48,8 @@ import { TransactionService } from '../../src/service/TransactionService'; describe('TransactionService', () => { let account: Account; let account2: Account; + let account3: Account; + let account4: Account; let url: string; let generationHash: string; let namespaceHttp: NamespaceHttp; @@ -57,6 +60,7 @@ describe('TransactionService', () => { let transactionHttp: TransactionHttp; let config; let transactionHashes: string[]; + let transactionHashesMultiple: string[]; before((done) => { const path = require('path'); @@ -68,11 +72,14 @@ describe('TransactionService', () => { config = json; account = Account.createFromPrivateKey(json.testAccount.privateKey, NetworkType.MIJIN_TEST); account2 = Account.createFromPrivateKey(json.testAccount2.privateKey, NetworkType.MIJIN_TEST); + account3 = Account.createFromPrivateKey(json.testAccount3.privateKey, NetworkType.MIJIN_TEST); + account4 = Account.createFromPrivateKey(json.cosignatory4Account.privateKey, NetworkType.MIJIN_TEST); url = json.apiUrl; generationHash = json.generationHash; namespaceHttp = new NamespaceHttp(json.apiUrl); transactionHttp = new TransactionHttp(json.apiUrl); transactionHashes = []; + transactionHashesMultiple = []; done(); }); }); @@ -96,7 +103,7 @@ describe('TransactionService', () => { const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( Deadline.create(), namespaceName, - UInt64.fromUint(9), + UInt64.fromUint(20), NetworkType.MIJIN_TEST, ); addressAlias = new NamespaceId(namespaceName); @@ -128,7 +135,7 @@ describe('TransactionService', () => { const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( Deadline.create(), namespaceName, - UInt64.fromUint(20), + UInt64.fromUint(50), NetworkType.MIJIN_TEST, ); mosaicAlias = new NamespaceId(namespaceName); @@ -196,7 +203,7 @@ describe('TransactionService', () => { mosaicId, MosaicFlags.create(true, true, false), 3, - UInt64.fromUint(0), + UInt64.fromUint(50), NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicDefinitionTransaction.signWith(account, generationHash); @@ -222,7 +229,7 @@ describe('TransactionService', () => { Deadline.create(), mosaicId, MosaicSupplyChangeAction.Increase, - UInt64.fromUint(10), + UInt64.fromUint(200000), NetworkType.MIJIN_TEST, ); const signedTransaction = mosaicSupplyChangeTransaction.signWith(account, generationHash); @@ -323,72 +330,107 @@ describe('TransactionService', () => { return listener.close(); }); it('aggregate', (done) => { + const signedTransaction = buildAggregateTransaction().signWith(account, generationHash); + transactionHashes.push(signedTransaction.hash); + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + /** + * ===================================== + * Setup test Multiple transaction on same block + * ===================================== + */ + + describe('Transfer mosaic to account 3', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + + it('Announce TransferTransaction', (done) => { const transferTransaction = TransferTransaction.create( Deadline.create(), - addressAlias, + account3.address, [ - NetworkCurrencyMosaic.createAbsolute(1), - new Mosaic(mosaicAlias, UInt64.fromUint(1)), + new Mosaic(mosaicAlias, UInt64.fromUint(200)), ], PlainMessage.create('test-message'), NetworkType.MIJIN_TEST, ); - // Unlink MosaicAlias - const mosaicAliasTransactionUnlink = MosaicAliasTransaction.create( - Deadline.create(), - AliasAction.Unlink, - mosaicAlias, - mosaicId, - NetworkType.MIJIN_TEST, - ); + const signedTransaction = transferTransaction.signWith(account, generationHash); - // Create a new Mosaic - const nonce = MosaicNonce.createRandom(); - newMosaicId = MosaicId.createFromNonce(nonce, account.publicAccount); - const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( - Deadline.create(), - nonce, - newMosaicId, - MosaicFlags.create(true, true, false), - 3, - UInt64.fromUint(0), - NetworkType.MIJIN_TEST, - ); + transactionHashes.push(signedTransaction.hash); + + listener.confirmed(account.address).subscribe(() => { + done(); + }); + listener.status(account.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + describe('Create multiple transfers with alias', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); - // Link namespace with new MosaicId - const mosaicAliasTransactionRelink = MosaicAliasTransaction.create( + it('Announce TransferTransaction', (done) => { + const transactions: SignedTransaction[] = []; + // 1. Transfer A -> B + const transaction1 = TransferTransaction.create( Deadline.create(), - AliasAction.Link, - mosaicAlias, - newMosaicId, + account2.address, + [ + new Mosaic(mosaicAlias, UInt64.fromUint(1)), + ], + PlainMessage.create('test-message'), NetworkType.MIJIN_TEST, ); + transactions.push(transaction1.signWith(account, generationHash)); - // Use new mosaicAlias in metadata - const mosaicMetadataTransaction = MosaicMetadataTransaction.create( + // 2. Transfer C -> D + const transaction2 = TransferTransaction.create( Deadline.create(), - account.publicKey, - UInt64.fromUint(5), - mosaicAlias, - 10, - Convert.uint8ToUtf8(new Uint8Array(10)), - NetworkType.MIJIN_TEST, - ); - const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + account4.address, [ - transferTransaction.toAggregate(account.publicAccount), - mosaicAliasTransactionUnlink.toAggregate(account.publicAccount), - mosaicDefinitionTransaction.toAggregate(account.publicAccount), - mosaicAliasTransactionRelink.toAggregate(account.publicAccount), - mosaicMetadataTransaction.toAggregate(account.publicAccount), - + new Mosaic(mosaicAlias, UInt64.fromUint(1)), ], + PlainMessage.create('test-message'), NetworkType.MIJIN_TEST, - [], ); - const signedTransaction = aggregateTransaction.signWith(account, generationHash); - transactionHashes.push(signedTransaction.hash); - listener.confirmed(account.address).subscribe(() => { + transactions.push(transaction2.signWith(account3, generationHash)); + + // 3. Aggregate + const lastSignedTx = buildAggregateTransaction().signWith(account, generationHash); + transactions.push(lastSignedTx); + + transactions.forEach((tx) => { + transactionHashesMultiple.push(tx.hash); + transactionHttp.announce(tx); + }); + listener.confirmed(account.address, lastSignedTx.hash).subscribe(() => { done(); }); listener.status(account.address).subscribe((error) => { @@ -396,7 +438,11 @@ describe('TransactionService', () => { assert(false); done(); }); - transactionHttp.announce(signedTransaction); + listener.status(account3.address).subscribe((error) => { + console.log('Error:', error); + assert(false); + done(); + }); }); }); @@ -409,7 +455,7 @@ describe('TransactionService', () => { describe('should return resolved transaction', () => { it('call transaction service', (done) => { const transactionService = new TransactionService(url); - return transactionService.resolveAliases(transactionHashes).subscribe((transactions) => { + transactionService.resolveAliases(transactionHashes).subscribe((transactions) => { expect(transactions.length).to.be.equal(8); transactions.map((tx) => { if (tx instanceof TransferTransaction) { @@ -427,7 +473,89 @@ describe('TransactionService', () => { .targetMosaicId.toHex() === newMosaicId.toHex()).to.be.true; } }); - }); + }, + done()); + }); + }); + + describe('Test resolve alias with multiple transaction in single block', () => { + it('call transaction service', (done) => { + const transactionService = new TransactionService(url); + transactionService.resolveAliases(transactionHashesMultiple).subscribe((tx) => { + expect(tx.length).to.be.equal(3); + expect((tx[0] as TransferTransaction).mosaics[0].id.toHex()).to.be.equal(mosaicId.toHex()); + expect((tx[1] as TransferTransaction).mosaics[0].id.toHex()).to.be.equal(mosaicId.toHex()); + expect(((tx[2] as AggregateTransaction).innerTransactions[4] as MosaicMetadataTransaction) + .targetMosaicId.toHex()).to.be.equal(newMosaicId.toHex()); + }, + done()); }); }); + + function buildAggregateTransaction(): AggregateTransaction { + const transferTransaction = TransferTransaction.create( + Deadline.create(), + addressAlias, + [ + NetworkCurrencyMosaic.createAbsolute(1), + new Mosaic(mosaicAlias, UInt64.fromUint(1)), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + // Unlink MosaicAlias + const mosaicAliasTransactionUnlink = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Unlink, + mosaicAlias, + mosaicId, + NetworkType.MIJIN_TEST, + ); + + // Create a new Mosaic + const nonce = MosaicNonce.createRandom(); + newMosaicId = MosaicId.createFromNonce(nonce, account.publicAccount); + const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( + Deadline.create(), + nonce, + newMosaicId, + MosaicFlags.create(true, true, false), + 3, + UInt64.fromUint(0), + NetworkType.MIJIN_TEST, + ); + + // Link namespace with new MosaicId + const mosaicAliasTransactionRelink = MosaicAliasTransaction.create( + Deadline.create(), + AliasAction.Link, + mosaicAlias, + newMosaicId, + NetworkType.MIJIN_TEST, + ); + + // Use new mosaicAlias in metadata + const mosaicMetadataTransaction = MosaicMetadataTransaction.create( + Deadline.create(), + account.publicKey, + UInt64.fromUint(5), + mosaicAlias, + 10, + Convert.uint8ToUtf8(new Uint8Array(10)), + NetworkType.MIJIN_TEST, + ); + return AggregateTransaction.createComplete(Deadline.create(), + [ + transferTransaction.toAggregate(account.publicAccount), + mosaicAliasTransactionUnlink.toAggregate(account.publicAccount), + mosaicDefinitionTransaction.toAggregate(account.publicAccount), + mosaicAliasTransactionRelink.toAggregate(account.publicAccount), + mosaicMetadataTransaction.toAggregate(account.publicAccount), + + ], + NetworkType.MIJIN_TEST, + [], + ); + } + }); diff --git a/src/infrastructure/Listener.ts b/src/infrastructure/Listener.ts index 582ef69ed2..1b4db4b1f2 100644 --- a/src/infrastructure/Listener.ts +++ b/src/infrastructure/Listener.ts @@ -239,15 +239,18 @@ export class Listener { * it emits a new Transaction in the event stream. * * @param address address we listen when a transaction is in confirmed state + * @param transactionHash transaction hash for the filter * @return an observable stream of Transaction with state confirmed */ - public confirmed(address: Address): Observable { + public confirmed(address: Address, transactionHash?: string): Observable { this.subscribeTo(`confirmedAdded/${address.plain()}`); return this.messageSubject.asObservable().pipe( filter((_) => _.channelName === ListenerChannelName.confirmedAdded), filter((_) => _.message instanceof Transaction), map((_) => _.message as Transaction), - filter((_) => this.transactionFromAddress(_, address))); + filter((_) => this.transactionFromAddress(_, address)), + filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + ); } /** @@ -289,15 +292,18 @@ export class Listener { * it emits a new {@link AggregateTransaction} in the event stream. * * @param address address we listen when a transaction with missing signatures state + * @param transactionHash transaction hash for the filter * @return an observable stream of AggregateTransaction with missing signatures state */ - public aggregateBondedAdded(address: Address): Observable { + public aggregateBondedAdded(address: Address, transactionHash?: string): Observable { this.subscribeTo(`partialAdded/${address.plain()}`); return this.messageSubject.asObservable().pipe( filter((_) => _.channelName === ListenerChannelName.aggregateBondedAdded), filter((_) => _.message instanceof AggregateTransaction), map((_) => _.message as AggregateTransaction), - filter((_) => this.transactionFromAddress(_, address))); + filter((_) => this.transactionFromAddress(_, address)), + filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + ); } /** diff --git a/src/model/receipt/ResolutionStatement.ts b/src/model/receipt/ResolutionStatement.ts index 051156d063..9d559bd4de 100644 --- a/src/model/receipt/ResolutionStatement.ts +++ b/src/model/receipt/ResolutionStatement.ts @@ -15,8 +15,10 @@ */ import { sha3_256 } from 'js-sha3'; +import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { GeneratorUtils } from '../../infrastructure/catbuffer/GeneratorUtils'; import { Address } from '../account/Address'; +import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; import { UInt64 } from '../UInt64'; @@ -24,8 +26,6 @@ import { ReceiptType } from './ReceiptType'; import { ReceiptVersion } from './ReceiptVersion'; import { ResolutionEntry } from './ResolutionEntry'; import { ResolutionType } from './ResolutionType'; -import { NetworkType } from "../blockchain/NetworkType"; -import { UnresolvedMapping } from "../../core/utils/UnresolvedMapping"; /** * When a transaction includes an alias, a so called resolution statement reflects the resolved value for that block: @@ -84,6 +84,76 @@ export class ResolutionStatement { return hasher.hex().toUpperCase(); } + /** + * @internal + * Find resolution entry for given primaryId and secondaryId + * @param primaryId Primary id + * @param secondaryId Secondary id + * @returns {ResolutionEntry | undefined} + */ + public getResolutionEntryById(primaryId: number, secondaryId: number): ResolutionEntry | undefined { + /* + Primary id and secondary id do not specifically map to the exact transaction index on the same block. + The ids are just the order of the resolution reflecting on the order of transactions (ordered by index). + E.g 1 - Bob -> 1 random.token -> Alice + 2 - Carol -> 1 random.token > Denis + Based on above example, 2 transactions (index 0 & 1) are created on the same block, however, only 1 + resolution entry get generated for both. + */ + const resolvedPrimaryId = this.getMaxAvailablePrimaryId(primaryId); + + if (resolvedPrimaryId === 0) { + return undefined; + } else if (primaryId > resolvedPrimaryId) { + /* + If the transaction index is greater than the overall most recent source primary id. + Use the most recent resolution entry (Max.PrimaryId + Max.SecondaryId) + */ + return this.resolutionEntries + .find((entry) => entry.source.primaryId === resolvedPrimaryId && + entry.source.secondaryId === this.getMaxSecondaryIdByPrimaryId(resolvedPrimaryId)); + } + + // When transaction index matches a primary id, get the most recent secondaryId + const resolvedSecondaryId = Math.max(...this.resolutionEntries + .map((entry) => secondaryId >= entry.source.secondaryId ? entry.source.secondaryId : 0)); + + if (resolvedSecondaryId === 0 && secondaryId !== resolvedSecondaryId) { + /* + If no most recent secondaryId matched transaction index, find previous resolution entry (most recent). + */ + const lastPrimaryId = this.getMaxAvailablePrimaryId(resolvedPrimaryId - 1); + return this.resolutionEntries + .find((entry) => entry.source.primaryId === lastPrimaryId && + entry.source.secondaryId === this.getMaxSecondaryIdByPrimaryId(lastPrimaryId)); + } + // All matched + return this.resolutionEntries + .find((entry) => entry.source.primaryId === resolvedPrimaryId && entry.source.secondaryId === resolvedSecondaryId); + } + + /** + * @internal + * Get most `recent` secondary id by a given primaryId + * @param primaryId Primary source id + * @returns {number} + */ + private getMaxSecondaryIdByPrimaryId(primaryId: number): number { + return Math.max(...this.resolutionEntries.filter((entry) => entry.source.primaryId === primaryId) + .map((filtered) => filtered.source.secondaryId)); + } + + /** + * @internal + * Get most `recent` primary source id by a given id (transaction index) as PrimaryId might not be the same as block transaction index. + * @param primaryId Primary source id + * @returns {number} + */ + private getMaxAvailablePrimaryId(primaryId: number): number { + return Math.max(...this.resolutionEntries + .map((entry) => primaryId >= entry.source.primaryId ? entry.source.primaryId : 0)); + } + /** * @internal * Generate buffer for unresulved diff --git a/src/model/receipt/Statement.ts b/src/model/receipt/Statement.ts index be18c4447f..f037fdc03b 100644 --- a/src/model/receipt/Statement.ts +++ b/src/model/receipt/Statement.ts @@ -14,7 +14,11 @@ * limitations under the License. */ +import { Address } from '../account/Address'; +import { MosaicId } from '../mosaic/MosaicId'; +import { NamespaceId } from '../namespace/NamespaceId'; import { ResolutionStatement } from './ResolutionStatement'; +import { ResolutionType } from './ResolutionType'; import { TransactionStatement } from './TransactionStatement'; export class Statement { @@ -39,4 +43,45 @@ export class Statement { */ public readonly mosaicResolutionStatements: ResolutionStatement[]) { } + + /** + * @internal + * Extract resolved address | mosaic from block receipt + * @param resolutionType Resolution type: Address / Mosaic + * @param unresolved Unresolved address / mosaicId + * @param transactionIndex Transaction index + * @param height Transaction height + * @param aggregateTransactionIndex Transaction index for aggregate + * @returns {MosaicId | Address} + */ + public getResolvedFromReceipt(resolutionType: ResolutionType, + unresolved: NamespaceId, + transactionIndex: number, + height: string, + aggregateTransactionIndex?: number): MosaicId | Address { + + const resolutionStatement = (resolutionType === ResolutionType.Address ? this.addressResolutionStatements : + this.mosaicResolutionStatements).find((resolution) => resolution.height.toString() === height && + (resolution.unresolved as NamespaceId).equals(unresolved)); + + if (!resolutionStatement) { + throw new Error(`No resolution statement found on block: ${height} for unresolved: ${unresolved.toHex()}`); + } + + // If only one entry exists on the statement, just return + if (resolutionStatement.resolutionEntries.length === 1) { + return resolutionStatement.resolutionEntries[0].resolved; + } + + // Get the most recent resolution entry + const resolutionEntry = resolutionStatement.getResolutionEntryById( + aggregateTransactionIndex !== undefined ? aggregateTransactionIndex + 1 : transactionIndex + 1, + aggregateTransactionIndex !== undefined ? transactionIndex + 1 : 0, + ); + + if (!resolutionEntry) { + throw new Error(`No resolution entry found on block: ${height} for unresolved: ${unresolved.toHex()}`); + } + return resolutionEntry.resolved; + } } diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index 4566a36068..b95208771c 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -217,8 +217,8 @@ export class AccountAddressRestrictionTransaction extends Transaction { map((statement) => { return this.restrictionAdditions.map((addition) => { return addition instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Address, addition as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : + statement.getResolvedFromReceipt(ResolutionType.Address, addition as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : addition; }); }), @@ -228,8 +228,8 @@ export class AccountAddressRestrictionTransaction extends Transaction { map((statement) => { return this.restrictionDeletions.map((deletion) => { return deletion instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Address, deletion as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : + statement.getResolvedFromReceipt(ResolutionType.Address, deletion as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : deletion; }); }), diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index cbfab8525c..fe26d38a43 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -217,8 +217,8 @@ export class AccountMosaicRestrictionTransaction extends Transaction { map((statement) => { return this.restrictionAdditions.map((addition) => { return addition instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, addition as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : + statement.getResolvedFromReceipt(ResolutionType.Mosaic, addition as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : addition; }); }), @@ -228,8 +228,8 @@ export class AccountMosaicRestrictionTransaction extends Transaction { map((statement) => { return this.restrictionDeletions.map((deletion) => { return deletion instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, deletion as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : + statement.getResolvedFromReceipt(ResolutionType.Mosaic, deletion as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : deletion; }); }), diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index e902ccf86f..dfb6c0bef2 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -232,8 +232,8 @@ export class LockFundsTransaction extends Transaction { this.version, this.deadline, this.maxFee, - new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaic.id as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), + new Mosaic(statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaic.id as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.mosaic.amount), this.duration, this.signedTransaction, diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 57c6213344..2b9979ed84 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -261,16 +261,16 @@ export class MosaicAddressRestrictionTransaction extends Transaction { const resolvedAddress = statementObservable.pipe( map((statement) => this.targetAddress instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.targetAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : + statement.getResolvedFromReceipt(ResolutionType.Address, this.targetAddress as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.targetAddress, ), ); const resolvedMosaicId = statementObservable.pipe( map((statement) => this.mosaicId instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : + statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.mosaicId, ), ); diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 39b5078252..06b2dbf5f8 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -270,16 +270,16 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { const resolvedMosaicId = statementObservable.pipe( map((statement) => this.mosaicId instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : + statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.mosaicId, ), ); const resolvedRefMosaicId = statementObservable.pipe( map((statement) => this.referenceMosaicId instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.referenceMosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : + statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.referenceMosaicId as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : this.referenceMosaicId, ), ); diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index 8cc77ba69d..2509570bc7 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -241,8 +241,8 @@ export class MosaicMetadataTransaction extends Transaction { this.maxFee, this.targetPublicKey, this.scopedMetadataKey, - TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.targetMosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, + statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.targetMosaicId as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.valueSizeDelta, this.value, this.signature, diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index db17c7ce2f..af7e91eed6 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -214,8 +214,8 @@ export class MosaicSupplyChangeTransaction extends Transaction { this.version, this.deadline, this.maxFee, - TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, + statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.action, this.delta, this.signature, diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index 6fb5c0de90..d25f479f3d 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -258,16 +258,16 @@ export class SecretLockTransaction extends Transaction { const resolvedRecipient = statementObservable.pipe( map((statement) => this.recipientAddress instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : + statement.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.recipientAddress, ), ); const resolvedMosaic = statementObservable.pipe( map((statement) => this.mosaic.id instanceof NamespaceId ? - new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), + new Mosaic(statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.recipientAddress as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, this.mosaic.amount) : this.mosaic, ), diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index f97fca4d30..73a35a4b0b 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -239,8 +239,8 @@ export class SecretProofTransaction extends Transaction { this.maxFee, this.hashType, this.secret, - TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address, + statement.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address, this.proof, this.signature, this.signer, diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index 7c3181f31e..3c062e5763 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -299,8 +299,8 @@ export class TransferTransaction extends Transaction { const resolvedRecipient = statementObservable.pipe( map((statement) => this.recipientAddress instanceof NamespaceId ? - TransactionService.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : + statement.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : this.recipientAddress, ), ); @@ -309,8 +309,8 @@ export class TransferTransaction extends Transaction { map((statement) => this.mosaics.map((mosaic) => mosaic.id instanceof NamespaceId ? - new Mosaic(TransactionService.getResolvedFromReceipt(ResolutionType.Mosaic, mosaic.id as NamespaceId, - statement, transactionInfo.index, transactionInfo.height.toString(), + new Mosaic(statement.getResolvedFromReceipt(ResolutionType.Mosaic, mosaic.id as NamespaceId, + transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, mosaic.amount) : mosaic, ), diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 089b035c91..854b7ecb39 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -18,11 +18,6 @@ import {Observable} from 'rxjs'; import { mergeMap, toArray} from 'rxjs/operators'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; -import { Address } from '../model/account/Address'; -import { MosaicId } from '../model/mosaic/MosaicId'; -import { NamespaceId } from '../model/namespace/NamespaceId'; -import { ResolutionType } from '../model/receipt/ResolutionType'; -import { Statement } from '../model/receipt/Statement'; import { Transaction } from '../model/transaction/Transaction'; import { ITransactionService } from './interfaces/ITransactionService'; @@ -42,44 +37,6 @@ export class TransactionService implements ITransactionService { this.receiptHttp = new ReceiptHttp(url); } - /** - * @internal - * Extract resolved address | mosaic from block receipt - * @param resolutionType Resolution type: Address / Mosaic - * @param unresolved Unresolved address / mosaicId - * @param statement Block receipt statement - * @param transactionIndex Transaction index - * @param height Transaction height - * @param aggregateTransactionIndex Transaction index for aggregate - * @returns {MosaicId | Address} - */ - public static getResolvedFromReceipt(resolutionType: ResolutionType, - unresolved: NamespaceId, - statement: Statement, - transactionIndex: number, - height: string, - aggregateTransactionIndex?: number): MosaicId | Address { - - const resolutionStatement = (resolutionType === ResolutionType.Address ? statement.addressResolutionStatements : - statement.mosaicResolutionStatements).find((resolution) => resolution.height.toString() === height && - (resolution.unresolved as NamespaceId).equals(unresolved)); - - if (!resolutionStatement) { - throw new Error('No resolution statement found'); - } - // source (0,0) is reserved for blocks, source (n, 0) is for txes, where n is 1-based index - const resolutionEntry = resolutionStatement.resolutionEntries - .find((entry) => entry.source.primaryId === - (aggregateTransactionIndex !== undefined ? aggregateTransactionIndex + 1 : transactionIndex + 1) && - entry.source.secondaryId === (aggregateTransactionIndex !== undefined ? transactionIndex + 1 : 0)); - - if (!resolutionEntry) { - throw new Error('No resolution entry found'); - } - - return resolutionEntry.resolved; - } - /** * @param transationHashes List of transaction hashes. * @returns Observable diff --git a/test/service/TransactionService.spec.ts b/test/model/receipt/Statement.spec.ts similarity index 90% rename from test/service/TransactionService.spec.ts rename to test/model/receipt/Statement.spec.ts index d4071b43b7..e1a6b774d1 100644 --- a/test/service/TransactionService.spec.ts +++ b/test/model/receipt/Statement.spec.ts @@ -15,14 +15,13 @@ */ import { expect } from 'chai'; -import { UnresolvedMapping } from '../../src/core/utils/UnresolvedMapping'; -import { CreateStatementFromDTO } from '../../src/infrastructure/receipt/CreateReceiptFromDTO'; -import { Account } from '../../src/model/account/Account'; -import { NetworkType } from '../../src/model/blockchain/NetworkType'; -import { Address, MosaicId, NamespaceId, ResolutionType } from '../../src/model/model'; -import { TransactionService } from '../../src/service/TransactionService'; +import { UnresolvedMapping } from '../../../src/core/utils/UnresolvedMapping'; +import { CreateStatementFromDTO } from '../../../src/infrastructure/receipt/CreateReceiptFromDTO'; +import { Account } from '../../../src/model/account/Account'; +import { NetworkType } from '../../../src/model/blockchain/NetworkType'; +import { Address, MosaicId, NamespaceId, ResolutionType } from '../../../src/model/model'; -describe('TransactionService', () => { +describe('Statement', () => { let account: Account; let transactionStatementsDTO; let addressResolutionStatementsDTO; @@ -111,8 +110,8 @@ describe('TransactionService', () => { it('should get reolved address from receipt', () => { const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); - const resolved = TransactionService - .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, statement, 0, '1473'); + const resolved = statement + .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, 0, '1473'); expect(resolved instanceof Address).to.be.true; expect((resolved as Address).equals(account.address)).to.be.true; @@ -142,8 +141,8 @@ describe('TransactionService', () => { }; const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); - const resolved = TransactionService - .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, statement, 0, '1473'); + const resolved = statement + .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, 0, '1473'); expect(resolved instanceof Address).to.be.true; expect((resolved as Address).equals(account.address)).to.be.true; @@ -152,8 +151,8 @@ describe('TransactionService', () => { it('should get reolved mosaic from receipt', () => { const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); - const resolved = TransactionService - .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, statement, 0, '1473'); + const resolved = statement + .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, 0, '1473'); expect(resolved instanceof MosaicId).to.be.true; expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; @@ -198,8 +197,8 @@ describe('TransactionService', () => { }; const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); - const resolved = TransactionService - .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, statement, 0, '1473'); + const resolved = statement + .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, 0, '1473'); expect(resolved instanceof MosaicId).to.be.true; expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; From 20aa6a68086d79a22d1b722e0cce88ed1daf17ca Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 23:11:31 +0000 Subject: [PATCH 22/50] expose getResolvedFromReceipt --- src/model/receipt/Statement.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/model/receipt/Statement.ts b/src/model/receipt/Statement.ts index f037fdc03b..db7eaa2157 100644 --- a/src/model/receipt/Statement.ts +++ b/src/model/receipt/Statement.ts @@ -45,7 +45,6 @@ export class Statement { } /** - * @internal * Extract resolved address | mosaic from block receipt * @param resolutionType Resolution type: Address / Mosaic * @param unresolved Unresolved address / mosaicId From 341badbdf6be781838cbb84884c368b0eae80918 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 09:04:27 +0000 Subject: [PATCH 23/50] Added unit tests for getResolutionEntryById --- .../model/receipt/ResolutionStatement.spec.ts | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 test/model/receipt/ResolutionStatement.spec.ts diff --git a/test/model/receipt/ResolutionStatement.spec.ts b/test/model/receipt/ResolutionStatement.spec.ts new file mode 100644 index 0000000000..c37018dd66 --- /dev/null +++ b/test/model/receipt/ResolutionStatement.spec.ts @@ -0,0 +1,167 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { UnresolvedMapping } from '../../../src/core/utils/UnresolvedMapping'; +import { CreateStatementFromDTO } from '../../../src/infrastructure/receipt/CreateReceiptFromDTO'; +import { Account } from '../../../src/model/account/Account'; +import { NetworkType } from '../../../src/model/blockchain/NetworkType'; +import { Address, MosaicId, NamespaceId, ResolutionType } from '../../../src/model/model'; + +describe('ResolutionStatement', () => { + let account: Account; + let transactionStatementsDTO; + let addressResolutionStatementsDTO; + let mosaicResolutionStatementsDTO; + let statementDTO; + + before(() => { + account = Account.createFromPrivateKey('81C18245507F9C15B61BDEDAFA2C10D9DC2C4E401E573A10935D45AA2A461FD5', NetworkType.MIJIN_TEST); + transactionStatementsDTO = [ + { + statement: { + height: '1473', + source: { + primaryId: 0, + secondaryId: 0, + }, + receipts: [ + { + version: 1, + type: 8515, + targetPublicKey: 'B2708D49C46F8AB5CDBD7A09C959EEA12E4A782592F3D1D3D17D54622E655D7F', + mosaicId: '504677C3281108DB', + amount: '0', + }, + ], + }, + }, + ]; + addressResolutionStatementsDTO = [ + { + statement: { + height: '1473', + unresolved: '9156258DE356F030A500000000000000000000000000000000', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '901D8D4741F80299E66BF7FEEB4F30943DA7B68E068B182319', + }, + ], + }, + }, + ]; + mosaicResolutionStatementsDTO = [ + { + statement: { + height: '1473', + unresolved: '85BBEA6CC462B244', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 0, + }, + resolved: '504677C3281108DB', + }, + { + source: { + primaryId: 3, + secondaryId: 5, + }, + resolved: '401F622A3111A3E4', + }, + ], + }, + }, + { + statement: { + height: '1473', + unresolved: 'E81F622A5B11A340', + resolutionEntries: [ + { + source: { + primaryId: 3, + secondaryId: 1, + }, + resolved: '756482FB80FD406C', + }, + ], + }, + }, + ]; + + statementDTO = { + transactionStatements: transactionStatementsDTO, + addressResolutionStatements: addressResolutionStatementsDTO, + mosaicResolutionStatements: mosaicResolutionStatementsDTO, + }; + }); + + it('should get resolve entry when both primaryId and secondaryId matched', () => { + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const entry = statement.addressResolutionStatements[0].getResolutionEntryById(1, 0); + + expect(entry!.resolved instanceof Address).to.be.true; + expect((entry!.resolved as Address).equals(account.address)).to.be.true; + }); + + it('should get resolved entry when primaryId is greater than max', () => { + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const entry = statement.mosaicResolutionStatements[0].getResolutionEntryById(4, 0); + expect(entry!.source.primaryId).to.be.equal(3); + expect(entry!.source.secondaryId).to.be.equal(5); + expect(entry!.resolved instanceof MosaicId).to.be.true; + expect((entry!.resolved as MosaicId).equals(new MosaicId('401F622A3111A3E4'))).to.be.true; + }); + + it('should get resolved entry when primaryId is in middle of 2 pirmaryIds', () => { + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const entry = statement.mosaicResolutionStatements[0].getResolutionEntryById(2, 1); + expect(entry!.source.primaryId).to.be.equal(1); + expect(entry!.source.secondaryId).to.be.equal(0); + expect(entry!.resolved instanceof MosaicId).to.be.true; + expect((entry!.resolved as MosaicId).equals(new MosaicId('504677C3281108DB'))).to.be.true; + }); + + it('should get resolved entry when primaryId matches but not secondaryId', () => { + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const entry = statement.mosaicResolutionStatements[0].getResolutionEntryById(3, 6); + expect(entry!.source.primaryId).to.be.equal(3); + expect(entry!.source.secondaryId).to.be.equal(5); + expect(entry!.resolved instanceof MosaicId).to.be.true; + expect((entry!.resolved as MosaicId).equals(new MosaicId('401F622A3111A3E4'))).to.be.true; + }); + + it('should get resolved entry when primaryId matches but secondaryId less than minimum', () => { + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const entry = statement.mosaicResolutionStatements[0].getResolutionEntryById(3, 1); + expect(entry!.source.primaryId).to.be.equal(1); + expect(entry!.source.secondaryId).to.be.equal(0); + expect(entry!.resolved instanceof MosaicId).to.be.true; + expect((entry!.resolved as MosaicId).equals(new MosaicId('504677C3281108DB'))).to.be.true; + }); + + it('should return undefined', () => { + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const entry = statement.addressResolutionStatements[0].getResolutionEntryById(0, 0); + expect(entry).to.be.undefined; + }); + +}); From fe7028ab45c8d9cdd390e016c97cb8361f626b33 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 24/50] Added #352 aggregate bonded announcing --- src/infrastructure/Listener.ts | 8 ++-- src/model/transaction/SignedTransaction.ts | 10 ++++ src/service/TransactionService.ts | 46 +++++++++++++++++++ src/service/interfaces/ITransactionService.ts | 26 ++++++++++- 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/infrastructure/Listener.ts b/src/infrastructure/Listener.ts index 1b4db4b1f2..f1778b29ed 100644 --- a/src/infrastructure/Listener.ts +++ b/src/infrastructure/Listener.ts @@ -239,7 +239,7 @@ export class Listener { * it emits a new Transaction in the event stream. * * @param address address we listen when a transaction is in confirmed state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of Transaction with state confirmed */ public confirmed(address: Address, transactionHash?: string): Observable { @@ -249,7 +249,7 @@ export class Listener { filter((_) => _.message instanceof Transaction), map((_) => _.message as Transaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } @@ -292,7 +292,7 @@ export class Listener { * it emits a new {@link AggregateTransaction} in the event stream. * * @param address address we listen when a transaction with missing signatures state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of AggregateTransaction with missing signatures state */ public aggregateBondedAdded(address: Address, transactionHash?: string): Observable { @@ -302,7 +302,7 @@ export class Listener { filter((_) => _.message instanceof AggregateTransaction), map((_) => _.message as AggregateTransaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } diff --git a/src/model/transaction/SignedTransaction.ts b/src/model/transaction/SignedTransaction.ts index addc04c6a1..bc776b4eb6 100644 --- a/src/model/transaction/SignedTransaction.ts +++ b/src/model/transaction/SignedTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Address } from '../account/Address'; +import { PublicAccount } from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; /** @@ -65,4 +67,12 @@ export class SignedTransaction { networkType: this.networkType, }; } + + /** + * Return signer's address + * @returns {Address} + */ + getSignerAddress(): Address { + return PublicAccount.createFromPublicKey(this.signerPublicKey, this.networkType).address; + } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 854b7ecb39..efbbf6e208 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -16,8 +16,17 @@ import {Observable} from 'rxjs'; import { mergeMap, toArray} from 'rxjs/operators'; +import { flatMap } from 'rxjs/operators'; +import { Listener } from '../infrastructure/Listener'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; +import { Address } from '../model/account/Address'; +import { MosaicId } from '../model/mosaic/MosaicId'; +import { NamespaceId } from '../model/namespace/NamespaceId'; +import { ResolutionType } from '../model/receipt/ResolutionType'; +import { Statement } from '../model/receipt/Statement'; +import { AggregateTransaction } from '../model/transaction/AggregateTransaction'; +import { SignedTransaction } from '../model/transaction/SignedTransaction'; import { Transaction } from '../model/transaction/Transaction'; import { ITransactionService } from './interfaces/ITransactionService'; @@ -28,6 +37,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -35,6 +45,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** @@ -48,4 +59,39 @@ export class TransactionService implements ITransactionService { toArray(), ); } + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable { + return this.announce(signedHashLockTransaction).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + ); + + } } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 6bbeb16160..37a0984911 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,8 @@ */ import {Observable} from 'rxjs'; +import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; +import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; /** @@ -24,7 +26,29 @@ export interface ITransactionService { /** * @param transationHashes List of transaction hashes. - * @returns Observable + * @returns {Observable} */ resolveAliases(transationHashes: string[]): Observable; + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + announce(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable; } From c1bf3ec94560833d33887022cd345fa69cde9b94 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 25/50] Moved listener to method --- ...TransactionService_AggregateBonded.spec.ts | 212 ++++++++++++++++++ src/service/TransactionService.ts | 28 +-- src/service/interfaces/ITransactionService.ts | 8 +- 3 files changed, 231 insertions(+), 17 deletions(-) create mode 100644 e2e/service/TransactionService_AggregateBonded.spec.ts diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts new file mode 100644 index 0000000000..53e6c0532d --- /dev/null +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -0,0 +1,212 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { Listener } from '../../src/infrastructure/Listener'; +import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; +import { Account } from '../../src/model/account/Account'; +import { Address } from '../../src/model/account/Address'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; +import { Deadline } from '../../src/model/transaction/Deadline'; +import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction'; +import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { TransactionService } from '../../src/service/TransactionService'; + +describe('TransactionService', () => { + let account: Account; + let account2: Account; + let multisigAccount: Account; + let cosignAccount1: Account; + let cosignAccount2: Account; + let cosignAccount3: Account; + let url: string; + let generationHash: string; + let transactionHttp: TransactionHttp; + let config; + + before((done) => { + const path = require('path'); + require('fs').readFile(path.resolve(__dirname, '../conf/network.conf'), (err, data) => { + if (err) { + throw err; + } + const json = JSON.parse(data); + config = json; + account = Account.createFromPrivateKey(json.testAccount.privateKey, NetworkType.MIJIN_TEST); + account2 = Account.createFromPrivateKey(json.testAccount2.privateKey, NetworkType.MIJIN_TEST); + multisigAccount = Account.createFromPrivateKey(json.multisigAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount1 = Account.createFromPrivateKey(json.cosignatoryAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount2 = Account.createFromPrivateKey(json.cosignatory2Account.privateKey, NetworkType.MIJIN_TEST); + cosignAccount3 = Account.createFromPrivateKey(json.cosignatory3Account.privateKey, NetworkType.MIJIN_TEST); + url = json.apiUrl; + generationHash = json.generationHash; + transactionHttp = new TransactionHttp(json.apiUrl); + done(); + }); + }); + + /** + * ========================= + * Setup test data + * ========================= + */ + describe('Setup test multisig account', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const modifyMultisigAccountTransaction = MultisigAccountModificationTransaction.create( + Deadline.create(), + 2, + 1, + [ + cosignAccount1.publicAccount, + cosignAccount2.publicAccount, + cosignAccount3.publicAccount, + ], + [], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [modifyMultisigAccountTransaction.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(multisigAccount, [cosignAccount1, cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(multisigAccount.address).subscribe(() => { + done(); + }); + listener.status(multisigAccount.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + /** + * ========================= + * Test + * ========================= + */ + + describe('should announce transaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const transactionService = new TransactionService(url); + const transferTransaction = TransferTransaction.create( + Deadline.create(), + account2.address, + [ + NetworkCurrencyMosaic.createAbsolute(1), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = transferTransaction.signWith(account, generationHash); + transactionService.announce(signedTransaction, listener).subscribe((tx: TransferTransaction) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect((tx.recipientAddress as Address).equals(account2.address)).to.be.true; + expect(tx.message.payload).to.be.equal('test-message'); + done(); + }); + }); + }); + + /** + * ========================= + * House Keeping + * ========================= + */ + + describe('Restore test multisig Accounts', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const removeCosigner1 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + 0, + [], + [ cosignAccount1.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + const removeCosigner2 = MultisigAccountModificationTransaction.create( + Deadline.create(), + 0, + 0, + [], + [ + cosignAccount2.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const removeCosigner3 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + -1, + [], + [ + cosignAccount3.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [removeCosigner1.toAggregate(multisigAccount.publicAccount), + removeCosigner2.toAggregate(multisigAccount.publicAccount), + removeCosigner3.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(cosignAccount1, [cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(cosignAccount1.address).subscribe(() => { + done(); + }); + listener.status(cosignAccount1.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); +}); diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index efbbf6e208..d1a5a029fa 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -20,11 +20,6 @@ import { flatMap } from 'rxjs/operators'; import { Listener } from '../infrastructure/Listener'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; -import { Address } from '../model/account/Address'; -import { MosaicId } from '../model/mosaic/MosaicId'; -import { NamespaceId } from '../model/namespace/NamespaceId'; -import { ResolutionType } from '../model/receipt/ResolutionType'; -import { Statement } from '../model/receipt/Statement'; import { AggregateTransaction } from '../model/transaction/AggregateTransaction'; import { SignedTransaction } from '../model/transaction/SignedTransaction'; import { Transaction } from '../model/transaction/Transaction'; @@ -37,7 +32,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -45,11 +39,12 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** + * Resolve unresolved mosaic / address from array of transactions * @param transationHashes List of transaction hashes. + * @param listener Websocket listener * @returns Observable */ public resolveAliases(transationHashes: string[]): Observable { @@ -61,23 +56,26 @@ export class TransactionService implements ITransactionService { } /** + * Announce transaction * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener * @returns {Observable} */ - public announce(signedTransaction: SignedTransaction): Observable { + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ - public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } @@ -85,12 +83,14 @@ export class TransactionService implements ITransactionService { * Announce aggregate bonded transaction with lock fund * @param signedHashLockTransaction Signed hash lock transaction. * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable { - return this.announce(signedHashLockTransaction).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), ); } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 37a0984911..3aa299ebd4 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,7 @@ */ import {Observable} from 'rxjs'; +import { Listener } from '../../infrastructure/Listener'; import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; @@ -34,14 +35,14 @@ export interface ITransactionService { * @param signedTransaction Signed transaction to be announced. * @returns {Observable} */ - announce(signedTransaction: SignedTransaction): Observable; + announce(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. * @returns {Observable} */ - announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate bonded transaction with lock fund @@ -50,5 +51,6 @@ export interface ITransactionService { * @returns {Observable} */ announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable; + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable; } From d1c4675d1b9e3963909d07a58dfa7fbf7f41c47c Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 23:11:56 +0000 Subject: [PATCH 26/50] Refactored --- src/model/receipt/Statement.ts | 66 +++++++++++- .../AccountAddressRestrictionTransaction.ts | 70 +++--------- .../transaction/AccountLinkTransaction.ts | 10 +- .../transaction/AccountMetadataTransaction.ts | 10 +- .../AccountMosaicRestrictionTransaction.ts | 70 +++--------- .../AccountOperationRestrictionTransaction.ts | 10 +- .../transaction/AddressAliasTransaction.ts | 7 +- src/model/transaction/AggregateTransaction.ts | 40 +++---- src/model/transaction/LockFundsTransaction.ts | 49 +++------ .../MosaicAddressRestrictionTransaction.ts | 70 ++++-------- .../transaction/MosaicAliasTransaction.ts | 10 +- .../MosaicDefinitionTransaction.ts | 10 +- .../MosaicGlobalRestrictionTransaction.ts | 73 ++++--------- .../transaction/MosaicMetadataTransaction.ts | 55 ++++------ .../MosaicSupplyChangeTransaction.ts | 50 +++------ .../MultisigAccountModificationTransaction.ts | 11 +- .../NamespaceMetadataTransaction.ts | 11 +- .../NamespaceRegistrationTransaction.ts | 10 +- .../transaction/SecretLockTransaction.ts | 71 ++++-------- .../transaction/SecretProofTransaction.ts | 45 +++----- src/model/transaction/Transaction.ts | 8 +- src/model/transaction/TransferTransaction.ts | 70 ++++-------- src/service/TransactionService.ts | 101 +++++++++++++++++- test/model/transaction/Transaction.spec.ts | 3 +- 24 files changed, 384 insertions(+), 546 deletions(-) diff --git a/src/model/receipt/Statement.ts b/src/model/receipt/Statement.ts index db7eaa2157..4753c63498 100644 --- a/src/model/receipt/Statement.ts +++ b/src/model/receipt/Statement.ts @@ -15,6 +15,7 @@ */ import { Address } from '../account/Address'; +import { Mosaic } from '../mosaic/Mosaic'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; import { ResolutionStatement } from './ResolutionStatement'; @@ -45,6 +46,61 @@ export class Statement { } /** + * Resolve unresolvedAddress from statement + * @param unresolvedAddress Unresolved address + * @param height Block height + * @param transactionIndex Transaction index + * @param aggregateTransactionIndex Aggregate transaction index + * @returns {Address} + */ + public resolveAddress(unresolvedAddress: Address | NamespaceId, + height: string, + transactionIndex: number, + aggregateTransactionIndex: number = 0): Address { + return unresolvedAddress instanceof NamespaceId ? + this.getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, + transactionIndex, height, aggregateTransactionIndex) as Address : + unresolvedAddress; + } + + /** + * Resolve unresolvedMosaicId from statement + * @param unresolvedMosaicId Unresolved mosaic id + * @param height Block height + * @param transactionIndex Transaction index + * @param aggregateTransactionIndex Aggregate transaction index + * @returns {MosaicId} + */ + public resolveMosaicId(unresolvedMosaicId: MosaicId | NamespaceId, + height: string, + transactionIndex: number, + aggregateTransactionIndex: number = 0): MosaicId { + return unresolvedMosaicId instanceof NamespaceId ? + this.getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaicId as NamespaceId, + transactionIndex, height, aggregateTransactionIndex) as MosaicId : + unresolvedMosaicId; + } + + /** + * Resolve unresolvedMosaic from statement + * @param unresolvedMosaic Unresolved mosaic + * @param height Block height + * @param transactionIndex Transaction index + * @param aggregateTransactionIndex Aggregate transaction index + * @returns {Mosaic} + */ + public resolveMosaic(unresolvedMosaic: Mosaic, + height: string, + transactionIndex: number, + aggregateTransactionIndex: number = 0): Mosaic { + return unresolvedMosaic.id instanceof NamespaceId ? + new Mosaic(this.getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic.id as NamespaceId, + transactionIndex, height, aggregateTransactionIndex) as MosaicId, unresolvedMosaic.amount) : + unresolvedMosaic; + } + + /** + * @internal * Extract resolved address | mosaic from block receipt * @param resolutionType Resolution type: Address / Mosaic * @param unresolved Unresolved address / mosaicId @@ -53,11 +109,11 @@ export class Statement { * @param aggregateTransactionIndex Transaction index for aggregate * @returns {MosaicId | Address} */ - public getResolvedFromReceipt(resolutionType: ResolutionType, - unresolved: NamespaceId, - transactionIndex: number, - height: string, - aggregateTransactionIndex?: number): MosaicId | Address { + private getResolvedFromReceipt(resolutionType: ResolutionType, + unresolved: NamespaceId, + transactionIndex: number, + height: string, + aggregateTransactionIndex?: number): MosaicId | Address { const resolutionStatement = (resolutionType === ResolutionType.Address ? this.addressResolutionStatements : this.mosaicResolutionStatements).find((resolution) => resolution.height.toString() === height && diff --git a/src/model/transaction/AccountAddressRestrictionTransaction.ts b/src/model/transaction/AccountAddressRestrictionTransaction.ts index b95208771c..62d28e2988 100644 --- a/src/model/transaction/AccountAddressRestrictionTransaction.ts +++ b/src/model/transaction/AccountAddressRestrictionTransaction.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import { combineLatest, of } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountAddressRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountAddressRestrictionTransactionBuilder'; @@ -28,13 +25,11 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -198,56 +193,25 @@ export class AccountAddressRestrictionTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {AccountAddressRestrictionTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || - this.restrictionDeletions.find((address) => address instanceof NamespaceId) !== undefined; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): AccountAddressRestrictionTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - const restrictionAdditions = statementObservable.pipe( - map((statement) => { - return this.restrictionAdditions.map((addition) => { - return addition instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Address, addition as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : - addition; - }); - }), + return new AccountAddressRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.restrictionFlags, + this.restrictionAdditions.map((addition) => statement.resolveAddress(addition, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex)), + this.restrictionDeletions.map((deletion) => statement.resolveAddress(deletion, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex)), + this.signature, + this.signer, + this.transactionInfo, ); - - const restrictionDeletions = statementObservable.pipe( - map((statement) => { - return this.restrictionDeletions.map((deletion) => { - return deletion instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Address, deletion as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : - deletion; - }); - }), - ); - - return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { - return new AccountAddressRestrictionTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.restrictionFlags, - additions, - deletions, - this.signature, - this.signer, - this.transactionInfo, - ); - }); } } diff --git a/src/model/transaction/AccountLinkTransaction.ts b/src/model/transaction/AccountLinkTransaction.ts index e1cb514b44..9e6e813de3 100644 --- a/src/model/transaction/AccountLinkTransaction.ts +++ b/src/model/transaction/AccountLinkTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountLinkTransactionBuilder } from '../../infrastructure/catbuffer/AccountLinkTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -23,7 +21,6 @@ import { EmbeddedAccountLinkTransactionBuilder } from '../../infrastructure/catb import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -169,10 +166,9 @@ export class AccountLinkTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {AccountLinkTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): AccountLinkTransaction { + return this; } } diff --git a/src/model/transaction/AccountMetadataTransaction.ts b/src/model/transaction/AccountMetadataTransaction.ts index b5e4a40558..78b2009887 100644 --- a/src/model/transaction/AccountMetadataTransaction.ts +++ b/src/model/transaction/AccountMetadataTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountMetadataTransactionBuilder } from '../../infrastructure/catbuffer/AccountMetadataTransactionBuilder'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -23,7 +21,6 @@ import { EmbeddedAccountMetadataTransactionBuilder } from '../../infrastructure/ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -199,10 +196,9 @@ export class AccountMetadataTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {AccountMetadataTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): AccountMetadataTransaction { + return this; } } diff --git a/src/model/transaction/AccountMosaicRestrictionTransaction.ts b/src/model/transaction/AccountMosaicRestrictionTransaction.ts index fe26d38a43..c06ff8dfcb 100644 --- a/src/model/transaction/AccountMosaicRestrictionTransaction.ts +++ b/src/model/transaction/AccountMosaicRestrictionTransaction.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import { combineLatest, of } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AccountMosaicRestrictionTransactionBuilder } from '../../infrastructure/catbuffer/AccountMosaicRestrictionTransactionBuilder'; @@ -28,13 +25,11 @@ import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -198,56 +193,25 @@ export class AccountMosaicRestrictionTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {AccountMosaicRestrictionTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || - this.restrictionDeletions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): AccountMosaicRestrictionTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - const restrictionAdditions = statementObservable.pipe( - map((statement) => { - return this.restrictionAdditions.map((addition) => { - return addition instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Mosaic, addition as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : - addition; - }); - }), + return new AccountMosaicRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.restrictionFlags, + this.restrictionAdditions.map((addition) => statement.resolveMosaicId(addition, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex)), + this.restrictionDeletions.map((deletion) => statement.resolveMosaicId(deletion, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex)), + this.signature, + this.signer, + this.transactionInfo, ); - - const restrictionDeletions = statementObservable.pipe( - map((statement) => { - return this.restrictionDeletions.map((deletion) => { - return deletion instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Mosaic, deletion as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : - deletion; - }); - }), - ); - - return combineLatest(restrictionAdditions, restrictionDeletions, (additions, deletions) => { - return new AccountMosaicRestrictionTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.restrictionFlags, - additions, - deletions, - this.signature, - this.signer, - this.transactionInfo, - ); - }); } } diff --git a/src/model/transaction/AccountOperationRestrictionTransaction.ts b/src/model/transaction/AccountOperationRestrictionTransaction.ts index b8086f56b0..899602794f 100644 --- a/src/model/transaction/AccountOperationRestrictionTransaction.ts +++ b/src/model/transaction/AccountOperationRestrictionTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AccountOperationRestrictionTransactionBuilder, @@ -27,7 +25,6 @@ import { import { KeyDto } from '../../infrastructure/catbuffer/KeyDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { AccountRestrictionFlags } from '../restriction/AccountRestrictionType'; @@ -180,10 +177,9 @@ export class AccountOperationRestrictionTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {AccountOperationRestrictionTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): AccountOperationRestrictionTransaction { + return this; } } diff --git a/src/model/transaction/AddressAliasTransaction.ts b/src/model/transaction/AddressAliasTransaction.ts index 20696aa65f..8f58f5d2a4 100644 --- a/src/model/transaction/AddressAliasTransaction.ts +++ b/src/model/transaction/AddressAliasTransaction.ts @@ -189,10 +189,9 @@ export class AddressAliasTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {AddressAliasTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): AddressAliasTransaction { + return this; } } diff --git a/src/model/transaction/AggregateTransaction.ts b/src/model/transaction/AggregateTransaction.ts index 98e6874626..250dd324b5 100644 --- a/src/model/transaction/AggregateTransaction.ts +++ b/src/model/transaction/AggregateTransaction.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import { from, of } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { map, mergeMap, toArray } from 'rxjs/operators'; import {KeyPair, MerkleHashBuilder, SHA3Hasher, SignSchema} from '../../core/crypto'; import {Convert} from '../../core/format'; import {AggregateBondedTransactionBuilder} from '../../infrastructure/catbuffer/AggregateBondedTransactionBuilder'; @@ -28,11 +25,11 @@ import { Hash256Dto } from '../../infrastructure/catbuffer/Hash256Dto'; import {KeyDto} from '../../infrastructure/catbuffer/KeyDto'; import {SignatureDto} from '../../infrastructure/catbuffer/SignatureDto'; import {TimestampDto} from '../../infrastructure/catbuffer/TimestampDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import {CreateTransactionFromPayload} from '../../infrastructure/transaction/CreateTransactionFromPayload'; import {Account} from '../account/Account'; import {PublicAccount} from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; +import { Statement } from '../receipt/Statement'; import {UInt64} from '../UInt64'; import {AggregateTransactionCosignature} from './AggregateTransactionCosignature'; import {CosignatureSignedTransaction} from './CosignatureSignedTransaction'; @@ -406,29 +403,22 @@ export class AggregateTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {AggregateTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { + resolveAliases(statement: Statement): AggregateTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - return from(this.innerTransactions).pipe( - mergeMap((transaction) => transaction.resolveAliases(receiptHttp, transactionInfo.index)), - map((transaction) => transaction as InnerTransaction), - toArray(), - ).pipe( - map((innerTransactions) => new AggregateTransaction( - this.networkType, - this.type, - this.version, - this.deadline, - this.maxFee, - innerTransactions.sort((a, b) => a.transactionInfo!.index - b.transactionInfo!.index), - this.cosignatures, - this.signature, - this.signer, - this.transactionInfo, - ), - ), + return new AggregateTransaction( + this.networkType, + this.type, + this.version, + this.deadline, + this.maxFee, + this.innerTransactions.map((tx) => tx.resolveAliases(statement, transactionInfo.index)) + .sort((a, b) => a.transactionInfo!.index - b.transactionInfo!.index), + this.cosignatures, + this.signature, + this.signer, + this.transactionInfo, ); } } diff --git a/src/model/transaction/LockFundsTransaction.ts b/src/model/transaction/LockFundsTransaction.ts index dfb6c0bef2..666c0cceb8 100644 --- a/src/model/transaction/LockFundsTransaction.ts +++ b/src/model/transaction/LockFundsTransaction.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; -import { map } from 'rxjs/internal/operators/map'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -28,14 +25,11 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; import { MosaicId } from '../mosaic/MosaicId'; -import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -212,35 +206,24 @@ export class LockFundsTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {LockFundsTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.mosaic.id instanceof NamespaceId; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): LockFundsTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - return statementObservable.pipe( - map((statement) => new LockFundsTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - new Mosaic(statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaic.id as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), - aggregateTransactionIndex) as MosaicId, this.mosaic.amount), - this.duration, - this.signedTransaction, - this.signature, - this.signer, - this.transactionInfo, - )), + return new LockFundsTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + statement.resolveMosaic(this.mosaic, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex), + this.duration, + this.signedTransaction, + this.signature, + this.signer, + this.transactionInfo, ); } } diff --git a/src/model/transaction/MosaicAddressRestrictionTransaction.ts b/src/model/transaction/MosaicAddressRestrictionTransaction.ts index 2b9979ed84..b6b513ba79 100644 --- a/src/model/transaction/MosaicAddressRestrictionTransaction.ts +++ b/src/model/transaction/MosaicAddressRestrictionTransaction.ts @@ -14,10 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { combineLatest } from 'rxjs/internal/observable/combineLatest'; -import { of } from 'rxjs/internal/observable/of'; -import { map } from 'rxjs/internal/operators/map'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -30,14 +26,12 @@ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -243,53 +237,27 @@ export class MosaicAddressRestrictionTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {MosaicAddressRestrictionTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.targetAddress instanceof NamespaceId || - this.mosaicId instanceof NamespaceId; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): MosaicAddressRestrictionTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - - const resolvedAddress = statementObservable.pipe( - map((statement) => this.targetAddress instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Address, this.targetAddress as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : - this.targetAddress, - ), - ); - - const resolvedMosaicId = statementObservable.pipe( - map((statement) => this.mosaicId instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : - this.mosaicId, - ), + return new MosaicAddressRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + statement.resolveMosaicId(this.mosaicId, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex), + this.restrictionKey, + statement.resolveAddress(this.targetAddress, + transactionInfo.height.toString(), transactionInfo.index, aggregateTransactionIndex), + this.previousRestrictionValue, + this.newRestrictionValue, + this.signature, + this.signer, + this.transactionInfo, ); - - return combineLatest(resolvedAddress, resolvedMosaicId, (address, mosaicId) => { - return new MosaicAddressRestrictionTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - mosaicId, - this.restrictionKey, - address, - this.previousRestrictionValue, - this.newRestrictionValue, - this.signature, - this.signer, - this.transactionInfo, - ); - }); } } diff --git a/src/model/transaction/MosaicAliasTransaction.ts b/src/model/transaction/MosaicAliasTransaction.ts index 50ef6548c3..f259c5af13 100644 --- a/src/model/transaction/MosaicAliasTransaction.ts +++ b/src/model/transaction/MosaicAliasTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedMosaicAliasTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedMosaicAliasTransactionBuilder'; @@ -25,7 +23,6 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; @@ -184,10 +181,9 @@ export class MosaicAliasTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {MosaicAliasTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): MosaicAliasTransaction { + return this; } } diff --git a/src/model/transaction/MosaicDefinitionTransaction.ts b/src/model/transaction/MosaicDefinitionTransaction.ts index 69eb9782c2..a43a733825 100644 --- a/src/model/transaction/MosaicDefinitionTransaction.ts +++ b/src/model/transaction/MosaicDefinitionTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -27,7 +25,6 @@ import { MosaicIdDto } from '../../infrastructure/catbuffer/MosaicIdDto'; import { MosaicNonceDto } from '../../infrastructure/catbuffer/MosaicNonceDto'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicFlags } from '../mosaic/MosaicFlags'; @@ -227,10 +224,9 @@ export class MosaicDefinitionTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {MosaicDefinitionTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): MosaicDefinitionTransaction { + return this; } } diff --git a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts index 06b2dbf5f8..5b6853092c 100644 --- a/src/model/transaction/MosaicGlobalRestrictionTransaction.ts +++ b/src/model/transaction/MosaicGlobalRestrictionTransaction.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import { combineLatest, of } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -28,13 +25,11 @@ import { MosaicGlobalRestrictionTransactionBuilder } from '../../infrastructure/ import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { MosaicRestrictionType } from '../restriction/MosaicRestrictionType'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; @@ -252,55 +247,29 @@ export class MosaicGlobalRestrictionTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {MosaicGlobalRestrictionTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.mosaicId instanceof NamespaceId || - this.referenceMosaicId instanceof NamespaceId; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): MosaicGlobalRestrictionTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - - const resolvedMosaicId = statementObservable.pipe( - map((statement) => this.mosaicId instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : - this.mosaicId, - ), - ); - - const resolvedRefMosaicId = statementObservable.pipe( - map((statement) => this.referenceMosaicId instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.referenceMosaicId as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId : - this.referenceMosaicId, - ), + return new MosaicGlobalRestrictionTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + statement.resolveMosaicId(this.mosaicId, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex), + statement.resolveMosaicId(this.referenceMosaicId, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex), + this.restrictionKey, + this.previousRestrictionValue, + this.previousRestrictionType, + this.newRestrictionValue, + this.newRestrictionType, + this.signature, + this.signer, + this.transactionInfo, ); - - return combineLatest(resolvedMosaicId, resolvedRefMosaicId, (mosaicId, refMosaicId) => { - return new MosaicGlobalRestrictionTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - mosaicId, - refMosaicId, - this.restrictionKey, - this.previousRestrictionValue, - this.previousRestrictionType, - this.newRestrictionValue, - this.newRestrictionType, - this.signature, - this.signer, - this.transactionInfo, - ); - }); } } diff --git a/src/model/transaction/MosaicMetadataTransaction.ts b/src/model/transaction/MosaicMetadataTransaction.ts index 2509570bc7..01ad53bc1d 100644 --- a/src/model/transaction/MosaicMetadataTransaction.ts +++ b/src/model/transaction/MosaicMetadataTransaction.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import { of } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -26,13 +23,11 @@ import { MosaicMetadataTransactionBuilder } from '../../infrastructure/catbuffer import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -218,38 +213,26 @@ export class MosaicMetadataTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {MosaicMetadataTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.targetMosaicId instanceof NamespaceId; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): MosaicMetadataTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - - return statementObservable.pipe( - map((statement) => new MosaicMetadataTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.targetPublicKey, - this.scopedMetadataKey, - statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.targetMosaicId as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, - this.valueSizeDelta, - this.value, - this.signature, - this.signer, - this.transactionInfo, - ), - ), - ); + return new MosaicMetadataTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.targetPublicKey, + this.scopedMetadataKey, + statement.resolveMosaicId(this.targetMosaicId, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex), + this.valueSizeDelta, + this.value, + this.signature, + this.signer, + this.transactionInfo, + ); } } diff --git a/src/model/transaction/MosaicSupplyChangeTransaction.ts b/src/model/transaction/MosaicSupplyChangeTransaction.ts index af7e91eed6..c60894309c 100644 --- a/src/model/transaction/MosaicSupplyChangeTransaction.ts +++ b/src/model/transaction/MosaicSupplyChangeTransaction.ts @@ -14,9 +14,6 @@ * limitations under the License. */ -import { of } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { map } from 'rxjs/operators'; import { Convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -26,14 +23,12 @@ import { MosaicSupplyChangeTransactionBuilder } from '../../infrastructure/catbu import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { MosaicId } from '../mosaic/MosaicId'; import { MosaicSupplyChangeAction } from '../mosaic/MosaicSupplyChangeAction'; import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { InnerTransaction } from './InnerTransaction'; @@ -192,37 +187,24 @@ export class MosaicSupplyChangeTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {MosaicSupplyChangeTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.mosaicId instanceof NamespaceId; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): MosaicSupplyChangeTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - - return statementObservable.pipe( - map((statement) => { - return new MosaicSupplyChangeTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.mosaicId as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as MosaicId, - this.action, - this.delta, - this.signature, - this.signer, - this.transactionInfo, - ); - }), + return new MosaicSupplyChangeTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + statement.resolveMosaicId(this.mosaicId, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex), + this.action, + this.delta, + this.signature, + this.signer, + this.transactionInfo, ); } } diff --git a/src/model/transaction/MultisigAccountModificationTransaction.ts b/src/model/transaction/MultisigAccountModificationTransaction.ts index cce5c9f6e0..d8a4dc1d77 100644 --- a/src/model/transaction/MultisigAccountModificationTransaction.ts +++ b/src/model/transaction/MultisigAccountModificationTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { @@ -26,8 +24,6 @@ import {MultisigAccountModificationTransactionBuilder, } from '../../infrastructure/catbuffer/MultisigAccountModificationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { UInt64 } from '../UInt64'; @@ -219,10 +215,9 @@ export class MultisigAccountModificationTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {MultisigAccountModificationTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): MultisigAccountModificationTransaction { + return this; } } diff --git a/src/model/transaction/NamespaceMetadataTransaction.ts b/src/model/transaction/NamespaceMetadataTransaction.ts index 29ee8a8948..f58453c268 100644 --- a/src/model/transaction/NamespaceMetadataTransaction.ts +++ b/src/model/transaction/NamespaceMetadataTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { EmbeddedNamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuffer/EmbeddedNamespaceMetadataTransactionBuilder'; @@ -24,8 +22,6 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceMetadataTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceMetadataTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; @@ -215,10 +211,9 @@ export class NamespaceMetadataTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {NamespaceMetadataTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): NamespaceMetadataTransaction { + return this; } } diff --git a/src/model/transaction/NamespaceRegistrationTransaction.ts b/src/model/transaction/NamespaceRegistrationTransaction.ts index ed631a043c..935ee02bc7 100644 --- a/src/model/transaction/NamespaceRegistrationTransaction.ts +++ b/src/model/transaction/NamespaceRegistrationTransaction.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Observable } from 'rxjs/internal/Observable'; -import { of } from 'rxjs/internal/observable/of'; import { Convert, Convert as convert } from '../../core/format'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; import { BlockDurationDto } from '../../infrastructure/catbuffer/BlockDurationDto'; @@ -27,7 +25,6 @@ import { NamespaceIdDto } from '../../infrastructure/catbuffer/NamespaceIdDto'; import { NamespaceRegistrationTransactionBuilder } from '../../infrastructure/catbuffer/NamespaceRegistrationTransactionBuilder'; import { SignatureDto } from '../../infrastructure/catbuffer/SignatureDto'; import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import {NamespaceMosaicIdGenerator} from '../../infrastructure/transaction/NamespaceMosaicIdGenerator'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; @@ -279,10 +276,9 @@ export class NamespaceRegistrationTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp - * @returns {Observable} + * @returns {NamespaceRegistrationTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp): Observable { - return of(this); + resolveAliases(): NamespaceRegistrationTransaction { + return this; } } diff --git a/src/model/transaction/SecretLockTransaction.ts b/src/model/transaction/SecretLockTransaction.ts index d25f479f3d..97ed1d75b3 100644 --- a/src/model/transaction/SecretLockTransaction.ts +++ b/src/model/transaction/SecretLockTransaction.ts @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { combineLatest, of } from 'rxjs'; -import { Observable } from 'rxjs/internal/Observable'; -import { map } from 'rxjs/operators'; import { Convert, Convert as convert } from '../../core/format'; import { UnresolvedMapping } from '../../core/utils/UnresolvedMapping'; import { AmountDto } from '../../infrastructure/catbuffer/AmountDto'; @@ -29,15 +26,12 @@ import { TimestampDto } from '../../infrastructure/catbuffer/TimestampDto'; import { UnresolvedAddressDto } from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import { UnresolvedMosaicBuilder } from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import { UnresolvedMosaicIdDto } from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import { Address } from '../account/Address'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { Mosaic } from '../mosaic/Mosaic'; -import { MosaicId } from '../mosaic/MosaicId'; import { NamespaceId } from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { HashType, HashTypeLengthValidator } from './HashType'; @@ -240,54 +234,27 @@ export class SecretLockTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {SecretLockTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.recipientAddress instanceof NamespaceId || - this.mosaic.id instanceof NamespaceId; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): SecretLockTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - - const resolvedRecipient = statementObservable.pipe( - map((statement) => this.recipientAddress instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : - this.recipientAddress, - ), - ); - - const resolvedMosaic = statementObservable.pipe( - map((statement) => this.mosaic.id instanceof NamespaceId ? - new Mosaic(statement.getResolvedFromReceipt(ResolutionType.Mosaic, this.recipientAddress as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), - aggregateTransactionIndex) as MosaicId, this.mosaic.amount) : - this.mosaic, - ), + return new SecretLockTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + statement.resolveMosaic(this.mosaic, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex), + this.duration, + this.hashType, + this.secret, + statement.resolveAddress(this.recipientAddress, + transactionInfo.height.toString(), transactionInfo.index, aggregateTransactionIndex), + this.signature, + this.signer, + this.transactionInfo, ); - - return combineLatest(resolvedRecipient, resolvedMosaic, (recipient, mosaic) => { - return new SecretLockTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - mosaic, - this.duration, - this.hashType, - this.secret, - recipient, - this.signature, - this.signer, - this.transactionInfo, - ); - }); } } diff --git a/src/model/transaction/SecretProofTransaction.ts b/src/model/transaction/SecretProofTransaction.ts index 73a35a4b0b..1ae4d90e1b 100644 --- a/src/model/transaction/SecretProofTransaction.ts +++ b/src/model/transaction/SecretProofTransaction.ts @@ -34,6 +34,7 @@ import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; import { NamespaceId } from '../namespace/NamespaceId'; import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import { UInt64 } from '../UInt64'; import { Deadline } from './Deadline'; import { HashType, HashTypeLengthValidator } from './HashType'; @@ -216,37 +217,25 @@ export class SecretProofTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {SecretProofTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.recipientAddress instanceof NamespaceId; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): SecretProofTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - - return statementObservable.pipe( - map((statement) => new SecretProofTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - this.hashType, - this.secret, - statement.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address, - this.proof, - this.signature, - this.signer, - this.transactionInfo, - ), - ), + return new SecretProofTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + this.hashType, + this.secret, + statement.resolveAddress(this.recipientAddress, + transactionInfo.height.toString(), transactionInfo.index, aggregateTransactionIndex), + this.proof, + this.signature, + this.signer, + this.transactionInfo, ); } } diff --git a/src/model/transaction/Transaction.ts b/src/model/transaction/Transaction.ts index 0af948d992..7fc41776c6 100644 --- a/src/model/transaction/Transaction.ts +++ b/src/model/transaction/Transaction.ts @@ -14,15 +14,13 @@ * limitations under the License. */ -import { Observable } from 'rxjs'; import { KeyPair, SHA3Hasher, SignSchema } from '../../core/crypto'; import { Convert } from '../../core/format'; -import { NamespaceHttp } from '../../infrastructure/NamespaceHttp'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; import { SerializeTransactionToJSON } from '../../infrastructure/transaction/SerializeTransactionToJSON'; import { Account } from '../account/Account'; import { PublicAccount } from '../account/PublicAccount'; import { NetworkType } from '../blockchain/NetworkType'; +import { Statement } from '../receipt/Statement'; import { UInt64 } from '../UInt64'; import { AggregateTransactionInfo } from './AggregateTransactionInfo'; import { Deadline } from './Deadline'; @@ -190,11 +188,11 @@ export abstract class Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param AggregateTransactionIndex Transaction index for aggregated transaction * @returns {Observable} */ - abstract resolveAliases(receiptHttp: ReceiptHttp, AggregateTransactionIndex?: number): Observable; + abstract resolveAliases(statement?: Statement, aggregateTransactionIndex?: number): Transaction; /** * @internal diff --git a/src/model/transaction/TransferTransaction.ts b/src/model/transaction/TransferTransaction.ts index 3c062e5763..48e449b60a 100644 --- a/src/model/transaction/TransferTransaction.ts +++ b/src/model/transaction/TransferTransaction.ts @@ -15,8 +15,6 @@ */ import * as Long from 'long'; -import { combineLatest, Observable, of } from 'rxjs'; -import { map } from 'rxjs/operators'; import {Convert} from '../../core/format'; import {UnresolvedMapping} from '../../core/utils/UnresolvedMapping'; import {AmountDto} from '../../infrastructure/catbuffer/AmountDto'; @@ -29,8 +27,6 @@ import {TransferTransactionBuilder} from '../../infrastructure/catbuffer/Transfe import {UnresolvedAddressDto} from '../../infrastructure/catbuffer/UnresolvedAddressDto'; import {UnresolvedMosaicBuilder} from '../../infrastructure/catbuffer/UnresolvedMosaicBuilder'; import {UnresolvedMosaicIdDto} from '../../infrastructure/catbuffer/UnresolvedMosaicIdDto'; -import { ReceiptHttp } from '../../infrastructure/ReceiptHttp'; -import { TransactionService } from '../../service/TransactionService'; import {Address} from '../account/Address'; import {PublicAccount} from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; @@ -39,9 +35,8 @@ import {Message} from '../message/Message'; import {MessageType} from '../message/MessageType'; import {PlainMessage} from '../message/PlainMessage'; import {Mosaic} from '../mosaic/Mosaic'; -import { MosaicId } from '../mosaic/MosaicId'; import {NamespaceId} from '../namespace/NamespaceId'; -import { ResolutionType } from '../receipt/ResolutionType'; +import { Statement } from '../receipt/Statement'; import {UInt64} from '../UInt64'; import {Deadline} from './Deadline'; import {InnerTransaction} from './InnerTransaction'; @@ -281,55 +276,26 @@ export class TransferTransaction extends Transaction { /** * @internal - * @param receiptHttp ReceiptHttp + * @param statement Block receipt statement * @param aggregateTransactionIndex Transaction index for aggregated transaction - * @returns {Observable} + * @returns {TransferTransaction} */ - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { - const hasUnresolved = this.recipientAddress instanceof NamespaceId || - this.mosaics.find((mosaic) => mosaic.id instanceof NamespaceId) !== undefined; - - if (!hasUnresolved) { - return of(this); - } - + resolveAliases(statement: Statement, aggregateTransactionIndex: number = 0): TransferTransaction { const transactionInfo = this.checkTransactionHeightAndIndex(); - - const statementObservable = receiptHttp.getBlockReceipts(transactionInfo.height.toString()); - - const resolvedRecipient = statementObservable.pipe( - map((statement) => this.recipientAddress instanceof NamespaceId ? - statement.getResolvedFromReceipt(ResolutionType.Address, this.recipientAddress as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), aggregateTransactionIndex) as Address : - this.recipientAddress, - ), - ); - - const resolvedMosaics = statementObservable.pipe( - map((statement) => - this.mosaics.map((mosaic) => - mosaic.id instanceof NamespaceId ? - new Mosaic(statement.getResolvedFromReceipt(ResolutionType.Mosaic, mosaic.id as NamespaceId, - transactionInfo.index, transactionInfo.height.toString(), - aggregateTransactionIndex) as MosaicId, mosaic.amount) : - mosaic, - ), - ), + return new TransferTransaction( + this.networkType, + this.version, + this.deadline, + this.maxFee, + statement.resolveAddress(this.recipientAddress, + transactionInfo.height.toString(), transactionInfo.index, aggregateTransactionIndex), + this.mosaics.map((mosaic) => + statement.resolveMosaic(mosaic, transactionInfo.height.toString(), + transactionInfo.index, aggregateTransactionIndex)), + this.message, + this.signature, + this.signer, + this.transactionInfo, ); - - return combineLatest(resolvedRecipient, resolvedMosaics, (recipient, mosaics) => { - return new TransferTransaction( - this.networkType, - this.version, - this.deadline, - this.maxFee, - recipient, - mosaics, - this.message, - this.signature, - this.signer, - this.transactionInfo, - ); - }); } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 854b7ecb39..a855138d49 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -14,11 +14,23 @@ * limitations under the License. */ -import {Observable} from 'rxjs'; -import { mergeMap, toArray} from 'rxjs/operators'; +import {Observable, of} from 'rxjs'; +import { map, mergeMap, toArray} from 'rxjs/operators'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; +import { NamespaceId } from '../model/namespace/NamespaceId'; +import { AccountAddressRestrictionTransaction } from '../model/transaction/AccountAddressRestrictionTransaction'; +import { AggregateTransaction } from '../model/transaction/AggregateTransaction'; +import { LockFundsTransaction } from '../model/transaction/LockFundsTransaction'; +import { MosaicAddressRestrictionTransaction } from '../model/transaction/MosaicAddressRestrictionTransaction'; +import { MosaicGlobalRestrictionTransaction } from '../model/transaction/MosaicGlobalRestrictionTransaction'; +import { MosaicMetadataTransaction } from '../model/transaction/MosaicMetadataTransaction'; +import { MosaicSupplyChangeTransaction } from '../model/transaction/MosaicSupplyChangeTransaction'; +import { SecretLockTransaction } from '../model/transaction/SecretLockTransaction'; +import { SecretProofTransaction } from '../model/transaction/SecretProofTransaction'; import { Transaction } from '../model/transaction/Transaction'; +import { TransactionType } from '../model/transaction/TransactionType'; +import { TransferTransaction } from '../model/transaction/TransferTransaction'; import { ITransactionService } from './interfaces/ITransactionService'; /** @@ -44,8 +56,91 @@ export class TransactionService implements ITransactionService { public resolveAliases(transationHashes: string[]): Observable { return this.transactionHttp.getTransactions(transationHashes).pipe( mergeMap((_) => _), - mergeMap((transaction) => transaction.resolveAliases(this.receiptHttp)), + mergeMap((transaction) => this.resolveTransaction(transaction)), toArray(), ); } + + /** + * Resolve transaction alias(s) + * @param transaction Transaction to be resolved + * @returns {Observable} + */ + private resolveTransaction(transaction: Transaction): Observable { + if ([TransactionType.AGGREGATE_BONDED, TransactionType.AGGREGATE_COMPLETE].includes(transaction.type)) { + if ((transaction as AggregateTransaction).innerTransactions.find((tx) => this.checkShouldResolve((tx as Transaction)))) { + return this.resolvedFromReceipt(transaction, transaction.transactionInfo!.index); + } + return of(transaction); + } + return this.checkShouldResolve(transaction) ? this.resolvedFromReceipt(transaction, 0) : of(transaction); + } + + /** + * @internal + * Check if receiptHttp needs to be called to resolve transaction alias + * @param transaction Transaction + * @return {boolean} + */ + private checkShouldResolve(transaction: Transaction): boolean { + switch (transaction.type) { + case TransactionType.LINK_ACCOUNT: + case TransactionType.ACCOUNT_METADATA_TRANSACTION: + case TransactionType.ACCOUNT_RESTRICTION_OPERATION: + case TransactionType.ADDRESS_ALIAS: + case TransactionType.MOSAIC_ALIAS: + case TransactionType.MOSAIC_DEFINITION: + case TransactionType.MODIFY_MULTISIG_ACCOUNT: + case TransactionType.NAMESPACE_METADATA_TRANSACTION: + case TransactionType.REGISTER_NAMESPACE: + return false; + case TransactionType.ACCOUNT_RESTRICTION_ADDRESS: + const accountAddressRestriction = transaction as AccountAddressRestrictionTransaction; + return accountAddressRestriction.restrictionAdditions.find((address) => address instanceof NamespaceId) !== undefined || + accountAddressRestriction.restrictionDeletions.find((address) => address instanceof NamespaceId) !== undefined; + case TransactionType.ACCOUNT_RESTRICTION_MOSAIC: + const accountMosaicRestriction = transaction as AccountAddressRestrictionTransaction; + return accountMosaicRestriction.restrictionAdditions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined || + accountMosaicRestriction.restrictionDeletions.find((mosaicId) => mosaicId instanceof NamespaceId) !== undefined; + case TransactionType.LOCK: + return (transaction as LockFundsTransaction).mosaic.id instanceof NamespaceId; + case TransactionType.MOSAIC_ADDRESS_RESTRICTION: + const mosaicAddressRestriction = transaction as MosaicAddressRestrictionTransaction; + return mosaicAddressRestriction.targetAddress instanceof NamespaceId || + mosaicAddressRestriction.mosaicId instanceof NamespaceId; + case TransactionType.MOSAIC_GLOBAL_RESTRICTION: + const mosaicGlobalRestriction = transaction as MosaicGlobalRestrictionTransaction; + return mosaicGlobalRestriction.referenceMosaicId instanceof NamespaceId || + mosaicGlobalRestriction.mosaicId instanceof NamespaceId; + case TransactionType.MOSAIC_METADATA_TRANSACTION: + return (transaction as MosaicMetadataTransaction).targetMosaicId instanceof NamespaceId; + case TransactionType.MOSAIC_SUPPLY_CHANGE: + return (transaction as MosaicSupplyChangeTransaction).mosaicId instanceof NamespaceId; + case TransactionType.SECRET_PROOF: + return (transaction as SecretProofTransaction).recipientAddress instanceof NamespaceId; + case TransactionType.SECRET_LOCK: + const secretLock = transaction as SecretLockTransaction; + return secretLock.recipientAddress instanceof NamespaceId || + secretLock.mosaic.id instanceof NamespaceId; + case TransactionType.TRANSFER: + const transfer = transaction as TransferTransaction; + return transfer.recipientAddress instanceof NamespaceId || + transfer.mosaics.find((mosaic) => mosaic.id instanceof NamespaceId) !== undefined; + default: + throw new Error ('Transaction type not not recogonised.'); + } + } + + /** + * @internal + * Resolve transaction alais(s) from block receipt by calling receiptHttp + * @param transaction Transaction to be resolved + * @param aggregateIndex Aggregate transaction index + * @return {Observable} + */ + private resolvedFromReceipt(transaction: Transaction, aggregateIndex: number): Observable { + return this.receiptHttp.getBlockReceipts(transaction.transactionInfo!.height.toString()).pipe( + map((statement) => transaction.resolveAliases(statement, aggregateIndex)), + ); + } } diff --git a/test/model/transaction/Transaction.spec.ts b/test/model/transaction/Transaction.spec.ts index b86267517f..1858bdef7d 100644 --- a/test/model/transaction/Transaction.spec.ts +++ b/test/model/transaction/Transaction.spec.ts @@ -17,7 +17,6 @@ import { expect } from 'chai'; import { Observable } from 'rxjs/internal/Observable'; import { Convert } from '../../../src/core/format/Convert'; -import { ReceiptHttp } from '../../../src/infrastructure/ReceiptHttp'; import { Account } from '../../../src/model/account/Account'; import { Address } from '../../../src/model/account/Address'; import { NetworkType } from '../../../src/model/blockchain/NetworkType'; @@ -404,7 +403,7 @@ class FakeTransaction extends Transaction { protected generateEmbeddedBytes(): Uint8Array { throw new Error('Not implemented'); } - resolveAliases(receiptHttp: ReceiptHttp, aggregateTransactionIndex?: number): Observable { + resolveAliases(): TransferTransaction { throw new Error('Not implemented'); } } From c34cdcdafb3c086c54f271691ca711f2cc2a4866 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 23:21:01 +0000 Subject: [PATCH 27/50] Fixed unit test --- test/model/receipt/Statement.spec.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/model/receipt/Statement.spec.ts b/test/model/receipt/Statement.spec.ts index e1a6b774d1..eb13175766 100644 --- a/test/model/receipt/Statement.spec.ts +++ b/test/model/receipt/Statement.spec.ts @@ -110,8 +110,7 @@ describe('Statement', () => { it('should get reolved address from receipt', () => { const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); - const resolved = statement - .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, 0, '1473'); + const resolved = statement.resolveAddress(unresolvedAddress as NamespaceId, '1473', 0); expect(resolved instanceof Address).to.be.true; expect((resolved as Address).equals(account.address)).to.be.true; @@ -141,8 +140,7 @@ describe('Statement', () => { }; const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); - const resolved = statement - .getResolvedFromReceipt(ResolutionType.Address, unresolvedAddress as NamespaceId, 0, '1473'); + const resolved = statement.resolveAddress(unresolvedAddress as NamespaceId, '1473', 0); expect(resolved instanceof Address).to.be.true; expect((resolved as Address).equals(account.address)).to.be.true; @@ -151,8 +149,7 @@ describe('Statement', () => { it('should get reolved mosaic from receipt', () => { const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); - const resolved = statement - .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, 0, '1473'); + const resolved = statement.resolveMosaicId(unresolvedMosaic as NamespaceId, '1473', 0); expect(resolved instanceof MosaicId).to.be.true; expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; @@ -197,8 +194,7 @@ describe('Statement', () => { }; const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); const statement = CreateStatementFromDTO(statementWithoutHarvesting, NetworkType.MIJIN_TEST); - const resolved = statement - .getResolvedFromReceipt(ResolutionType.Mosaic, unresolvedMosaic as NamespaceId, 0, '1473'); + const resolved = statement.resolveMosaicId(unresolvedMosaic as NamespaceId, '1473', 0); expect(resolved instanceof MosaicId).to.be.true; expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; From 2997e4fc92d78c5249664e67093f88192c74029a Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 28/50] Added #352 aggregate bonded announcing --- src/infrastructure/Listener.ts | 8 ++-- src/model/transaction/SignedTransaction.ts | 10 +++++ src/service/TransactionService.ts | 39 +++++++++++++++++++ src/service/interfaces/ITransactionService.ts | 26 ++++++++++++- 4 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/infrastructure/Listener.ts b/src/infrastructure/Listener.ts index 1b4db4b1f2..f1778b29ed 100644 --- a/src/infrastructure/Listener.ts +++ b/src/infrastructure/Listener.ts @@ -239,7 +239,7 @@ export class Listener { * it emits a new Transaction in the event stream. * * @param address address we listen when a transaction is in confirmed state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of Transaction with state confirmed */ public confirmed(address: Address, transactionHash?: string): Observable { @@ -249,7 +249,7 @@ export class Listener { filter((_) => _.message instanceof Transaction), map((_) => _.message as Transaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } @@ -292,7 +292,7 @@ export class Listener { * it emits a new {@link AggregateTransaction} in the event stream. * * @param address address we listen when a transaction with missing signatures state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of AggregateTransaction with missing signatures state */ public aggregateBondedAdded(address: Address, transactionHash?: string): Observable { @@ -302,7 +302,7 @@ export class Listener { filter((_) => _.message instanceof AggregateTransaction), map((_) => _.message as AggregateTransaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } diff --git a/src/model/transaction/SignedTransaction.ts b/src/model/transaction/SignedTransaction.ts index addc04c6a1..bc776b4eb6 100644 --- a/src/model/transaction/SignedTransaction.ts +++ b/src/model/transaction/SignedTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Address } from '../account/Address'; +import { PublicAccount } from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; /** @@ -65,4 +67,12 @@ export class SignedTransaction { networkType: this.networkType, }; } + + /** + * Return signer's address + * @returns {Address} + */ + getSignerAddress(): Address { + return PublicAccount.createFromPublicKey(this.signerPublicKey, this.networkType).address; + } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index a855138d49..bc547563d1 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -16,6 +16,8 @@ import {Observable, of} from 'rxjs'; import { map, mergeMap, toArray} from 'rxjs/operators'; +import { flatMap } from 'rxjs/operators'; +import { Listener } from '../infrastructure/Listener'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; import { NamespaceId } from '../model/namespace/NamespaceId'; @@ -40,6 +42,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -47,6 +50,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** @@ -143,4 +147,39 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable { + return this.announce(signedHashLockTransaction).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + ); + + } } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 6bbeb16160..37a0984911 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,8 @@ */ import {Observable} from 'rxjs'; +import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; +import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; /** @@ -24,7 +26,29 @@ export interface ITransactionService { /** * @param transationHashes List of transaction hashes. - * @returns Observable + * @returns {Observable} */ resolveAliases(transationHashes: string[]): Observable; + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + announce(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable; } From 835ba0bb05ff363fcc45320d18e8065d7e19ae7c Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 29/50] Moved listener to method --- ...TransactionService_AggregateBonded.spec.ts | 212 ++++++++++++++++++ src/service/TransactionService.ts | 22 +- src/service/interfaces/ITransactionService.ts | 8 +- 3 files changed, 230 insertions(+), 12 deletions(-) create mode 100644 e2e/service/TransactionService_AggregateBonded.spec.ts diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts new file mode 100644 index 0000000000..53e6c0532d --- /dev/null +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -0,0 +1,212 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { Listener } from '../../src/infrastructure/Listener'; +import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; +import { Account } from '../../src/model/account/Account'; +import { Address } from '../../src/model/account/Address'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; +import { Deadline } from '../../src/model/transaction/Deadline'; +import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction'; +import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { TransactionService } from '../../src/service/TransactionService'; + +describe('TransactionService', () => { + let account: Account; + let account2: Account; + let multisigAccount: Account; + let cosignAccount1: Account; + let cosignAccount2: Account; + let cosignAccount3: Account; + let url: string; + let generationHash: string; + let transactionHttp: TransactionHttp; + let config; + + before((done) => { + const path = require('path'); + require('fs').readFile(path.resolve(__dirname, '../conf/network.conf'), (err, data) => { + if (err) { + throw err; + } + const json = JSON.parse(data); + config = json; + account = Account.createFromPrivateKey(json.testAccount.privateKey, NetworkType.MIJIN_TEST); + account2 = Account.createFromPrivateKey(json.testAccount2.privateKey, NetworkType.MIJIN_TEST); + multisigAccount = Account.createFromPrivateKey(json.multisigAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount1 = Account.createFromPrivateKey(json.cosignatoryAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount2 = Account.createFromPrivateKey(json.cosignatory2Account.privateKey, NetworkType.MIJIN_TEST); + cosignAccount3 = Account.createFromPrivateKey(json.cosignatory3Account.privateKey, NetworkType.MIJIN_TEST); + url = json.apiUrl; + generationHash = json.generationHash; + transactionHttp = new TransactionHttp(json.apiUrl); + done(); + }); + }); + + /** + * ========================= + * Setup test data + * ========================= + */ + describe('Setup test multisig account', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const modifyMultisigAccountTransaction = MultisigAccountModificationTransaction.create( + Deadline.create(), + 2, + 1, + [ + cosignAccount1.publicAccount, + cosignAccount2.publicAccount, + cosignAccount3.publicAccount, + ], + [], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [modifyMultisigAccountTransaction.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(multisigAccount, [cosignAccount1, cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(multisigAccount.address).subscribe(() => { + done(); + }); + listener.status(multisigAccount.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + /** + * ========================= + * Test + * ========================= + */ + + describe('should announce transaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const transactionService = new TransactionService(url); + const transferTransaction = TransferTransaction.create( + Deadline.create(), + account2.address, + [ + NetworkCurrencyMosaic.createAbsolute(1), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = transferTransaction.signWith(account, generationHash); + transactionService.announce(signedTransaction, listener).subscribe((tx: TransferTransaction) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect((tx.recipientAddress as Address).equals(account2.address)).to.be.true; + expect(tx.message.payload).to.be.equal('test-message'); + done(); + }); + }); + }); + + /** + * ========================= + * House Keeping + * ========================= + */ + + describe('Restore test multisig Accounts', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const removeCosigner1 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + 0, + [], + [ cosignAccount1.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + const removeCosigner2 = MultisigAccountModificationTransaction.create( + Deadline.create(), + 0, + 0, + [], + [ + cosignAccount2.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const removeCosigner3 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + -1, + [], + [ + cosignAccount3.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [removeCosigner1.toAggregate(multisigAccount.publicAccount), + removeCosigner2.toAggregate(multisigAccount.publicAccount), + removeCosigner3.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(cosignAccount1, [cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(cosignAccount1.address).subscribe(() => { + done(); + }); + listener.status(cosignAccount1.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); +}); diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index bc547563d1..cde1ec560a 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,7 +42,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -50,11 +49,12 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** + * Resolve unresolved mosaic / address from array of transactions * @param transationHashes List of transaction hashes. + * @param listener Websocket listener * @returns Observable */ public resolveAliases(transationHashes: string[]): Observable { @@ -150,22 +150,24 @@ export class TransactionService implements ITransactionService { /** * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener * @returns {Observable} */ - public announce(signedTransaction: SignedTransaction): Observable { + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ - public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } @@ -173,12 +175,14 @@ export class TransactionService implements ITransactionService { * Announce aggregate bonded transaction with lock fund * @param signedHashLockTransaction Signed hash lock transaction. * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable { - return this.announce(signedHashLockTransaction).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), ); } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 37a0984911..3aa299ebd4 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,7 @@ */ import {Observable} from 'rxjs'; +import { Listener } from '../../infrastructure/Listener'; import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; @@ -34,14 +35,14 @@ export interface ITransactionService { * @param signedTransaction Signed transaction to be announced. * @returns {Observable} */ - announce(signedTransaction: SignedTransaction): Observable; + announce(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. * @returns {Observable} */ - announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate bonded transaction with lock fund @@ -50,5 +51,6 @@ export interface ITransactionService { * @returns {Observable} */ announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable; + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable; } From 256747936f13086805eae7ebba523b9ff0d8dd1c Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 5 Dec 2019 12:28:54 +0000 Subject: [PATCH 30/50] Added more e2e tests --- ...TransactionService_AggregateBonded.spec.ts | 84 ++++++++++++++++++- src/service/TransactionService.ts | 80 +++++++++--------- 2 files changed, 123 insertions(+), 41 deletions(-) diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts index 53e6c0532d..780ccb8d49 100644 --- a/e2e/service/TransactionService_AggregateBonded.spec.ts +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -16,17 +16,25 @@ import { expect } from 'chai'; import { Listener } from '../../src/infrastructure/Listener'; +import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; import { Account } from '../../src/model/account/Account'; import { Address } from '../../src/model/account/Address'; import { NetworkType } from '../../src/model/blockchain/NetworkType'; import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { Mosaic } from '../../src/model/mosaic/Mosaic'; +import { MosaicId } from '../../src/model/mosaic/MosaicId'; import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { NamespaceId } from '../../src/model/namespace/NamespaceId'; import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; import { Deadline } from '../../src/model/transaction/Deadline'; +import { LockFundsTransaction } from '../../src/model/transaction/LockFundsTransaction'; import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction'; +import { TransactionType } from '../../src/model/transaction/TransactionType'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { UInt64 } from '../../src/model/UInt64'; import { TransactionService } from '../../src/service/TransactionService'; +import { TransactionUtils } from '../infrastructure/TransactionUtils'; describe('TransactionService', () => { let account: Account; @@ -35,9 +43,12 @@ describe('TransactionService', () => { let cosignAccount1: Account; let cosignAccount2: Account; let cosignAccount3: Account; + let networkCurrencyMosaicId: MosaicId; let url: string; let generationHash: string; let transactionHttp: TransactionHttp; + let transactionService: TransactionService; + let namespaceHttp: NamespaceHttp; let config; before((done) => { @@ -56,7 +67,9 @@ describe('TransactionService', () => { cosignAccount3 = Account.createFromPrivateKey(json.cosignatory3Account.privateKey, NetworkType.MIJIN_TEST); url = json.apiUrl; generationHash = json.generationHash; - transactionHttp = new TransactionHttp(json.apiUrl); + transactionHttp = new TransactionHttp(url); + namespaceHttp = new NamespaceHttp(url); + transactionService = new TransactionService(url); done(); }); }); @@ -66,6 +79,15 @@ describe('TransactionService', () => { * Setup test data * ========================= */ + describe('Get network currency mosaic id', () => { + it('get mosaicId', (done) => { + namespaceHttp.getLinkedMosaicId(new NamespaceId('cat.currency')).subscribe((networkMosaicId) => { + networkCurrencyMosaicId = networkMosaicId; + done(); + }); + }); + }); + describe('Setup test multisig account', () => { let listener: Listener; before (() => { @@ -123,7 +145,6 @@ describe('TransactionService', () => { return listener.close(); }); it('announce', (done) => { - const transactionService = new TransactionService(url); const transferTransaction = TransferTransaction.create( Deadline.create(), account2.address, @@ -143,6 +164,65 @@ describe('TransactionService', () => { }); }); + describe('should announce aggregate bonded with hashlock', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const signedAggregatedTransaction = + TransactionUtils.createSignedAggregatedBondTransaction(multisigAccount, account, account2.address, generationHash); + const lockFundsTransaction = LockFundsTransaction.create( + Deadline.create(), + new Mosaic(networkCurrencyMosaicId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyMosaic.DIVISIBILITY))), + UInt64.fromUint(1000), + signedAggregatedTransaction, + NetworkType.MIJIN_TEST, + ); + const signedLockFundsTransaction = lockFundsTransaction.signWith(account, generationHash); + transactionService + .announceHashLockAggregateBonded(signedLockFundsTransaction, signedAggregatedTransaction, listener).subscribe((tx) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect(tx.type).to.be.equal(TransactionType.AGGREGATE_BONDED); + done(); + }); + }); + }); + + describe('should announce aggregate bonded transaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const signedAggregatedTransaction = + TransactionUtils.createSignedAggregatedBondTransaction(multisigAccount, account, account2.address, generationHash); + const lockFundsTransaction = LockFundsTransaction.create( + Deadline.create(), + new Mosaic(networkCurrencyMosaicId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyMosaic.DIVISIBILITY))), + UInt64.fromUint(1000), + signedAggregatedTransaction, + NetworkType.MIJIN_TEST, + ); + const signedLockFundsTransaction = lockFundsTransaction.signWith(account, generationHash); + transactionService.announce(signedLockFundsTransaction, listener).subscribe(() => { + transactionService.announceAggregateBonded(signedAggregatedTransaction, listener).subscribe((tx) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect(tx.type).to.be.equal(TransactionType.AGGREGATE_BONDED); + done(); + }); + }); + }); + }); + /** * ========================= * House Keeping diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index cde1ec560a..c82c9ea2aa 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -30,6 +30,7 @@ import { MosaicMetadataTransaction } from '../model/transaction/MosaicMetadataTr import { MosaicSupplyChangeTransaction } from '../model/transaction/MosaicSupplyChangeTransaction'; import { SecretLockTransaction } from '../model/transaction/SecretLockTransaction'; import { SecretProofTransaction } from '../model/transaction/SecretProofTransaction'; +import { SignedTransaction } from '../model/transaction/SignedTransaction'; import { Transaction } from '../model/transaction/Transaction'; import { TransactionType } from '../model/transaction/TransactionType'; import { TransferTransaction } from '../model/transaction/TransferTransaction'; @@ -65,6 +66,46 @@ export class TransactionService implements ITransactionService { ); } + /** + * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * **NOTE** A lock fund transaction for this aggregate bonded should exists + * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), + ); + + } + /** * Resolve transaction alias(s) * @param transaction Transaction to be resolved @@ -147,43 +188,4 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } - - /** - * @param signedTransaction Signed transaction to be announced. - * @param listener Websocket listener - * @returns {Observable} - */ - public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate transaction - * @param signedTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate bonded transaction with lock fund - * @param signedHashLockTransaction Signed hash lock transaction. - * @param signedAggregateTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction, - listener: Listener): Observable { - return this.announce(signedHashLockTransaction, listener).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), - ); - - } } From a06a4e48a83d49623ceb9ef128eda9a35430697a Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 5 Dec 2019 12:50:05 +0000 Subject: [PATCH 31/50] Bug fixed on resolutionStatement --- src/model/receipt/ResolutionStatement.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/model/receipt/ResolutionStatement.ts b/src/model/receipt/ResolutionStatement.ts index 9d559bd4de..40be459336 100644 --- a/src/model/receipt/ResolutionStatement.ts +++ b/src/model/receipt/ResolutionStatement.ts @@ -115,8 +115,7 @@ export class ResolutionStatement { } // When transaction index matches a primary id, get the most recent secondaryId - const resolvedSecondaryId = Math.max(...this.resolutionEntries - .map((entry) => secondaryId >= entry.source.secondaryId ? entry.source.secondaryId : 0)); + const resolvedSecondaryId = this.getMaxSecondaryIdByPrimaryId(resolvedPrimaryId); if (resolvedSecondaryId === 0 && secondaryId !== resolvedSecondaryId) { /* From a7890a61c54de25e109fcd194255a09633781c71 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 5 Dec 2019 18:19:57 +0000 Subject: [PATCH 32/50] Fixed bug and added scenarior unit test which not covered in e2e --- src/model/receipt/ResolutionStatement.ts | 65 +++++++++++++++---- .../model/receipt/ResolutionStatement.spec.ts | 52 +++++++++++++++ 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/src/model/receipt/ResolutionStatement.ts b/src/model/receipt/ResolutionStatement.ts index 40be459336..bf30c07145 100644 --- a/src/model/receipt/ResolutionStatement.ts +++ b/src/model/receipt/ResolutionStatement.ts @@ -102,38 +102,70 @@ export class ResolutionStatement { */ const resolvedPrimaryId = this.getMaxAvailablePrimaryId(primaryId); + /* + If no primaryId found, it means there's no resolution entry available for the process. Invalid entry. + + e.g. Given: + Entries: [{P:2, S:0}, {P5:, S:6}] + Transaction: [Inx:1(0+1), AggInx:0] + It should return Entry: undefined + */ if (resolvedPrimaryId === 0) { return undefined; } else if (primaryId > resolvedPrimaryId) { /* If the transaction index is greater than the overall most recent source primary id. Use the most recent resolution entry (Max.PrimaryId + Max.SecondaryId) + + e.g. Given: + Entries: [{P:1, S:0}, {P:2, S:0}, {P:4, S:2}, {P:4, S:4} {P7:, S:6}] + Transaction: [Inx:5(0+1), AggInx:0] + It should return Entry: {P:3, S:4} + + e.g. Given: + Entries: [{P:1, S:0}, {P:2, S:0}, {P:4, S:2}, {P:4, S:4}, {P7:, S:6}] + Transaction: [Inx:3(2+1), AggInx:0] + It should return Entry: {P:2, S:0} */ return this.resolutionEntries .find((entry) => entry.source.primaryId === resolvedPrimaryId && entry.source.secondaryId === this.getMaxSecondaryIdByPrimaryId(resolvedPrimaryId)); } - // When transaction index matches a primary id, get the most recent secondaryId - const resolvedSecondaryId = this.getMaxSecondaryIdByPrimaryId(resolvedPrimaryId); + // When transaction index matches a primary id, get the most recent secondaryId (resolvedPrimaryId can only <= primaryId) + const resolvedSecondaryId = this.getMaxSecondaryIdByPrimaryIdAndSecondaryId(resolvedPrimaryId, secondaryId); - if (resolvedSecondaryId === 0 && secondaryId !== resolvedSecondaryId) { - /* - If no most recent secondaryId matched transaction index, find previous resolution entry (most recent). - */ + /* + If no most recent secondaryId matched transaction index, find previous resolution entry (most recent). + This means the resolution entry for the specific innter transaction (inside Aggregate) / + was generated previously outside the aggregate. It should return the previous entry (privious primarId) + + e.g. Given: + Entries: [{P:1, S:0}, {P:2, S:0}, {P5:, S:6}] + Transaction: [Inx:5(4+1), AggInx:3(2+1)] + It should return Entry: {P:2, S:0} + */ + if (resolvedSecondaryId === 0 && resolvedSecondaryId !== secondaryId) { const lastPrimaryId = this.getMaxAvailablePrimaryId(resolvedPrimaryId - 1); - return this.resolutionEntries - .find((entry) => entry.source.primaryId === lastPrimaryId && - entry.source.secondaryId === this.getMaxSecondaryIdByPrimaryId(lastPrimaryId)); + return this.resolutionEntries.find((entry) => entry.source.primaryId === lastPrimaryId && + entry.source.secondaryId === this.getMaxSecondaryIdByPrimaryId(lastPrimaryId)); } - // All matched + + /* + Found a matched resolution entry on both primaryId and secondaryId + + e.g. Given: + Entries: [{P:1, S:0}, {P:2, S:0}, {P5:, S:6}] + Transaction: [Inx:5(4+1), AggInx:6(2+1)] + It should return Entry: {P:5, S:6} + */ return this.resolutionEntries .find((entry) => entry.source.primaryId === resolvedPrimaryId && entry.source.secondaryId === resolvedSecondaryId); } /** * @internal - * Get most `recent` secondary id by a given primaryId + * Get max secondary id by a given primaryId * @param primaryId Primary source id * @returns {number} */ @@ -142,6 +174,17 @@ export class ResolutionStatement { .map((filtered) => filtered.source.secondaryId)); } + /** + * Get most `recent` available secondary id by a given primaryId + * @param primaryId Primary source id + * @param secondaryId Secondary source id + * @returns {number} + */ + private getMaxSecondaryIdByPrimaryIdAndSecondaryId(primaryId: number, secondaryId: number): number { + return Math.max(...this.resolutionEntries.filter((entry) => entry.source.primaryId === primaryId) + .map((filtered) => secondaryId >= filtered.source.secondaryId ? filtered.source.secondaryId : 0)); + } + /** * @internal * Get most `recent` primary source id by a given id (transaction index) as PrimaryId might not be the same as block transaction index. diff --git a/test/model/receipt/ResolutionStatement.spec.ts b/test/model/receipt/ResolutionStatement.spec.ts index c37018dd66..65d5d57fe1 100644 --- a/test/model/receipt/ResolutionStatement.spec.ts +++ b/test/model/receipt/ResolutionStatement.spec.ts @@ -105,6 +105,42 @@ describe('ResolutionStatement', () => { ], }, }, + { + statement: { + height: '1500', + unresolved: '85BBEA6CC462B244', + resolutionEntries: [ + { + source: { + primaryId: 1, + secondaryId: 1, + }, + resolved: '0DC67FBE1CAD29E5', + }, + { + source: { + primaryId: 1, + secondaryId: 4, + }, + resolved: '7CDF3B117A3C40CC', + }, + { + source: { + primaryId: 1, + secondaryId: 7, + }, + resolved: '0DC67FBE1CAD29E5', + }, + { + source: { + primaryId: 2, + secondaryId: 4, + }, + resolved: '7CDF3B117A3C40CC', + }, + ], + }, + }, ]; statementDTO = { @@ -164,4 +200,20 @@ describe('ResolutionStatement', () => { expect(entry).to.be.undefined; }); + it('resolution change in the block (more than one AGGREGATE)', () => { + const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); + const resolution = statement.mosaicResolutionStatements[2]; + expect((resolution.getResolutionEntryById(1, 1)!.resolved as MosaicId).toHex()).to.be.equal('0DC67FBE1CAD29E5'); + expect((resolution.getResolutionEntryById(1, 4)!.resolved as MosaicId).toHex()).to.be.equal('7CDF3B117A3C40CC'); + expect((resolution.getResolutionEntryById(1, 7)!.resolved as MosaicId).toHex()).to.be.equal('0DC67FBE1CAD29E5'); + expect((resolution.getResolutionEntryById(2, 1)!.resolved as MosaicId).toHex()).to.be.equal('0DC67FBE1CAD29E5'); + expect((resolution.getResolutionEntryById(2, 4)!.resolved as MosaicId).toHex()).to.be.equal('7CDF3B117A3C40CC'); + + expect((resolution.getResolutionEntryById(3, 0)!.resolved as MosaicId).toHex()).to.be.equal('7CDF3B117A3C40CC'); + expect((resolution.getResolutionEntryById(2, 2)!.resolved as MosaicId).toHex()).to.be.equal('0DC67FBE1CAD29E5'); + expect(resolution.getResolutionEntryById(1, 0)).to.be.undefined; + expect((resolution.getResolutionEntryById(1, 6)!.resolved as MosaicId).toHex()).to.be.equal('7CDF3B117A3C40CC'); + expect((resolution.getResolutionEntryById(1, 2)!.resolved as MosaicId).toHex()).to.be.equal('0DC67FBE1CAD29E5'); + }); + }); From e295b5a394c91d2408ef22da3732004734f8c576 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 33/50] Added #352 aggregate bonded announcing --- src/infrastructure/Listener.ts | 4 +- src/model/transaction/SignedTransaction.ts | 10 +++++ src/service/TransactionService.ts | 41 ++++++++++++++++++- src/service/interfaces/ITransactionService.ts | 26 +++++++++++- 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/infrastructure/Listener.ts b/src/infrastructure/Listener.ts index 1b4db4b1f2..1c69cde5d1 100644 --- a/src/infrastructure/Listener.ts +++ b/src/infrastructure/Listener.ts @@ -239,7 +239,7 @@ export class Listener { * it emits a new Transaction in the event stream. * * @param address address we listen when a transaction is in confirmed state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of Transaction with state confirmed */ public confirmed(address: Address, transactionHash?: string): Observable { @@ -292,7 +292,7 @@ export class Listener { * it emits a new {@link AggregateTransaction} in the event stream. * * @param address address we listen when a transaction with missing signatures state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of AggregateTransaction with missing signatures state */ public aggregateBondedAdded(address: Address, transactionHash?: string): Observable { diff --git a/src/model/transaction/SignedTransaction.ts b/src/model/transaction/SignedTransaction.ts index addc04c6a1..bc776b4eb6 100644 --- a/src/model/transaction/SignedTransaction.ts +++ b/src/model/transaction/SignedTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Address } from '../account/Address'; +import { PublicAccount } from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; /** @@ -65,4 +67,12 @@ export class SignedTransaction { networkType: this.networkType, }; } + + /** + * Return signer's address + * @returns {Address} + */ + getSignerAddress(): Address { + return PublicAccount.createFromPublicKey(this.signerPublicKey, this.networkType).address; + } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index a855138d49..5dca792362 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -15,7 +15,8 @@ */ import {Observable, of} from 'rxjs'; -import { map, mergeMap, toArray} from 'rxjs/operators'; +import { flatMap, map, mergeMap, toArray} from 'rxjs/operators'; +import { Listener } from '../infrastructure/Listener'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; import { NamespaceId } from '../model/namespace/NamespaceId'; @@ -28,6 +29,7 @@ import { MosaicMetadataTransaction } from '../model/transaction/MosaicMetadataTr import { MosaicSupplyChangeTransaction } from '../model/transaction/MosaicSupplyChangeTransaction'; import { SecretLockTransaction } from '../model/transaction/SecretLockTransaction'; import { SecretProofTransaction } from '../model/transaction/SecretProofTransaction'; +import { SignedTransaction } from '../model/transaction/SignedTransaction'; import { Transaction } from '../model/transaction/Transaction'; import { TransactionType } from '../model/transaction/TransactionType'; import { TransferTransaction } from '../model/transaction/TransferTransaction'; @@ -40,6 +42,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -47,6 +50,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** @@ -143,4 +147,39 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable { + return this.announce(signedHashLockTransaction).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + ); + + } } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 6bbeb16160..37a0984911 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,8 @@ */ import {Observable} from 'rxjs'; +import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; +import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; /** @@ -24,7 +26,29 @@ export interface ITransactionService { /** * @param transationHashes List of transaction hashes. - * @returns Observable + * @returns {Observable} */ resolveAliases(transationHashes: string[]): Observable; + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + announce(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable; } From e4234d14edc00cd1c6f64be3cbc5bc66b38ad75c Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 34/50] Added #352 aggregate bonded announcing --- src/infrastructure/Listener.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/infrastructure/Listener.ts b/src/infrastructure/Listener.ts index 1c69cde5d1..f1778b29ed 100644 --- a/src/infrastructure/Listener.ts +++ b/src/infrastructure/Listener.ts @@ -249,7 +249,7 @@ export class Listener { filter((_) => _.message instanceof Transaction), map((_) => _.message as Transaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } @@ -302,7 +302,7 @@ export class Listener { filter((_) => _.message instanceof AggregateTransaction), map((_) => _.message as AggregateTransaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } From 73927641502372e6bdfc629122fd4caff68c1099 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 35/50] Moved listener to method --- ...TransactionService_AggregateBonded.spec.ts | 212 ++++++++++++++++++ src/service/TransactionService.ts | 22 +- src/service/interfaces/ITransactionService.ts | 8 +- 3 files changed, 230 insertions(+), 12 deletions(-) create mode 100644 e2e/service/TransactionService_AggregateBonded.spec.ts diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts new file mode 100644 index 0000000000..53e6c0532d --- /dev/null +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -0,0 +1,212 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { Listener } from '../../src/infrastructure/Listener'; +import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; +import { Account } from '../../src/model/account/Account'; +import { Address } from '../../src/model/account/Address'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; +import { Deadline } from '../../src/model/transaction/Deadline'; +import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction'; +import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { TransactionService } from '../../src/service/TransactionService'; + +describe('TransactionService', () => { + let account: Account; + let account2: Account; + let multisigAccount: Account; + let cosignAccount1: Account; + let cosignAccount2: Account; + let cosignAccount3: Account; + let url: string; + let generationHash: string; + let transactionHttp: TransactionHttp; + let config; + + before((done) => { + const path = require('path'); + require('fs').readFile(path.resolve(__dirname, '../conf/network.conf'), (err, data) => { + if (err) { + throw err; + } + const json = JSON.parse(data); + config = json; + account = Account.createFromPrivateKey(json.testAccount.privateKey, NetworkType.MIJIN_TEST); + account2 = Account.createFromPrivateKey(json.testAccount2.privateKey, NetworkType.MIJIN_TEST); + multisigAccount = Account.createFromPrivateKey(json.multisigAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount1 = Account.createFromPrivateKey(json.cosignatoryAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount2 = Account.createFromPrivateKey(json.cosignatory2Account.privateKey, NetworkType.MIJIN_TEST); + cosignAccount3 = Account.createFromPrivateKey(json.cosignatory3Account.privateKey, NetworkType.MIJIN_TEST); + url = json.apiUrl; + generationHash = json.generationHash; + transactionHttp = new TransactionHttp(json.apiUrl); + done(); + }); + }); + + /** + * ========================= + * Setup test data + * ========================= + */ + describe('Setup test multisig account', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const modifyMultisigAccountTransaction = MultisigAccountModificationTransaction.create( + Deadline.create(), + 2, + 1, + [ + cosignAccount1.publicAccount, + cosignAccount2.publicAccount, + cosignAccount3.publicAccount, + ], + [], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [modifyMultisigAccountTransaction.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(multisigAccount, [cosignAccount1, cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(multisigAccount.address).subscribe(() => { + done(); + }); + listener.status(multisigAccount.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + /** + * ========================= + * Test + * ========================= + */ + + describe('should announce transaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const transactionService = new TransactionService(url); + const transferTransaction = TransferTransaction.create( + Deadline.create(), + account2.address, + [ + NetworkCurrencyMosaic.createAbsolute(1), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = transferTransaction.signWith(account, generationHash); + transactionService.announce(signedTransaction, listener).subscribe((tx: TransferTransaction) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect((tx.recipientAddress as Address).equals(account2.address)).to.be.true; + expect(tx.message.payload).to.be.equal('test-message'); + done(); + }); + }); + }); + + /** + * ========================= + * House Keeping + * ========================= + */ + + describe('Restore test multisig Accounts', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const removeCosigner1 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + 0, + [], + [ cosignAccount1.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + const removeCosigner2 = MultisigAccountModificationTransaction.create( + Deadline.create(), + 0, + 0, + [], + [ + cosignAccount2.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const removeCosigner3 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + -1, + [], + [ + cosignAccount3.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [removeCosigner1.toAggregate(multisigAccount.publicAccount), + removeCosigner2.toAggregate(multisigAccount.publicAccount), + removeCosigner3.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(cosignAccount1, [cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(cosignAccount1.address).subscribe(() => { + done(); + }); + listener.status(cosignAccount1.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); +}); diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 5dca792362..bff9c2100a 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,7 +42,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -50,11 +49,12 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** + * Resolve unresolved mosaic / address from array of transactions * @param transationHashes List of transaction hashes. + * @param listener Websocket listener * @returns Observable */ public resolveAliases(transationHashes: string[]): Observable { @@ -150,22 +150,24 @@ export class TransactionService implements ITransactionService { /** * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener * @returns {Observable} */ - public announce(signedTransaction: SignedTransaction): Observable { + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ - public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } @@ -173,12 +175,14 @@ export class TransactionService implements ITransactionService { * Announce aggregate bonded transaction with lock fund * @param signedHashLockTransaction Signed hash lock transaction. * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable { - return this.announce(signedHashLockTransaction).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), ); } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 37a0984911..3aa299ebd4 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,7 @@ */ import {Observable} from 'rxjs'; +import { Listener } from '../../infrastructure/Listener'; import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; @@ -34,14 +35,14 @@ export interface ITransactionService { * @param signedTransaction Signed transaction to be announced. * @returns {Observable} */ - announce(signedTransaction: SignedTransaction): Observable; + announce(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. * @returns {Observable} */ - announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate bonded transaction with lock fund @@ -50,5 +51,6 @@ export interface ITransactionService { * @returns {Observable} */ announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable; + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable; } From 1e3ebe1bf9dffb5853d692d3aa50547ab1f5a049 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 36/50] Added #352 aggregate bonded announcing --- src/service/TransactionService.ts | 2 ++ src/service/interfaces/ITransactionService.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index bff9c2100a..21c7612072 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,6 +42,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -49,6 +50,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 3aa299ebd4..43bd0ae7fa 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -33,6 +33,7 @@ export interface ITransactionService { /** * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener * @returns {Observable} */ announce(signedTransaction: SignedTransaction, listener: Listener): Observable; @@ -40,6 +41,7 @@ export interface ITransactionService { /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable; @@ -48,6 +50,7 @@ export interface ITransactionService { * Announce aggregate bonded transaction with lock fund * @param signedHashLockTransaction Signed hash lock transaction. * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, From fc2dc923c65f4737b3b2c57b63756d0893ab45b2 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 37/50] Moved listener to method --- src/service/TransactionService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 21c7612072..bff9c2100a 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,7 +42,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -50,7 +49,6 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** From 98d0e7932b1b7917c8c06e9efd770058b83959d9 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 5 Dec 2019 12:28:54 +0000 Subject: [PATCH 38/50] Added more e2e tests --- ...TransactionService_AggregateBonded.spec.ts | 84 ++++++++++++++++++- src/service/TransactionService.ts | 79 ++++++++--------- 2 files changed, 122 insertions(+), 41 deletions(-) diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts index 53e6c0532d..780ccb8d49 100644 --- a/e2e/service/TransactionService_AggregateBonded.spec.ts +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -16,17 +16,25 @@ import { expect } from 'chai'; import { Listener } from '../../src/infrastructure/Listener'; +import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; import { Account } from '../../src/model/account/Account'; import { Address } from '../../src/model/account/Address'; import { NetworkType } from '../../src/model/blockchain/NetworkType'; import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { Mosaic } from '../../src/model/mosaic/Mosaic'; +import { MosaicId } from '../../src/model/mosaic/MosaicId'; import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { NamespaceId } from '../../src/model/namespace/NamespaceId'; import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; import { Deadline } from '../../src/model/transaction/Deadline'; +import { LockFundsTransaction } from '../../src/model/transaction/LockFundsTransaction'; import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction'; +import { TransactionType } from '../../src/model/transaction/TransactionType'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { UInt64 } from '../../src/model/UInt64'; import { TransactionService } from '../../src/service/TransactionService'; +import { TransactionUtils } from '../infrastructure/TransactionUtils'; describe('TransactionService', () => { let account: Account; @@ -35,9 +43,12 @@ describe('TransactionService', () => { let cosignAccount1: Account; let cosignAccount2: Account; let cosignAccount3: Account; + let networkCurrencyMosaicId: MosaicId; let url: string; let generationHash: string; let transactionHttp: TransactionHttp; + let transactionService: TransactionService; + let namespaceHttp: NamespaceHttp; let config; before((done) => { @@ -56,7 +67,9 @@ describe('TransactionService', () => { cosignAccount3 = Account.createFromPrivateKey(json.cosignatory3Account.privateKey, NetworkType.MIJIN_TEST); url = json.apiUrl; generationHash = json.generationHash; - transactionHttp = new TransactionHttp(json.apiUrl); + transactionHttp = new TransactionHttp(url); + namespaceHttp = new NamespaceHttp(url); + transactionService = new TransactionService(url); done(); }); }); @@ -66,6 +79,15 @@ describe('TransactionService', () => { * Setup test data * ========================= */ + describe('Get network currency mosaic id', () => { + it('get mosaicId', (done) => { + namespaceHttp.getLinkedMosaicId(new NamespaceId('cat.currency')).subscribe((networkMosaicId) => { + networkCurrencyMosaicId = networkMosaicId; + done(); + }); + }); + }); + describe('Setup test multisig account', () => { let listener: Listener; before (() => { @@ -123,7 +145,6 @@ describe('TransactionService', () => { return listener.close(); }); it('announce', (done) => { - const transactionService = new TransactionService(url); const transferTransaction = TransferTransaction.create( Deadline.create(), account2.address, @@ -143,6 +164,65 @@ describe('TransactionService', () => { }); }); + describe('should announce aggregate bonded with hashlock', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const signedAggregatedTransaction = + TransactionUtils.createSignedAggregatedBondTransaction(multisigAccount, account, account2.address, generationHash); + const lockFundsTransaction = LockFundsTransaction.create( + Deadline.create(), + new Mosaic(networkCurrencyMosaicId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyMosaic.DIVISIBILITY))), + UInt64.fromUint(1000), + signedAggregatedTransaction, + NetworkType.MIJIN_TEST, + ); + const signedLockFundsTransaction = lockFundsTransaction.signWith(account, generationHash); + transactionService + .announceHashLockAggregateBonded(signedLockFundsTransaction, signedAggregatedTransaction, listener).subscribe((tx) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect(tx.type).to.be.equal(TransactionType.AGGREGATE_BONDED); + done(); + }); + }); + }); + + describe('should announce aggregate bonded transaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const signedAggregatedTransaction = + TransactionUtils.createSignedAggregatedBondTransaction(multisigAccount, account, account2.address, generationHash); + const lockFundsTransaction = LockFundsTransaction.create( + Deadline.create(), + new Mosaic(networkCurrencyMosaicId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyMosaic.DIVISIBILITY))), + UInt64.fromUint(1000), + signedAggregatedTransaction, + NetworkType.MIJIN_TEST, + ); + const signedLockFundsTransaction = lockFundsTransaction.signWith(account, generationHash); + transactionService.announce(signedLockFundsTransaction, listener).subscribe(() => { + transactionService.announceAggregateBonded(signedAggregatedTransaction, listener).subscribe((tx) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect(tx.type).to.be.equal(TransactionType.AGGREGATE_BONDED); + done(); + }); + }); + }); + }); + /** * ========================= * House Keeping diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index bff9c2100a..d0f54ba621 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -65,6 +65,46 @@ export class TransactionService implements ITransactionService { ); } + /** + * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * **NOTE** A lock fund transaction for this aggregate bonded should exists + * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), + ); + + } + /** * Resolve transaction alias(s) * @param transaction Transaction to be resolved @@ -147,43 +187,4 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } - - /** - * @param signedTransaction Signed transaction to be announced. - * @param listener Websocket listener - * @returns {Observable} - */ - public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate transaction - * @param signedTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate bonded transaction with lock fund - * @param signedHashLockTransaction Signed hash lock transaction. - * @param signedAggregateTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction, - listener: Listener): Observable { - return this.announce(signedHashLockTransaction, listener).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), - ); - - } } From 5c8c1833ee592d06de726554df0237e3ce4ac661 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 6 Dec 2019 11:26:55 +0000 Subject: [PATCH 39/50] Fixed typos in comments --- src/model/receipt/ResolutionStatement.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/model/receipt/ResolutionStatement.ts b/src/model/receipt/ResolutionStatement.ts index bf30c07145..141e4ebadf 100644 --- a/src/model/receipt/ResolutionStatement.ts +++ b/src/model/receipt/ResolutionStatement.ts @@ -106,7 +106,7 @@ export class ResolutionStatement { If no primaryId found, it means there's no resolution entry available for the process. Invalid entry. e.g. Given: - Entries: [{P:2, S:0}, {P5:, S:6}] + Entries: [{P:2, S:0}, {P:5, S:6}] Transaction: [Inx:1(0+1), AggInx:0] It should return Entry: undefined */ @@ -118,12 +118,12 @@ export class ResolutionStatement { Use the most recent resolution entry (Max.PrimaryId + Max.SecondaryId) e.g. Given: - Entries: [{P:1, S:0}, {P:2, S:0}, {P:4, S:2}, {P:4, S:4} {P7:, S:6}] - Transaction: [Inx:5(0+1), AggInx:0] - It should return Entry: {P:3, S:4} + Entries: [{P:1, S:0}, {P:2, S:0}, {P:4, S:2}, {P:4, S:4} {P:7, S:6}] + Transaction: [Inx:5(4+1), AggInx:0] + It should return Entry: {P:4, S:4} e.g. Given: - Entries: [{P:1, S:0}, {P:2, S:0}, {P:4, S:2}, {P:4, S:4}, {P7:, S:6}] + Entries: [{P:1, S:0}, {P:2, S:0}, {P:4, S:2}, {P:4, S:4}, {P:7, S:6}] Transaction: [Inx:3(2+1), AggInx:0] It should return Entry: {P:2, S:0} */ @@ -132,16 +132,16 @@ export class ResolutionStatement { entry.source.secondaryId === this.getMaxSecondaryIdByPrimaryId(resolvedPrimaryId)); } - // When transaction index matches a primary id, get the most recent secondaryId (resolvedPrimaryId can only <= primaryId) + // When transaction index matches a primaryId, get the most recent secondaryId (resolvedPrimaryId can only <= primaryId) const resolvedSecondaryId = this.getMaxSecondaryIdByPrimaryIdAndSecondaryId(resolvedPrimaryId, secondaryId); /* If no most recent secondaryId matched transaction index, find previous resolution entry (most recent). - This means the resolution entry for the specific innter transaction (inside Aggregate) / - was generated previously outside the aggregate. It should return the previous entry (privious primarId) + This means the resolution entry for the specific inner transaction (inside Aggregate) / + was generated previously outside the aggregate. It should return the previous entry (previous primaryId) e.g. Given: - Entries: [{P:1, S:0}, {P:2, S:0}, {P5:, S:6}] + Entries: [{P:1, S:0}, {P:2, S:0}, {P:5, S:6}] Transaction: [Inx:5(4+1), AggInx:3(2+1)] It should return Entry: {P:2, S:0} */ @@ -155,7 +155,7 @@ export class ResolutionStatement { Found a matched resolution entry on both primaryId and secondaryId e.g. Given: - Entries: [{P:1, S:0}, {P:2, S:0}, {P5:, S:6}] + Entries: [{P:1, S:0}, {P:2, S:0}, {P:5, S:6}] Transaction: [Inx:5(4+1), AggInx:6(2+1)] It should return Entry: {P:5, S:6} */ From 8996a72e2c3b129b6fc3c342eabbefd48ad8f3b4 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 40/50] Added #352 aggregate bonded announcing --- src/infrastructure/Listener.ts | 8 ++-- src/model/transaction/SignedTransaction.ts | 10 +++++ src/service/TransactionService.ts | 37 +++++++++++++++++++ src/service/interfaces/ITransactionService.ts | 26 ++++++++++++- 4 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/infrastructure/Listener.ts b/src/infrastructure/Listener.ts index 1b4db4b1f2..f1778b29ed 100644 --- a/src/infrastructure/Listener.ts +++ b/src/infrastructure/Listener.ts @@ -239,7 +239,7 @@ export class Listener { * it emits a new Transaction in the event stream. * * @param address address we listen when a transaction is in confirmed state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of Transaction with state confirmed */ public confirmed(address: Address, transactionHash?: string): Observable { @@ -249,7 +249,7 @@ export class Listener { filter((_) => _.message instanceof Transaction), map((_) => _.message as Transaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } @@ -292,7 +292,7 @@ export class Listener { * it emits a new {@link AggregateTransaction} in the event stream. * * @param address address we listen when a transaction with missing signatures state - * @param transactionHash transaction hash for the filter + * @param transactionHash transactionHash for filtering multiple transactions * @return an observable stream of AggregateTransaction with missing signatures state */ public aggregateBondedAdded(address: Address, transactionHash?: string): Observable { @@ -302,7 +302,7 @@ export class Listener { filter((_) => _.message instanceof AggregateTransaction), map((_) => _.message as AggregateTransaction), filter((_) => this.transactionFromAddress(_, address)), - filter((_) => _.transactionInfo!.hash === transactionHash || transactionHash === undefined), + filter((_) => transactionHash === undefined || _.transactionInfo!.hash === transactionHash), ); } diff --git a/src/model/transaction/SignedTransaction.ts b/src/model/transaction/SignedTransaction.ts index addc04c6a1..bc776b4eb6 100644 --- a/src/model/transaction/SignedTransaction.ts +++ b/src/model/transaction/SignedTransaction.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { Address } from '../account/Address'; +import { PublicAccount } from '../account/PublicAccount'; import {NetworkType} from '../blockchain/NetworkType'; /** @@ -65,4 +67,12 @@ export class SignedTransaction { networkType: this.networkType, }; } + + /** + * Return signer's address + * @returns {Address} + */ + getSignerAddress(): Address { + return PublicAccount.createFromPublicKey(this.signerPublicKey, this.networkType).address; + } } diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index a855138d49..831fb48359 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -40,6 +40,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -47,6 +48,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** @@ -143,4 +145,39 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable { + return this.announce(signedHashLockTransaction).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + ); + + } } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 6bbeb16160..37a0984911 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,8 @@ */ import {Observable} from 'rxjs'; +import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; +import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; /** @@ -24,7 +26,29 @@ export interface ITransactionService { /** * @param transationHashes List of transaction hashes. - * @returns Observable + * @returns {Observable} */ resolveAliases(transationHashes: string[]): Observable; + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + announce(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable; } From 81ff79228ea5416438ee6f3832f5b9d08fda9faf Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 41/50] Moved listener to method --- ...TransactionService_AggregateBonded.spec.ts | 212 ++++++++++++++++++ src/service/TransactionService.ts | 26 ++- src/service/interfaces/ITransactionService.ts | 8 +- 3 files changed, 233 insertions(+), 13 deletions(-) create mode 100644 e2e/service/TransactionService_AggregateBonded.spec.ts diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts new file mode 100644 index 0000000000..53e6c0532d --- /dev/null +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -0,0 +1,212 @@ +/* + * Copyright 2019 NEM + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from 'chai'; +import { Listener } from '../../src/infrastructure/Listener'; +import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; +import { Account } from '../../src/model/account/Account'; +import { Address } from '../../src/model/account/Address'; +import { NetworkType } from '../../src/model/blockchain/NetworkType'; +import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; +import { Deadline } from '../../src/model/transaction/Deadline'; +import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction'; +import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { TransactionService } from '../../src/service/TransactionService'; + +describe('TransactionService', () => { + let account: Account; + let account2: Account; + let multisigAccount: Account; + let cosignAccount1: Account; + let cosignAccount2: Account; + let cosignAccount3: Account; + let url: string; + let generationHash: string; + let transactionHttp: TransactionHttp; + let config; + + before((done) => { + const path = require('path'); + require('fs').readFile(path.resolve(__dirname, '../conf/network.conf'), (err, data) => { + if (err) { + throw err; + } + const json = JSON.parse(data); + config = json; + account = Account.createFromPrivateKey(json.testAccount.privateKey, NetworkType.MIJIN_TEST); + account2 = Account.createFromPrivateKey(json.testAccount2.privateKey, NetworkType.MIJIN_TEST); + multisigAccount = Account.createFromPrivateKey(json.multisigAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount1 = Account.createFromPrivateKey(json.cosignatoryAccount.privateKey, NetworkType.MIJIN_TEST); + cosignAccount2 = Account.createFromPrivateKey(json.cosignatory2Account.privateKey, NetworkType.MIJIN_TEST); + cosignAccount3 = Account.createFromPrivateKey(json.cosignatory3Account.privateKey, NetworkType.MIJIN_TEST); + url = json.apiUrl; + generationHash = json.generationHash; + transactionHttp = new TransactionHttp(json.apiUrl); + done(); + }); + }); + + /** + * ========================= + * Setup test data + * ========================= + */ + describe('Setup test multisig account', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const modifyMultisigAccountTransaction = MultisigAccountModificationTransaction.create( + Deadline.create(), + 2, + 1, + [ + cosignAccount1.publicAccount, + cosignAccount2.publicAccount, + cosignAccount3.publicAccount, + ], + [], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [modifyMultisigAccountTransaction.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(multisigAccount, [cosignAccount1, cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(multisigAccount.address).subscribe(() => { + done(); + }); + listener.status(multisigAccount.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); + + /** + * ========================= + * Test + * ========================= + */ + + describe('should announce transaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const transactionService = new TransactionService(url); + const transferTransaction = TransferTransaction.create( + Deadline.create(), + account2.address, + [ + NetworkCurrencyMosaic.createAbsolute(1), + ], + PlainMessage.create('test-message'), + NetworkType.MIJIN_TEST, + ); + const signedTransaction = transferTransaction.signWith(account, generationHash); + transactionService.announce(signedTransaction, listener).subscribe((tx: TransferTransaction) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect((tx.recipientAddress as Address).equals(account2.address)).to.be.true; + expect(tx.message.payload).to.be.equal('test-message'); + done(); + }); + }); + }); + + /** + * ========================= + * House Keeping + * ========================= + */ + + describe('Restore test multisig Accounts', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('Announce MultisigAccountModificationTransaction', (done) => { + const removeCosigner1 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + 0, + [], + [ cosignAccount1.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + const removeCosigner2 = MultisigAccountModificationTransaction.create( + Deadline.create(), + 0, + 0, + [], + [ + cosignAccount2.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const removeCosigner3 = MultisigAccountModificationTransaction.create( + Deadline.create(), + -1, + -1, + [], + [ + cosignAccount3.publicAccount, + ], + NetworkType.MIJIN_TEST, + ); + + const aggregateTransaction = AggregateTransaction.createComplete(Deadline.create(), + [removeCosigner1.toAggregate(multisigAccount.publicAccount), + removeCosigner2.toAggregate(multisigAccount.publicAccount), + removeCosigner3.toAggregate(multisigAccount.publicAccount)], + NetworkType.MIJIN_TEST, + []); + const signedTransaction = aggregateTransaction + .signTransactionWithCosignatories(cosignAccount1, [cosignAccount2, cosignAccount3], generationHash); + + listener.confirmed(cosignAccount1.address).subscribe(() => { + done(); + }); + listener.status(cosignAccount1.address).subscribe((error) => { + console.log('Error:', error); + done(); + }); + transactionHttp.announce(signedTransaction); + }); + }); +}); diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 831fb48359..bff9c2100a 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -15,7 +15,8 @@ */ import {Observable, of} from 'rxjs'; -import { map, mergeMap, toArray} from 'rxjs/operators'; +import { flatMap, map, mergeMap, toArray} from 'rxjs/operators'; +import { Listener } from '../infrastructure/Listener'; import { ReceiptHttp } from '../infrastructure/ReceiptHttp'; import { TransactionHttp } from '../infrastructure/TransactionHttp'; import { NamespaceId } from '../model/namespace/NamespaceId'; @@ -28,6 +29,7 @@ import { MosaicMetadataTransaction } from '../model/transaction/MosaicMetadataTr import { MosaicSupplyChangeTransaction } from '../model/transaction/MosaicSupplyChangeTransaction'; import { SecretLockTransaction } from '../model/transaction/SecretLockTransaction'; import { SecretProofTransaction } from '../model/transaction/SecretProofTransaction'; +import { SignedTransaction } from '../model/transaction/SignedTransaction'; import { Transaction } from '../model/transaction/Transaction'; import { TransactionType } from '../model/transaction/TransactionType'; import { TransferTransaction } from '../model/transaction/TransferTransaction'; @@ -40,7 +42,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -48,11 +49,12 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** + * Resolve unresolved mosaic / address from array of transactions * @param transationHashes List of transaction hashes. + * @param listener Websocket listener * @returns Observable */ public resolveAliases(transationHashes: string[]): Observable { @@ -148,22 +150,24 @@ export class TransactionService implements ITransactionService { /** * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener * @returns {Observable} */ - public announce(signedTransaction: SignedTransaction): Observable { + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ - public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } @@ -171,12 +175,14 @@ export class TransactionService implements ITransactionService { * Announce aggregate bonded transaction with lock fund * @param signedHashLockTransaction Signed hash lock transaction. * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable { - return this.announce(signedHashLockTransaction).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), ); } diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 37a0984911..3aa299ebd4 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -15,6 +15,7 @@ */ import {Observable} from 'rxjs'; +import { Listener } from '../../infrastructure/Listener'; import { AggregateTransaction } from '../../model/transaction/AggregateTransaction'; import { SignedTransaction } from '../../model/transaction/SignedTransaction'; import { Transaction } from '../../model/transaction/Transaction'; @@ -34,14 +35,14 @@ export interface ITransactionService { * @param signedTransaction Signed transaction to be announced. * @returns {Observable} */ - announce(signedTransaction: SignedTransaction): Observable; + announce(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. * @returns {Observable} */ - announceAggregateBonded(signedTransaction: SignedTransaction): Observable; + announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable; /** * Announce aggregate bonded transaction with lock fund @@ -50,5 +51,6 @@ export interface ITransactionService { * @returns {Observable} */ announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable; + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable; } From c547dd2d0516b83779c08e909f60711938222eb0 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 42/50] Added #352 aggregate bonded announcing --- src/service/TransactionService.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index bff9c2100a..21c7612072 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,6 +42,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -49,6 +50,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** From 5bc520d5bfdfae38a6392fc47446ed072d2ce2be Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 43/50] Moved listener to method --- src/service/TransactionService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 21c7612072..bff9c2100a 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,7 +42,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -50,7 +49,6 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** From 1be9cec8bd47db7134c228e21efd0a12a22d4343 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 5 Dec 2019 12:28:54 +0000 Subject: [PATCH 44/50] Added more e2e tests --- ...TransactionService_AggregateBonded.spec.ts | 84 ++++++++++++++++++- src/service/TransactionService.ts | 79 ++++++++--------- 2 files changed, 122 insertions(+), 41 deletions(-) diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts index 53e6c0532d..780ccb8d49 100644 --- a/e2e/service/TransactionService_AggregateBonded.spec.ts +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -16,17 +16,25 @@ import { expect } from 'chai'; import { Listener } from '../../src/infrastructure/Listener'; +import { NamespaceHttp } from '../../src/infrastructure/NamespaceHttp'; import { TransactionHttp } from '../../src/infrastructure/TransactionHttp'; import { Account } from '../../src/model/account/Account'; import { Address } from '../../src/model/account/Address'; import { NetworkType } from '../../src/model/blockchain/NetworkType'; import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { Mosaic } from '../../src/model/mosaic/Mosaic'; +import { MosaicId } from '../../src/model/mosaic/MosaicId'; import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic'; +import { NamespaceId } from '../../src/model/namespace/NamespaceId'; import { AggregateTransaction } from '../../src/model/transaction/AggregateTransaction'; import { Deadline } from '../../src/model/transaction/Deadline'; +import { LockFundsTransaction } from '../../src/model/transaction/LockFundsTransaction'; import { MultisigAccountModificationTransaction } from '../../src/model/transaction/MultisigAccountModificationTransaction'; +import { TransactionType } from '../../src/model/transaction/TransactionType'; import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { UInt64 } from '../../src/model/UInt64'; import { TransactionService } from '../../src/service/TransactionService'; +import { TransactionUtils } from '../infrastructure/TransactionUtils'; describe('TransactionService', () => { let account: Account; @@ -35,9 +43,12 @@ describe('TransactionService', () => { let cosignAccount1: Account; let cosignAccount2: Account; let cosignAccount3: Account; + let networkCurrencyMosaicId: MosaicId; let url: string; let generationHash: string; let transactionHttp: TransactionHttp; + let transactionService: TransactionService; + let namespaceHttp: NamespaceHttp; let config; before((done) => { @@ -56,7 +67,9 @@ describe('TransactionService', () => { cosignAccount3 = Account.createFromPrivateKey(json.cosignatory3Account.privateKey, NetworkType.MIJIN_TEST); url = json.apiUrl; generationHash = json.generationHash; - transactionHttp = new TransactionHttp(json.apiUrl); + transactionHttp = new TransactionHttp(url); + namespaceHttp = new NamespaceHttp(url); + transactionService = new TransactionService(url); done(); }); }); @@ -66,6 +79,15 @@ describe('TransactionService', () => { * Setup test data * ========================= */ + describe('Get network currency mosaic id', () => { + it('get mosaicId', (done) => { + namespaceHttp.getLinkedMosaicId(new NamespaceId('cat.currency')).subscribe((networkMosaicId) => { + networkCurrencyMosaicId = networkMosaicId; + done(); + }); + }); + }); + describe('Setup test multisig account', () => { let listener: Listener; before (() => { @@ -123,7 +145,6 @@ describe('TransactionService', () => { return listener.close(); }); it('announce', (done) => { - const transactionService = new TransactionService(url); const transferTransaction = TransferTransaction.create( Deadline.create(), account2.address, @@ -143,6 +164,65 @@ describe('TransactionService', () => { }); }); + describe('should announce aggregate bonded with hashlock', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const signedAggregatedTransaction = + TransactionUtils.createSignedAggregatedBondTransaction(multisigAccount, account, account2.address, generationHash); + const lockFundsTransaction = LockFundsTransaction.create( + Deadline.create(), + new Mosaic(networkCurrencyMosaicId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyMosaic.DIVISIBILITY))), + UInt64.fromUint(1000), + signedAggregatedTransaction, + NetworkType.MIJIN_TEST, + ); + const signedLockFundsTransaction = lockFundsTransaction.signWith(account, generationHash); + transactionService + .announceHashLockAggregateBonded(signedLockFundsTransaction, signedAggregatedTransaction, listener).subscribe((tx) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect(tx.type).to.be.equal(TransactionType.AGGREGATE_BONDED); + done(); + }); + }); + }); + + describe('should announce aggregate bonded transaction', () => { + let listener: Listener; + before (() => { + listener = new Listener(config.apiUrl); + return listener.open(); + }); + after(() => { + return listener.close(); + }); + it('announce', (done) => { + const signedAggregatedTransaction = + TransactionUtils.createSignedAggregatedBondTransaction(multisigAccount, account, account2.address, generationHash); + const lockFundsTransaction = LockFundsTransaction.create( + Deadline.create(), + new Mosaic(networkCurrencyMosaicId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyMosaic.DIVISIBILITY))), + UInt64.fromUint(1000), + signedAggregatedTransaction, + NetworkType.MIJIN_TEST, + ); + const signedLockFundsTransaction = lockFundsTransaction.signWith(account, generationHash); + transactionService.announce(signedLockFundsTransaction, listener).subscribe(() => { + transactionService.announceAggregateBonded(signedAggregatedTransaction, listener).subscribe((tx) => { + expect(tx.signer!.publicKey).to.be.equal(account.publicKey); + expect(tx.type).to.be.equal(TransactionType.AGGREGATE_BONDED); + done(); + }); + }); + }); + }); + /** * ========================= * House Keeping diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index bff9c2100a..d0f54ba621 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -65,6 +65,46 @@ export class TransactionService implements ITransactionService { ); } + /** + * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * **NOTE** A lock fund transaction for this aggregate bonded should exists + * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), + ); + + } + /** * Resolve transaction alias(s) * @param transaction Transaction to be resolved @@ -147,43 +187,4 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } - - /** - * @param signedTransaction Signed transaction to be announced. - * @param listener Websocket listener - * @returns {Observable} - */ - public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate transaction - * @param signedTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate bonded transaction with lock fund - * @param signedHashLockTransaction Signed hash lock transaction. - * @param signedAggregateTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction, - listener: Listener): Observable { - return this.announce(signedHashLockTransaction, listener).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), - ); - - } } From 519b0de631750d01a36191a20919e300d8d0142d Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 45/50] Added #352 aggregate bonded announcing --- src/service/TransactionService.ts | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index d0f54ba621..9a078c29f6 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,6 +42,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -49,6 +50,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** @@ -187,4 +189,39 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } + + /** + * @param signedTransaction Signed transaction to be announced. + * @returns {Observable} + */ + public announce(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announce(signedTransaction).pipe( + flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate transaction + * @param signedTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( + flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + ); + } + + /** + * Announce aggregate bonded transaction with lock fund + * @param signedHashLockTransaction Signed hash lock transaction. + * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @returns {Observable} + */ + public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, + signedAggregateTransaction: SignedTransaction): Observable { + return this.announce(signedHashLockTransaction).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + ); + + } } From c2adec6f32293b20bce7f824107d98348768d10e Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 46/50] Moved listener to method --- src/service/TransactionService.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 9a078c29f6..e3f87dac90 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,7 +42,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -50,7 +49,6 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** @@ -192,22 +190,24 @@ export class TransactionService implements ITransactionService { /** * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener * @returns {Observable} */ - public announce(signedTransaction: SignedTransaction): Observable { + public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => this.listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ - public announceAggregateBonded(signedTransaction: SignedTransaction): Observable { + public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => this.listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), + flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), ); } @@ -215,12 +215,14 @@ export class TransactionService implements ITransactionService { * Announce aggregate bonded transaction with lock fund * @param signedHashLockTransaction Signed hash lock transaction. * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction): Observable { - return this.announce(signedHashLockTransaction).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction)), + signedAggregateTransaction: SignedTransaction, + listener: Listener): Observable { + return this.announce(signedHashLockTransaction, listener).pipe( + flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), ); } From 1fe8b953a40e0f9a42a0af00227bad55a4ea9c44 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Tue, 3 Dec 2019 15:43:50 +0000 Subject: [PATCH 47/50] Added #352 aggregate bonded announcing --- src/service/TransactionService.ts | 2 ++ src/service/interfaces/ITransactionService.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index e3f87dac90..17a71261f9 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,6 +42,7 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; + private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -49,6 +50,7 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); + this.listener = new Listener(url); } /** diff --git a/src/service/interfaces/ITransactionService.ts b/src/service/interfaces/ITransactionService.ts index 3aa299ebd4..43bd0ae7fa 100644 --- a/src/service/interfaces/ITransactionService.ts +++ b/src/service/interfaces/ITransactionService.ts @@ -33,6 +33,7 @@ export interface ITransactionService { /** * @param signedTransaction Signed transaction to be announced. + * @param listener Websocket listener * @returns {Observable} */ announce(signedTransaction: SignedTransaction, listener: Listener): Observable; @@ -40,6 +41,7 @@ export interface ITransactionService { /** * Announce aggregate transaction * @param signedTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable; @@ -48,6 +50,7 @@ export interface ITransactionService { * Announce aggregate bonded transaction with lock fund * @param signedHashLockTransaction Signed hash lock transaction. * @param signedAggregateTransaction Signed aggregate bonded transaction. + * @param listener Websocket listener * @returns {Observable} */ announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, From 5a515c5f1c9ece64886a63aa49aeae32fc104959 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Wed, 4 Dec 2019 16:02:54 +0000 Subject: [PATCH 48/50] Moved listener to method --- src/service/TransactionService.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index 17a71261f9..e3f87dac90 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -42,7 +42,6 @@ export class TransactionService implements ITransactionService { private readonly transactionHttp: TransactionHttp; private readonly receiptHttp: ReceiptHttp; - private readonly listener: Listener; /** * Constructor * @param url Base catapult-rest url @@ -50,7 +49,6 @@ export class TransactionService implements ITransactionService { constructor(url: string) { this.transactionHttp = new TransactionHttp(url); this.receiptHttp = new ReceiptHttp(url); - this.listener = new Listener(url); } /** From ddb8d2456a0f9083a72b7171062d972cbc07c2c1 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Thu, 5 Dec 2019 12:28:54 +0000 Subject: [PATCH 49/50] Added more e2e tests --- src/service/TransactionService.ts | 39 ------------------------------- 1 file changed, 39 deletions(-) diff --git a/src/service/TransactionService.ts b/src/service/TransactionService.ts index e3f87dac90..d0f54ba621 100644 --- a/src/service/TransactionService.ts +++ b/src/service/TransactionService.ts @@ -187,43 +187,4 @@ export class TransactionService implements ITransactionService { map((statement) => transaction.resolveAliases(statement, aggregateIndex)), ); } - - /** - * @param signedTransaction Signed transaction to be announced. - * @param listener Websocket listener - * @returns {Observable} - */ - public announce(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announce(signedTransaction).pipe( - flatMap(() => listener.confirmed(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate transaction - * @param signedTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceAggregateBonded(signedTransaction: SignedTransaction, listener: Listener): Observable { - return this.transactionHttp.announceAggregateBonded(signedTransaction).pipe( - flatMap(() => listener.aggregateBondedAdded(signedTransaction.getSignerAddress(), signedTransaction.hash)), - ); - } - - /** - * Announce aggregate bonded transaction with lock fund - * @param signedHashLockTransaction Signed hash lock transaction. - * @param signedAggregateTransaction Signed aggregate bonded transaction. - * @param listener Websocket listener - * @returns {Observable} - */ - public announceHashLockAggregateBonded(signedHashLockTransaction: SignedTransaction, - signedAggregateTransaction: SignedTransaction, - listener: Listener): Observable { - return this.announce(signedHashLockTransaction, listener).pipe( - flatMap(() => this.announceAggregateBonded(signedAggregateTransaction, listener)), - ); - - } } From 0d21737fbc2883dd433a695b42af8c410007b051 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 6 Dec 2019 13:41:51 +0000 Subject: [PATCH 50/50] Fixed typo --- test/model/receipt/Statement.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/model/receipt/Statement.spec.ts b/test/model/receipt/Statement.spec.ts index eb13175766..b0ef2c0e2e 100644 --- a/test/model/receipt/Statement.spec.ts +++ b/test/model/receipt/Statement.spec.ts @@ -107,7 +107,7 @@ describe('Statement', () => { }; }); - it('should get reolved address from receipt', () => { + it('should get resolved address from receipt', () => { const unresolvedAddress = UnresolvedMapping.toUnresolvedAddress('9156258DE356F030A500000000000000000000000000000000'); const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); const resolved = statement.resolveAddress(unresolvedAddress as NamespaceId, '1473', 0); @@ -116,7 +116,7 @@ describe('Statement', () => { expect((resolved as Address).equals(account.address)).to.be.true; }); - it('should get reolved address from receipt without Harvesting_Fee', () => { + it('should get resolved address from receipt without Harvesting_Fee', () => { const statementWithoutHarvesting = { transactionStatements: [], addressResolutionStatements: [ @@ -146,7 +146,7 @@ describe('Statement', () => { expect((resolved as Address).equals(account.address)).to.be.true; }); - it('should get reolved mosaic from receipt', () => { + it('should get resolved mosaic from receipt', () => { const unresolvedMosaic = UnresolvedMapping.toUnresolvedMosaic('E81F622A5B11A340'); const statement = CreateStatementFromDTO(statementDTO, NetworkType.MIJIN_TEST); const resolved = statement.resolveMosaicId(unresolvedMosaic as NamespaceId, '1473', 0); @@ -155,7 +155,7 @@ describe('Statement', () => { expect((resolved as MosaicId).equals(new MosaicId('756482FB80FD406C'))).to.be.true; }); - it('should get reolved mosaic from receipt without Harvesting_Fee', () => { + it('should get resolved mosaic from receipt without Harvesting_Fee', () => { const statementWithoutHarvesting = { transactionStatements: [], addressResolutionStatements: [],