Skip to content

Commit

Permalink
Update topicMessage REST response to use transactionId json format (#…
Browse files Browse the repository at this point in the history
…3222)

In v0.49.0 we added transactionId info to the topicMessage chunkInfo response.
Given the nature of the transactionId format a more scalable format should be used to allow for expansion

- Add a `transactionIdViewModel.js` to handle display format logic from Protobuf or db schema
- Update `topicMessageViewModel.js` to use `transactionIdViewModel.js` as a component
- Add a `transactionId.js` model class to dictate transactionId format for use by `transactionIdViewModel`
- Update OpenAPI spec
- Update spec test files
- Update viewmodel test js files

Signed-off-by: Nana-EC <nana.essilfie-conduah@hedera.com>
Signed-off-by: Matheus DallRosa <matheus.dallrosa@swirlds.com>
  • Loading branch information
Nana-EC authored and matheus-dallrosa committed Feb 21, 2022
1 parent 60415fd commit 1629a19
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@
"responseStatus": 200,
"responseJson": {
"chunk_info": {
"initial_transaction_id": {
"account_id": "0.0.3",
"nonce": 1,
"scheduled": true,
"transaction_valid_start": "1234567890.000000000"
},
"number": 2,
"total": 3,
"initial_transaction_id": "0.0.3-1234567890-000000000",
"nonce": 1,
"scheduled": true
"total": 3
},
"consensus_timestamp": "1234567890.000000002",
"message": "bWVzc2FnZQ==",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@
"responseStatus": 200,
"responseJson": {
"chunk_info": {
"initial_transaction_id": "0.0.10-1234567890-000000000",
"nonce": null,
"initial_transaction_id": {
"account_id": "0.0.10",
"nonce": null,
"scheduled": null,
"transaction_valid_start": "1234567890.000000000"
},
"number": 2,
"scheduled": null,
"total": 3
},
"consensus_timestamp": "1234567890.000000002",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@
},
{
"chunk_info": {
"initial_transaction_id": "0.0.3-1234567890-000000000",
"nonce": 1,
"initial_transaction_id": {
"account_id": "0.0.3",
"nonce": 1,
"scheduled": true,
"transaction_valid_start": "1234567890.000000000"
},
"number": 1,
"scheduled": true,
"total": 1
},
"consensus_timestamp": "1234567890.000000002",
Expand All @@ -67,10 +70,13 @@
},
{
"chunk_info": {
"initial_transaction_id": "0.0.10-1234567890-000000000",
"nonce": null,
"initial_transaction_id": {
"account_id": "0.0.10",
"nonce": null,
"scheduled": null,
"transaction_valid_start": "1234567890.000000000"
},
"number": 2,
"scheduled": null,
"total": 3
},
"consensus_timestamp": "1234567890.000000003",
Expand Down
15 changes: 0 additions & 15 deletions hedera-mirror-rest/__tests__/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,6 @@ describe('Utils createTransactionId tests', () => {
});
});

describe('Utils createTransactionIdFromProto tests', () => {
test('Verify correct result for valid input', () => {
const timestamp = Timestamp.create({seconds: 1234567890, nanos: 123});
const accountId = AccountID.create({shardNum: 1, realmNum: 2, accountNum: 3});
const transactionId = TransactionID.create({accountID: accountId, transactionValidStart: timestamp});
expect(utils.createTransactionIdFromProto(transactionId)).toEqual('1.2.3-1234567890-000000123');
});
test('Verify correct result for default input', () => {
const timestamp = Timestamp.create();
const accountId = AccountID.create({accountNum: 0}); //accountNum must be populated
const transactionId = TransactionID.create({accountID: accountId, transactionValidStart: timestamp});
expect(utils.createTransactionIdFromProto(transactionId)).toEqual('0.0.0-0-000000000');
});
});

