UNPKG

lisk-framework

Version:

Lisk blockchain application platform

97 lines 5.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InitializeStateRecoveryCommand = void 0; const lisk_validator_1 = require("@liskhq/lisk-validator"); const lisk_codec_1 = require("@liskhq/lisk-codec"); const lisk_cryptography_1 = require("@liskhq/lisk-cryptography"); const lisk_db_1 = require("@liskhq/lisk-db"); const state_machine_1 = require("../../../../state_machine"); const base_interoperability_command_1 = require("../../base_interoperability_command"); const constants_1 = require("../../constants"); const schemas_1 = require("../../schemas"); const chain_account_1 = require("../../stores/chain_account"); const own_chain_account_1 = require("../../stores/own_chain_account"); const terminated_state_1 = require("../../stores/terminated_state"); const utils_1 = require("../../utils"); const invalid_smt_verification_1 = require("../../events/invalid_smt_verification"); class InitializeStateRecoveryCommand extends base_interoperability_command_1.BaseInteroperabilityCommand { constructor() { super(...arguments); this.schema = schemas_1.stateRecoveryInitParamsSchema; } async verify(context) { const { params } = context; const { chainID, sidechainAccount } = params; const ownChainAccount = await this.stores.get(own_chain_account_1.OwnChainAccountStore).get(context, constants_1.EMPTY_BYTES); const mainchainID = (0, utils_1.getMainchainID)(ownChainAccount.chainID); if (chainID.equals(mainchainID) || chainID.equals(ownChainAccount.chainID)) { throw new Error('Chain ID is not valid.'); } const terminatedStateSubstore = this.stores.get(terminated_state_1.TerminatedStateStore); const terminatedStateAccountExists = await terminatedStateSubstore.has(context, chainID); let terminatedStateAccount; if (terminatedStateAccountExists) { terminatedStateAccount = await terminatedStateSubstore.get(context, chainID); if (terminatedStateAccount.initialized) { throw new Error('Sidechain is already terminated.'); } } const deserializedSidechainAccount = lisk_codec_1.codec.decode(chain_account_1.chainDataSchema, sidechainAccount); lisk_validator_1.validator.validate(chain_account_1.chainDataSchema, deserializedSidechainAccount); const mainchainAccount = await this.stores.get(chain_account_1.ChainAccountStore).get(context, mainchainID); if (deserializedSidechainAccount.status === 0) { throw new Error('Sidechain has status registered.'); } if (deserializedSidechainAccount.status === 1 && mainchainAccount.lastCertificate.timestamp - deserializedSidechainAccount.lastCertificate.timestamp <= constants_1.LIVENESS_LIMIT) { throw new Error('Sidechain is still active and obeys the liveness requirement.'); } return { status: state_machine_1.VerifyStatus.OK, }; } async execute(context) { const { params: { chainID, siblingHashes, bitmap, sidechainAccount: sidechainAccountBuffer }, } = context; const terminatedStateSubstore = this.stores.get(terminated_state_1.TerminatedStateStore); const terminatedStateAccountExists = await terminatedStateSubstore.has(context, chainID); const chainStore = this.stores.get(chain_account_1.ChainAccountStore); const queryKey = Buffer.concat([chainStore.key, lisk_cryptography_1.utils.hash(chainID)]); const query = { key: queryKey, value: lisk_cryptography_1.utils.hash(sidechainAccountBuffer), bitmap }; const proofOfInclusion = { siblingHashes, queries: [query] }; const smt = new lisk_db_1.SparseMerkleTree(); let stateRoot; if (terminatedStateAccountExists) { const terminatedStateAccount = await terminatedStateSubstore.get(context, chainID); stateRoot = terminatedStateAccount.mainchainStateRoot; } else { const mainchainID = (0, utils_1.getMainchainID)(context.chainID); const mainchainAccount = await this.stores.get(chain_account_1.ChainAccountStore).get(context, mainchainID); stateRoot = mainchainAccount.lastCertificate.stateRoot; } const verified = await smt.verifyInclusionProof(stateRoot, [queryKey], proofOfInclusion); if (!verified) { this.events.get(invalid_smt_verification_1.InvalidSMTVerificationEvent).error(context); throw new Error('State recovery initialization proof of inclusion is not valid.'); } const deserializedSidechainAccount = lisk_codec_1.codec.decode(chain_account_1.chainDataSchema, sidechainAccountBuffer); const doesTerminatedStateAccountExist = await this.stores .get(terminated_state_1.TerminatedStateStore) .has(context, chainID); if (doesTerminatedStateAccountExist) { const newTerminatedStateAccount = { stateRoot: deserializedSidechainAccount.lastCertificate.stateRoot, mainchainStateRoot: constants_1.EMPTY_HASH, initialized: true, }; const store = this.stores.get(terminated_state_1.TerminatedStateStore); await store.set(context, chainID, newTerminatedStateAccount); return; } await this.internalMethod.createTerminatedStateAccount(context, chainID, deserializedSidechainAccount.lastCertificate.stateRoot); } } exports.InitializeStateRecoveryCommand = InitializeStateRecoveryCommand; //# sourceMappingURL=initialize_state_recovery.js.map