UNPKG

lisk-framework

Version:

Lisk blockchain application platform

124 lines 5.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseStateRecoveryCommand = void 0; const lisk_utils_1 = require("@liskhq/lisk-utils"); const lisk_db_1 = require("@liskhq/lisk-db"); const lisk_cryptography_1 = require("@liskhq/lisk-cryptography"); const base_interoperability_command_1 = require("./base_interoperability_command"); const constants_1 = require("./constants"); const schemas_1 = require("./schemas"); const state_machine_1 = require("../../state_machine"); const terminated_state_1 = require("./stores/terminated_state"); const base_store_1 = require("../base_store"); const invalid_smt_verification_1 = require("./events/invalid_smt_verification"); class BaseStateRecoveryCommand extends base_interoperability_command_1.BaseInteroperabilityCommand { constructor() { super(...arguments); this.schema = schemas_1.stateRecoveryParamsSchema; } async verify(context) { const { params: { chainID, storeEntries, module }, } = context; const terminatedStateSubstore = this.stores.get(terminated_state_1.TerminatedStateStore); const terminatedStateAccountExists = await terminatedStateSubstore.has(context, chainID); if (!terminatedStateAccountExists) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('The terminated state does not exist.'), }; } const terminatedStateAccount = await terminatedStateSubstore.get(context, chainID); if (!terminatedStateAccount.initialized) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('The terminated state is not initialized.'), }; } const moduleMethod = this.interoperableCCMethods.get(module); if (!moduleMethod) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Module is not registered on the chain.'), }; } if (!moduleMethod.recover) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Module is not recoverable.'), }; } const queryKeys = []; for (const entry of storeEntries) { const queryKey = Buffer.concat([entry.substorePrefix, entry.storeKey]); queryKeys.push(queryKey); } if (!lisk_utils_1.objects.bufferArrayUniqueItems(queryKeys)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Recovered store keys are not pairwise distinct.'), }; } return { status: state_machine_1.VerifyStatus.OK, }; } async execute(context) { const { params: { chainID, storeEntries, module, siblingHashes }, } = context; const storeQueriesVerify = []; const queryKeys = []; const storePrefix = (0, base_store_1.computeStorePrefix)(module); for (const entry of storeEntries) { const queryKey = Buffer.concat([ storePrefix, entry.substorePrefix, lisk_cryptography_1.utils.hash(entry.storeKey), ]); queryKeys.push(queryKey); storeQueriesVerify.push({ key: queryKey, value: lisk_cryptography_1.utils.hash(entry.storeValue), bitmap: entry.bitmap, }); } const terminatedStateAccount = await this.stores .get(terminated_state_1.TerminatedStateStore) .get(context, chainID); const proofOfInclusionStores = { siblingHashes, queries: storeQueriesVerify }; const smtVerified = await new lisk_db_1.SparseMerkleTree().verifyInclusionProof(terminatedStateAccount.stateRoot, queryKeys, proofOfInclusionStores); if (!smtVerified) { this.events.get(invalid_smt_verification_1.InvalidSMTVerificationEvent).error(context); throw new Error('State recovery proof of inclusion is not valid.'); } const moduleMethod = this.interoperableCCMethods.get(module); const storeQueriesUpdate = []; for (const entry of storeEntries) { try { await moduleMethod.recover({ ...context, module, terminatedChainID: chainID, substorePrefix: entry.substorePrefix, storeKey: entry.storeKey, storeValue: entry.storeValue, }); storeQueriesUpdate.push({ key: Buffer.concat([storePrefix, entry.substorePrefix, lisk_cryptography_1.utils.hash(entry.storeKey)]), value: constants_1.RECOVERED_STORE_VALUE, bitmap: entry.bitmap, }); } catch (err) { throw new Error(`Recovery failed for module: ${module}`); } } const root = await new lisk_db_1.SparseMerkleTree().calculateRoot({ queries: storeQueriesUpdate, siblingHashes, }); await this.stores.get(terminated_state_1.TerminatedStateStore).set(context, chainID, { ...terminatedStateAccount, stateRoot: root, }); } } exports.BaseStateRecoveryCommand = BaseStateRecoveryCommand; //# sourceMappingURL=base_state_recovery.js.map