Skip to content

Commit b7e28cc

Browse files
committed
Fixed #449
Added blockService
1 parent c76f413 commit b7e28cc

File tree

3 files changed

+205
-0
lines changed

3 files changed

+205
-0
lines changed

e2e/service/BlockService.spec.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2019 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { assert, expect } from 'chai';
18+
import { ReceiptRepository } from '../../src/infrastructure/ReceiptRepository';
19+
import { TransactionRepository } from '../../src/infrastructure/TransactionRepository';
20+
import { Account } from '../../src/model/account/Account';
21+
import { NetworkType } from '../../src/model/blockchain/NetworkType';
22+
import { PlainMessage } from '../../src/model/message/PlainMessage';
23+
import { NetworkCurrencyMosaic } from '../../src/model/mosaic/NetworkCurrencyMosaic';
24+
import { Deadline } from '../../src/model/transaction/Deadline';
25+
import { TransferTransaction } from '../../src/model/transaction/TransferTransaction';
26+
import { UInt64 } from '../../src/model/UInt64';
27+
import { BlockService } from '../../src/service/BlockService';
28+
import { IntegrationTestHelper } from '../infrastructure/IntegrationTestHelper';
29+
30+
describe('BlockService', () => {
31+
const helper = new IntegrationTestHelper();
32+
let generationHash: string;
33+
let account: Account;
34+
let account2: Account;
35+
let account3: Account;
36+
let networkType: NetworkType;
37+
let transactionHash: string;
38+
let blockService: BlockService;
39+
let transactionRepository: TransactionRepository;
40+
let receiptRepository: ReceiptRepository;
41+
42+
before(() => {
43+
return helper.start().then(() => {
44+
account = helper.account;
45+
account2 = helper.account2;
46+
account3 = helper.account3;
47+
generationHash = helper.generationHash;
48+
networkType = helper.networkType;
49+
transactionRepository = helper.repositoryFactory.createTransactionRepository();
50+
receiptRepository = helper.repositoryFactory.createReceiptRepository();
51+
blockService = new BlockService(helper.repositoryFactory.createBlockRepository(), receiptRepository);
52+
});
53+
});
54+
before(() => {
55+
return helper.listener.open();
56+
});
57+
58+
after(() => {
59+
helper.listener.close();
60+
});
61+
62+
/**
63+
* =========================
64+
* Setup test data
65+
* =========================
66+
*/
67+
describe('Create a transfer', () => {
68+
it('Announce TransferTransaction', () => {
69+
const transferTransaction = TransferTransaction.create(
70+
Deadline.create(),
71+
account2.address,
72+
[NetworkCurrencyMosaic.createAbsolute(1)],
73+
PlainMessage.create('test-message'),
74+
networkType,
75+
helper.maxFee,
76+
);
77+
78+
const signedTransaction = transferTransaction.signWith(account, generationHash);
79+
transactionHash = signedTransaction.hash;
80+
return helper.announce(signedTransaction);
81+
});
82+
});
83+
84+
/**
85+
* =========================
86+
* Test
87+
* =========================
88+
*/
89+
90+
describe('Validate transansaction', () => {
91+
it('call block service', () => {
92+
return transactionRepository.getTransaction(transactionHash).subscribe(
93+
(transaction) => {
94+
const transactionInfo = transaction.transactionInfo;
95+
if (transactionInfo && transactionInfo.height !== undefined) {
96+
const validationResult = blockService.validateTransactionInBlock(transactionHash, transactionInfo.height);
97+
expect(validationResult).to.be.true;
98+
}
99+
assert(false, `Transaction (hash: ${transactionHash}) not found`);
100+
},
101+
);
102+
});
103+
});
104+
105+
describe('Validate receipt', () => {
106+
it('call block service', () => {
107+
return receiptRepository.getBlockReceipts(UInt64.fromUint(1)).subscribe(
108+
(statement) => {
109+
const receipt = statement.transactionStatements[0];
110+
const validationResult = blockService.validateReceiptInBlock(receipt.generateHash(), UInt64.fromUint(1));
111+
expect(validationResult).to.be.true;
112+
},
113+
);
114+
});
115+
});
116+
117+
});

src/service/BlockService.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2020 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { sha3_256 } from 'js-sha3';
18+
import { combineLatest, Observable } from 'rxjs';
19+
import { map } from 'rxjs/operators';
20+
import { BlockRepository } from '../infrastructure/BlockRepository';
21+
import { ReceiptRepository } from '../infrastructure/ReceiptRepository';
22+
import { MerklePathItem } from '../model/blockchain/MerklePathItem';
23+
import { UInt64 } from '../model/UInt64';
24+
25+
/**
26+
* Transaction Service
27+
*/
28+
export class BlockService {
29+
30+
/**
31+
* Constructor
32+
* @param blockRepository
33+
* @param receiptRepository
34+
*/
35+
constructor(private readonly blockRepository: BlockRepository, private readonly receiptRepository: ReceiptRepository) {
36+
}
37+
38+
/**
39+
* Validate transaction hash in block
40+
* @param leaf transaction hash
41+
* @param height block height
42+
*/
43+
public validateTransactionInBlock(leaf: string, height: UInt64): Observable<boolean> {
44+
const rootHashObservable = this.blockRepository.getBlockByHeight(height);
45+
const merklePathItemObservable = this.blockRepository.getMerkleTransaction(height, leaf);
46+
return combineLatest(rootHashObservable, merklePathItemObservable).pipe(
47+
map((combined) => this.validateInBlock(leaf, combined[1].merklePath, combined[0].blockTransactionsHash)),
48+
);
49+
}
50+
51+
/**
52+
* Validate receipt hash in block
53+
* @param leaf receipt hash
54+
* @param height block height
55+
*/
56+
public validateReceiptInBlock(leaf: string, height: UInt64): Observable<boolean> {
57+
const rootHashObservable = this.blockRepository.getBlockByHeight(height);
58+
const merklePathItemObservable = this.receiptRepository.getMerkleReceipts(height, leaf);
59+
return combineLatest(rootHashObservable, merklePathItemObservable).pipe(
60+
map((combined) => this.validateInBlock(leaf, combined[1].merklePath, combined[0].blockReceiptsHash)),
61+
);
62+
}
63+
64+
/**
65+
* @internal
66+
* Validate leaf against merkle tree in block
67+
* @param leaf Leaf hash in merkle tree
68+
* @param merklePathItem Merkle path item array
69+
* @param rootHash Block root hash
70+
*/
71+
private validateInBlock(leaf: string, merklePathItem: MerklePathItem[] = [], rootHash: string): boolean {
72+
if (merklePathItem.length === 0) {
73+
return leaf.toUpperCase() === rootHash.toUpperCase();
74+
}
75+
const rootToCompare = merklePathItem.reduce((proofHash, pathItem) => {
76+
const hasher = sha3_256.create();
77+
// Left
78+
if (pathItem.position === 1) {
79+
return hasher.update(Buffer.from(pathItem.hash + proofHash, 'hex')).hex();
80+
} else {
81+
// Right
82+
return hasher.update(Buffer.from(proofHash + pathItem.hash, 'hex')).hex();
83+
}
84+
}, leaf);
85+
return rootToCompare.toUpperCase() === rootHash.toUpperCase();
86+
}
87+
}

src/service/service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ export * from './AggregateTransactionService';
2020
export * from './MetadataTransactionService';
2121
export * from './MosaicRestrictionTransactionService';
2222
export * from './TransactionService';
23+
export * from './BlockService';

0 commit comments

Comments
 (0)