Skip to content

Commit

Permalink
Custom fees REST api (#2247)
Browse files Browse the repository at this point in the history
- Add assessed custom fees to /api/v1/transactions/:transactionId endpoint
- Add custom fees schedule to/api/v1/tokens/:tokenId endpoint
- Add model/viewmodel for assessed custom fees and custom fees schedule
- Add integration domain support for assessed custom fees and custom fees schedule
- Update openapi spec
- Fix EntityId throwing exception with nullable undefined value
- Move queryQuietly to pool class prototype
- Add/Update integration tests

Signed-off-by: Xin Li <xin.li@hedera.com>
Signed-off-by: Ian Jungmann <ian.jungmann@hedera.com>
  • Loading branch information
xin-hedera authored and Ian Jungmann committed Jul 16, 2021
1 parent 1a5d6f2 commit 2ca03f9
Show file tree
Hide file tree
Showing 42 changed files with 2,038 additions and 355 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ exports[`EntityId fromString a 1`] = `"invalid entity ID string \\"a\\""`;
exports[`EntityId fromString a.b.c 1`] = `"invalid entity ID string \\"a.b.c\\""`;

exports[`EntityId fromString null 1`] = `"Null entity ID"`;

exports[`EntityId fromString undefined 1`] = `"Null entity ID"`;
74 changes: 55 additions & 19 deletions hedera-mirror-rest/__tests__/__snapshots__/tokens.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,68 +72,104 @@ Array [
]
`;

exports[`utils validateAndParseFilters account.id tests Verify validateAndParseFilters for invalid {"key":"account.id","operator":"eq","value":"@.#.$"} 1`] = `
exports[`utils buildAndValidateFilters serialnumbers tests Verify buildAndValidateFilters for invalid {"serialnumber":"-1"} 1`] = `
Array [
"Invalid parameter: account.id",
"Invalid parameter: serialnumber",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify validateAndParseFilters for invalid {"key":"account.id","operator":"eq","value":"-1"} 1`] = `
exports[`utils buildAndValidateFilters serialnumbers tests Verify buildAndValidateFilters for invalid {"serialnumber":"0"} 1`] = `
Array [
"Invalid parameter: account.id",
"Invalid parameter: serialnumber",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify validateAndParseFilters for invalid {"key":"account.id","operator":"eq","value":"-1.-1.-1"} 1`] = `
exports[`utils buildAndValidateFilters serialnumbers tests Verify buildAndValidateFilters for invalid {"serialnumber":"deb"} 1`] = `
Array [
"Invalid parameter: account.id",
"Invalid parameter: serialnumber",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify validateAndParseFilters for invalid {"key":"account.id","operator":"eq","value":"0.1.2.3"} 1`] = `
exports[`utils buildAndValidateFilters token info query timestamp filter tests Verify buildAndValidateFilters for invalid {"serialnumber":"123456"} 1`] = `
Array [
"Invalid parameter: account.id",
"Invalid parameter: serialnumber",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify validateAndParseFilters for invalid {"key":"account.id","operator":"eq","value":"L"} 1`] = `
exports[`utils buildAndValidateFilters token info query timestamp filter tests Verify buildAndValidateFilters for invalid {"timestamp":""} 1`] = `
Array [
"Invalid parameter: account.id",
"Invalid parameter: timestamp",
]
`;

exports[`utils validateAndParseFilters serialnumbers tests Verify validateAndParseFilters for invalid {"key":"serialnumber","operator":"eq","value":"-1"} 1`] = `
exports[`utils buildAndValidateFilters token info query timestamp filter tests Verify buildAndValidateFilters for invalid {"timestamp":"abc"} 1`] = `
Array [
"Invalid parameter: serialnumber",
"Invalid parameter: timestamp",
]
`;

exports[`utils validateAndParseFilters serialnumbers tests Verify validateAndParseFilters for invalid {"key":"serialnumber","operator":"eq","value":"0"} 1`] = `
exports[`utils buildAndValidateFilters token info query timestamp filter tests Verify buildAndValidateFilters for invalid {"timestamp":"gt:1234"} 1`] = `
Array [
"Invalid parameter: serialnumber",
"Invalid parameter: timestamp",
]
`;

exports[`utils validateAndParseFilters serialnumbers tests Verify validateAndParseFilters for invalid {"key":"serialnumber","operator":"eq","value":"deb"} 1`] = `
exports[`utils buildAndValidateFilters token info query timestamp filter tests Verify buildAndValidateFilters for invalid {"timestamp":"gte:1234"} 1`] = `
Array [
"Invalid parameter: serialnumber",
"Invalid parameter: timestamp",
]
`;

exports[`utils buildAndValidateFilters token info query timestamp filter tests Verify buildAndValidateFilters for invalid {"timestamp":"ne:1234"} 1`] = `
Array [
"Invalid parameter: timestamp",
]
`;

exports[`utils validateAndParseFilters token type tests Verify validateAndParseFilters for invalid {"key":"type","operator":"eq","value":"-1"} 1`] = `
exports[`utils buildAndValidateFilters token type tests Verify buildAndValidateFilters for invalid {"type":"-1"} 1`] = `
Array [
"Invalid parameter: type",
]
`;

exports[`utils validateAndParseFilters token type tests Verify validateAndParseFilters for invalid {"key":"type","operator":"eq","value":"cred"} 1`] = `
exports[`utils buildAndValidateFilters token type tests Verify buildAndValidateFilters for invalid {"type":"cred"} 1`] = `
Array [
"Invalid parameter: type",
]
`;

exports[`utils validateAndParseFilters token type tests Verify validateAndParseFilters for invalid {"key":"type","operator":"eq","value":"deb"} 1`] = `
exports[`utils buildAndValidateFilters token type tests Verify buildAndValidateFilters for invalid {"type":"deb"} 1`] = `
Array [
"Invalid parameter: type",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify buildAndValidateFilters for invalid {"account.id":"@.#.$"} 1`] = `
Array [
"Invalid parameter: account.id",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify buildAndValidateFilters for invalid {"account.id":"-1"} 1`] = `
Array [
"Invalid parameter: account.id",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify buildAndValidateFilters for invalid {"account.id":"-1.-1.-1"} 1`] = `
Array [
"Invalid parameter: account.id",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify buildAndValidateFilters for invalid {"account.id":"0.1.2.3"} 1`] = `
Array [
"Invalid parameter: account.id",
]
`;

