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

Implement cross chain command for interoperability modules - Closes #7038 & #7039 #7165

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b84a7ea
♻️ Export calculateRootFromRightWitness from lisk-tree
ishantiw May 12, 2022
d5cf04e
🌱 Implement ccu on mainchain
ishantiw May 12, 2022
a3cd3bd
🌱 Implement CCU command on sidechain
ishantiw May 12, 2022
7a30804
♻️ Fix deepscan issues
ishantiw May 12, 2022
ee24dda
♻️ Improve CCU verify and execution logic
ishantiw May 16, 2022
5add708
♻️ Handle when ccm is undefined
ishantiw May 16, 2022
f919551
✅ Fix unit tests
ishantiw May 16, 2022
c8deece
♻️ Separate verify steps to utils functions for CCU
ishantiw May 16, 2022
0f63b21
♻️ Extract CCU common execution logic to utils
ishantiw May 16, 2022
b7d26a8
♻️ Refactoring based on feedback
ishantiw May 18, 2022
e2475c3
♻️ Update sidechain cc_update command
ishantiw May 18, 2022
5197a16
♻️ Apply feedback
ishantiw May 19, 2022
a45db0c
✅ CCU utils unit tests
ishantiw May 19, 2022
b49e322
✅ Add unit tests for CCU mainchain verify
ishantiw May 19, 2022
7607e61
♻️ Skip CCMs when terminatedChain is called
ishantiw May 23, 2022
1f53ce5
✅ Add execute mainchain CCU tests
ishantiw May 23, 2022
58c8fb8
♻️ Add unit tests for sidechain CCU verify and execute
ishantiw May 23, 2022
a2a208c
♻️ Add blsKey length in schema and remove check from util
ishantiw May 23, 2022
11d57fe
♻️ Improve inboxUpdate check and add certificate emptiness util func
ishantiw May 23, 2022
d5d15af
♻️ Refactor checkInboxUpdateValidity
ishantiw May 24, 2022
fad0aac
✅ Add unit tests for checkInboxUpdateValidity
ishantiw May 24, 2022
4873c02
♻️ Use unsorted activeValidatorsUpdate for test
ishantiw May 24, 2022
73dd954
♻️ Remove unnecessary isInboxUpdateEmpty in condition
ishantiw May 25, 2022
2cfb4b6
♻️ Improve error message and fix sidechain ccu execution condition
ishantiw May 27, 2022
6f6cfd8
♻️ Move checkValidatorsHashWithCertificate to verify function and up…
ishantiw May 27, 2022
f3ea460
♻️ Split checkCertificateTimestampAndSignature to verifyCertificateS…
ishantiw May 27, 2022
4cb5d73
✅ Update the test for checkCertificateTimestamp and verifyCertificate…
ishantiw May 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 60 additions & 53 deletions framework/src/modules/interoperability/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
CrossChainUpdateTransactionParams,
ChainValidators,
InboxUpdate,
MsgWitness,
} from './types';
import {
CCM_STATUS_OK,
Expand Down Expand Up @@ -232,6 +233,11 @@ export const isCertificateEmpty = (decodedCertificate: Certificate) =>
decodedCertificate.validatorsHash.equals(EMPTY_BYTES) ||
decodedCertificate.timestamp === 0;

export const isMessageWitnessEmpty = (messageWitness: MsgWitness) =>
!(
messageWitness.partnerChainOutboxSize !== BigInt(0) || messageWitness.siblingHashes.length !== 0
);
shuse2 marked this conversation as resolved.
Show resolved Hide resolved

export const checkLivenessRequirementFirstCCU = (
partnerChainAccount: ChainAccount,
txParams: CrossChainUpdateTransactionParams,
Expand Down Expand Up @@ -321,14 +327,14 @@ export const checkInboxUpdateValidity = (
txParams: CrossChainUpdateTransactionParams,
partnerChannelData: ChannelData,
): VerificationResult => {
// If inboxUpdate is empty then return success
if (isInboxUpdateEmpty(txParams.inboxUpdate)) {
ishantiw marked this conversation as resolved.
Show resolved Hide resolved
return {
status: VerifyStatus.OK,
};
}

const partnerChainIDBuffer = getIDAsKeyForStore(txParams.sendingChainID);
const decodedCertificate = codec.decode<Certificate>(certificateSchema, txParams.certificate);
const partnerChainIDBuffer = getIDAsKeyForStore(txParams.sendingChainID);
const { crossChainMessages, messageWitness, outboxRootWitness } = txParams.inboxUpdate;
const ccmHashes = crossChainMessages.map(ccm => hash(ccm));
shuse2 marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -345,61 +351,62 @@ export const checkInboxUpdateValidity = (
newInboxSize = size;
newInboxRoot = root;
}
// If inboxUpdate contains a non-empty messageWitness, then update newInboxRoot to the output
if (
!txParams.certificate.equals(EMPTY_BYTES) &&
txParams.inboxUpdate.messageWitness.partnerChainOutboxSize !== BigInt(0) &&
txParams.inboxUpdate.messageWitness.siblingHashes.length !== 0
) {
newInboxRoot = regularMerkleTree.calculateRootFromRightWitness(
newInboxSize,
newInboxAppendPath,
messageWitness.siblingHashes,
);
}

const proof = {
siblingHashes: outboxRootWitness.siblingHashes,
queries: [
{
key: partnerChainIDBuffer,
value: newInboxRoot as Buffer,
bitmap: outboxRootWitness.bitmap,
},
],
};
const outboxKey = rawStateStoreKey(STORE_PREFIX_OUTBOX_ROOT);
const querykeys = [outboxKey];
const isSMTRootValid = sparseMerkleTree.verify(
querykeys,
proof,
decodedCertificate.stateRoot,
SMT_KEY_LENGTH,
);
if (!isSMTRootValid) {
return {
status: VerifyStatus.FAIL,
error: new Error(
'Failed at verifying state root when messageWitness and certificate are non-empty.',
),
// non-empty certificate and an inboxUpdate
if (!isCertificateEmpty(decodedCertificate) && !isInboxUpdateEmpty(txParams.inboxUpdate)) {
shuse2 marked this conversation as resolved.
Show resolved Hide resolved
// If inboxUpdate contains a non-empty messageWitness, then update newInboxRoot to the output
if (!isMessageWitnessEmpty(txParams.inboxUpdate.messageWitness)) {
newInboxRoot = regularMerkleTree.calculateRootFromRightWitness(
newInboxSize,
newInboxAppendPath,
messageWitness.siblingHashes,
);
}
const proof = {
shuse2 marked this conversation as resolved.
Show resolved Hide resolved
siblingHashes: outboxRootWitness.siblingHashes,
queries: [
{
key: partnerChainIDBuffer,
shuse2 marked this conversation as resolved.
Show resolved Hide resolved
value: newInboxRoot as Buffer,
bitmap: outboxRootWitness.bitmap,
},
],
};
}

if (isCertificateEmpty(decodedCertificate) && isInboxUpdateEmpty(txParams.inboxUpdate)) {
newInboxRoot = regularMerkleTree.calculateRootFromRightWitness(
newInboxSize,
newInboxAppendPath,
messageWitness.siblingHashes,
const outboxKey = rawStateStoreKey(STORE_PREFIX_OUTBOX_ROOT);
const querykeys = [outboxKey];
const isSMTRootValid = sparseMerkleTree.verify(
querykeys,
proof,
decodedCertificate.stateRoot,
SMT_KEY_LENGTH,
);
if (!isSMTRootValid) {
return {
status: VerifyStatus.FAIL,
error: new Error(
'Failed at verifying state root when messageWitness and certificate are non-empty.',
),
};
}
}

if (!(newInboxRoot as Buffer).equals(partnerChannelData.partnerChainOutboxRoot)) {
return {
status: VerifyStatus.FAIL,
error: new Error(
'Failed at verifying state root when messageWitness is non-empty and certificate is empty.',
),
};
// empty certificate and a non-empty inboxUpdate
if (isCertificateEmpty(decodedCertificate) && !isInboxUpdateEmpty(txParams.inboxUpdate)) {
shuse2 marked this conversation as resolved.
Show resolved Hide resolved
// If inboxUpdate contains a non-empty messageWitness, then update newInboxRoot to the output
if (!isMessageWitnessEmpty(txParams.inboxUpdate.messageWitness)) {
newInboxRoot = regularMerkleTree.calculateRootFromRightWitness(
newInboxSize,
newInboxAppendPath,
messageWitness.siblingHashes,
);
}
if (!(newInboxRoot as Buffer).equals(partnerChannelData.partnerChainOutboxRoot)) {
return {
status: VerifyStatus.FAIL,
error: new Error(
'Failed at verifying state root when messageWitness is non-empty and certificate is empty.',
),
};
}
}

return {
Expand Down
Loading