From 6d15984b297c3991c32b253555283e24551b928a Mon Sep 17 00:00:00 2001 From: Khalid Hameed Date: Mon, 6 Nov 2023 19:05:43 +0200 Subject: [PATCH 1/7] Update message recovery code & tests --- .../mainchain/commands/recover_message.ts | 25 +++- .../commands/recover_message.spec.ts | 139 +++++++++++++++++- 2 files changed, 154 insertions(+), 10 deletions(-) diff --git a/framework/src/modules/interoperability/mainchain/commands/recover_message.ts b/framework/src/modules/interoperability/mainchain/commands/recover_message.ts index ebcac70eae..31a3eaa385 100644 --- a/framework/src/modules/interoperability/mainchain/commands/recover_message.ts +++ b/framework/src/modules/interoperability/mainchain/commands/recover_message.ts @@ -78,6 +78,7 @@ export class RecoverMessageCommand extends BaseInteroperabilityCommand idxs[i + 1]) { return { @@ -96,8 +98,10 @@ export class RecoverMessageCommand extends BaseInteroperabilityCommand { expect(result.error?.message).toInclude(`Cross-chain message does not have a valid index.`); }); - it('should return error if idxs[0] <= 1', async () => { + it('should return error if idxs[0] === 1', async () => { transactionParams.idxs = [1]; ccms = [ccms[0]]; ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); @@ -396,7 +396,9 @@ describe('MessageRecoveryCommand', () => { const result = await command.verify(commandVerifyContext); expect(result.status).toBe(VerifyStatus.FAIL); - expect(result.error?.message).toInclude(`Cross-chain message status is not valid.`); + expect(result.error?.message).toInclude( + `Cross-chain message status must be equal to value ${CCMStatusCode.OK}.`, + ); }); it('should return error if cross-chain message receiving chain ID is not valid', async () => { @@ -468,7 +470,140 @@ describe('MessageRecoveryCommand', () => { expect(result.error?.message).toInclude(`Cross-chain message sending chain is not live.`); }); + it('should not return error if OWN_CHAIN_ID === getMainchainID() but ccm.sendingChainID != OWN_CHAIN_ID', async () => { + const chainIDLocal = Buffer.from([0, 0, 0, 0]); + ccms = [ + { + nonce: BigInt(0), + module: MODULE_NAME_INTEROPERABILITY, + crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, + sendingChainID: Buffer.from([1, 2, 3, 4]), // *** + receivingChainID: chainIDLocal, + fee: BigInt(1), + status: CCMStatusCode.OK, + params: Buffer.alloc(0), + }, + ]; + ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); + transactionParams.crossChainMessages = [...ccmsEncoded]; + transactionParams.chainID = chainIDLocal; // *** + transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); + + commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); + + await interopModule.stores + .get(TerminatedOutboxStore) + .set(createStoreGetter(commandVerifyContext.stateStore as any), chainIDLocal, { + outboxRoot, + outboxSize: terminatedChainOutboxSize, + partnerChainInboxSize: 0, + }); + + const result = await command.verify(commandVerifyContext); + expect(result.status).toBe(VerifyStatus.OK); + }); + + it('should not return error if OWN_CHAIN_ID !== getMainchainID() but ccm.sendingChainID === OWN_CHAIN_ID', async () => { + const chainIDLocal = Buffer.from([1, 2, 3, 4]); + ccms = [ + { + nonce: BigInt(0), + module: MODULE_NAME_INTEROPERABILITY, + crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, + sendingChainID: chainIDLocal, // *** + receivingChainID: chainIDLocal, + fee: BigInt(1), + status: CCMStatusCode.OK, + params: Buffer.alloc(0), + }, + ]; + ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); + transactionParams.crossChainMessages = [...ccmsEncoded]; + transactionParams.chainID = chainIDLocal; // *** + transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); + + commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); + + await interopModule.stores + .get(TerminatedOutboxStore) + .set(createStoreGetter(commandVerifyContext.stateStore as any), chainIDLocal, { + outboxRoot, + outboxSize: terminatedChainOutboxSize, + partnerChainInboxSize: 0, + }); + + const result = await command.verify(commandVerifyContext); + expect(result.status).toBe(VerifyStatus.OK); + }); + + it('should return error if OWN_CHAIN_ID != getMainchainID() and ccm.sendingChainID != OWN_CHAIN_ID', async () => { + const chainIDLocal = Buffer.from([1, 2, 3, 4]); + ccms = [ + { + nonce: BigInt(0), + module: MODULE_NAME_INTEROPERABILITY, + crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, + sendingChainID: Buffer.from([5, 6, 7, 8]), // *** + receivingChainID: chainIDLocal, + fee: BigInt(1), + status: CCMStatusCode.OK, + params: Buffer.alloc(0), + }, + ]; + ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); + transactionParams.crossChainMessages = [...ccmsEncoded]; + transactionParams.chainID = chainIDLocal; // *** + transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); + + commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); + + await interopModule.stores + .get(TerminatedOutboxStore) + .set( + createStoreGetter(commandVerifyContext.stateStore as any), + commandVerifyContext.params.chainID, + { + outboxRoot, + outboxSize: terminatedChainOutboxSize, + partnerChainInboxSize: 0, + }, + ); + + const result = await command.verify(commandVerifyContext); + + expect(result.status).toBe(VerifyStatus.FAIL); + expect(result.error?.message).toInclude('Cross-chain message sending chain ID is not valid.'); + }); + it('should return status OK for valid params', async () => { + const chainIDLocal = Buffer.from([0, 0, 0, 0]); + ccms = [ + { + nonce: BigInt(0), + module: MODULE_NAME_INTEROPERABILITY, + crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, + sendingChainID: Buffer.from([1, 2, 3, 4]), + receivingChainID: chainIDLocal, + fee: BigInt(1), + status: CCMStatusCode.OK, + params: Buffer.alloc(0), + }, + ]; + ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); + transactionParams.crossChainMessages = [...ccmsEncoded]; + transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); + + commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); + commandVerifyContext.params.chainID = chainIDLocal; + + await interopModule.stores + .get(TerminatedOutboxStore) + .set(createStoreGetter(commandVerifyContext.stateStore as any), chainIDLocal, { + outboxRoot, + outboxSize: terminatedChainOutboxSize, + partnerChainInboxSize: 0, + }); + const result = await command.verify(commandVerifyContext); expect(result.status).toBe(VerifyStatus.OK); }); From d1e24f0d1ff8b6054e219f5b5fff1c65d7b9153b Mon Sep 17 00:00:00 2001 From: Khalid Hameed Date: Mon, 6 Nov 2023 19:21:06 +0200 Subject: [PATCH 2/7] Add missing test for schema verification --- .../commands/recover_message.spec.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts index 19c54b5df1..8f20e48477 100644 --- a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts +++ b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts @@ -366,6 +366,42 @@ describe('MessageRecoveryCommand', () => { expect(result.error?.message).toInclude(`Cross-chain message was never in the outbox.`); }); + it('should return error if ccm has invalid schema', async () => { + ccms = [ + { + nonce: BigInt(0), + module: MODULE_NAME_INTEROPERABILITY, + crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, + sendingChainID: utils.intToBuffer(0, 2), // *** + receivingChainID: utils.intToBuffer(3, 4), + fee: BigInt(1), + status: CCMStatusCode.FAILED_CCM, + params: Buffer.alloc(0), + }, + ]; + ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); + transactionParams.crossChainMessages = [...ccmsEncoded]; + transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); + + commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); + + await interopModule.stores + .get(TerminatedOutboxStore) + .set(createStoreGetter(commandVerifyContext.stateStore as any), chainID, { + outboxRoot, + outboxSize: terminatedChainOutboxSize, + partnerChainInboxSize: 0, + }); + + try { + await command.verify(commandVerifyContext); + } catch (err: any) { + expect((err as Error).message).toInclude( + `Property '.sendingChainID' minLength not satisfied`, + ); + } + }); + it('should return error if ccm.status !== CCMStatusCode.OK', async () => { ccms = [ { From 142e54717bbd1433c865e0243fb3b42625dd7bc6 Mon Sep 17 00:00:00 2001 From: Khalid Hameed Date: Thu, 9 Nov 2023 17:27:41 +0200 Subject: [PATCH 3/7] Revert check, since this check would be needed only in case message recovery gets enabled in sidechains --- .../mainchain/commands/recover_message.ts | 8 -- .../commands/recover_message.spec.ts | 105 ------------------ 2 files changed, 113 deletions(-) diff --git a/framework/src/modules/interoperability/mainchain/commands/recover_message.ts b/framework/src/modules/interoperability/mainchain/commands/recover_message.ts index 31a3eaa385..3051240220 100644 --- a/framework/src/modules/interoperability/mainchain/commands/recover_message.ts +++ b/framework/src/modules/interoperability/mainchain/commands/recover_message.ts @@ -163,14 +163,6 @@ export class RecoverMessageCommand extends BaseInteroperabilityCommand { expect(result.error?.message).toInclude(`Cross-chain message sending chain is not live.`); }); - it('should not return error if OWN_CHAIN_ID === getMainchainID() but ccm.sendingChainID != OWN_CHAIN_ID', async () => { - const chainIDLocal = Buffer.from([0, 0, 0, 0]); - ccms = [ - { - nonce: BigInt(0), - module: MODULE_NAME_INTEROPERABILITY, - crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, - sendingChainID: Buffer.from([1, 2, 3, 4]), // *** - receivingChainID: chainIDLocal, - fee: BigInt(1), - status: CCMStatusCode.OK, - params: Buffer.alloc(0), - }, - ]; - ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); - transactionParams.crossChainMessages = [...ccmsEncoded]; - transactionParams.chainID = chainIDLocal; // *** - transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); - - commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); - - await interopModule.stores - .get(TerminatedOutboxStore) - .set(createStoreGetter(commandVerifyContext.stateStore as any), chainIDLocal, { - outboxRoot, - outboxSize: terminatedChainOutboxSize, - partnerChainInboxSize: 0, - }); - - const result = await command.verify(commandVerifyContext); - expect(result.status).toBe(VerifyStatus.OK); - }); - - it('should not return error if OWN_CHAIN_ID !== getMainchainID() but ccm.sendingChainID === OWN_CHAIN_ID', async () => { - const chainIDLocal = Buffer.from([1, 2, 3, 4]); - ccms = [ - { - nonce: BigInt(0), - module: MODULE_NAME_INTEROPERABILITY, - crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, - sendingChainID: chainIDLocal, // *** - receivingChainID: chainIDLocal, - fee: BigInt(1), - status: CCMStatusCode.OK, - params: Buffer.alloc(0), - }, - ]; - ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); - transactionParams.crossChainMessages = [...ccmsEncoded]; - transactionParams.chainID = chainIDLocal; // *** - transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); - - commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); - - await interopModule.stores - .get(TerminatedOutboxStore) - .set(createStoreGetter(commandVerifyContext.stateStore as any), chainIDLocal, { - outboxRoot, - outboxSize: terminatedChainOutboxSize, - partnerChainInboxSize: 0, - }); - - const result = await command.verify(commandVerifyContext); - expect(result.status).toBe(VerifyStatus.OK); - }); - - it('should return error if OWN_CHAIN_ID != getMainchainID() and ccm.sendingChainID != OWN_CHAIN_ID', async () => { - const chainIDLocal = Buffer.from([1, 2, 3, 4]); - ccms = [ - { - nonce: BigInt(0), - module: MODULE_NAME_INTEROPERABILITY, - crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, - sendingChainID: Buffer.from([5, 6, 7, 8]), // *** - receivingChainID: chainIDLocal, - fee: BigInt(1), - status: CCMStatusCode.OK, - params: Buffer.alloc(0), - }, - ]; - ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); - transactionParams.crossChainMessages = [...ccmsEncoded]; - transactionParams.chainID = chainIDLocal; // *** - transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); - - commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); - - await interopModule.stores - .get(TerminatedOutboxStore) - .set( - createStoreGetter(commandVerifyContext.stateStore as any), - commandVerifyContext.params.chainID, - { - outboxRoot, - outboxSize: terminatedChainOutboxSize, - partnerChainInboxSize: 0, - }, - ); - - const result = await command.verify(commandVerifyContext); - - expect(result.status).toBe(VerifyStatus.FAIL); - expect(result.error?.message).toInclude('Cross-chain message sending chain ID is not valid.'); - }); - it('should return status OK for valid params', async () => { const chainIDLocal = Buffer.from([0, 0, 0, 0]); ccms = [ From 62fe7747aef4085ec09fb1d3a6d4a6ac43df716d Mon Sep 17 00:00:00 2001 From: Khalid Hameed Date: Thu, 9 Nov 2023 17:32:48 +0200 Subject: [PATCH 4/7] Revert test for valid params --- .../commands/recover_message.spec.ts | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts index c9bb4e5206..a1318c19df 100644 --- a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts +++ b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts @@ -507,34 +507,6 @@ describe('MessageRecoveryCommand', () => { }); it('should return status OK for valid params', async () => { - const chainIDLocal = Buffer.from([0, 0, 0, 0]); - ccms = [ - { - nonce: BigInt(0), - module: MODULE_NAME_INTEROPERABILITY, - crossChainCommand: CROSS_CHAIN_COMMAND_REGISTRATION, - sendingChainID: Buffer.from([1, 2, 3, 4]), - receivingChainID: chainIDLocal, - fee: BigInt(1), - status: CCMStatusCode.OK, - params: Buffer.alloc(0), - }, - ]; - ccmsEncoded = ccms.map(ccm => codec.encode(ccmSchema, ccm)); - transactionParams.crossChainMessages = [...ccmsEncoded]; - transactionParams.idxs = appendPrecedingToIndices([1], terminatedChainOutboxSize); - - commandVerifyContext = createCommandVerifyContext(transaction, transactionParams); - commandVerifyContext.params.chainID = chainIDLocal; - - await interopModule.stores - .get(TerminatedOutboxStore) - .set(createStoreGetter(commandVerifyContext.stateStore as any), chainIDLocal, { - outboxRoot, - outboxSize: terminatedChainOutboxSize, - partnerChainInboxSize: 0, - }); - const result = await command.verify(commandVerifyContext); expect(result.status).toBe(VerifyStatus.OK); }); From fd5c2cec32347dbe3aa2d869f32e3bb0c9195a83 Mon Sep 17 00:00:00 2001 From: Khalid Hameed Date: Thu, 16 Nov 2023 18:54:40 +0200 Subject: [PATCH 5/7] Rearrange expects per code & cover recoveredCCMs part --- .../commands/recover_message.spec.ts | 95 +++++++++++++++---- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts index a1318c19df..556ac7306d 100644 --- a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts +++ b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts @@ -16,7 +16,7 @@ import { codec } from '@liskhq/lisk-codec'; import { Transaction } from '@liskhq/lisk-chain'; import { utils } from '@liskhq/lisk-cryptography'; -import { MerkleTree } from '@liskhq/lisk-tree'; +import { MerkleTree, regularMerkleTree } from '@liskhq/lisk-tree'; import { Proof } from '@liskhq/lisk-tree/dist-node/merkle_tree/types'; import { CROSS_CHAIN_COMMAND_NAME_TRANSFER, @@ -574,6 +574,13 @@ describe('MessageRecoveryCommand', () => { await expect(command.execute(commandExecuteContext)).resolves.toBeUndefined(); + expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( + 1, + CONTEXT_STORE_KEY_CCM_PROCESSING, + true, + ); + + const recoveredCCMs: Buffer[] = []; for (const crossChainMessage of commandExecuteContext.params.crossChainMessages) { const ccm = codec.decode(ccmSchema, crossChainMessage); const ctx: CrossChainMessageContext = { @@ -584,25 +591,53 @@ describe('MessageRecoveryCommand', () => { ), }; + const recoveredCCM = await command['_applyRecovery'](ctx); + recoveredCCMs.push(codec.encode(ccmSchema, recoveredCCM)); + expect(command['_applyRecovery']).toHaveBeenCalledWith(ctx); - expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( - 1, - CONTEXT_STORE_KEY_CCM_PROCESSING, - true, - ); - expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( - 2, - CONTEXT_STORE_KEY_CCM_PROCESSING, - false, - ); } - expect(interopModule.stores.get(TerminatedOutboxStore).set).toHaveBeenCalledTimes(1); + expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( + 2, + CONTEXT_STORE_KEY_CCM_PROCESSING, + false, + ); + + const terminatedOutboxSubstore = interopModule.stores.get(TerminatedOutboxStore); + jest.spyOn(terminatedOutboxSubstore, 'set'); + + expect(terminatedOutboxSubstore.set).toHaveBeenCalledTimes(1); + + const terminatedOutboxAccount = await terminatedOutboxSubstore.get( + commandExecuteContext, + commandExecuteContext.params.chainID, + ); + const proofLocal = { + size: terminatedOutboxAccount.outboxSize, + idxs: commandExecuteContext.params.idxs, + siblingHashes: commandExecuteContext.params.siblingHashes, + }; + terminatedOutboxAccount.outboxRoot = regularMerkleTree.calculateRootFromUpdateData( + recoveredCCMs.map(ccm => utils.hash(ccm)), + { ...proofLocal, indexes: proofLocal.idxs }, + ); + expect(terminatedOutboxSubstore.set).toHaveBeenCalledWith( + commandExecuteContext, + commandExecuteContext.params.chainID, + terminatedOutboxAccount, + ); }); it('should call forwardRecovery when sending chain is not mainchain', async () => { await expect(command.execute(commandExecuteContext)).resolves.toBeUndefined(); + expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( + 1, + CONTEXT_STORE_KEY_CCM_PROCESSING, + true, + ); + + const recoveredCCMs: Buffer[] = []; for (const crossChainMessage of commandExecuteContext.params.crossChainMessages) { const ccm = codec.decode(ccmSchema, crossChainMessage); const ctx: CrossChainMessageContext = { @@ -613,23 +648,41 @@ describe('MessageRecoveryCommand', () => { ), }; + const recoveredCCM = await command['_forwardRecovery'](ctx); + recoveredCCMs.push(codec.encode(ccmSchema, recoveredCCM)); + expect(command['_forwardRecovery']).toHaveBeenCalledWith(ctx); } - const terminatedOutboxStore = command['stores'].get(TerminatedOutboxStore); - jest.spyOn(terminatedOutboxStore, 'set'); - - expect(terminatedOutboxStore.set).toHaveBeenCalledTimes(1); - expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( - 1, - CONTEXT_STORE_KEY_CCM_PROCESSING, - true, - ); expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( 2, CONTEXT_STORE_KEY_CCM_PROCESSING, false, ); + + const terminatedOutboxSubstore = command['stores'].get(TerminatedOutboxStore); + const terminatedOutboxAccount = await terminatedOutboxSubstore.get( + commandExecuteContext, + commandExecuteContext.params.chainID, + ); + jest.spyOn(terminatedOutboxSubstore, 'set'); + + expect(terminatedOutboxSubstore.set).toHaveBeenCalledTimes(1); + + const proofLocal = { + size: terminatedOutboxAccount.outboxSize, + idxs: commandExecuteContext.params.idxs, + siblingHashes: commandExecuteContext.params.siblingHashes, + }; + terminatedOutboxAccount.outboxRoot = regularMerkleTree.calculateRootFromUpdateData( + recoveredCCMs.map(ccm => utils.hash(ccm)), + { ...proofLocal, indexes: proofLocal.idxs }, + ); + expect(terminatedOutboxSubstore.set).toHaveBeenCalledWith( + commandExecuteContext, + commandExecuteContext.params.chainID, + terminatedOutboxAccount, + ); }); }); From ebefc844de862c556dd90bb73ef72bba2d109e69 Mon Sep 17 00:00:00 2001 From: Khalid Hameed Date: Tue, 21 Nov 2023 13:33:07 +0200 Subject: [PATCH 6/7] Simplify tests --- .../commands/recover_message.spec.ts | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts index 556ac7306d..77499b84b7 100644 --- a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts +++ b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts @@ -31,7 +31,6 @@ import { CONTEXT_STORE_KEY_CCM_PROCESSING, CROSS_CHAIN_COMMAND_CHANNEL_TERMINATED, CROSS_CHAIN_COMMAND_REGISTRATION, - EVENT_TOPIC_CCM_EXECUTION, MODULE_NAME_INTEROPERABILITY, } from '../../../../../../src/modules/interoperability/constants'; import { RecoverMessageCommand } from '../../../../../../src/modules/interoperability/mainchain/commands/recover_message'; @@ -583,18 +582,15 @@ describe('MessageRecoveryCommand', () => { const recoveredCCMs: Buffer[] = []; for (const crossChainMessage of commandExecuteContext.params.crossChainMessages) { const ccm = codec.decode(ccmSchema, crossChainMessage); - const ctx: CrossChainMessageContext = { - ...commandExecuteContext, - ccm, - eventQueue: commandExecuteContext.eventQueue.getChildQueue( - Buffer.concat([EVENT_TOPIC_CCM_EXECUTION, utils.hash(crossChainMessage)]), - ), + const recoveredCCM: CCMsg = { + ...ccm, + status: CCMStatusCode.RECOVERED, + sendingChainID: ccm.receivingChainID, + receivingChainID: ccm.sendingChainID, }; - - const recoveredCCM = await command['_applyRecovery'](ctx); recoveredCCMs.push(codec.encode(ccmSchema, recoveredCCM)); - expect(command['_applyRecovery']).toHaveBeenCalledWith(ctx); + expect(command['_applyRecovery']).toHaveBeenCalled(); } expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( @@ -640,18 +636,15 @@ describe('MessageRecoveryCommand', () => { const recoveredCCMs: Buffer[] = []; for (const crossChainMessage of commandExecuteContext.params.crossChainMessages) { const ccm = codec.decode(ccmSchema, crossChainMessage); - const ctx: CrossChainMessageContext = { - ...commandExecuteContext, - ccm, - eventQueue: commandExecuteContext.eventQueue.getChildQueue( - Buffer.concat([EVENT_TOPIC_CCM_EXECUTION, utils.hash(crossChainMessage)]), - ), + const recoveredCCM: CCMsg = { + ...ccm, + status: CCMStatusCode.RECOVERED, + sendingChainID: ccm.receivingChainID, + receivingChainID: ccm.sendingChainID, }; - - const recoveredCCM = await command['_forwardRecovery'](ctx); recoveredCCMs.push(codec.encode(ccmSchema, recoveredCCM)); - expect(command['_forwardRecovery']).toHaveBeenCalledWith(ctx); + expect(command['_forwardRecovery']).toHaveBeenCalled(); } expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( From 9b506381df05715a9b7bc9ba86abe85bc817557b Mon Sep 17 00:00:00 2001 From: Khalid Hameed Date: Tue, 21 Nov 2023 13:49:13 +0200 Subject: [PATCH 7/7] Better use `.toHaveBeenCalledWith(ctx)` --- .../commands/recover_message.spec.ts | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts index 77499b84b7..2bd7b295e7 100644 --- a/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts +++ b/framework/test/unit/modules/interoperability/mainchain/commands/recover_message.spec.ts @@ -32,6 +32,7 @@ import { CROSS_CHAIN_COMMAND_CHANNEL_TERMINATED, CROSS_CHAIN_COMMAND_REGISTRATION, MODULE_NAME_INTEROPERABILITY, + EVENT_TOPIC_CCM_EXECUTION, } from '../../../../../../src/modules/interoperability/constants'; import { RecoverMessageCommand } from '../../../../../../src/modules/interoperability/mainchain/commands/recover_message'; import { @@ -48,7 +49,10 @@ import { createCrossChainMessageContext, createTransactionContext, } from '../../../../../../src/testing'; -import { getMainchainID } from '../../../../../../src/modules/interoperability/utils'; +import { + getMainchainID, + getDecodedCCMAndID, +} from '../../../../../../src/modules/interoperability/utils'; import { TerminatedOutboxStore } from '../../../../../../src/modules/interoperability/stores/terminated_outbox'; import { createStoreGetter } from '../../../../../../src/testing/utils'; import { @@ -581,7 +585,17 @@ describe('MessageRecoveryCommand', () => { const recoveredCCMs: Buffer[] = []; for (const crossChainMessage of commandExecuteContext.params.crossChainMessages) { - const ccm = codec.decode(ccmSchema, crossChainMessage); + const { decodedCCM: ccm, ccmID } = getDecodedCCMAndID(crossChainMessage); + const ctx: CrossChainMessageContext = { + ...commandExecuteContext, + ccm, + eventQueue: commandExecuteContext.eventQueue.getChildQueue( + Buffer.concat([EVENT_TOPIC_CCM_EXECUTION, ccmID]), + ), + }; + + expect(command['_applyRecovery']).toHaveBeenCalledWith(ctx); + const recoveredCCM: CCMsg = { ...ccm, status: CCMStatusCode.RECOVERED, @@ -589,8 +603,6 @@ describe('MessageRecoveryCommand', () => { receivingChainID: ccm.sendingChainID, }; recoveredCCMs.push(codec.encode(ccmSchema, recoveredCCM)); - - expect(command['_applyRecovery']).toHaveBeenCalled(); } expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith( @@ -635,16 +647,24 @@ describe('MessageRecoveryCommand', () => { const recoveredCCMs: Buffer[] = []; for (const crossChainMessage of commandExecuteContext.params.crossChainMessages) { - const ccm = codec.decode(ccmSchema, crossChainMessage); + const { decodedCCM: ccm, ccmID } = getDecodedCCMAndID(crossChainMessage); + const ctx: CrossChainMessageContext = { + ...commandExecuteContext, + ccm, + eventQueue: commandExecuteContext.eventQueue.getChildQueue( + Buffer.concat([EVENT_TOPIC_CCM_EXECUTION, ccmID]), + ), + }; + + expect(command['_forwardRecovery']).toHaveBeenCalledWith(ctx); + const recoveredCCM: CCMsg = { - ...ccm, + ...ctx.ccm, status: CCMStatusCode.RECOVERED, - sendingChainID: ccm.receivingChainID, - receivingChainID: ccm.sendingChainID, + sendingChainID: ctx.ccm.receivingChainID, + receivingChainID: ctx.ccm.sendingChainID, }; recoveredCCMs.push(codec.encode(ccmSchema, recoveredCCM)); - - expect(command['_forwardRecovery']).toHaveBeenCalled(); } expect(commandExecuteContext.contextStore.set).toHaveBeenNthCalledWith(