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

Commit

Permalink
Update Terminate Chain (#7806)
Browse files Browse the repository at this point in the history
### What was the problem?

This PR resolves #7557

### How was it solved?

Implemented `terminateChain` function

### How was it tested?

Updated unit test
  • Loading branch information
ishantiw authored Nov 24, 2022
2 parents 1326a4b + 7db5642 commit 6be19a8
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@ import { BaseCCMethod } from './base_cc_method';
import { NamedRegistry } from '../named_registry';
import { ImmutableMethodContext, MethodContext } from '../../state_machine';
import { ChainAccount, ChainAccountStore } from './stores/chain_account';
import { CCMsg, TerminateChainContext } from './types';
import { BaseInteroperabilityInternalMethod } from './base_interoperability_internal_methods';
import {
EMPTY_BYTES,
MAINCHAIN_ID_BUFFER,
MAX_RESERVED_ERROR_STATUS,
EMPTY_FEE_ADDRESS,
MODULE_NAME_INTEROPERABILITY,
CROSS_CHAIN_COMMAND_CHANNEL_TERMINATED,
CCMStatusCode,
} from './constants';
import { TokenMethod } from '../token';
import { OwnChainAccountStore } from './stores/own_chain_account';
import { ChannelDataStore } from './stores/channel_data';
import { TerminatedStateStore } from './stores/terminated_state';
import { TerminatedOutboxStore } from './stores/terminated_outbox';
import { CCMsg } from './types';

export abstract class BaseInteroperabilityMethod<
T extends BaseInteroperabilityInternalMethod
Expand Down Expand Up @@ -143,8 +146,23 @@ export abstract class BaseInteroperabilityMethod<
);
}

// eslint-disable-next-line @typescript-eslint/require-await
public async terminateChain(_methodContext: MethodContext, _chainID: Buffer): Promise<void> {
throw new Error('Need to be implemented');
// https://github.com/LiskHQ/lips/blob/main/proposals/lip-0045.md#terminatechain
public async terminateChain(context: TerminateChainContext, chainID: Buffer): Promise<void> {
if (await this.getTerminatedStateAccount(context, chainID)) {
return;
}

await this.internalMethod.sendInternal(
context,
EMPTY_FEE_ADDRESS,
MODULE_NAME_INTEROPERABILITY,
CROSS_CHAIN_COMMAND_CHANNEL_TERMINATED,
chainID,
BigInt(0),
CCMStatusCode.OK,
EMPTY_BYTES,
);

await this.internalMethod.createTerminatedStateAccount(context, chainID);
}
}
5 changes: 4 additions & 1 deletion framework/src/modules/interoperability/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,14 @@ export const MAX_CROSS_CHAIN_COMMAND_NAME_LENGTH = 32;
export const CHAIN_ID_LENGTH = 4;
export const MODULE_ID_LENGTH = 4;

// Cross chain commands
// Cross chain command names
export const CROSS_CHAIN_COMMAND_NAME_REGISTRATION = 'registration';
export const CROSS_CHAIN_COMMAND_NAME_CHANNEL_TERMINATED = 'channelTerminated';
export const CROSS_CHAIN_COMMAND_NAME_SIDECHAIN_TERMINATED = 'sidechainTerminated';

// Cross chain commands
export const CROSS_CHAIN_COMMAND_CHANNEL_TERMINATED = 'channelTerminated';