exports[`utils validateAndParseFilters account.id tests Verify buildAndValidateFilters for invalid {"account.id":"L"} 1`] = `
Array [
"Invalid parameter: account.id",
]
`;
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`utils buildAndValidateFilters test validator fails 1`] = `
Array [
"Invalid parameter: account.id",
"Invalid parameter: limit",
"Invalid parameter: timestamp",
]
`;

exports[`utils validateAndParseFilters account balance key tests Verify validateAndParseFilters for invalid {"key":"account.balance","operator":"eq","value":"-1"} 1`] = `
Array [
"Invalid parameter: account.balance",
Expand Down
15 changes: 15 additions & 0 deletions hedera-mirror-rest/__tests__/entityId.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,19 @@ describe('EntityId fromString', () => {
isNullable: true,
expected: EntityId.of(null, null, null),
},
{
isNullable: true,
expected: EntityId.of(null, null, null),
},
{
entityIdStr: null,
isNullable: false,
expectErr: true,
},
{
isNullable: false,
expectErr: true,
},
{
entityIdStr: '0.1.x',
paramName: 'demo param',
Expand Down Expand Up @@ -241,10 +249,17 @@ describe('EntityId fromEncodedId', () => {
isNullable: true,
expected: EntityId.of(null, null, null),
},
{
isNullable: true,
expected: EntityId.of(null, null, null),
},
{
encodedId: null,
expectErr: true,
},
{
expectErr: true,
},
];

for (const spec of specs) {
Expand Down
22 changes: 11 additions & 11 deletions hedera-mirror-rest/__tests__/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jest.setTimeout(40000);

let sqlConnection;

// set timeout for beforeAll to 2 minutes as downloading docker image if not exists can take quite some time
// set timeout for beforeAll to 4 minutes as downloading docker image if not exists can take quite some time
const defaultBeforeAllTimeoutMillis = 240 * 1000;

beforeAll(async () => {
Expand Down Expand Up @@ -288,19 +288,19 @@ const expectedTransactionRowsMap = expectedTransactionRowsDesc.reduce((m, row) =
}, {});

test('DB integration test - transactions.reqToSql - no query string - 3 txn 9 xfers', async () => {
const sql = await transactions.reqToSql({query: {}});
const sql = transactions.reqToSql({query: {}});
const res = await integrationDbOps.runSqlQuery(sql.query, sql.params);
expect(mapTransactionResults(res.rows)).toEqual(expectedTransactionRowsDesc);
});

test('DB integration test - transactions.reqToSql - single valid account - 1 txn 3 xfers', async () => {
const sql = await transactions.reqToSql({query: {'account.id': `${defaultShard}.${defaultRealm}.8`}});
const sql = transactions.reqToSql({query: {'account.id': `${defaultShard}.${defaultRealm}.8`}});
const res = await integrationDbOps.runSqlQuery(sql.query, sql.params);
expect(mapTransactionResults(res.rows)).toEqual([expectedTransactionRowsMap['1052']]);
});

test('DB integration test - transactions.reqToSql - invalid account', async () => {
const sql = await transactions.reqToSql({query: {'account.id': '0.17.666'}});
const sql = transactions.reqToSql({query: {'account.id': '0.17.666'}});
const res = await integrationDbOps.runSqlQuery(sql.query, sql.params);
expect(res.rowCount).toEqual(0);
});
Expand All @@ -310,15 +310,15 @@ test('DB integration test - transactions.reqToSql - null validDurationSeconds an
await addCryptoTransferTransaction(1063, '0.15.5', '0.15.4', 70, null, 777); // null validDurationSeconds
await addCryptoTransferTransaction(1064, '0.15.5', '0.15.4', 70, null, null); // valid validDurationSeconds and maxFee

const sql = await transactions.reqToSql({query: {'account.id': '0.15.5'}});
const sql = transactions.reqToSql({query: {'account.id': '0.15.5'}});
const res = await integrationDbOps.runSqlQuery(sql.query, sql.params);
expect(extractDurationAndMaxFeeFromTransactionResults(res.rows)).toEqual(['null, null', 'null, 777', '5, null']);
});

test('DB integration test - transactions.reqToSql - Unknown transaction result and type', async () => {
await addCryptoTransferTransaction(1070, '0.15.7', '0.15.1', 2, 11, 33, -1, -1);

const sql = await transactions.reqToSql({query: {timestamp: '0.000001070'}});
const sql = transactions.reqToSql({query: {timestamp: '0.000001070'}});
const res = await integrationDbOps.runSqlQuery(sql.query, sql.params);
expect(extractNameAndResultFromTransactionResults(res.rows)).toEqual(['UNKNOWN, UNKNOWN']);
});
Expand Down Expand Up @@ -352,7 +352,7 @@ test('DB integration test - transactions.reqToSql - Account range filtered trans
},
];

const sql = await transactions.reqToSql({query: {'account.id': ['gte:0.15.70', 'lte:0.15.97']}});
const sql = transactions.reqToSql({query: {'account.id': ['gte:0.15.70', 'lte:0.15.97']}});
const res = await integrationDbOps.runSqlQuery(sql.query, sql.params);

// 2 transactions, each with 3 transfers, are applicable. For each transfer negative amount from self, amount to
Expand All @@ -377,7 +377,7 @@ describe('DB integration test - spec based', () => {
const bucketName = 'hedera-demo-streams';
const s3TestDataRoot = path.join(__dirname, 'data', 's3');

let configOverriden = false;
let configOverridden = false;
let configClone;
let s3Ops;

Expand Down Expand Up @@ -495,18 +495,18 @@ describe('DB integration test - spec based', () => {
}

_.merge(config, override);
configOverriden = true;
configOverridden = true;
};

const restoreConfig = () => {
if (configOverriden) {
if (configOverridden) {
Object.assign(config, configClone);
Object.keys(config).forEach((key) => {
if (!(key in configClone)) {
delete config[key];
}
});
configOverriden = false;
configOverridden = false;
}
};

Expand Down
7 changes: 4 additions & 3 deletions hedera-mirror-rest/__tests__/integrationDbOps.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ const {execSync} = require('child_process');
const fs = require('fs');
const log4js = require('log4js');
const path = require('path');
const SqlConnectionPool = require('pg').Pool;
const {GenericContainer} = require('testcontainers');
const {db: dbConfig} = require('../config');
const {isDockerInstalled} = require('./integrationUtils');
const {randomString} = require('../utils');
const {getPoolClass, randomString} = require('../utils');

const logger = log4js.getLogger();

const Pool = getPoolClass();

let oldPool;
let dockerDb;
let sqlConnection;
Expand Down Expand Up @@ -66,7 +67,7 @@ const schemaConfigs = process.env.MIRROR_NODE_SCHEMA === 'v2' ? v2SchemaConfigs

const getConnection = () => {
logger.info(`sqlConnection will use postgresql://${dbConfig.host}:${dbConfig.port}/${dbConfig.name}`);
sqlConnection = new SqlConnectionPool({
sqlConnection = new Pool({
user: dbAdminUser,
host: dbConfig.host,
database: dbConfig.name,
Expand Down
Loading

0 comments on commit 2ca03f9

Please sign in to comment.