lisk-framework
Version:
Lisk blockchain application platform
97 lines • 5.7 kB
JavaScript
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
;