export const enum CCMStatusCode {
// Value of status of a new CCM which is not a response due do an error
OK = 0,
Expand Down
85 changes: 84 additions & 1 deletion framework/test/unit/modules/interoperability/method.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@
* Removal or modification of this copyright notice is prohibited.
*/

import { utils } from '@liskhq/lisk-cryptography';
import { address, utils } from '@liskhq/lisk-cryptography';
import { codec } from '@liskhq/lisk-codec';
import { MainchainInteroperabilityModule, TokenMethod } from '../../../../src';
import { BaseInteroperabilityMethod } from '../../../../src/modules/interoperability/base_interoperability_method';
import {
CCMStatusCode,
CHAIN_ID_MAINCHAIN,
CROSS_CHAIN_COMMAND_CHANNEL_TERMINATED,
EMPTY_BYTES,
EMPTY_FEE_ADDRESS,
HASH_LENGTH,
MAINCHAIN_ID_BUFFER,
MAX_CCM_SIZE,
MODULE_NAME_INTEROPERABILITY,
} from '../../../../src/modules/interoperability/constants';
import {
CCMSentFailedCode,
Expand All @@ -40,6 +44,10 @@ import { createTransientMethodContext } from '../../../../src/testing';
import { ChannelDataStore } from '../../../../src/modules/interoperability/stores/channel_data';
import { TerminatedStateStore } from '../../../../src/modules/interoperability/stores/terminated_state';
import { TerminatedOutboxStore } from '../../../../src/modules/interoperability/stores/terminated_outbox';
import { TerminateChainContext } from '../../../../src/modules/interoperability/types';
import { CHAIN_ID_LENGTH } from '../../../../src/modules/token/constants';
import { loggerMock } from '../../../../src/testing/mocks';
import { PrefixedStateReadWriter } from '../../../../src/state_machine/prefixed_state_read_writer';

class SampleInteroperabilityMethod extends BaseInteroperabilityMethod<MainchainInteroperabilityInternalMethod> {
protected getInteroperabilityInternalMethod = (): MainchainInteroperabilityInternalMethod =>
Expand All @@ -52,6 +60,11 @@ class SampleInteroperabilityMethod extends BaseInteroperabilityMethod<MainchainI

describe('Sample Method', () => {
const interopMod = new MainchainInteroperabilityModule();
const defaultPublicKey = Buffer.from(
'5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09',
'hex',
);
const defaultAddress = address.getAddressFromPublicKey(defaultPublicKey);
const chainID = utils.intToBuffer(1, 4);
const interoperableCCMethods = new Map();
const chainAccountStoreMock = {
Expand Down Expand Up @@ -79,15 +92,32 @@ describe('Sample Method', () => {
set: jest.fn(),
has: jest.fn(),
};
let stateStore: PrefixedStateReadWriter;
let sampleInteroperabilityMethod: SampleInteroperabilityMethod;
let methodContext: MethodContext;
let terminateChainContext: TerminateChainContext;
let tokenMethodMock: TokenMethod;
let ccmSendFailEventMock: CcmSentFailedEvent;
let ccmSendSuccessEventMock: CcmSendSuccessEvent;

beforeEach(() => {
const defaultEventQueue = new EventQueue(0, [], [utils.hash(utils.getRandomBytes(32))]);
methodContext = createTransientMethodContext({ eventQueue: defaultEventQueue });
terminateChainContext = {
...methodContext,
getMethodContext: jest.fn(),
logger: loggerMock,
chainID,
transaction: {
fee: BigInt(0),
senderAddress: defaultAddress,
},
header: {
height: 0,
timestamp: 0,
},
stateStore,
};
tokenMethodMock = {
payMessageFee: jest.fn(),
} as any;
Expand Down Expand Up @@ -448,4 +478,57 @@ describe('Sample Method', () => {
expect(channelStoreMock.get).toHaveBeenCalledWith(expect.anything(), newChainID);
});
});

describe('terminateChain', () => {
const sidechainChainAccount = {
name: 'sidechain1',
chainID: Buffer.alloc(CHAIN_ID_LENGTH),
lastCertificate: {
height: 10,
stateRoot: utils.getRandomBytes(32),
timestamp: 100,
validatorsHash: utils.getRandomBytes(32),
},
status: ChainStatus.TERMINATED,
};

beforeEach(() => {
interopMod['internalMethod'].sendInternal = jest.fn();
interopMod['internalMethod'].createTerminatedStateAccount = jest.fn();
});

it('should do nothing if chain was already terminated', async () => {
jest.spyOn(sampleInteroperabilityMethod, 'getTerminatedStateAccount').mockResolvedValue({
stateRoot: sidechainChainAccount.lastCertificate.stateRoot,
mainchainStateRoot: Buffer.alloc(HASH_LENGTH),
initialized: true,
});
await sampleInteroperabilityMethod.terminateChain(terminateChainContext, chainID);

expect(interopMod['internalMethod'].sendInternal).not.toHaveBeenCalled();
});

it('should process with input chainID', async () => {
jest
.spyOn(sampleInteroperabilityMethod as any, 'getTerminatedStateAccount')
.mockResolvedValue(undefined);

await sampleInteroperabilityMethod.terminateChain(terminateChainContext, chainID);

expect(interopMod['internalMethod'].sendInternal).toHaveBeenCalledWith(
terminateChainContext,
EMPTY_FEE_ADDRESS,
MODULE_NAME_INTEROPERABILITY,
CROSS_CHAIN_COMMAND_CHANNEL_TERMINATED,
chainID,
BigInt(0),
CCMStatusCode.OK,
EMPTY_BYTES,
);
expect(interopMod['internalMethod'].createTerminatedStateAccount).toHaveBeenCalledWith(
terminateChainContext,
chainID,
);
});
});
});

0 comments on commit 6be19a8

Please sign in to comment.