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

Commit

Permalink
Apply review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
sitetester committed Oct 29, 2023
1 parent faa634e commit 8c48e08
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 14 deletions.
8 changes: 5 additions & 3 deletions framework/src/modules/interoperability/base_state_recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ export class BaseStateRecoveryCommand<
};
}

const queryKeys = [];
// For efficiency, only subStorePrefix+storeKey is enough to check for pairwise distinct keys in verification
const queryKeys = storeEntries.map(entry =>
Buffer.concat([entry.substorePrefix, entry.storeKey]),
);
for (const entry of storeEntries) {
const queryKey = Buffer.concat([entry.substorePrefix, entry.storeKey]);
queryKeys.push(queryKey);
}

// Check that all keys are pairwise distinct, meaning that we are not trying to recover the same entry twice.
if (!objectUtils.bufferArrayUniqueItems(queryKeys)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,8 @@ export class InitializeStateRecoveryCommand extends BaseInteroperabilityCommand<
const ownChainAccount = await this.stores.get(OwnChainAccountStore).get(context, EMPTY_BYTES);

const mainchainID = getMainchainID(ownChainAccount.chainID);
if (chainID.equals(mainchainID)) {
throw new Error(
`Chain ID must not be equal to mainchain ID: ${mainchainID.toString('hex')}.`,
);
} else if (chainID.equals(ownChainAccount.chainID)) {
throw new Error('Chain ID must not be equal to own chain ID.');
if (chainID.equals(mainchainID) || chainID.equals(ownChainAccount.chainID)) {
throw new Error('Chain ID is not valid.');
}

// The commands fails if the sidechain is already terminated & initialized on this chain.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,23 +207,22 @@ describe('Sidechain InitializeStateRecoveryCommand', () => {
});

it('should return error if chain id is same as mainchain id', async () => {
const chainID = utils.intToBuffer(0, 4);
commandVerifyContext.params.chainID = chainID;
commandVerifyContext.params.chainID = getMainchainID(ownChainAccount.chainID);

await expect(stateRecoveryInitCommand.verify(commandVerifyContext)).rejects.toThrow(
`Chain ID must not be equal to mainchain ID: ${getMainchainID(chainID).toString('hex')}.`,
'Chain ID is not valid.',
);
});

it('should return error if chain id is same as own chain account id', async () => {
commandVerifyContext.params.chainID = ownChainAccount.chainID;

await expect(stateRecoveryInitCommand.verify(commandVerifyContext)).rejects.toThrow(
'Chain ID must not be equal to own chain ID.',
'Chain ID is not valid.',
);
});

it("should not return error if terminated state account doesn't exists", async () => {
it("should not return error if terminated state account doesn't exist", async () => {
await terminatedStateSubstore.del(createStoreGetter(stateStore), transactionParams.chainID);

await expect(stateRecoveryInitCommand.verify(commandVerifyContext)).resolves.not.toThrow(
Expand Down Expand Up @@ -387,6 +386,61 @@ describe('Sidechain InitializeStateRecoveryCommand', () => {
'Sidechain is still active and obeys the liveness requirement.',
);
});

it('should not return error if the sidechain is active on the mainchain and does violate the liveness requirement', async () => {
await terminatedStateSubstore.set(createStoreGetter(stateStore), transactionParams.chainID, {
...terminatedStateAccount,
initialized: false,
});
const mainchainID = getMainchainID(transactionParams.chainID);
when(chainAccountStoreMock.get)
.calledWith(expect.anything(), mainchainID)
.mockResolvedValue({
...mainchainAccount,
lastCertificate: {
...mainchainAccount.lastCertificate,
timestamp: LIVENESS_LIMIT + 50,
},
} as ChainAccount);
sidechainChainAccount = {
name: 'sidechain1',
lastCertificate: {
height: 10,
stateRoot: utils.getRandomBytes(32),
timestamp: 10,
validatorsHash: utils.getRandomBytes(32),
},
status: ChainStatus.ACTIVE,
};
sidechainChainAccountEncoded = codec.encode(chainDataSchema, sidechainChainAccount);
transactionParams = {
chainID: utils.intToBuffer(3, 4),
bitmap: Buffer.alloc(0),
siblingHashes: [],
sidechainAccount: sidechainChainAccountEncoded,
};
encodedTransactionParams = codec.encode(stateRecoveryInitParamsSchema, transactionParams);
transaction = new Transaction({
module: MODULE_NAME_INTEROPERABILITY,
command: COMMAND_NAME_STATE_RECOVERY_INIT,
fee: BigInt(100000000),
nonce: BigInt(0),
params: encodedTransactionParams,
senderPublicKey: utils.getRandomBytes(32),
signatures: [],
});
transactionContext = createTransactionContext({
transaction,
stateStore,
});
commandVerifyContext = transactionContext.createCommandVerifyContext<StateRecoveryInitParams>(
stateRecoveryInitParamsSchema,
);

await expect(stateRecoveryInitCommand.verify(commandVerifyContext)).resolves.not.toThrow(
'Sidechain is still active and obeys the liveness requirement.',
);
});
});

describe('execute', () => {
Expand Down

0 comments on commit 8c48e08

Please sign in to comment.