lisk-framework
Version:
Lisk blockchain application platform
217 lines • 9.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChainEndpoint = void 0;
const lisk_chain_1 = require("@liskhq/lisk-chain");
const lisk_db_1 = require("@liskhq/lisk-db");
const lisk_validator_1 = require("@liskhq/lisk-validator");
const lisk_cryptography_1 = require("@liskhq/lisk-cryptography");
const constants_1 = require("../bft/constants");
const schemas_1 = require("../bft/schemas");
const utils_1 = require("../bft/utils");
const bft_params_1 = require("../bft/bft_params");
const constants_2 = require("../consensus/constants");
const proveEventsRequestSchema = {
$id: '/node/endpoint/proveEventsRequestSchema',
type: 'object',
required: ['height', 'queries'],
properties: {
height: {
type: 'integer',
minimum: 0,
},
queries: {
type: 'array',
items: {
type: 'string',
format: 'hex',
},
},
},
};
class ChainEndpoint {
constructor(args) {
this._chain = args.chain;
this._bftMethod = args.bftMethod;
}
init(db) {
this._db = db;
}
async getBlockByID(context) {
const { id } = context.params;
if (!(0, lisk_validator_1.isHexString)(id)) {
throw new Error('Invalid parameters. id must be a valid hex string.');
}
const block = await this._chain.dataAccess.getBlockByID(Buffer.from(id, 'hex'));
return block.toJSON();
}
async getBlocksByIDs(context) {
const { ids } = context.params;
if (!Array.isArray(ids) || ids.length === 0) {
throw new Error('Invalid parameters. ids must be a non empty array.');
}
if (!ids.every(id => (0, lisk_validator_1.isHexString)(id))) {
throw new Error('Invalid parameters. id must a valid hex string.');
}
const blocks = [];
try {
for (const id of ids) {
const block = await this._chain.dataAccess.getBlockByID(Buffer.from(id, 'hex'));
blocks.push(block);
}
}
catch (error) {
if (!(error instanceof lisk_db_1.NotFoundError)) {
throw error;
}
}
return blocks.map(block => block.toJSON());
}
async getBlockByHeight(context) {
const { height } = context.params;
if (typeof height !== 'number') {
throw new Error('Invalid parameters. height must be a number.');
}
const block = await this._chain.dataAccess.getBlockByHeight(height);
return block.toJSON();
}
async getBlocksByHeightBetween(context) {
const { from, to } = context.params;
if (typeof from !== 'number' || typeof to !== 'number') {
throw new Error('Invalid parameters. from and to must be a number.');
}
const blocks = await this._chain.dataAccess.getBlocksByHeightBetween(from, to);
return blocks.map(b => b.toJSON());
}
async getTransactionByID(context) {
const { id } = context.params;
if (!(0, lisk_validator_1.isHexString)(id)) {
throw new Error('Invalid parameters. id must be a valid hex string.');
}
const transaction = await this._chain.dataAccess.getTransactionByID(Buffer.from(id, 'hex'));
return transaction.toJSON();
}
async getTransactionsByIDs(context) {
const { ids } = context.params;
if (!Array.isArray(ids) || ids.length === 0) {
throw new Error('Invalid parameters. ids must be a non empty array.');
}
if (!ids.every(id => (0, lisk_validator_1.isHexString)(id))) {
throw new Error('Invalid parameters. id must a valid hex string.');
}
const transactions = [];
try {
for (const id of ids) {
const transaction = await this._chain.dataAccess.getTransactionByID(Buffer.from(id, 'hex'));
transactions.push(transaction);
}
}
catch (error) {
if (!(error instanceof lisk_db_1.NotFoundError)) {
throw error;
}
}
return transactions.map(tx => tx.toJSON());
}
async getTransactionsByHeight(context) {
const { height } = context.params;
if (typeof height !== 'number' || height < 0) {
throw new Error('Invalid parameters. height must be zero or a positive number.');
}
const block = await this._chain.dataAccess.getBlockByHeight(height);
return block.transactions.map(tx => tx.toJSON());
}
async getAssetsByHeight(context) {
const { height } = context.params;
if (typeof height !== 'number' || height < 0) {
throw new Error('Invalid parameters. height must be zero or a positive number.');
}
const block = await this._chain.dataAccess.getBlockByHeight(height);
return block.assets.toJSON();
}
getLastBlock() {
return this._chain.lastBlock.toJSON();
}
async getEvents(context) {
const { height } = context.params;
if (typeof height !== 'number' || height < 0) {
throw new Error('Invalid parameters. height must be zero or a positive number.');
}
const events = await this._chain.dataAccess.getEvents(height);
return events.map(e => e.toJSON());
}
async getInclusionProofsAtHeight(context) {
const { height } = context.params;
if (typeof height !== 'number' || height < 0) {
throw new Error('Invalid parameters. height must be zero or a positive number.');
}
const inclusionProof = await this._chain.dataAccess.getInclusionProofs(height);
return {
proof: {
queries: inclusionProof.queries.map(q => ({
bitmap: q.bitmap.toString('hex'),
key: q.key.toString('hex'),
value: q.value.toString('hex'),
})),
siblingHashes: inclusionProof.siblingHashes.map(h => h.toString('hex')),
},
};
}
async proveEvents(context) {
lisk_validator_1.validator.validate(proveEventsRequestSchema, context.params);
const { height, queries } = context.params;
const queryBytes = queries.map(q => Buffer.from(q, 'hex'));
const events = await this._chain.dataAccess.getEvents(height);
const eventSMT = new lisk_db_1.SparseMerkleTree(lisk_chain_1.EVENT_KEY_LENGTH);
const data = [];
for (const e of events) {
const pairs = e.keyPair();
for (const pair of pairs) {
data.push(pair);
}
}
const root = await eventSMT.update(constants_2.EMPTY_HASH, data);
const proof = await eventSMT.prove(root, queryBytes);
return {
queries: proof.queries.map(q => ({
bitmap: q.bitmap.toString('hex'),
key: q.key.toString('hex'),
value: q.value.toString('hex'),
})),
siblingHashes: proof.siblingHashes.map(h => h.toString('hex')),
};
}
async getGeneratorList(_) {
const stateStore = new lisk_chain_1.StateStore(this._db);
const votesStore = stateStore.getStore(constants_1.MODULE_STORE_PREFIX_BFT, constants_1.STORE_PREFIX_BFT_VOTES);
const bftVotes = await votesStore.getWithSchema(constants_1.EMPTY_KEY, schemas_1.bftVotesSchema);
const { height: currentHeight } = bftVotes.blockBFTInfos.length > 0 ? bftVotes.blockBFTInfos[0] : { height: 0 };
const bftStore = stateStore.getStore(constants_1.MODULE_STORE_PREFIX_BFT, constants_1.STORE_PREFIX_BFT_PARAMETERS);
const bftParams = await (0, bft_params_1.getBFTParameters)(bftStore, currentHeight + 1);
const slot = this._bftMethod.getSlotNumber(Math.floor(Date.now() / 1000));
const startTime = this._bftMethod.getSlotTime(slot);
let nextAllocatedTime = startTime;
const slotInRound = slot % bftParams.validators.length;
const generatorsInfo = [];
for (let i = slotInRound; i < slotInRound + bftParams.validators.length; i += 1) {
generatorsInfo.push({
address: lisk_cryptography_1.address.getLisk32AddressFromAddress(bftParams.validators[i % bftParams.validators.length].address),
nextAllocatedTime,
});
nextAllocatedTime += this._bftMethod.blockTime();
}
return {
list: generatorsInfo,
};
}
async areHeadersContradicting(context) {
lisk_validator_1.validator.validate(schemas_1.areHeadersContradictingRequestSchema, context.params);
const bftHeader1 = lisk_chain_1.BlockHeader.fromBytes(Buffer.from(context.params.header1, 'hex'));
const bftHeader2 = lisk_chain_1.BlockHeader.fromBytes(Buffer.from(context.params.header2, 'hex'));
if (bftHeader1.id.equals(bftHeader2.id)) {
return { valid: false };
}
return { valid: (0, utils_1.areDistinctHeadersContradicting)(bftHeader1, bftHeader2) };
}
}
exports.ChainEndpoint = ChainEndpoint;
//# sourceMappingURL=chain.js.map