Skip to content
This repository has been archived by the owner on Jun 10, 2022. It is now read-only.

Commit

Permalink
Dev -> Main (#559)
Browse files Browse the repository at this point in the history
* Fixed aggregate transaction codex issue

* fixed lint

* Updated change log

* Updated change log

* - Added fromHeight & toHeight to receipt endpoint (#557)

* Cosigner notification fix (#554)

* Fixed transactions

* Added multisig check on ws channel subscription

* Fixed lint

* Updated bootstrap

* reset symbol-bootstrap version for travis build

* - Added fromHeight & toHeight to receipt endpoint (#557)

* Fixed transactions

* Added multisig check on ws channel subscription

* Fixed lint

* Updated bootstrap

* reset symbol-bootstrap version for travis build

* Use async in buildAccountConditions

* PR review fixes

* - Restored the changes on subscription manager

* Fixed bug in catapultDB, add self to the multisig list

* Only check multisig account for partial transactions

* Account pagination after filter (#560)

* Fixed #558

* Update package.json

Co-authored-by: fboucquez <fboucquez@gmail.com>

* Updated symbol-bootstrap version

* Removed pageIndex in account search second query

* Restore previous comments

* v2.3.2 change log (#565)

* v2.3.2 change log

* Fixed travis and travis tests

Co-authored-by: fernando <fboucquez@gmail.com>

Co-authored-by: Steven Liu <xian.f.liu@gmail.com>
  • Loading branch information
fboucquez and rg911 authored Feb 2, 2021
1 parent 7d077ba commit 488004b
Show file tree
Hide file tree
Showing 13 changed files with 184 additions and 91 deletions.
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ node_js:
- "12"
services:
- docker
- mongodb
env:
global:
- RELEASE_BRANCH=main
Expand All @@ -19,6 +20,8 @@ before_script:
- . ./travis/docker-functions.sh
- log_env_variables
- echo '$SUBPROJECT'
- mongo mydb_test --eval 'db.createUser({user:"travis",pwd:"test",roles:["readWrite"]});'
- if [[ ! -z "$DOCKER_USERNAME" ]] ; then echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin; fi
- sh yarn_setup.sh

script: cd ${SUBPROJECT} && yarn run lint && yarn run test:travis && cd ..
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.

The changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [v2.3.2] - 02-Feb-2021

### Added

- `FromHeight` and `ToHeight` to receipt search endpoint.

### Fixed

- Fixed issues on only multisig and aggregate initiator can query partial transactions.

## [v2.3.1] - 19-Jan-2021

### Fixed
Expand Down
1 change: 1 addition & 0 deletions rest/bootstrap-preset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ nodes:
- trustedHosts: '127.0.0.1, 172.20.0.25, 172.20.0.1'
localNetworks: '127.0.0.1, 172.20.0.25, 172.20.0.1'
brokerOpenPort: 7902
openPort: '{{add $index 7900}}'
gateways:
- excludeDockerService: true
name: rest
Expand Down
6 changes: 3 additions & 3 deletions rest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
"test": "mocha --full-trace --recursive",
"test:coverage": "nyc npm test && nyc report --reporter=text-lcov",
"test:jenkins": "cross-env JUNIT_REPORT_PATH=test-results.xml mocha --reporter mocha-jenkins-reporter --mongoHost db --forbid-only --full-trace --recursive test || exit 0",
"test:travis": "npm run bootstrap-start-detached && nyc npm test && nyc report --reporter=text-lcov | coveralls && npm run bootstrap-stop ",
"test:travis": "nyc npm test && nyc report --reporter=text-lcov | coveralls",
"lint": "eslint src test",
"lint:fix": "eslint src test --fix",
"lint:jenkins": "eslint -o tests.catapult.lint.xml -f junit src test || exit 0",
"bootstrap-clean": "symbol-bootstrap clean",
"bootstrap-start": "symbol-bootstrap start -a light -c bootstrap-preset.yml --healthCheck",
"bootstrap-start-testnet": "symbol-bootstrap start -p testnet -a dual -c bootstrap-preset-testnet.yml --healthCheck",
"bootstrap-start-detached": "symbol-bootstrap start -a light -c bootstrap-preset.yml --detached --healthCheck",
"bootstrap-start-detached": "symbol-bootstrap start -a light -c bootstrap-preset.yml --detached --healthCheck --pullImages",
"bootstrap-stop": "symbol-bootstrap stop",
"bootstrap-run": "symbol-bootstrap run",
"bootstrap-run-detached": "symbol-bootstrap run --detached --healthCheck",
Expand All @@ -47,7 +47,7 @@
"nodemon": "^2.0.6",
"rimraf": "^2.6.3",
"sinon": "^7.3.2",
"symbol-bootstrap": "0.3.0-alpha-202012081631"
"symbol-bootstrap": "0.4.1"
},
"dependencies": {
"catapult-sdk": "link:../catapult-sdk",
Expand Down
35 changes: 23 additions & 12 deletions rest/src/db/CatapultDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

const connector = require('./connector');
const { convertToLong, buildOffsetCondition } = require('./dbUtils');
const MultisigDb = require('../plugins/multisig/MultisigDb');
const catapult = require('catapult-sdk');
const MongoDb = require('mongodb');

Expand Down Expand Up @@ -304,24 +305,33 @@ class CatapultDb {
* `pageSize` and `pageNumber`. 'sortField' must be within allowed 'sortingOptions'.
* @returns {Promise.<object>} Transactions page.
*/
transactions(group, filters, options) {
async transactions(group, filters, options) {
const sortingOptions = { id: '_id' };

const buildAccountConditions = () => {
if (undefined !== filters.address)
const buildAccountConditions = async () => {
// Check multisig graph if address is used in search criteria for cosigning,
// Then, show transactions for other cosigers.
if (undefined !== filters.address) {
if ('partial' === group) {
const multisigEntries = await new MultisigDb(this).multisigsByAddresses([filters.address]);

if (multisigEntries.length && multisigEntries[0].multisig.multisigAddresses.length) {
const buffers = multisigEntries[0].multisig.multisigAddresses.map(address => address.buffer);
buffers.push(Buffer.from(filters.address));
return { 'meta.addresses': { $in: buffers } };
}
}
return { 'meta.addresses': Buffer.from(filters.address) };

}
const accountConditions = {};
if (undefined !== filters.signerPublicKey)
accountConditions['transaction.signerPublicKey'] = Buffer.from(filters.signerPublicKey);

if (undefined !== filters.recipientAddress)
accountConditions['transaction.recipientAddress'] = Buffer.from(filters.recipientAddress);

return accountConditions;
};

const buildConditions = () => {
const buildConditions = async () => {
let conditions = {};

const offsetCondition = buildOffsetCondition(options, sortingOptions);
Expand Down Expand Up @@ -363,7 +373,7 @@ class CatapultDb {
conditions[amountPath].$lte = convertToLong(filters.toTransferAmount);
}

const accountConditions = buildAccountConditions();
const accountConditions = await buildAccountConditions();
if (accountConditions)
conditions = Object.assign(conditions, accountConditions);

Expand All @@ -372,7 +382,7 @@ class CatapultDb {

const removedFields = ['meta.addresses'];
const sortConditions = { [sortingOptions[options.sortField]]: options.sortDirection };
const conditions = buildConditions();
const conditions = await buildConditions();

return this.queryPagedDocuments(conditions, removedFields, sortConditions, TransactionGroup[group], options);
}
Expand Down Expand Up @@ -470,17 +480,18 @@ class CatapultDb {
// fetch result sorted by specific mosaic amount, this unwinds mosaics and only returns matching mosaics (incomplete response)
queryPromise = this.database.collection('accounts')
.aggregate([], { promoteLongs: false })
.skip(pageSize * pageIndex)
.limit(pageSize)
.unwind('$account.mosaics')
.match(conditions)
.sort(sortConditions)
.skip(pageSize * pageIndex)
.limit(pageSize)
.toArray()
.then(accounts => {
const accountIds = accounts.map(account => account._id);
const newConditions = { _id: { $in: accountIds } };

// repeat the response with the found and sorted account ids, so that the result can be complete with all the mosaics
// Second query set pageIndex to 0;
options.pageNumber = 1;
return this.queryPagedDocuments(newConditions, [], {}, 'accounts', options)
.then(fullAccountsPage => {
// $in results do not preserve query order
Expand Down
52 changes: 2 additions & 50 deletions rest/src/plugins/multisig/multisigRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* along with Catapult. If not, see <http://www.gnu.org/licenses/>.
*/

const multisigUtils = require('./multisigUtils');
const merkleUtils = require('../../routes/merkleUtils');
const routeUtils = require('../../routes/routeUtils');
const catapult = require('catapult-sdk');
Expand All @@ -44,58 +45,9 @@ module.exports = {
});
});

const getMultisigEntries = (multisigEntries, fieldName) => {
const addresses = new Set();
multisigEntries.forEach(multisigEntry => multisigEntry.multisig[fieldName].forEach(address => {
addresses.add(address.buffer);
}));

return db.multisigsByAddresses(Array.from(addresses));
};

server.get('/account/:address/multisig/graph', (req, res, next) => {
const accountAddress = routeUtils.parseArgument(req.params, 'address', 'address');

const multisigLevels = [];
return db.multisigsByAddresses([accountAddress])
.then(multisigEntries => {
if (0 === multisigEntries.length)
return Promise.resolve(undefined);

multisigLevels.push({
level: 0,
multisigEntries: [multisigEntries[0]]
});

return Promise.resolve(multisigEntries[0]);
})
.then(multisigEntry => {
if (undefined === multisigEntry)
return Promise.resolve(undefined);

const handleUpstream = (level, multisigEntries) => getMultisigEntries(multisigEntries, 'multisigAddresses')
.then(entries => {
if (0 === entries.length)
return Promise.resolve();

multisigLevels.unshift({ level, multisigEntries: entries });
return handleUpstream(level - 1, entries);
});

const handleDownstream = (level, multisigEntries) => getMultisigEntries(multisigEntries, 'cosignatoryAddresses')
.then(entries => {
if (0 === entries.length)
return Promise.resolve();

multisigLevels.push({ level, multisigEntries: entries });
return handleDownstream(level + 1, entries);
});

const upstreamPromise = handleUpstream(-1, [multisigEntry]);
const downstreamPromise = handleDownstream(1, [multisigEntry]);
return Promise.all([upstreamPromise, downstreamPromise])
.then(() => multisigLevels);
})
return multisigUtils.getMultisigGraph(db, accountAddress)
.then(response => {
const sender = routeUtils.createSender('multisigGraph');
return undefined === response
Expand Down
77 changes: 77 additions & 0 deletions rest/src/plugins/multisig/multisigUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2016-2019, Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp.
* Copyright (c) 2020-present, Jaguar0625, gimre, BloodyRookie.
* All rights reserved.
*
* This file is part of Catapult.
*
* Catapult is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Catapult is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Catapult. If not, see <http://www.gnu.org/licenses/>.
*/

const multisigUtils = {
getMultisigGraph: (db, address) => {
const getMultisigEntries = (multisigEntries, fieldName) => {
const addresses = new Set();
multisigEntries.forEach(multisigEntry => multisigEntry.multisig[fieldName].forEach(multisigAddress => {
addresses.add(multisigAddress.buffer);
}));

return db.multisigsByAddresses(Array.from(addresses));
};

const multisigLevels = [];
return db.multisigsByAddresses([address])
.then(multisigEntries => {
if (0 === multisigEntries.length)
return Promise.resolve(undefined);

multisigLevels.push({
level: 0,
multisigEntries: [multisigEntries[0]]
});

return Promise.resolve(multisigEntries[0]);
})
.then(multisigEntry => {
if (undefined === multisigEntry)
return Promise.resolve(undefined);

const handleUpstream = (level, multisigEntries) => getMultisigEntries(multisigEntries, 'multisigAddresses')
.then(entries => {
if (0 === entries.length)
return Promise.resolve();

multisigLevels.unshift({ level, multisigEntries: entries });
return handleUpstream(level - 1, entries);
});

const handleDownstream = (level, multisigEntries) => getMultisigEntries(multisigEntries, 'cosignatoryAddresses')
.then(entries => {
if (0 === entries.length)
return Promise.resolve();

multisigLevels.push({ level, multisigEntries: entries });
return handleDownstream(level + 1, entries);
});

const upstreamPromise = handleUpstream(-1, [multisigEntry]);
const downstreamPromise = handleDownstream(1, [multisigEntry]);
return Promise.all([upstreamPromise, downstreamPromise])
.then(() => multisigLevels);
});
}

};

module.exports = multisigUtils;
11 changes: 11 additions & 0 deletions rest/src/plugins/receipts/ReceiptsDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ class ReceiptsDb {
conditions[[`statement.receipts.${artifactIdType}`]] = convertToLong(filters.artifactId);
}

if (undefined !== filters.fromHeight || undefined !== filters.toHeight) {
const heightPath = 'statement.height';
conditions[heightPath] = {};

if (undefined !== filters.fromHeight)
conditions[heightPath].$gte = convertToLong(filters.fromHeight);

if (undefined !== filters.toHeight)
conditions[heightPath].$lte = convertToLong(filters.toHeight);
}

const sortConditions = { [sortingOptions[options.sortField]]: options.sortDirection };
return this.catapultDb.queryPagedDocuments(conditions, [], sortConditions, 'transactionStatements', options);
}
Expand Down
2 changes: 2 additions & 0 deletions rest/src/plugins/receipts/receiptsRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ module.exports = {
const { params } = req;
const filters = {
height: params.height ? routeUtils.parseArgument(params, 'height', 'uint64') : undefined,
fromHeight: params.fromHeight ? routeUtils.parseArgument(params, 'fromHeight', 'uint64') : undefined,
toHeight: params.toHeight ? routeUtils.parseArgument(params, 'toHeight', 'uint64') : undefined,
receiptType: params.receiptType ? routeUtils.parseArgumentAsArray(params, 'receiptType', 'uint') : undefined,
recipientAddress: params.recipientAddress ? routeUtils.parseArgument(params, 'recipientAddress', 'address') : undefined,
senderAddress: params.senderAddress ? routeUtils.parseArgument(params, 'senderAddress', 'address') : undefined,
Expand Down
2 changes: 0 additions & 2 deletions rest/src/routes/transactionRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,13 @@ module.exports = {
recipientAddress: params.recipientAddress ? routeUtils.parseArgument(params, 'recipientAddress', 'address') : undefined,
transactionTypes: params.type ? routeUtils.parseArgumentAsArray(params, 'type', 'uint') : undefined,
embedded: params.embedded ? routeUtils.parseArgument(params, 'embedded', 'boolean') : undefined,

/** transfer transaction specific filters */
transferMosaicId: params.transferMosaicId ? routeUtils.parseArgument(params, 'transferMosaicId', 'uint64hex') : undefined,
fromTransferAmount: params.fromTransferAmount
? routeUtils.parseArgument(params, 'fromTransferAmount', 'uint64') : undefined,
toTransferAmount: params.toTransferAmount ? routeUtils.parseArgument(params, 'toTransferAmount', 'uint64') : undefined
};
const options = routeUtils.parsePaginationArguments(params, services.config.pageSize, { id: 'objectId' });

return db.transactions(params.group, filters, options)
.then(result => routeUtils.createSender(routeResultTypes.transaction).sendPage(res, next)(result));
});
Expand Down
28 changes: 28 additions & 0 deletions rest/test/plugins/receipts/receiptsRoutes_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,34 @@ describe('receipts routes', () => {
});
});

it('forwards fromHeight', () => {
// Arrange:
const req = { params: { fromHeight: '123' } };

// Act:
return mockServer.callRoute(route, req).then(() => {
// Assert:
expect(dbTransactionStatementsFake.calledOnce).to.equal(true);
expect(dbTransactionStatementsFake.firstCall.args[0].fromHeight).to.deep.equal([123, 0]);

expect(mockServer.next.calledOnce).to.equal(true);
});
});

it('forwards toHeight', () => {
// Arrange:
const req = { params: { toHeight: '123' } };

// Act:
return mockServer.callRoute(route, req).then(() => {
// Assert:
expect(dbTransactionStatementsFake.calledOnce).to.equal(true);
expect(dbTransactionStatementsFake.firstCall.args[0].toHeight).to.deep.equal([123, 0]);

expect(mockServer.next.calledOnce).to.equal(true);
});
});

describe('forwards receiptType', () => {
it('one element', () => {
// Arrange:
Expand Down
Loading

0 comments on commit 488004b

Please sign in to comment.