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

Add receivingChainID request param support to transactions endpoint #1934

4 changes: 0 additions & 4 deletions framework/tests/unit/cacheRedis.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
* Removal or modification of this copyright notice is prohibited.
*
*/
// TODO: mock Redis
// const { redis } = require('redis-mock');
// jest.doMock('redis', () => redis);

const Cache = require('../../src/cacheRedis');

const customMemoryBank = 'memBank';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ const {

const COMMAND_EXECUTION_RESULT_TOPICS = ['transactionID'];

// TODO: Remove when SDK exposes topics information in metadata
const EVENT_TOPIC_MAPPINGS_BY_MODULE = {
[MODULE_NAME_AUTH]: {
[EVENT_NAME_MULTISIGNATURE_REGISTERED]: ['transactionID', 'senderAddress'],
Expand Down
22 changes: 9 additions & 13 deletions services/blockchain-connector/shared/sdk/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const {
getBlockAssetDataSchemaByModule,
getTransactionSchema,
getTransactionParamsSchema,
getDataSchemaByEventName,
getDataSchemaByEvent,
getEventSchema,
} = require('./schema');

Expand Down Expand Up @@ -146,7 +146,7 @@ const formatEvent = (event, skipDecode) => {
if (skipDecode) {
eventData = event.data;
} else {
const eventDataSchema = getDataSchemaByEventName(event.name);
const eventDataSchema = getDataSchemaByEvent(event);
try {
eventData = eventDataSchema
? codec.decodeJSON(eventDataSchema, Buffer.from(event.data, 'hex'))
Expand All @@ -157,13 +157,11 @@ const formatEvent = (event, skipDecode) => {
}

if (!eventDataSchema) {
// TODO: Remove this after SDK exposes all event schemas (before tagging rc.0)
console.error(`Event data schema missing for ${event.module}:${event.name}.`);
logger.error(
`Unable to decode event data. Event data schema missing for ${event.module}:${event.name}.`,
);
} else {
// TODO: Remove after SDK fixes the address format (before tagging rc.0)
// TODO: Remove after SDK fixes the address format (https://github.com/LiskHQ/lisk-sdk/issues/7629)
Object.keys(eventDataSchema.properties).forEach(prop => {
if (prop.endsWith('Address')) {
eventData[prop] = getLisk32Address(eventData[prop].toString('hex'));
Expand All @@ -173,24 +171,22 @@ const formatEvent = (event, skipDecode) => {
}

const eventTopicMappings = EVENT_TOPIC_MAPPINGS_BY_MODULE[event.module] || {};
// TODO: Remove after all transaction types are tested (before tagging rc.0)
if (!(event.module in EVENT_TOPIC_MAPPINGS_BY_MODULE)) {
console.error(`EVENT_TOPIC_MAPPINGS_BY_MODULE missing for module: ${event.module}.`);
console.info(inspect(event));
logger.error(`EVENT_TOPIC_MAPPINGS_BY_MODULE missing for module: ${event.module}.`);
logger.info(inspect(event));
}

const topics =
event.name === EVENT_NAME_COMMAND_EXECUTION_RESULT
? COMMAND_EXECUTION_RESULT_TOPICS
: eventTopicMappings[event.name];

// TODO: Remove after all transaction types are tested (before tagging rc.0)
if (!topics || topics.length === 0) {
console.error(`EVENT_TOPIC_MAPPINGS_BY_MODULE undefined for event: ${event.name}.`);
console.info(inspect(event));
logger.error(`EVENT_TOPIC_MAPPINGS_BY_MODULE undefined for event: ${event.name}.`);
logger.info(inspect(event));
} else if (topics.length !== event.topics.length) {
console.error(`EVENT_TOPIC_MAPPINGS_BY_MODULE defined incorrectly for event: ${event.name}.`);
console.info(inspect(event));
logger.error(`EVENT_TOPIC_MAPPINGS_BY_MODULE defined incorrectly for event: ${event.name}.`);
logger.info(inspect(event));
}

let eventTopics;
Expand Down
24 changes: 12 additions & 12 deletions services/blockchain-connector/shared/sdk/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const { EVENT_NAME_COMMAND_EXECUTION_RESULT } = require('./constants/names');

let schemas;
let metadata;
const eventSchemaLookup = {};

const setSchemas = _schemas => (schemas = _schemas);

Expand Down Expand Up @@ -48,20 +49,19 @@ const getBlockAssetDataSchemaByModule = _module => {
return schema;
};

const getDataSchemaByEventName = eventName => {
if (EVENT_NAME_COMMAND_EXECUTION_RESULT === eventName) return schemas.standardEvent;
const getDataSchemaByEvent = event => {
if (EVENT_NAME_COMMAND_EXECUTION_RESULT === event.name) return schemas.standardEvent;

// TODO: Optimize
for (let i = 0; i < metadata.modules.length; i++) {
const module = metadata.modules[i];

for (let eventIndex = 0; eventIndex < module.events.length; eventIndex++) {
const moduleEvent = module.events[eventIndex];
if (moduleEvent.name === eventName) return module.events[eventIndex].data;
}
// Populate the eventSchemaLookup map with module events if not exists
if (Object.keys(eventSchemaLookup).length === 0) {
metadata.modules.forEach(module => {
module.events.forEach(moduleEvent => {
eventSchemaLookup[`${module.name}_${moduleEvent.name}`] = moduleEvent.data;
});
});
}

return null;
return eventSchemaLookup[`${event.module}_${event.name}`] || null;
};

module.exports = {
Expand All @@ -76,6 +76,6 @@ module.exports = {
getEventSchema,
getTransactionSchema,
getTransactionParamsSchema,
getDataSchemaByEventName,
getDataSchemaByEvent,
getCCMSchema,
};
2 changes: 1 addition & 1 deletion services/blockchain-connector/shared/utils/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const getLisk32AddressFromPublicKey = publicKey =>
const getLisk32AddressFromHexAddress = address =>
getLisk32AddressFromAddress(Buffer.from(address, 'hex'));

// TODO: Remove once SDK returns address in Lisk32 format
// TODO: Remove once SDK returns address in Lisk32 format (https://github.com/LiskHQ/lisk-sdk/issues/7629)
const getLisk32Address = address =>
address.startsWith('lsk') ? address : getLisk32AddressFromHexAddress(address);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const getLSKTokenID = async () => {
};

const getBlockchainApps = async params => {
// TODO: Update implementation when interoperability_getOwnChainAccount is available
const blockchainAppsTable = await getBlockchainAppsTable();

const blockchainAppsInfo = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ const getBlockchainAppsStatistics = async () => {

const reloadBlockchainAppsStats = async () => {
try {
// TODO: Update implementation once interoperability_getOwnChainAccount is available
const blockchainAppsTable = await getBlockchainAppsTable();

const numActivatedChains = await blockchainAppsTable.count({ status: APP_STATUS.ACTIVATED });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const {

const logger = Logger();

const { getCurrentChainID } = require('./interoperability/chain');
const { normalizeTransaction } = require('./transactions');
const { getIndexedAccountInfo } = require('../utils/account');
const { requestConnector } = require('../../utils/request');
Expand Down Expand Up @@ -92,7 +93,18 @@ const validateParams = async params => {
if (params.senderAddress) validatedParams.senderAddress = params.senderAddress;
if (params.recipientAddress) validatedParams.recipientAddress = params.recipientAddress;
if (params.moduleCommand) validatedParams.moduleCommand = params.moduleCommand;
if (params.receivingChainID) validatedParams.receivingChainID = params.receivingChainID;

// If receivingChainID is currentChainID then return all the transactions where receivingChainID = null
if (params.receivingChainID) {
const currentChainID = await getCurrentChainID();

if (params.receivingChainID === currentChainID) {
validatedParams.currentChainTransactions = true;
} else {
validatedParams.receivingChainID = params.receivingChainID;
}
}

if (params.sort) validatedParams.sort = params.sort;

return validatedParams;
Expand Down Expand Up @@ -135,7 +147,8 @@ const getPendingTransactions = async params => {
(!validatedParams.moduleCommand ||
transaction.moduleCommand === validatedParams.moduleCommand) &&
(!validatedParams.receivingChainID ||
transaction.params.receivingChainID === validatedParams.receivingChainID),
transaction.params.receivingChainID === validatedParams.receivingChainID) &&
(!validatedParams.currentChainTransactions || !transaction.params.receivingChainID),
);

pendingTransactions.data = filteredPendingTxs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ const getStakers = async params => {
params = remParams;

const address = getLisk32AddressFromPublicKey(publicKey);
// TODO: Remove once gateway param pairings check is updated
if (params.validatorAddress && params.validatorAddress !== address) return stakersResponse;

params.validatorAddress = address;
stakersResponse.meta.validator.address = params.validatorAddress;
Expand All @@ -75,8 +73,6 @@ const getStakers = async params => {
params = remParams;

const { address } = await getIndexedAccountInfo({ name }, ['address']);
// TODO: Remove once gateway param pairings check is updated
if (params.validatorAddress && params.validatorAddress !== address) return stakersResponse;

params.validatorAddress = address;
stakersResponse.meta.validator.name = name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const verifyIfPunished = async validator => {
const latestBlockString = await lastBlockCache.get(LAST_BLOCK_KEY);
const latestBlock = latestBlockString ? JSON.parse(latestBlockString) : {};

// TODO: Get this information from SDK directly once available
const isPunished = validator.reportMisbehaviorHeights.some(
reportMisbehaviorHeight =>
reportMisbehaviorHeight.start <= latestBlock.height &&
Expand All @@ -47,9 +46,6 @@ const getPosValidators = async params => {
validatorAddressList,
async validatorAddress => {
const validator = await requestConnector('getPosValidator', { address: validatorAddress });
// TODO: Add error handling
// TODO: Verify
// TODO: Check if it is possible to move this logic to the connector
if (validator.isBanned || (await verifyIfPunished(validator))) {
validator.validatorWeight = BigInt('0');
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const {
const { getBlockByID } = require('./blocks');
const { getEventsByHeight } = require('./events');

const { getCurrentChainID } = require('./interoperability/chain');
const { getIndexedAccountInfo } = require('../utils/account');
const { requestConnector } = require('../../utils/request');
const { normalizeRangeParam } = require('../../utils/param');
Expand Down Expand Up @@ -88,6 +89,15 @@ const validateParams = async params => {
);
}

// If recieving chainID is current chain ID then return all transactions with receivingChainID = null
if (params.receivingChainID) {
const currentChainID = await getCurrentChainID();

if (params.receivingChainID === currentChainID) {
params.receivingChainID = null;
}
}

if (params.executionStatus) {
const { executionStatus, ...remParams } = params;
params = remParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const getGenerators = async params => {
const generatorsList = await business.getGenerators();
const validatorList = await getAllValidators();

// TODO: Optimize. Generate the map with every 'chain_*' event and maintain in the memory
const validatorMap = new Map(validatorList.map(validator => [validator.address, validator]));
generatorsList.forEach(generator => {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,6 @@ const getPosValidators = async params => {
return parseToJSONCompatObj(validators);
};

// TODO: Test
// Keep the validator cache up-to-date
const updateValidatorListEveryBlock = () => {
const EVENT_NEW_BLOCK = 'newBlock';
Expand All @@ -271,15 +270,13 @@ const updateValidatorListEveryBlock = () => {
if ([COMMAND.REGISTER_VALIDATOR, COMMAND.CHANGE_COMMISSION].includes(tx.command)) {
updatedValidatorAddresses.push(getLisk32AddressFromPublicKey(tx.senderPublicKey));
} else if (tx.command === COMMAND.STAKE) {
// TODO: Verify
tx.params.stakes.forEach(stake =>
updatedValidatorAddresses.push(stake.validatorAddress),
);
}
}
});

// TODO: Validate the logic if there is need to update validator cache on (un-)stake tx
if (updatedValidatorAddresses.length) {
const updatedValidatorAccounts = await business.getPosValidators({
addresses: updatedValidatorAddresses,
Expand Down Expand Up @@ -317,7 +314,6 @@ const updateValidatorListEveryBlock = () => {
validatorList[validatorIndex] &&
Object.getOwnPropertyNames(validatorList[validatorIndex]).length
) {
// TODO: Update
if (
validatorList[validatorIndex].generatedBlocks &&
validatorList[validatorIndex].rewards
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const {
mockRecipientAddress,
} = require('../../constants/pendingTransactions');

const {
getCurrentChainID,
} = require('../../../../../shared/dataService/business/interoperability/chain');

jest.mock('lisk-service-framework', () => {
const actual = jest.requireActual('lisk-service-framework');
return {
Expand Down Expand Up @@ -51,6 +55,10 @@ jest.mock('../../../../../shared/dataService/utils/account', () => ({
getIndexedAccountInfo: jest.fn(() => mockSenderAccountDetails),
}));

jest.mock('../../../../../shared/dataService/business/interoperability/chain', () => ({
getCurrentChainID: jest.fn(),
}));

const {
validateParams,
loadAllPendingTransactions,
Expand Down Expand Up @@ -88,6 +96,10 @@ describe('Test getPendingTransactions method', () => {
await loadAllPendingTransactions();
});

beforeEach(async () => {
jest.resetModules();
});

it('should return all pending transactions without any filters', async () => {
const params = {
sort: 'id:asc',
Expand Down Expand Up @@ -131,14 +143,16 @@ describe('Test getPendingTransactions method', () => {
expect(result.data.length).toBe(txCountWithParams);
});

it('should return pending transactions with receivingChainID', async () => {
it('should return pending transactions with receivingChainID and receivingChainID is not currentChainID', async () => {
const params = {
receivingChainID: '02000000',
sort: 'id:asc',
offset: 0,
limit: 10,
};

getCurrentChainID.mockResolvedValue('02000001');

const result = await getPendingTransactions(params);

let txCountWithParams = 0;
Expand All @@ -151,6 +165,28 @@ describe('Test getPendingTransactions method', () => {
expect(result.data.length).toBe(txCountWithParams);
});

it('should return pending transactions with receivingChainID and receivingChainID is currentChainID', async () => {
const params = {
receivingChainID: '02000000',
sort: 'id:asc',
offset: 0,
limit: 10,
};

getCurrentChainID.mockResolvedValue('02000000');

const result = await getPendingTransactions(params);

let txCountWithParams = 0;
mockPendingTransactions.forEach(transaction => {
if (transaction.params && !transaction.params.receivingChainID) {
txCountWithParams++;
}
});

expect(result.data.length).toBe(txCountWithParams);
});

it('should throw ValidationException for invalid parameters', async () => {
const params = {
nonce: 123,
Expand Down
4 changes: 2 additions & 2 deletions services/gateway/apis/http-exports/swagger/responses.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"responses": {
"badParameter": {
"400": {
"description": "Bad request",
"schema": {
"$ref": "#/definitions/badRequest"
}
},
"notFound": {
"404": {
"description": "Not found",
"schema": {
"$ref": "#/definitions/notFound"
Expand Down
Loading