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

Commit

Permalink
Add applyRecovery for message recovery command (#7789)
Browse files Browse the repository at this point in the history
### What was the problem?

This PR resolves #7764 

### How was it solved?

- Add applyRecovery for mainchain message recovery

### How was it tested?

- Add unit tests
  • Loading branch information
ishantiw authored Nov 18, 2022
2 parents 8cf4f6e + 8391e50 commit e0da956
Show file tree
Hide file tree
Showing 2 changed files with 482 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
CommandVerifyContext,
VerificationResult,
} from '../../../../state_machine/types';
import { CCMsg, MessageRecoveryParams } from '../../types';
import { CCMsg, CrossChainMessageContext, MessageRecoveryParams } from '../../types';
import { BaseInteroperabilityCommand } from '../../base_interoperability_command';
import { MainchainInteroperabilityInternalMethod } from '../internal_method';
import { verifyMessageRecovery, swapReceivingAndSendingChainIDs } from '../../utils';
Expand All @@ -31,6 +31,11 @@ import { BaseCCMethod } from '../../base_cc_method';
import { TerminatedOutboxAccount, TerminatedOutboxStore } from '../../stores/terminated_outbox';
import { OwnChainAccountStore } from '../../stores/own_chain_account';
import { ChainAccountStore, ChainStatus } from '../../stores/chain_account';
import {
CCMProcessedCode,
CcmProcessedEvent,
CCMProcessedResult,
} from '../../events/ccm_processed';

export class MainchainMessageRecoveryCommand extends BaseInteroperabilityCommand<MainchainInteroperabilityInternalMethod> {
public schema = messageRecoveryParamsSchema;
Expand Down Expand Up @@ -156,4 +161,154 @@ export class MainchainMessageRecoveryCommand extends BaseInteroperabilityCommand
await this.internalMethod.addToOutbox(context, ccmChainId, newCcm);
}
}

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
private async _applyRecovery(context: CrossChainMessageContext): Promise<void> {
const { logger } = context;
const ccmID = utils.hash(codec.encode(ccmSchema, context.ccm));
const ccm: CCMsg = {
...context.ccm,
status: CCMStatusCode.RECOVERED,
sendingChainID: context.ccm.receivingChainID,
receivingChainID: context.ccm.sendingChainID,
};

try {
for (const [module, method] of this.interoperableCCMethods.entries()) {
if (method.verifyCrossChainMessage) {
logger.debug(
{
moduleName: module,
commandName: ccm.crossChainCommand,
ccmID: ccmID.toString('hex'),
},
'Execute verifyCrossChainMessage',
);
await method.verifyCrossChainMessage(context);
}
}
} catch (error) {
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.INVALID_CCM_VERIFY_CCM_EXCEPTION,
result: CCMProcessedResult.DISCARDED,
});
return;
}
const commands = this.ccCommands.get(ccm.module);
if (!commands) {
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.MODULE_NOT_SUPPORTED,
result: CCMProcessedResult.DISCARDED,
});
return;
}
const command = commands.find(com => com.name === ccm.crossChainCommand);
if (!command) {
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.CROSS_CHAIN_COMMAND_NOT_SUPPORTED,
result: CCMProcessedResult.DISCARDED,
});
return;
}
if (command.verify) {
try {
await command.verify(context);
} catch (error) {
logger.info(
{ err: error as Error, moduleName: ccm.module, commandName: ccm.crossChainCommand },
'Fail to verify cross chain command.',
);
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.INVALID_CCM_VERIFY_EXCEPTION,
result: CCMProcessedResult.DISCARDED,
});
return;
}
}
const baseEventSnapshotID = context.eventQueue.createSnapshot();
const baseStateSnapshotID = context.stateStore.createSnapshot();

try {
for (const [module, method] of this.interoperableCCMethods.entries()) {
if (method.beforeCrossChainCommandExecute) {
logger.debug(
{
moduleName: module,
commandName: ccm.crossChainCommand,
ccmID: ccmID.toString('hex'),
},
'Execute beforeCrossChainCommandExecute',
);
await method.beforeCrossChainCommandExecute(context);
}
}
} catch (error) {
context.eventQueue.restoreSnapshot(baseEventSnapshotID);
context.stateStore.restoreSnapshot(baseStateSnapshotID);
logger.info(
{ err: error as Error, moduleName: ccm.module, commandName: ccm.crossChainCommand },
'Fail to execute beforeCrossChainCommandExecute.',
);
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.INVALID_CCM_BEFORE_CCC_EXECUTION_EXCEPTION,
result: CCMProcessedResult.DISCARDED,
});
return;
}

const execEventSnapshotID = context.eventQueue.createSnapshot();
const execStateSnapshotID = context.stateStore.createSnapshot();

try {
const params = command.schema ? codec.decode(command.schema, ccm.params) : {};
await command.execute({ ...context, params });
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.SUCCESS,
result: CCMProcessedResult.APPLIED,
});
} catch (error) {
context.eventQueue.restoreSnapshot(execEventSnapshotID);
context.stateStore.restoreSnapshot(execStateSnapshotID);
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.FAILED_CCM,
result: CCMProcessedResult.DISCARDED,
});
}

try {
for (const [module, method] of this.interoperableCCMethods.entries()) {
if (method.afterCrossChainCommandExecute) {
logger.debug(
{
moduleName: module,
commandName: ccm.crossChainCommand,
ccmID: ccmID.toString('hex'),
},
'Execute afterCrossChainCommandExecute',
);
await method.afterCrossChainCommandExecute(context);
}
}
} catch (error) {
context.eventQueue.restoreSnapshot(baseEventSnapshotID);
context.stateStore.restoreSnapshot(baseStateSnapshotID);
logger.info(
{ err: error as Error, moduleName: module, commandName: ccm.crossChainCommand },
'Fail to execute afterCrossChainCommandExecute',
);
this.events.get(CcmProcessedEvent).log(context, ccm.sendingChainID, ccm.receivingChainID, {
ccmID,
code: CCMProcessedCode.INVALID_CCM_AFTER_CCC_EXECUTION_EXCEPTION,
result: CCMProcessedResult.DISCARDED,
});
}
}
}
Loading

0 comments on commit e0da956

Please sign in to comment.