From a0978cdb2c90ed69865f750bae8a68d288b50ed3 Mon Sep 17 00:00:00 2001 From: Ishan Tiwari Date: Mon, 25 Jul 2022 19:49:26 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20Return=20JSON=20format?= =?UTF-8?q?=20results=20from=20endpoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interoperability/mainchain/endpoint.ts | 128 +++++++++-- .../interoperability/sidechain/endpoint.ts | 128 +++++++++-- .../src/modules/interoperability/types.ts | 57 +++++ .../mainchain/endpoint.spec.ts | 209 +++++++++++++++--- .../sidechain/endpoint.spec.ts | 209 +++++++++++++++--- 5 files changed, 641 insertions(+), 90 deletions(-) diff --git a/framework/src/modules/interoperability/mainchain/endpoint.ts b/framework/src/modules/interoperability/mainchain/endpoint.ts index 8476af20b96..1eccbc28821 100644 --- a/framework/src/modules/interoperability/mainchain/endpoint.ts +++ b/framework/src/modules/interoperability/mainchain/endpoint.ts @@ -14,7 +14,19 @@ import { BaseEndpoint } from '../../base_endpoint'; import { MainchainInteroperabilityStore } from './store'; -import { ImmutableStoreCallback, StoreCallback } from '../types'; +import { + ChainAccountJSON, + ChannelDataJSON, + ImmutableStoreCallback, + InboxJSON, + LastCertificateJSON, + MessageFeeTokenIDJSON, + OutboxJSON, + OwnChainAccountJSON, + StoreCallback, + TerminatedOutboxAccountJSON, + TerminatedStateAccountJSON, +} from '../types'; import { BaseInteroperableAPI } from '../base_interoperable_api'; import { ModuleEndpointContext } from '../../../types'; @@ -26,43 +38,119 @@ export class MainchainInteroperabilityEndpoint extends BaseEndpoint { this.interoperableCCAPIs = interoperableCCAPIs; } - public async getChainAccount(context: ModuleEndpointContext, chainID: Buffer) { + public async getChainAccount( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getChainAccount(chainID); - - return result; + const { + lastCertificate, + name, + networkID, + status, + } = await interoperabilityStore.getChainAccount(chainID); + + const lastCertificateJSON: LastCertificateJSON = { + height: lastCertificate.height, + timestamp: lastCertificate.timestamp, + stateRoot: lastCertificate.stateRoot.toString('hex'), + validatorsHash: lastCertificate.validatorsHash.toString('hex'), + }; + + return { + lastCertificate: lastCertificateJSON, + name, + status, + networkID: networkID.toString('hex'), + }; } - public async getChannel(context: ModuleEndpointContext, chainID: Buffer) { + public async getChannel( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getChannel(chainID); - - return result; + const { + inbox, + messageFeeTokenID, + outbox, + partnerChainOutboxRoot, + } = await interoperabilityStore.getChannel(chainID); + + const inboxJSON: InboxJSON = { + appendPath: inbox.appendPath.map(ap => ap.toString('hex')), + root: inbox.root.toString('hex'), + size: inbox.size, + }; + + const outboxJSON: OutboxJSON = { + appendPath: outbox.appendPath.map(ap => ap.toString('hex')), + root: outbox.root.toString('hex'), + size: outbox.size, + }; + + const messageFeeTokenIDJSON: MessageFeeTokenIDJSON = { + chainID: messageFeeTokenID.chainID.toString('hex'), + localID: messageFeeTokenID.localID.toString('hex'), + }; + + return { + messageFeeTokenID: messageFeeTokenIDJSON, + outbox: outboxJSON, + inbox: inboxJSON, + partnerChainOutboxRoot: partnerChainOutboxRoot.toString('hex'), + }; } - public async getOwnChainAccount(context: ModuleEndpointContext) { + public async getOwnChainAccount(context: ModuleEndpointContext): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getOwnChainAccount(); + const { id, name, nonce } = await interoperabilityStore.getOwnChainAccount(); - return result; + return { + id: id.toString('hex'), + name, + nonce: nonce.toString(), + }; } - public async getTerminatedStateAccount(context: ModuleEndpointContext, chainID: Buffer) { + public async getTerminatedStateAccount( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getTerminatedStateAccount(chainID); - - return result; + const { + stateRoot, + initialized, + mainchainStateRoot, + } = await interoperabilityStore.getTerminatedStateAccount(chainID); + + return { + stateRoot: stateRoot.toString('hex'), + initialized, + mainchainStateRoot: mainchainStateRoot?.toString('hex'), + }; } - public async getTerminatedOutboxAccount(context: ModuleEndpointContext, chainID: Buffer) { + public async getTerminatedOutboxAccount( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getTerminatedOutboxAccount(chainID); - - return result; + const { + outboxRoot, + outboxSize, + partnerChainInboxSize, + } = await interoperabilityStore.getTerminatedOutboxAccount(chainID); + + return { + outboxRoot: outboxRoot.toString('hex'), + outboxSize, + partnerChainInboxSize, + }; } protected getInteroperabilityStore( diff --git a/framework/src/modules/interoperability/sidechain/endpoint.ts b/framework/src/modules/interoperability/sidechain/endpoint.ts index a85e9d3230d..2b42561c6a0 100644 --- a/framework/src/modules/interoperability/sidechain/endpoint.ts +++ b/framework/src/modules/interoperability/sidechain/endpoint.ts @@ -14,7 +14,19 @@ import { BaseEndpoint } from '../../base_endpoint'; import { SidechainInteroperabilityStore } from './store'; -import { ImmutableStoreCallback, StoreCallback } from '../types'; +import { + ChainAccountJSON, + ChannelDataJSON, + ImmutableStoreCallback, + InboxJSON, + LastCertificateJSON, + MessageFeeTokenIDJSON, + OutboxJSON, + OwnChainAccountJSON, + StoreCallback, + TerminatedOutboxAccountJSON, + TerminatedStateAccountJSON, +} from '../types'; import { BaseInteroperableAPI } from '../base_interoperable_api'; import { ModuleEndpointContext } from '../../../types'; @@ -26,43 +38,119 @@ export class SidechainInteroperabilityEndpoint extends BaseEndpoint { this.interoperableCCAPIs = interoperableCCAPIs; } - public async getChainAccount(context: ModuleEndpointContext, chainID: Buffer) { + public async getChainAccount( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getChainAccount(chainID); - - return result; + const { + lastCertificate, + name, + networkID, + status, + } = await interoperabilityStore.getChainAccount(chainID); + + const lastCertificateJSON: LastCertificateJSON = { + height: lastCertificate.height, + timestamp: lastCertificate.timestamp, + stateRoot: lastCertificate.stateRoot.toString('hex'), + validatorsHash: lastCertificate.validatorsHash.toString('hex'), + }; + + return { + lastCertificate: lastCertificateJSON, + name, + status, + networkID: networkID.toString('hex'), + }; } - public async getChannel(context: ModuleEndpointContext, chainID: Buffer) { + public async getChannel( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getChannel(chainID); - - return result; + const { + inbox, + messageFeeTokenID, + outbox, + partnerChainOutboxRoot, + } = await interoperabilityStore.getChannel(chainID); + + const inboxJSON: InboxJSON = { + appendPath: inbox.appendPath.map(ap => ap.toString('hex')), + root: inbox.root.toString('hex'), + size: inbox.size, + }; + + const outboxJSON: OutboxJSON = { + appendPath: outbox.appendPath.map(ap => ap.toString('hex')), + root: outbox.root.toString('hex'), + size: outbox.size, + }; + + const messageFeeTokenIDJSON: MessageFeeTokenIDJSON = { + chainID: messageFeeTokenID.chainID.toString('hex'), + localID: messageFeeTokenID.localID.toString('hex'), + }; + + return { + messageFeeTokenID: messageFeeTokenIDJSON, + outbox: outboxJSON, + inbox: inboxJSON, + partnerChainOutboxRoot: partnerChainOutboxRoot.toString('hex'), + }; } - public async getOwnChainAccount(context: ModuleEndpointContext) { + public async getOwnChainAccount(context: ModuleEndpointContext): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getOwnChainAccount(); + const { id, name, nonce } = await interoperabilityStore.getOwnChainAccount(); - return result; + return { + id: id.toString('hex'), + name, + nonce: nonce.toString(), + }; } - public async getTerminatedStateAccount(context: ModuleEndpointContext, chainID: Buffer) { + public async getTerminatedStateAccount( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getTerminatedStateAccount(chainID); - - return result; + const { + stateRoot, + initialized, + mainchainStateRoot, + } = await interoperabilityStore.getTerminatedStateAccount(chainID); + + return { + stateRoot: stateRoot.toString('hex'), + initialized, + mainchainStateRoot: mainchainStateRoot?.toString('hex'), + }; } - public async getTerminatedOutboxAccount(context: ModuleEndpointContext, chainID: Buffer) { + public async getTerminatedOutboxAccount( + context: ModuleEndpointContext, + chainID: Buffer, + ): Promise { const interoperabilityStore = this.getInteroperabilityStore(context.getStore); - const result = await interoperabilityStore.getTerminatedOutboxAccount(chainID); - - return result; + const { + outboxRoot, + outboxSize, + partnerChainInboxSize, + } = await interoperabilityStore.getTerminatedOutboxAccount(chainID); + + return { + outboxRoot: outboxRoot.toString('hex'), + outboxSize, + partnerChainInboxSize, + }; } protected getInteroperabilityStore( diff --git a/framework/src/modules/interoperability/types.ts b/framework/src/modules/interoperability/types.ts index 143853c74db..fb2881ef489 100644 --- a/framework/src/modules/interoperability/types.ts +++ b/framework/src/modules/interoperability/types.ts @@ -144,6 +144,13 @@ export interface LastCertificate { validatorsHash: Buffer; } +export interface LastCertificateJSON { + height: number; + timestamp: number; + stateRoot: string; + validatorsHash: string; +} + export interface ChainAccount { name: string; networkID: Buffer; @@ -151,28 +158,59 @@ export interface ChainAccount { status: number; } +export interface ChainAccountJSON { + name: string; + networkID: string; + lastCertificate: LastCertificateJSON; + status: number; +} + export interface OwnChainAccount { name: string; id: Buffer; nonce: bigint; } +export interface OwnChainAccountJSON { + name: string; + id: string; + nonce: string; +} + export interface Inbox { appendPath: Buffer[]; size: number; root: Buffer; } +export interface InboxJSON { + appendPath: string[]; + size: number; + root: string; +} + export interface Outbox { appendPath: Buffer[]; size: number; root: Buffer; } +export interface OutboxJSON { + appendPath: string[]; + size: number; + root: string; +} + export interface MessageFeeTokenID { chainID: Buffer; localID: Buffer; } + +export interface MessageFeeTokenIDJSON { + chainID: string; + localID: string; +} + export interface ChannelData { inbox: Inbox; outbox: Outbox; @@ -180,12 +218,25 @@ export interface ChannelData { messageFeeTokenID: MessageFeeTokenID; } +export interface ChannelDataJSON { + inbox: InboxJSON; + outbox: OutboxJSON; + partnerChainOutboxRoot: string; + messageFeeTokenID: MessageFeeTokenIDJSON; +} + export interface TerminatedStateAccount { stateRoot: Buffer; mainchainStateRoot?: Buffer; initialized?: boolean; } +export interface TerminatedStateAccountJSON { + stateRoot: string; + mainchainStateRoot?: string; + initialized?: boolean; +} + export interface CCCommandExecuteContext { logger: Logger; networkIdentifier: Buffer; @@ -246,6 +297,12 @@ export interface TerminatedOutboxAccount { partnerChainInboxSize: number; } +export interface TerminatedOutboxAccountJSON { + outboxRoot: string; + outboxSize: number; + partnerChainInboxSize: number; +} + export interface MessageRecoveryParams { chainID: Buffer; crossChainMessages: Buffer[]; diff --git a/framework/test/unit/modules/interoperability/mainchain/endpoint.spec.ts b/framework/test/unit/modules/interoperability/mainchain/endpoint.spec.ts index 00388662cbe..b7a9b1036cf 100644 --- a/framework/test/unit/modules/interoperability/mainchain/endpoint.spec.ts +++ b/framework/test/unit/modules/interoperability/mainchain/endpoint.spec.ts @@ -13,8 +13,21 @@ */ import { utils } from '@liskhq/lisk-cryptography'; +import { intToBuffer } from '@liskhq/lisk-cryptography/dist-node/utils'; import { MainchainInteroperabilityEndpoint } from '../../../../../src/modules/interoperability/mainchain/endpoint'; import { MainchainInteroperabilityStore } from '../../../../../src/modules/interoperability/mainchain/store'; +import { + ChainAccount, + ChainAccountJSON, + ChannelData, + ChannelDataJSON, + OwnChainAccount, + OwnChainAccountJSON, + TerminatedOutboxAccount, + TerminatedOutboxAccountJSON, + TerminatedStateAccount, + TerminatedStateAccountJSON, +} from '../../../../../src/modules/interoperability/types'; describe('Mainchain endpoint', () => { const moduleID = utils.intToBuffer(1, 4); @@ -29,6 +42,103 @@ describe('Mainchain endpoint', () => { params: {}, logger: {} as any, }; + + const chainAccount: ChainAccount = { + lastCertificate: { + height: 100, + stateRoot: utils.getRandomBytes(32), + timestamp: Date.now(), + validatorsHash: utils.getRandomBytes(32), + }, + name: 'nft', + networkID: utils.getRandomBytes(32), + status: 1, + }; + + const chainAccountJSON: ChainAccountJSON = { + lastCertificate: { + height: chainAccount.lastCertificate.height, + stateRoot: chainAccount.lastCertificate.stateRoot.toString('hex'), + timestamp: chainAccount.lastCertificate.timestamp, + validatorsHash: chainAccount.lastCertificate.validatorsHash.toString('hex'), + }, + name: chainAccount.name, + networkID: chainAccount.networkID.toString('hex'), + status: chainAccount.status, + }; + + const channelData: ChannelData = { + inbox: { + appendPath: [], + root: utils.getRandomBytes(32), + size: 10, + }, + messageFeeTokenID: { + chainID: intToBuffer(0, 4), + localID: intToBuffer(1, 4), + }, + outbox: { + appendPath: [], + root: utils.getRandomBytes(32), + size: 10, + }, + partnerChainOutboxRoot: utils.getRandomBytes(32), + }; + + const channelDataJSON: ChannelDataJSON = { + inbox: { + appendPath: channelData.inbox.appendPath.map(ap => ap.toString('hex')), + root: channelData.inbox.root.toString('hex'), + size: channelData.inbox.size, + }, + messageFeeTokenID: { + chainID: channelData.messageFeeTokenID.chainID.toString('hex'), + localID: channelData.messageFeeTokenID.localID.toString('hex'), + }, + outbox: { + appendPath: channelData.outbox.appendPath.map(ap => ap.toString('hex')), + root: channelData.outbox.root.toString('hex'), + size: channelData.outbox.size, + }, + partnerChainOutboxRoot: channelData.partnerChainOutboxRoot.toString('hex'), + }; + + const terminateStateAccount: TerminatedStateAccount = { + stateRoot: utils.getRandomBytes(32), + initialized: true, + mainchainStateRoot: utils.getRandomBytes(32), + }; + + const terminateStateAccountJSON: TerminatedStateAccountJSON = { + stateRoot: terminateStateAccount.stateRoot.toString('hex'), + initialized: terminateStateAccount.initialized, + mainchainStateRoot: terminateStateAccount.mainchainStateRoot?.toString('hex'), + }; + + const terminatedOutboxAccount: TerminatedOutboxAccount = { + outboxRoot: utils.getRandomBytes(32), + outboxSize: 10, + partnerChainInboxSize: 10, + }; + + const terminatedOutboxAccountJSON: TerminatedOutboxAccountJSON = { + outboxRoot: terminatedOutboxAccount.outboxRoot.toString('hex'), + outboxSize: terminatedOutboxAccount.outboxSize, + partnerChainInboxSize: terminatedOutboxAccount.partnerChainInboxSize, + }; + + const ownChainAccount: OwnChainAccount = { + id: intToBuffer(1, 4), + name: 'main', + nonce: BigInt(10), + }; + + const ownChainAccountJSON: OwnChainAccountJSON = { + id: ownChainAccount.id.toString('hex'), + name: ownChainAccount.name, + nonce: ownChainAccount.nonce.toString(), + }; + let mainchainInteroperabilityEndpoint: MainchainInteroperabilityEndpoint; let mainchainInteroperabilityStore = new MainchainInteroperabilityStore( moduleID, @@ -49,92 +159,141 @@ describe('Mainchain endpoint', () => { jest .spyOn(mainchainInteroperabilityEndpoint as any, 'getInteroperabilityStore') .mockReturnValue(mainchainInteroperabilityStore); - jest.spyOn(mainchainInteroperabilityStore, 'getChainAccount'); - jest.spyOn(mainchainInteroperabilityStore, 'getChannel'); - jest.spyOn(mainchainInteroperabilityStore, 'getOwnChainAccount'); - jest.spyOn(mainchainInteroperabilityStore, 'getTerminatedStateAccount'); - jest.spyOn(mainchainInteroperabilityStore, 'getTerminatedOutboxAccount'); + jest.spyOn(mainchainInteroperabilityStore, 'getChainAccount').mockResolvedValue(chainAccount); + jest.spyOn(mainchainInteroperabilityStore, 'getChannel').mockResolvedValue(channelData); + jest + .spyOn(mainchainInteroperabilityStore, 'getOwnChainAccount') + .mockResolvedValue(ownChainAccount); + jest + .spyOn(mainchainInteroperabilityStore, 'getTerminatedStateAccount') + .mockResolvedValue(terminateStateAccount); + jest + .spyOn(mainchainInteroperabilityStore, 'getTerminatedOutboxAccount') + .mockResolvedValue(terminatedOutboxAccount); }); describe('getChainAccount', () => { - it('should call getInteroperabilityStore', async () => { - await mainchainInteroperabilityEndpoint.getChainAccount(moduleContext, chainID); + let chainAccountResult: ChainAccountJSON; + beforeEach(async () => { + chainAccountResult = await mainchainInteroperabilityEndpoint.getChainAccount( + moduleContext, + chainID, + ); + }); + it('should call getInteroperabilityStore', async () => { expect(mainchainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getChainAccount', async () => { - await mainchainInteroperabilityEndpoint.getChainAccount(moduleContext, chainID); - expect(mainchainInteroperabilityStore.getChainAccount).toHaveBeenCalledWith(chainID); }); + + it('should return JSON format result', () => { + expect(chainAccountResult).toEqual(chainAccountJSON); + }); }); describe('getChannel', () => { - it('should call getInteroperabilityStore', async () => { - await mainchainInteroperabilityEndpoint.getChannel(moduleContext, chainID); + let channelDataResult: ChannelDataJSON; + beforeEach(async () => { + channelDataResult = await mainchainInteroperabilityEndpoint.getChannel( + moduleContext, + chainID, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(mainchainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getChannel', async () => { - await mainchainInteroperabilityEndpoint.getChannel(moduleContext, chainID); - expect(mainchainInteroperabilityStore.getChannel).toHaveBeenCalledWith(chainID); }); + + it('should return JSON format result', () => { + expect(channelDataResult).toEqual(channelDataJSON); + }); }); describe('getOwnChainAccount', () => { - it('should call getInteroperabilityStore', async () => { - await mainchainInteroperabilityEndpoint.getOwnChainAccount(moduleContext); + let ownChainAccountResult: OwnChainAccountJSON; + beforeEach(async () => { + ownChainAccountResult = await mainchainInteroperabilityEndpoint.getOwnChainAccount( + moduleContext, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(mainchainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getOwnChainAccount', async () => { - await mainchainInteroperabilityEndpoint.getOwnChainAccount(moduleContext); - expect(mainchainInteroperabilityStore.getOwnChainAccount).toHaveBeenCalled(); }); + + it('should return JSON format result', () => { + expect(ownChainAccountResult).toEqual(ownChainAccountJSON); + }); }); describe('getTerminatedStateAccount', () => { - it('should call getInteroperabilityStore', async () => { - await mainchainInteroperabilityEndpoint.getTerminatedStateAccount(moduleContext, chainID); + let terminateStateAccountResult: TerminatedStateAccountJSON; + beforeEach(async () => { + terminateStateAccountResult = await mainchainInteroperabilityEndpoint.getTerminatedStateAccount( + moduleContext, + chainID, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(mainchainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getTerminatedStateAccount', async () => { - await mainchainInteroperabilityEndpoint.getTerminatedStateAccount(moduleContext, chainID); - expect(mainchainInteroperabilityStore.getTerminatedStateAccount).toHaveBeenCalled(); }); + + it('should return JSON format result', () => { + expect(terminateStateAccountResult).toEqual(terminateStateAccountJSON); + }); }); describe('getTerminatedOutboxAccount', () => { - it('should call getInteroperabilityStore', async () => { - await mainchainInteroperabilityEndpoint.getTerminatedOutboxAccount(moduleContext, chainID); + let terminatedOutboxAccountResult: TerminatedOutboxAccountJSON; + beforeEach(async () => { + terminatedOutboxAccountResult = await mainchainInteroperabilityEndpoint.getTerminatedOutboxAccount( + moduleContext, + chainID, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(mainchainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getTerminatedStateAccount', async () => { - await mainchainInteroperabilityEndpoint.getTerminatedOutboxAccount(moduleContext, chainID); - expect(mainchainInteroperabilityStore.getTerminatedOutboxAccount).toHaveBeenCalledWith( chainID, ); }); + + it('should return JSON format result', () => { + expect(terminatedOutboxAccountResult).toEqual(terminatedOutboxAccountJSON); + }); }); }); diff --git a/framework/test/unit/modules/interoperability/sidechain/endpoint.spec.ts b/framework/test/unit/modules/interoperability/sidechain/endpoint.spec.ts index 041c569f54c..6ac92a1e9dc 100644 --- a/framework/test/unit/modules/interoperability/sidechain/endpoint.spec.ts +++ b/framework/test/unit/modules/interoperability/sidechain/endpoint.spec.ts @@ -13,8 +13,21 @@ */ import { utils } from '@liskhq/lisk-cryptography'; +import { intToBuffer } from '@liskhq/lisk-cryptography/dist-node/utils'; import { SidechainInteroperabilityEndpoint } from '../../../../../src/modules/interoperability/sidechain/endpoint'; import { SidechainInteroperabilityStore } from '../../../../../src/modules/interoperability/sidechain/store'; +import { + ChainAccount, + ChainAccountJSON, + ChannelData, + ChannelDataJSON, + OwnChainAccount, + OwnChainAccountJSON, + TerminatedOutboxAccount, + TerminatedOutboxAccountJSON, + TerminatedStateAccount, + TerminatedStateAccountJSON, +} from '../../../../../src/modules/interoperability/types'; describe('Sidechain endpoint', () => { const moduleID = utils.intToBuffer(1, 4); @@ -29,6 +42,103 @@ describe('Sidechain endpoint', () => { params: {}, logger: {} as any, }; + + const chainAccount: ChainAccount = { + lastCertificate: { + height: 100, + stateRoot: utils.getRandomBytes(32), + timestamp: Date.now(), + validatorsHash: utils.getRandomBytes(32), + }, + name: 'nft', + networkID: utils.getRandomBytes(32), + status: 1, + }; + + const chainAccountJSON: ChainAccountJSON = { + lastCertificate: { + height: chainAccount.lastCertificate.height, + stateRoot: chainAccount.lastCertificate.stateRoot.toString('hex'), + timestamp: chainAccount.lastCertificate.timestamp, + validatorsHash: chainAccount.lastCertificate.validatorsHash.toString('hex'), + }, + name: chainAccount.name, + networkID: chainAccount.networkID.toString('hex'), + status: chainAccount.status, + }; + + const channelData: ChannelData = { + inbox: { + appendPath: [], + root: utils.getRandomBytes(32), + size: 10, + }, + messageFeeTokenID: { + chainID: intToBuffer(0, 4), + localID: intToBuffer(1, 4), + }, + outbox: { + appendPath: [], + root: utils.getRandomBytes(32), + size: 10, + }, + partnerChainOutboxRoot: utils.getRandomBytes(32), + }; + + const channelDataJSON: ChannelDataJSON = { + inbox: { + appendPath: channelData.inbox.appendPath.map(ap => ap.toString('hex')), + root: channelData.inbox.root.toString('hex'), + size: channelData.inbox.size, + }, + messageFeeTokenID: { + chainID: channelData.messageFeeTokenID.chainID.toString('hex'), + localID: channelData.messageFeeTokenID.localID.toString('hex'), + }, + outbox: { + appendPath: channelData.outbox.appendPath.map(ap => ap.toString('hex')), + root: channelData.outbox.root.toString('hex'), + size: channelData.outbox.size, + }, + partnerChainOutboxRoot: channelData.partnerChainOutboxRoot.toString('hex'), + }; + + const terminateStateAccount: TerminatedStateAccount = { + stateRoot: utils.getRandomBytes(32), + initialized: true, + mainchainStateRoot: utils.getRandomBytes(32), + }; + + const terminateStateAccountJSON: TerminatedStateAccountJSON = { + stateRoot: terminateStateAccount.stateRoot.toString('hex'), + initialized: terminateStateAccount.initialized, + mainchainStateRoot: terminateStateAccount.mainchainStateRoot?.toString('hex'), + }; + + const terminatedOutboxAccount: TerminatedOutboxAccount = { + outboxRoot: utils.getRandomBytes(32), + outboxSize: 10, + partnerChainInboxSize: 10, + }; + + const terminatedOutboxAccountJSON: TerminatedOutboxAccountJSON = { + outboxRoot: terminatedOutboxAccount.outboxRoot.toString('hex'), + outboxSize: terminatedOutboxAccount.outboxSize, + partnerChainInboxSize: terminatedOutboxAccount.partnerChainInboxSize, + }; + + const ownChainAccount: OwnChainAccount = { + id: intToBuffer(1, 4), + name: 'main', + nonce: BigInt(10), + }; + + const ownChainAccountJSON: OwnChainAccountJSON = { + id: ownChainAccount.id.toString('hex'), + name: ownChainAccount.name, + nonce: ownChainAccount.nonce.toString(), + }; + let sidechainInteroperabilityEndpoint: SidechainInteroperabilityEndpoint; let sidechainInteroperabilityStore = new SidechainInteroperabilityStore( moduleID, @@ -49,92 +159,141 @@ describe('Sidechain endpoint', () => { jest .spyOn(sidechainInteroperabilityEndpoint as any, 'getInteroperabilityStore') .mockReturnValue(sidechainInteroperabilityStore); - jest.spyOn(sidechainInteroperabilityStore, 'getChainAccount'); - jest.spyOn(sidechainInteroperabilityStore, 'getChannel'); - jest.spyOn(sidechainInteroperabilityStore, 'getOwnChainAccount'); - jest.spyOn(sidechainInteroperabilityStore, 'getTerminatedStateAccount'); - jest.spyOn(sidechainInteroperabilityStore, 'getTerminatedOutboxAccount'); + jest.spyOn(sidechainInteroperabilityStore, 'getChainAccount').mockResolvedValue(chainAccount); + jest.spyOn(sidechainInteroperabilityStore, 'getChannel').mockResolvedValue(channelData); + jest + .spyOn(sidechainInteroperabilityStore, 'getOwnChainAccount') + .mockResolvedValue(ownChainAccount); + jest + .spyOn(sidechainInteroperabilityStore, 'getTerminatedStateAccount') + .mockResolvedValue(terminateStateAccount); + jest + .spyOn(sidechainInteroperabilityStore, 'getTerminatedOutboxAccount') + .mockResolvedValue(terminatedOutboxAccount); }); describe('getChainAccount', () => { - it('should call getInteroperabilityStore', async () => { - await sidechainInteroperabilityEndpoint.getChainAccount(moduleContext, chainID); + let chainAccountResult: ChainAccountJSON; + beforeEach(async () => { + chainAccountResult = await sidechainInteroperabilityEndpoint.getChainAccount( + moduleContext, + chainID, + ); + }); + it('should call getInteroperabilityStore', async () => { expect(sidechainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getChainAccount', async () => { - await sidechainInteroperabilityEndpoint.getChainAccount(moduleContext, chainID); - expect(sidechainInteroperabilityStore.getChainAccount).toHaveBeenCalledWith(chainID); }); + + it('should return JSON format result', () => { + expect(chainAccountResult).toEqual(chainAccountJSON); + }); }); describe('getChannel', () => { - it('should call getInteroperabilityStore', async () => { - await sidechainInteroperabilityEndpoint.getChannel(moduleContext, chainID); + let channelDataResult: ChannelDataJSON; + beforeEach(async () => { + channelDataResult = await sidechainInteroperabilityEndpoint.getChannel( + moduleContext, + chainID, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(sidechainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getChannel', async () => { - await sidechainInteroperabilityEndpoint.getChannel(moduleContext, chainID); - expect(sidechainInteroperabilityStore.getChannel).toHaveBeenCalledWith(chainID); }); + + it('should return JSON format result', () => { + expect(channelDataResult).toEqual(channelDataJSON); + }); }); describe('getOwnChainAccount', () => { - it('should call getInteroperabilityStore', async () => { - await sidechainInteroperabilityEndpoint.getOwnChainAccount(moduleContext); + let ownChainAccountResult: OwnChainAccountJSON; + beforeEach(async () => { + ownChainAccountResult = await sidechainInteroperabilityEndpoint.getOwnChainAccount( + moduleContext, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(sidechainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getOwnChainAccount', async () => { - await sidechainInteroperabilityEndpoint.getOwnChainAccount(moduleContext); - expect(sidechainInteroperabilityStore.getOwnChainAccount).toHaveBeenCalled(); }); + + it('should return JSON format result', () => { + expect(ownChainAccountResult).toEqual(ownChainAccountJSON); + }); }); describe('getTerminatedStateAccount', () => { - it('should call getInteroperabilityStore', async () => { - await sidechainInteroperabilityEndpoint.getTerminatedStateAccount(moduleContext, chainID); + let terminateStateAccountResult: TerminatedStateAccountJSON; + beforeEach(async () => { + terminateStateAccountResult = await sidechainInteroperabilityEndpoint.getTerminatedStateAccount( + moduleContext, + chainID, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(sidechainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getTerminatedStateAccount', async () => { - await sidechainInteroperabilityEndpoint.getTerminatedStateAccount(moduleContext, chainID); - expect(sidechainInteroperabilityStore.getTerminatedStateAccount).toHaveBeenCalled(); }); + + it('should return JSON format result', () => { + expect(terminateStateAccountResult).toEqual(terminateStateAccountJSON); + }); }); describe('getTerminatedOutboxAccount', () => { - it('should call getInteroperabilityStore', async () => { - await sidechainInteroperabilityEndpoint.getTerminatedOutboxAccount(moduleContext, chainID); + let terminatedOutboxAccountResult: TerminatedOutboxAccountJSON; + beforeEach(async () => { + terminatedOutboxAccountResult = await sidechainInteroperabilityEndpoint.getTerminatedOutboxAccount( + moduleContext, + chainID, + ); + }); + + it('should call getInteroperabilityStore', async () => { expect(sidechainInteroperabilityEndpoint['getInteroperabilityStore']).toHaveBeenCalledWith( moduleContext.getStore, ); }); it('should call getTerminatedStateAccount', async () => { - await sidechainInteroperabilityEndpoint.getTerminatedOutboxAccount(moduleContext, chainID); - expect(sidechainInteroperabilityStore.getTerminatedOutboxAccount).toHaveBeenCalledWith( chainID, ); }); + + it('should return JSON format result', () => { + expect(terminatedOutboxAccountResult).toEqual(terminatedOutboxAccountJSON); + }); }); });