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

Commit

Permalink
feat: block's timestamp and feeMultiplier in transactions (#658)
Browse files Browse the repository at this point in the history
  • Loading branch information
fboucquez authored Sep 7, 2021
1 parent 015bbac commit 6d0ed74
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 54 deletions.
4 changes: 3 additions & 1 deletion catapult-sdk/src/model/ModelSchemaBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ class ModelSchemaBuilder {
height: ModelType.uint64,
hash: ModelType.binary,
merkleComponentHash: ModelType.binary,
index: ModelType.int
index: ModelType.int,
timestamp: ModelType.uint64,
feeMultiplier: ModelType.uint32
},
transactionWithMetadata: {
id: ModelType.objectId,
Expand Down
2 changes: 2 additions & 0 deletions catapult-sdk/test/model/ModelSchemaBuilder_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ describe('model schema builder', () => {
'transaction.deadline',
'transaction.maxFee',
'transactionMetadata.height',
'transactionMetadata.timestamp',

'transactionStatus.deadline',
'transactionStatus.height',
Expand Down Expand Up @@ -408,6 +409,7 @@ describe('model schema builder', () => {
'finalizationProof.finalizationEpoch',
'finalizationProof.finalizationPoint',
'messageGroup.stage',
'transactionMetadata.feeMultiplier',
'activityBucket.beneficiaryCount',
'votingPublicKey.startEpoch',
'votingPublicKey.endEpoch'
Expand Down
1 change: 1 addition & 0 deletions rest/bootstrap-preset-mainnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ gateways:
restLoggingFilename: target/rest.log
databaseHost: localhost
apiNodeHost: localhost
restProtocol: HTTP

1 change: 1 addition & 0 deletions rest/bootstrap-preset-testnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ gateways:
restLoggingFilename: target/rest.log
databaseHost: localhost
apiNodeHost: localhost
restProtocol: HTTP

81 changes: 77 additions & 4 deletions rest/src/db/CatapultDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/** @module db/CatapultDb */

const connector = require('./connector');
const { convertToLong, buildOffsetCondition } = require('./dbUtils');
const { convertToLong, buildOffsetCondition, uniqueLongList } = require('./dbUtils');
const MultisigDb = require('../plugins/multisig/MultisigDb');
const catapult = require('catapult-sdk');
const MongoDb = require('mongodb');
Expand Down Expand Up @@ -401,20 +401,29 @@ class CatapultDb {
const sortConditions = { [sortingOptions[options.sortField]]: options.sortDirection };
const conditions = await buildConditions();

return this.queryPagedDocuments(conditions, removedFields, sortConditions, TransactionGroup[group], options);
return this.queryPagedDocuments(conditions, removedFields, sortConditions, TransactionGroup[group], options).then(async page => {
const data = await this.addBlockMetaToTransactionList(page.data);
return ({
...page,
data
});
});
}

transactionsByIdsImpl(collectionName, conditions) {
return this.queryDocumentsAndCopyIds(collectionName, conditions, { projection: { 'meta.addresses': 0 } })
.then(documents => Promise.all(documents.map(document => {
.then(list => this.addBlockMetaToTransactionList(list)).then(documents => Promise.all(documents.map(document => {
if (!document || !isAggregateType(document))
return document;

return this.queryDependentDocuments(collectionName, [document.id]).then(dependentDocuments => {
dependentDocuments.forEach(dependentDocument => {
if (!document.transaction.transactions)
document.transaction.transactions = [];

if (document.meta.timestamp !== undefined && document.meta.feeMultiplier !== undefined) {
dependentDocument.meta.timestamp = document.meta.timestamp;
dependentDocument.meta.feeMultiplier = document.meta.feeMultiplier;
}
document.transaction.transactions.push(dependentDocument);
});

Expand All @@ -423,6 +432,70 @@ class CatapultDb {
})));
}

/**
* It retrieves and adds the block information to the transactions' meta.
*
* The block information includes its timestamp and feeMultiplier
*
* @param {object[]} list the transaction list without the added block information.
* @returns {Promise<object[]>} the list with the added block information.
*/
addBlockMetaToTransactionList(list) {
return this.addBlockMetaToEntityList(list, ['timestamp', 'feeMultiplier'], item => item.meta.height);
}

/**
* It retrieves and adds the block information to the entities' meta.
*
* @param {object[]} list the entity list without the added block information.
* @param {string[]} fields the list of fields to be be copied from the block's to the entity's meta.
* @param {Function} getHeight a function that returns the block's height of a given entity.
* @returns {Promise<object[]>} this list with the added block information.
*/
async addBlockMetaToEntityList(list, fields, getHeight) {
const isValidHeight = height => height && 0 !== height.toInt();

const blockHeights = uniqueLongList(
list.map(item => getHeight(item)).filter(isValidHeight)
);

const projection = {
'block.height': 1,
...fields.reduce((acc, field) => {
acc[`block.${field}`] = 1;
return acc;
}, {})
};
const blocks = await this.blocksAtHeights(blockHeights, projection);

return list.map(item => {
const height = getHeight(item);
if (!isValidHeight(height))
return item;
const block = blocks.find(
blockInfo => blockInfo.block.height.equals(
height
)
);
if (!block) {
throw new Error(
`Cannot find block with height ${height.toString()}`
);
}
item.meta = item.meta || {};
fields.forEach(field => {
const value = block.block[field];
if (value === undefined) {
throw new Error(
`Cannot find ${field} in block with height ${height.toString()}`
);
}
item.meta[field] = value;
});
return item;
});
}

transactionsByIds(group, ids) {
return this.transactionsByIdsImpl(TransactionGroup[group], { _id: { $in: ids.map(id => new ObjectId(id)) } });
}
Expand Down
29 changes: 3 additions & 26 deletions rest/src/plugins/receipts/ReceiptsDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* along with Catapult. If not, see <http://www.gnu.org/licenses/>.
*/

const { convertToLong, buildOffsetCondition, uniqueLongList } = require('../../db/dbUtils');
const { convertToLong, buildOffsetCondition } = require('../../db/dbUtils');
const catapult = require('catapult-sdk');

const { convert, uint64 } = catapult.utils;
Expand Down Expand Up @@ -116,38 +116,15 @@ class ReceiptsDb {
}

/**
* It retrives and adds the blocks information to the statements' meta.
* It retrieves and adds the blocks information to the statements' meta.
*
* The block information includes the its timestamp
*
* @param {object} page the page without meta in the items.
* @returns {Promise<{pagination, data}>} the page with the added block's meta to the items.
*/
async addBlockMeta(page) {
const blockHeights = uniqueLongList(
page.data.map(pageItem => pageItem.statement.height)
);
const blocks = await this.catapultDb.blocksAtHeights(blockHeights,
{ 'block.timestamp': 1, 'block.height': 1 });
const data = page.data.map(pageItem => {
const statementBlock = blocks.find(
blockInfo => blockInfo.block.height.equals(
pageItem.statement.height
)
);
if (!statementBlock) {
throw new Error(
`Cannot find block with height ${pageItem.statement.height.toString()}`
);
}
if (!statementBlock.block.timestamp) {
throw new Error(
`Cannot find timestamp in block with height ${pageItem.statement.height.toString()}`
);
}
// creates a copy of the page item with the added timestamp to the meta field.
return { meta: { ...pageItem.meta, timestamp: statementBlock.block.timestamp }, ...pageItem };
});
const data = await this.catapultDb.addBlockMetaToEntityList(page.data, ['timestamp'], item => item.statement.height);
return { data, pagination: page.pagination };
}
}
Expand Down
Loading

0 comments on commit 6d0ed74

Please sign in to comment.