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

Missing test(s) for message recovery #9137

Merged
merged 8 commits into from
Nov 23, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class RecoverMessageCommand extends BaseInteroperabilityCommand<Mainchain
};
}

// Check that there is exactly one index per cross-chain message.
if (idxs.length !== crossChainMessages.length) {
return {
status: VerifyStatus.FAIL,
Expand All @@ -87,6 +88,7 @@ export class RecoverMessageCommand extends BaseInteroperabilityCommand<Mainchain
};
}

// Check that the idxs are strictly increasing
for (let i = 0; i < idxs.length - 1; i += 1) {
if (idxs[i] > idxs[i + 1]) {
return {
Expand All @@ -96,20 +98,17 @@ export class RecoverMessageCommand extends BaseInteroperabilityCommand<Mainchain
}
}

// Ensure that there are at least two bits, i.e. the value must be larger than 1.
// It's sufficient to check only the first one due the ascending order.
// Check that the CCMs are still pending. We check only the first one,
// as the idxs are sorted in ascending order. Note that one must unset the most significant
// bit of an encoded index in idxs in order to get the position in the tree. To do this
// we must ensure that there are at least two bits, i.e. the value must be larger than 1.
// See https://github.com/LiskHQ/lips/blob/main/proposals/lip-0031.md#proof-serialization.
if (idxs[0] <= 1) {
return {
status: VerifyStatus.FAIL,
error: new Error('Cross-chain message does not have a valid index.'),
};
}

// Check that the CCMs are still pending. We can check only the first one,
// as the idxs are sorted in ascending order. Note that one must unset the most significant
// bit a of an encoded index in idxs in order to get the position in the tree.
// See https://github.com/LiskHQ/lips/blob/main/proposals/lip-0031.md#proof-serialization.
const firstPosition = parseInt(idxs[0].toString(2).slice(1), 2);
if (firstPosition < terminatedOutboxAccount.partnerChainInboxSize) {
return {
Expand Down Expand Up @@ -138,7 +137,9 @@ export class RecoverMessageCommand extends BaseInteroperabilityCommand<Mainchain
if (ccm.status !== CCMStatusCode.OK) {
return {
status: VerifyStatus.FAIL,
error: new Error('Cross-chain message status is not valid.'),
error: new Error(
`Cross-chain message status must be equal to value ${CCMStatusCode.OK}.`,
),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ describe('MessageRecoveryCommand', () => {
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));
Expand Down Expand Up @@ -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 = [
{
Expand Down Expand Up @@ -396,7 +432,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 () => {
Expand Down