describe('Utils encodeKey', () => {
test('Null', () => expect(utils.encodeKey(null)).toBe(null));
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ describe('topicMessageViewModel tests', () => {

const expected = buildDefaultTopicMessageViewModel();
expected.chunk_info = {
initial_transaction_id: '0.0.3-1234567890-000000000',
nonce: null,
initial_transaction_id: {
account_id: '0.0.3',
nonce: null,
scheduled: null,
transaction_valid_start: '1234567890.000000000',
},
number: 1,
scheduled: null,
total: 10,
};

Expand All @@ -69,11 +72,14 @@ describe('topicMessageViewModel tests', () => {

const expected = buildDefaultTopicMessageViewModel();
expected.chunk_info = {
initial_transaction_id: '0.0.3-1234567890-000000321',
nonce: 1,
initial_transaction_id: {
account_id: '0.0.3',
nonce: 1,
scheduled: true,
transaction_valid_start: '1234567890.000000321',
},
number: 1,
total: 10,
scheduled: true,
};

expect(actual).toEqual(expected);
Expand Down
32 changes: 19 additions & 13 deletions hedera-mirror-rest/api/v1/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1005,23 +1005,13 @@ components:
nullable: true
properties:
initial_transaction_id:
type: string
nonce:
type: integer
nullable: true
$ref: '#/components/schemas/TransactionId'
number:
example: 1
type: integer
scheduled:
type: boolean
nullable: true
total:
example: 2
type: integer
example:
initial_transaction_id: "0.0.3-1234567890-000000321"
nonce: 2
number: 1
scheduled: true
total: 2
Contract:
type: object
properties:
Expand Down Expand Up @@ -1864,6 +1854,22 @@ components:
- 0.0.8
- 0.0.72
token_id: 0.0.90001
TransactionId:
type: object
properties:
account_id:
$ref: '#/components/schemas/EntityId'
nonce:
example: 0
type: integer
minimum: 0
nullable: true
scheduled:
example: false
type: boolean
nullable: true
transaction_valid_start:
$ref: '#/components/schemas/Timestamp'
Transactions:
type: array
items:
Expand Down
1 change: 1 addition & 0 deletions hedera-mirror-rest/model/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports = {
TokenTransfer: require('./tokenTransfer'),
TopicMessage: require('./topicMessage'),
Transaction: require('./transaction'),
TransactionId: require('./transactionId'),
TransactionResult: require('./transactionResult'),
TransactionType: require('./transactionType'),
};
32 changes: 32 additions & 0 deletions hedera-mirror-rest/model/transactionId.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*-
* ‌
* Hedera Mirror Node
* ​
* Copyright (C) 2019 - 2022 Hedera Hashgraph, LLC
* ​
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ‍
*/

'use strict';

class TransactionId {
constructor(payerAccountId, validStartTimestamp, nonce, scheduled) {
this.payerAccountId = payerAccountId;
this.nonce = nonce;
this.scheduled = scheduled;
this.validStartTimestamp = validStartTimestamp;
}
}

module.exports = TransactionId;
13 changes: 0 additions & 13 deletions hedera-mirror-rest/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -781,18 +781,6 @@ const createTransactionId = (entityStr, validStartTimestamp) => {
return `${entityStr}-${nsToSecNsWithHyphen(validStartTimestamp)}`;
};

/**
* Creates a transactionId from a protobuf TransactionID
* @param {TransactionID} protoTransactionId
* @returns {string} transactionId of format shard.realm.num-sssssssssss-nnnnnnnnn
*/
const createTransactionIdFromProto = (protoTransactionId) => {
const {accountID, transactionValidStart} = protoTransactionId;
const entityStr = EntityId.of(accountID.shardNum, accountID.realmNum, accountID.accountNum).toString();
const timestampString = `${transactionValidStart.seconds}-${transactionValidStart.nanos.toString().padStart(9, '0')}`;
return `${entityStr}-${timestampString}`;
};

/**
* Builds the filters from HTTP request query, validates and parses the filters.
*
Expand Down Expand Up @@ -1109,7 +1097,6 @@ module.exports = {
buildPgSqlObject,
checkTimestampRange,
createTransactionId,
createTransactionIdFromProto,
convertMySqlStyleQueryToPostgres,
encodeBase64,
encodeBinary,
Expand Down
1 change: 1 addition & 0 deletions hedera-mirror-rest/viewmodel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ module.exports = {
NftTransferViewModel: require('./nftTransferViewModel'),
NftViewModel: require('./nftViewModel'),
TopicMessageViewModel: require('./topicMessageViewModel'),
TransactionIdViewModel: require('./transactionIdViewModel'),
};
23 changes: 10 additions & 13 deletions hedera-mirror-rest/viewmodel/topicMessageViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ const _ = require('lodash');

const EntityId = require('../entityId');
const utils = require('../utils');
const TransactionId = require('../model/transactionId');
const {TransactionID} = require('@hashgraph/proto');
const TransactionIdViewModel = require('./transactionIdViewModel');

/**
* Topic message view model
Expand All @@ -50,24 +52,19 @@ class TopicMessageViewModel {

class ChunkInfoViewModel {
constructor(topicMessage) {
let initialTransactionId, nonce, scheduled;
let initialTransactionId;
if (!_.isNil(topicMessage.initialTransactionId)) {
const transactionId = TransactionID.decode(topicMessage.initialTransactionId);
initialTransactionId = utils.createTransactionIdFromProto(transactionId);
nonce = transactionId.nonce;
scheduled = transactionId.scheduled;
initialTransactionId = TransactionID.decode(topicMessage.initialTransactionId);
} else {
initialTransactionId = utils.createTransactionId(
EntityId.parse(topicMessage.payerAccountId).toString(),
topicMessage.validStartTimestamp
initialTransactionId = new TransactionId(
topicMessage.payerAccountId,
topicMessage.validStartTimestamp,
null,
null
);
nonce = null;
scheduled = null;
}
this.initial_transaction_id = initialTransactionId;
this.nonce = nonce;
this.initial_transaction_id = new TransactionIdViewModel(initialTransactionId);
this.number = topicMessage.chunkNum;
this.scheduled = scheduled;
this.total = topicMessage.chunkTotal;
}
}
Expand Down
58 changes: 58 additions & 0 deletions hedera-mirror-rest/viewmodel/transactionIdViewModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*-
* ‌
* Hedera Mirror Node
* ​
* Copyright (C) 2019 - 2022 Hedera Hashgraph, LLC
* ​
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ‍
*/

'use strict';

const _ = require('lodash');

const EntityId = require('../entityId');
const {TransactionID} = require('@hashgraph/proto');
const utils = require('../utils');

/**
* TransactionId view model
*/
class TransactionIdViewModel {
/**
* Constructs transactionId view model from proto transaction id or TransactionId model
*
* @param {TransactionId|TransactionID} transactionId
*/
constructor(transactionId) {
if (transactionId instanceof TransactionID) {
// handle proto format
const {accountID, transactionValidStart, nonce, scheduled} = transactionId;
this.account_id = EntityId.of(accountID.shardNum, accountID.realmNum, accountID.accountNum).toString();
this.nonce = Number(nonce);
this.scheduled = scheduled;
this.transaction_valid_start = `${transactionValidStart.seconds}.${transactionValidStart.nanos
.toString()
.padStart(9, '0')}`;
} else {
// handle db format. Handle nil case for nonce and scheduled
this.account_id = EntityId.parse(transactionId.payerAccountId).toString();
this.nonce = _.isNil(transactionId.nonce) ? null : Number(transactionId.nonce);
this.scheduled = transactionId.scheduled;
this.transaction_valid_start = utils.nsToSecNs(transactionId.validStartTimestamp);
}
}
}

module.exports = TransactionIdViewModel;

0 comments on commit 1629a19

Please sign in to comment.