From c17558a0c9c83dd36f8295214fee0124f3902aaf Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 9 Oct 2020 11:45:24 +0100 Subject: [PATCH 1/3] Fixed #620 - Added merkle hash calculation for block transactions --- package-lock.json | 35 +++++++++++++++++++++--- package.json | 2 +- src/service/BlockService.ts | 45 ++++++++++++++++++++++++++++++- test/service/BlockService.spec.ts | 40 +++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8db24d8665..b9a17826c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5198,9 +5198,9 @@ "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" }, "merkletreejs": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.1.11.tgz", - "integrity": "sha512-nJN3VIHeIAyB/PjO5Dj/Y0SEK7CGCCLD2IbV4el2kUIwlOtX3GOr5MwVO4EU+0AXvoDnJ0nmaLe5O86uIjWz/Q==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.2.9.tgz", + "integrity": "sha512-MgpwiIHrTu0YQAZ7GVTTqC+BzBVdD7JstN3cFRUUIijHOPII3iCWgSc9XgRP5vCIkQLCkRaTAbTMOXUebwOhFQ==", "requires": { "buffer-reverse": "^1.0.1", "crypto-js": "^3.1.9-1", @@ -6021,7 +6021,7 @@ }, "which-module": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, @@ -7669,6 +7669,33 @@ "ws": "^7.2.3" }, "dependencies": { + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "merkletreejs": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.1.11.tgz", + "integrity": "sha512-nJN3VIHeIAyB/PjO5Dj/Y0SEK7CGCCLD2IbV4el2kUIwlOtX3GOr5MwVO4EU+0AXvoDnJ0nmaLe5O86uIjWz/Q==", + "dev": true, + "requires": { + "buffer-reverse": "^1.0.1", + "crypto-js": "^3.1.9-1", + "is-buffer": "^2.0.3", + "merkle-lib": "^2.0.10", + "treeify": "^1.1.0" + }, + "dependencies": { + "crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + } + } + }, "utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", diff --git a/package.json b/package.json index d04fa3807f..318367c367 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "js-sha3": "^0.8.0", "js-sha512": "^0.8.0", "long": "^4.0.0", - "merkletreejs": "^0.1.11", + "merkletreejs": "^0.2.9", "minimist": "^1.2.5", "node-fetch": "^2.6.0", "ripemd160": "^2.0.2", diff --git a/src/service/BlockService.ts b/src/service/BlockService.ts index 86de459b59..1dfe9af066 100644 --- a/src/service/BlockService.ts +++ b/src/service/BlockService.ts @@ -16,19 +16,25 @@ import { sha3_256 } from 'js-sha3'; import { combineLatest, Observable, of } from 'rxjs'; -import { catchError, map } from 'rxjs/operators'; +import { catchError, map, toArray } from 'rxjs/operators'; import { BlockRepository } from '../infrastructure/BlockRepository'; import { RepositoryFactory } from '../infrastructure/RepositoryFactory'; import { MerklePathItem } from '../model/blockchain/MerklePathItem'; import { UInt64 } from '../model/UInt64'; import { IBlockService } from './interfaces/IBlockService'; import { MerklePosition } from '../model/blockchain/MerklePosition'; +import { TransactionPaginationStreamer } from '../infrastructure/paginationStreamer/TransactionPaginationStreamer'; +import { TransactionGroup } from '../infrastructure/TransactionGroup'; +import { Transaction } from '../model/transaction/Transaction'; +import MerkleTree from 'merkletreejs'; +import { TransactionRepository } from '../infrastructure/TransactionRepository'; /** * Block Service */ export class BlockService implements IBlockService { private readonly blockRepository: BlockRepository; + private readonly transactionRepository: TransactionRepository; /** * Constructor @@ -36,6 +42,7 @@ export class BlockService implements IBlockService { */ constructor(public readonly repositoryFactory: RepositoryFactory) { this.blockRepository = repositoryFactory.createBlockRepository(); + this.transactionRepository = repositoryFactory.createTransactionRepository(); } /** @@ -64,6 +71,19 @@ export class BlockService implements IBlockService { .pipe(catchError(() => of(false))); } + /** + * Calculate transactions merkle root hash from a block + * @param height block height + * @returns root hash + */ + public calculateTransactionsMerkleRootHash(height: UInt64): Observable { + const streamer = new TransactionPaginationStreamer(this.transactionRepository); + return streamer + .search({ group: TransactionGroup.Confirmed, height: height }) + .pipe(toArray()) + .pipe(map((transactions) => this.getTransacactionMerkleRoot(transactions).toUpperCase())); + } + /** * @internal * Validate leaf against merkle tree in block @@ -87,4 +107,27 @@ export class BlockService implements IBlockService { }, leaf); return rootToCompare.toUpperCase() === rootHash.toUpperCase(); } + + /** + * @internal + * Create merkle root hash for block transactions + * @param transactions Block transactions + * @returns calculated root hash + */ + private getTransacactionMerkleRoot(transactions: Transaction[]): string { + console.log(transactions); + const leaves = transactions + .sort((n1, n2) => n1.transactionInfo!.index - n2.transactionInfo!.index) + .map((transaction) => transaction.transactionInfo!.hash); + + const tree = new MerkleTree(leaves, sha3_256, { + duplicateOdd: true, + hashLeaves: false, + sort: false, + sortLeaves: false, + sortPairs: false, + isBitcoinTree: false, + }); + return tree.getRoot().toString('hex'); + } } diff --git a/test/service/BlockService.spec.ts b/test/service/BlockService.spec.ts index fc578773be..12d194fe83 100644 --- a/test/service/BlockService.spec.ts +++ b/test/service/BlockService.spec.ts @@ -29,6 +29,13 @@ import { UInt64 } from '../../src/model/UInt64'; import { BlockService } from '../../src/service/BlockService'; import { TestingAccount } from '../conf/conf.spec'; import { MerklePosition } from '../../src/model/blockchain/MerklePosition'; +import { TransactionRepository } from '../../src/infrastructure/TransactionRepository'; +import { Page } from '../../src/infrastructure/Page'; +import { Transaction } from '../../src/model/transaction/Transaction'; +import { TransferTransaction } from '../../src/model/transaction/TransferTransaction'; +import { Deadline, TransactionInfo } from '../../src/model/model'; +import { PlainMessage } from '../../src/model/message/PlainMessage'; +import { TransactionGroup } from '../../src/infrastructure/TransactionGroup'; describe('BlockService', () => { const mockBlockHash = 'D4EC16FCFE696EFDBF1820F68245C88135ACF4C6F888599C8E18BC09B9F08C7B'; @@ -111,10 +118,27 @@ describe('BlockService', () => { ); } + function mockTransactions(): Page { + const tx = new TransferTransaction( + NetworkType.TEST_NET, + 1, + Deadline.createEmtpy(), + UInt64.fromUint(0), + TestingAccount.address, + [], + PlainMessage.create(''), + undefined, + undefined, + new TransactionInfo(UInt64.fromUint(1), 0, 'id', 'DCD14A040BC5096348FC55CACBD0D459DD6F81779C7E7C526EA52309BD6595F7'), + ); + return new Page([tx], 1, 20); + } + before(() => { account = TestingAccount; const mockBlockRepository = mock(); const mockReceiptRepository = mock(); + const mockTransactionReposity = mock(); const mockRepoFactory = mock(); when(mockBlockRepository.getBlockByHeight(deepEqual(UInt64.fromUint(1)))).thenReturn(observableOf(mockBlockInfo())); @@ -128,11 +152,22 @@ describe('BlockService', () => { when(mockBlockRepository.getMerkleReceipts(deepEqual(UInt64.fromUint(1)), leaf)).thenReturn(observableOf(mockMerklePath())); when(mockBlockRepository.getMerkleReceipts(deepEqual(UInt64.fromUint(2)), leaf)).thenReturn(observableOf(mockMerklePath())); when(mockBlockRepository.getMerkleReceipts(deepEqual(UInt64.fromUint(3)), leaf)).thenReject(new Error()); + when( + mockTransactionReposity.search( + deepEqual({ + group: TransactionGroup.Confirmed, + height: UInt64.fromUint(1), + pageNumber: 1, + }), + ), + ).thenReturn(observableOf(mockTransactions())); const blockRepository = instance(mockBlockRepository); const receiptRepository = instance(mockReceiptRepository); + const transactionRepository = instance(mockTransactionReposity); when(mockRepoFactory.createBlockRepository()).thenReturn(blockRepository); when(mockRepoFactory.createReceiptRepository()).thenReturn(receiptRepository); + when(mockRepoFactory.createTransactionRepository()).thenReturn(transactionRepository); const repoFactory = instance(mockRepoFactory); blockService = new BlockService(repoFactory); }); @@ -171,4 +206,9 @@ describe('BlockService', () => { const result = await blockService.validateStatementInBlock(leaf, UInt64.fromUint(3)).toPromise(); expect(result).to.be.false; }); + + it('should calculate root transaction merkle hash', async () => { + const result = await blockService.calculateTransactionsMerkleRootHash(UInt64.fromUint(1)).toPromise(); + expect(result).to.be.equal('DCD14A040BC5096348FC55CACBD0D459DD6F81779C7E7C526EA52309BD6595F7'); + }); }); From e0959713a1ef8d371c814467c9666affab43ebb9 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 9 Oct 2020 20:04:05 +0100 Subject: [PATCH 2/3] Added e2e test - fixed some bugs --- .../PersistentHarvesting.spec.ts | 11 +++--- e2e/infrastructure/SecretLockHttp.spec.ts | 4 +-- e2e/service/AccountService.spec.ts | 4 +-- e2e/service/BlockService.spec.ts | 16 +++++++-- e2e/service/TransactionService.spec.ts | 36 +++++++++---------- ...TransactionService_AggregateBonded.spec.ts | 25 +++++++------ src/service/BlockService.ts | 1 - 7 files changed, 48 insertions(+), 49 deletions(-) diff --git a/e2e/infrastructure/PersistentHarvesting.spec.ts b/e2e/infrastructure/PersistentHarvesting.spec.ts index 637cc25333..fc02e9abec 100644 --- a/e2e/infrastructure/PersistentHarvesting.spec.ts +++ b/e2e/infrastructure/PersistentHarvesting.spec.ts @@ -23,7 +23,6 @@ import { AccountKeyLinkTransaction } from '../../src/model/transaction/AccountKe import { PersistentDelegationRequestTransaction } from '../../src/model/transaction/PersistentDelegationRequestTransaction'; import { VrfKeyLinkTransaction } from '../../src/model/transaction/VrfKeyLinkTransaction'; import { NodeKeyLinkTransaction } from '../../src/model/transaction/NodeKeyLinkTransaction'; -import { Duration } from 'js-joda'; describe('PersistentHarvesting', () => { const helper = new IntegrationTestHelper(); @@ -32,8 +31,6 @@ describe('PersistentHarvesting', () => { let networkType: NetworkType; let remoteAccount: Account; - const epochAdjustment = Duration.ofSeconds(1573430400); - const vrfKeyPair = Account.createFromPrivateKey( '82798EA9A2D2D202AFCCC82C40A287780BCA3C7F7A2FD5B754832804C6BE1BAA', NetworkType.MIJIN_TEST, @@ -62,7 +59,7 @@ describe('PersistentHarvesting', () => { describe('AccountKeyLinkTransaction', () => { it('standalone', () => { const accountLinkTransaction = AccountKeyLinkTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), remoteAccount.publicKey, LinkAction.Link, networkType, @@ -77,7 +74,7 @@ describe('PersistentHarvesting', () => { describe('VrfKeyLinkTransaction', () => { it('standalone', () => { const vrfKeyLinkTransaction = VrfKeyLinkTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), vrfKeyPair.publicKey, LinkAction.Link, networkType, @@ -92,7 +89,7 @@ describe('PersistentHarvesting', () => { describe('NodeKeyLinkTransaction', () => { it('standalone', () => { const nodeKeyLinkTransaction = NodeKeyLinkTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), 'cfd84eca83508bbee954668e4aecca736caefa615367da76afe6985d695381db', LinkAction.Link, networkType, @@ -112,7 +109,7 @@ describe('PersistentHarvesting', () => { describe('transactions', () => { it('should create delegated harvesting transaction', () => { const tx = PersistentDelegationRequestTransaction.createPersistentDelegationRequestTransaction( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), remoteAccount.privateKey, vrfKeyPair.privateKey, 'cfd84eca83508bbee954668e4aecca736caefa615367da76afe6985d695381db', diff --git a/e2e/infrastructure/SecretLockHttp.spec.ts b/e2e/infrastructure/SecretLockHttp.spec.ts index dd9c213577..2243df80d6 100644 --- a/e2e/infrastructure/SecretLockHttp.spec.ts +++ b/e2e/infrastructure/SecretLockHttp.spec.ts @@ -28,7 +28,6 @@ import { SecretLockTransaction } from '../../src/model/transaction/SecretLockTra import { LockHashAlgorithm } from '../../src/model/lock/LockHashAlgorithm'; import { sha3_256 } from 'js-sha3'; import { Crypto } from '../../src/core/crypto'; -import { Duration } from 'js-joda'; describe('SecretLockHttp', () => { const helper = new IntegrationTestHelper(); @@ -38,7 +37,6 @@ describe('SecretLockHttp', () => { let generationHash: string; let networkType: NetworkType; let secret: string; - const epochAdjustment = Duration.ofSeconds(1573430400); before(() => { return helper.start({ openListener: true }).then(() => { @@ -64,7 +62,7 @@ describe('SecretLockHttp', () => { describe('Create a hash lock', () => { it('Announce SecretLockTransaction', () => { const secretLockTransaction = SecretLockTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), helper.createNetworkCurrency(10, false), UInt64.fromUint(100), LockHashAlgorithm.Op_Sha3_256, diff --git a/e2e/service/AccountService.spec.ts b/e2e/service/AccountService.spec.ts index c5db172306..de832a187a 100644 --- a/e2e/service/AccountService.spec.ts +++ b/e2e/service/AccountService.spec.ts @@ -23,7 +23,6 @@ import { IntegrationTestHelper } from '../infrastructure/IntegrationTestHelper'; import { AccountService } from '../../src/service/AccountService'; import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction'; import { NamespaceId } from '../../src/model/namespace/NamespaceId'; -import { Duration } from 'js-joda'; describe('AccountService', () => { const helper = new IntegrationTestHelper(); @@ -33,7 +32,6 @@ describe('AccountService', () => { let accountService: AccountService; let namespaceId: NamespaceId; const name = 'root-test-namespace-' + Math.floor(Math.random() * 10000); - const epochAdjustment = Duration.ofSeconds(1573430400); before(() => { return helper.start({ openListener: true }).then(() => { @@ -56,7 +54,7 @@ describe('AccountService', () => { describe('Create a namespace', () => { it('Announce NamespaceRegistrationTransaction', () => { const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), name, UInt64.fromUint(300000), networkType, diff --git a/e2e/service/BlockService.spec.ts b/e2e/service/BlockService.spec.ts index f826c4760c..a43cac9481 100644 --- a/e2e/service/BlockService.spec.ts +++ b/e2e/service/BlockService.spec.ts @@ -28,7 +28,7 @@ import { BlockService } from '../../src/service/BlockService'; import { IntegrationTestHelper } from '../infrastructure/IntegrationTestHelper'; import { TransactionGroup } from '../../src/infrastructure/TransactionGroup'; import { TransactionStatement } from '../../src/model/receipt/TransactionStatement'; -import { Duration } from 'js-joda'; +import { BlockRepository } from '../../src/infrastructure/BlockRepository'; describe('BlockService', () => { const helper = new IntegrationTestHelper(); @@ -40,7 +40,7 @@ describe('BlockService', () => { let blockService: BlockService; let transactionRepository: TransactionRepository; let receiptRepository: ReceiptRepository; - const epochAdjustment = Duration.ofSeconds(1573430400); + let blockRepository: BlockRepository; before(() => { return helper.start({ openListener: true }).then(() => { @@ -50,6 +50,7 @@ describe('BlockService', () => { networkType = helper.networkType; transactionRepository = helper.repositoryFactory.createTransactionRepository(); receiptRepository = helper.repositoryFactory.createReceiptRepository(); + blockRepository = helper.repositoryFactory.createBlockRepository(); blockService = new BlockService(helper.repositoryFactory); }); }); @@ -66,7 +67,7 @@ describe('BlockService', () => { describe('Create a transfer', () => { it('Announce TransferTransaction', () => { const transferTransaction = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), account2.address, [NetworkCurrencyLocal.createAbsolute(1)], PlainMessage.create('test-message'), @@ -107,4 +108,13 @@ describe('BlockService', () => { expect(validationResult).to.be.true; }); }); + + describe('Calculate merkler transaction root hash', () => { + it('Calculate merkler transaction root hash', async () => { + const calculated = await blockService.calculateTransactionsMerkleRootHash(UInt64.fromUint(1)).toPromise(); + const block = await blockRepository.getBlockByHeight(UInt64.fromUint(1)).toPromise(); + const rootHash = block.blockTransactionsHash; + expect(rootHash).to.be.equal(calculated); + }); + }); }); diff --git a/e2e/service/TransactionService.spec.ts b/e2e/service/TransactionService.spec.ts index cd57d7f80a..2c02a1a1bf 100644 --- a/e2e/service/TransactionService.spec.ts +++ b/e2e/service/TransactionService.spec.ts @@ -15,7 +15,6 @@ */ import { assert, expect } from 'chai'; -import { Duration } from 'js-joda'; import { Convert } from '../../src/core/format/Convert'; import { TransactionRepository } from '../../src/infrastructure/TransactionRepository'; import { Account } from '../../src/model/account/Account'; @@ -60,7 +59,6 @@ describe('TransactionService', () => { let networkType: NetworkType; let transactionService: TransactionService; let transactionRepository: TransactionRepository; - const epochAdjustment = Duration.ofSeconds(1573430400); before(() => { return helper.start({ openListener: true }).then(() => { @@ -86,7 +84,7 @@ describe('TransactionService', () => { function buildAggregateTransaction(): AggregateTransaction { const transferTransaction = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), addressAlias, [NetworkCurrencyLocal.createAbsolute(1), new Mosaic(mosaicAlias, UInt64.fromUint(1))], PlainMessage.create('test-message'), @@ -95,7 +93,7 @@ describe('TransactionService', () => { ); // Unlink MosaicAlias const mosaicAliasTransactionUnlink = MosaicAliasTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), AliasAction.Unlink, mosaicAlias, mosaicId, @@ -107,7 +105,7 @@ describe('TransactionService', () => { const nonce = MosaicNonce.createRandom(); newMosaicId = MosaicId.createFromNonce(nonce, account.address); const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), nonce, newMosaicId, MosaicFlags.create(true, true, false), @@ -118,7 +116,7 @@ describe('TransactionService', () => { ); const mosaicSupplyChangeTransaction = MosaicSupplyChangeTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), newMosaicId, MosaicSupplyChangeAction.Increase, UInt64.fromUint(200000), @@ -128,7 +126,7 @@ describe('TransactionService', () => { // Link namespace with new MosaicId const mosaicAliasTransactionRelink = MosaicAliasTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), AliasAction.Link, mosaicAlias, newMosaicId, @@ -138,7 +136,7 @@ describe('TransactionService', () => { // Use new mosaicAlias in metadata const mosaicMetadataTransaction = MosaicMetadataTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), account.address, UInt64.fromUint(5), mosaicAlias, @@ -148,7 +146,7 @@ describe('TransactionService', () => { helper.maxFee, ); return AggregateTransaction.createComplete( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), [ transferTransaction.toAggregate(account.publicAccount), mosaicAliasTransactionUnlink.toAggregate(account.publicAccount), @@ -172,7 +170,7 @@ describe('TransactionService', () => { it('Announce NamespaceRegistrationTransaction', () => { const namespaceName = 'root-test-namespace-' + Math.floor(Math.random() * 10000); const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), namespaceName, UInt64.fromUint(20), networkType, @@ -189,7 +187,7 @@ describe('TransactionService', () => { it('Announce NamespaceRegistrationTransaction', () => { const namespaceName = 'root-test-namespace-' + Math.floor(Math.random() * 10000); const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), namespaceName, UInt64.fromUint(50), networkType, @@ -205,7 +203,7 @@ describe('TransactionService', () => { describe('Setup test AddressAlias', () => { it('Announce addressAliasTransaction', () => { const addressAliasTransaction = AddressAliasTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), AliasAction.Link, addressAlias, account.address, @@ -224,7 +222,7 @@ describe('TransactionService', () => { const nonce = MosaicNonce.createRandom(); mosaicId = MosaicId.createFromNonce(nonce, account.address); const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), nonce, mosaicId, MosaicFlags.create(true, true, false), @@ -243,7 +241,7 @@ describe('TransactionService', () => { describe('MosaicSupplyChangeTransaction', () => { it('standalone', () => { const mosaicSupplyChangeTransaction = MosaicSupplyChangeTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), mosaicId, MosaicSupplyChangeAction.Increase, UInt64.fromUint(200000), @@ -259,7 +257,7 @@ describe('TransactionService', () => { describe('Setup MosaicAlias', () => { it('Announce MosaicAliasTransaction', () => { const mosaicAliasTransaction = MosaicAliasTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), AliasAction.Link, mosaicAlias, mosaicId, @@ -275,7 +273,7 @@ describe('TransactionService', () => { describe('Create Transfer with alias', () => { it('Announce TransferTransaction', () => { const transferTransaction = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), addressAlias, [NetworkCurrencyLocal.createAbsolute(1), new Mosaic(mosaicAlias, UInt64.fromUint(1))], PlainMessage.create('test-message'), @@ -313,7 +311,7 @@ describe('TransactionService', () => { describe('Transfer mosaic to account 3', () => { it('Announce TransferTransaction', () => { const transferTransaction = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), account3.address, [new Mosaic(mosaicAlias, UInt64.fromUint(1))], PlainMessage.create('test-message'), @@ -331,7 +329,7 @@ describe('TransactionService', () => { const transactions: SignedTransaction[] = []; // 1. Transfer A -> B const transaction1 = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), account2.address, [new Mosaic(mosaicAlias, UInt64.fromUint(1))], PlainMessage.create('test-message'), @@ -342,7 +340,7 @@ describe('TransactionService', () => { // 2. Transfer C -> D const transaction2 = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), cosignAccount4.address, [new Mosaic(mosaicAlias, UInt64.fromUint(1))], PlainMessage.create('test-message'), diff --git a/e2e/service/TransactionService_AggregateBonded.spec.ts b/e2e/service/TransactionService_AggregateBonded.spec.ts index 6c777ae3b9..60477f96d5 100644 --- a/e2e/service/TransactionService_AggregateBonded.spec.ts +++ b/e2e/service/TransactionService_AggregateBonded.spec.ts @@ -15,7 +15,7 @@ */ import { expect } from 'chai'; -import { ChronoUnit, Duration } from 'js-joda'; +import { ChronoUnit } from 'js-joda'; import { NamespaceRepository } from '../../src/infrastructure/NamespaceRepository'; import { Account } from '../../src/model/account/Account'; import { Address } from '../../src/model/account/Address'; @@ -49,7 +49,6 @@ describe('TransactionService - AggregateBonded', () => { let networkType: NetworkType; let transactionService: TransactionService; let NetworkCurrencyLocalId: MosaicId; - const epochAdjustment = Duration.ofSeconds(1573430400); before(() => { return helper.start({ openListener: true }).then(() => { @@ -75,7 +74,7 @@ describe('TransactionService - AggregateBonded', () => { const createSignedAggregatedBondTransaction = (aggregatedTo: Account, signer: Account, recipient: Address): SignedTransaction => { const transferTransaction = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), recipient, [], PlainMessage.create('test-message'), @@ -84,7 +83,7 @@ describe('TransactionService - AggregateBonded', () => { ); const aggregateTransaction = AggregateTransaction.createBonded( - Deadline.create(epochAdjustment, 2, ChronoUnit.MINUTES), + Deadline.create(helper.epochAdjustment, 2, ChronoUnit.MINUTES), [transferTransaction.toAggregate(aggregatedTo.publicAccount)], networkType, [], @@ -112,7 +111,7 @@ describe('TransactionService - AggregateBonded', () => { describe('Setup test multisig account', () => { it('Announce MultisigAccountModificationTransaction', () => { const modifyMultisigAccountTransaction = MultisigAccountModificationTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), 2, 1, [cosignAccount1.address, cosignAccount2.address, cosignAccount3.address], @@ -122,7 +121,7 @@ describe('TransactionService - AggregateBonded', () => { ); const aggregateTransaction = AggregateTransaction.createComplete( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), [modifyMultisigAccountTransaction.toAggregate(multisigAccount.publicAccount)], networkType, [], @@ -147,7 +146,7 @@ describe('TransactionService - AggregateBonded', () => { describe('should announce transaction', () => { it('announce', () => { const transferTransaction = TransferTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), account2.address, [NetworkCurrencyLocal.createAbsolute(1)], PlainMessage.create('test-message'), @@ -170,7 +169,7 @@ describe('TransactionService - AggregateBonded', () => { it('announce', async () => { const signedAggregatedTransaction = createSignedAggregatedBondTransaction(multisigAccount, account, account2.address); const lockFundsTransaction = LockFundsTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), new Mosaic(NetworkCurrencyLocalId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyLocal.DIVISIBILITY))), UInt64.fromUint(1000), signedAggregatedTransaction, @@ -190,7 +189,7 @@ describe('TransactionService - AggregateBonded', () => { it('announce', async () => { const signedAggregatedTransaction = createSignedAggregatedBondTransaction(multisigAccount, account, account2.address); const lockFundsTransaction = LockFundsTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), new Mosaic(NetworkCurrencyLocalId, UInt64.fromUint(10 * Math.pow(10, NetworkCurrencyLocal.DIVISIBILITY))), UInt64.fromUint(1000), signedAggregatedTransaction, @@ -217,7 +216,7 @@ describe('TransactionService - AggregateBonded', () => { describe('Restore test multisig Accounts', () => { it('Announce MultisigAccountModificationTransaction', async () => { const removeCosigner1 = MultisigAccountModificationTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), -1, 0, [], @@ -226,7 +225,7 @@ describe('TransactionService - AggregateBonded', () => { helper.maxFee, ); const removeCosigner2 = MultisigAccountModificationTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), 0, 0, [], @@ -236,7 +235,7 @@ describe('TransactionService - AggregateBonded', () => { ); const removeCosigner3 = MultisigAccountModificationTransaction.create( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), -1, -1, [], @@ -246,7 +245,7 @@ describe('TransactionService - AggregateBonded', () => { ); const aggregateTransaction = AggregateTransaction.createComplete( - Deadline.create(epochAdjustment), + Deadline.create(helper.epochAdjustment), [ removeCosigner1.toAggregate(multisigAccount.publicAccount), removeCosigner2.toAggregate(multisigAccount.publicAccount), diff --git a/src/service/BlockService.ts b/src/service/BlockService.ts index 1dfe9af066..3ba1a7db2b 100644 --- a/src/service/BlockService.ts +++ b/src/service/BlockService.ts @@ -115,7 +115,6 @@ export class BlockService implements IBlockService { * @returns calculated root hash */ private getTransacactionMerkleRoot(transactions: Transaction[]): string { - console.log(transactions); const leaves = transactions .sort((n1, n2) => n1.transactionInfo!.index - n2.transactionInfo!.index) .map((transaction) => transaction.transactionInfo!.hash); From 01ef4e5cd126613e1ca9b19547bfc647192dca74 Mon Sep 17 00:00:00 2001 From: Steven Liu Date: Fri, 9 Oct 2020 20:15:52 +0100 Subject: [PATCH 3/3] Improved streamer toArray --- src/service/BlockService.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/service/BlockService.ts b/src/service/BlockService.ts index 3ba1a7db2b..b1ca98a8b1 100644 --- a/src/service/BlockService.ts +++ b/src/service/BlockService.ts @@ -25,7 +25,6 @@ import { IBlockService } from './interfaces/IBlockService'; import { MerklePosition } from '../model/blockchain/MerklePosition'; import { TransactionPaginationStreamer } from '../infrastructure/paginationStreamer/TransactionPaginationStreamer'; import { TransactionGroup } from '../infrastructure/TransactionGroup'; -import { Transaction } from '../model/transaction/Transaction'; import MerkleTree from 'merkletreejs'; import { TransactionRepository } from '../infrastructure/TransactionRepository'; @@ -80,6 +79,7 @@ export class BlockService implements IBlockService { const streamer = new TransactionPaginationStreamer(this.transactionRepository); return streamer .search({ group: TransactionGroup.Confirmed, height: height }) + .pipe(map((t) => ({ index: t.transactionInfo!.index, hash: t.transactionInfo!.hash }))) .pipe(toArray()) .pipe(map((transactions) => this.getTransacactionMerkleRoot(transactions).toUpperCase())); } @@ -114,11 +114,8 @@ export class BlockService implements IBlockService { * @param transactions Block transactions * @returns calculated root hash */ - private getTransacactionMerkleRoot(transactions: Transaction[]): string { - const leaves = transactions - .sort((n1, n2) => n1.transactionInfo!.index - n2.transactionInfo!.index) - .map((transaction) => transaction.transactionInfo!.hash); - + private getTransacactionMerkleRoot(transactions: { index: number; hash: string | undefined }[]): string { + const leaves = transactions.sort((n1, n2) => n1.index - n2.index).map((transaction) => transaction!.hash); const tree = new MerkleTree(leaves, sha3_256, { duplicateOdd: true, hashLeaves: false,