lisk-framework
Version: 
Lisk blockchain application platform
152 lines • 6.47 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ABIClient = void 0;
const lisk_codec_1 = require("@liskhq/lisk-codec");
const zeromq_1 = require("zeromq");
const abi_1 = require("../abi");
const DEFAULT_TIMEOUT = 3000;
const MAX_UINT64 = BigInt(2) ** BigInt(64) - BigInt(1);
const defer = () => {
    let resolve;
    let reject;
    const promise = new Promise((_resolve, _reject) => {
        resolve = _resolve;
        reject = _reject;
    });
    return { promise, resolve, reject };
};
const timeout = async (ms, message) => new Promise((_, reject) => {
    const id = setTimeout(() => {
        clearTimeout(id);
        reject(new Error(message !== null && message !== void 0 ? message : `Timed out in ${ms}ms.`));
    }, ms);
});
class ABIClient {
    constructor(logger, socketPath) {
        this._pendingRequests = {};
        this._globalID = BigInt(0);
        this._logger = logger;
        this._socketPath = socketPath;
        this._dealer = new zeromq_1.Dealer();
    }
    async start() {
        await new Promise((resolve, reject) => {
            const connectionTimeout = setTimeout(() => {
                reject(new Error('IPC Socket client connection timeout. Please check if IPC server is running.'));
            }, DEFAULT_TIMEOUT);
            this._dealer.events.on('connect', () => {
                clearTimeout(connectionTimeout);
                resolve(undefined);
            });
            this._dealer.events.on('bind:error', reject);
            this._dealer.connect(this._socketPath);
        });
        this._listenToRPCResponse().catch(err => {
            this._logger.debug({ err: err }, 'Failed to listen to the ABI response');
        });
    }
    stop() {
        this._dealer.disconnect(this._socketPath);
        this._pendingRequests = {};
        this._globalID = BigInt(0);
    }
    async init(req) {
        return this._call('init', req, abi_1.initRequestSchema, abi_1.initResponseSchema);
    }
    async initStateMachine(req) {
        return this._call('initStateMachine', req, abi_1.initStateMachineRequestSchema, abi_1.initStateMachineResponseSchema);
    }
    async initGenesisState(req) {
        return this._call('initGenesisState', req, abi_1.initGenesisStateRequestSchema, abi_1.initGenesisStateResponseSchema);
    }
    async insertAssets(req) {
        return this._call('insertAssets', req, abi_1.insertAssetsRequestSchema, abi_1.insertAssetsResponseSchema);
    }
    async verifyAssets(req) {
        return this._call('verifyAssets', req, abi_1.verifyAssetsRequestSchema, abi_1.verifyAssetsResponseSchema);
    }
    async beforeTransactionsExecute(req) {
        return this._call('beforeTransactionsExecute', req, abi_1.beforeTransactionsExecuteRequestSchema, abi_1.beforeTransactionsExecuteResponseSchema);
    }
    async afterTransactionsExecute(req) {
        return this._call('afterTransactionsExecute', req, abi_1.afterTransactionsExecuteRequestSchema, abi_1.afterTransactionsExecuteResponseSchema);
    }
    async verifyTransaction(req) {
        return this._call('verifyTransaction', req, abi_1.verifyTransactionRequestSchema, abi_1.verifyTransactionResponseSchema);
    }
    async executeTransaction(req) {
        return this._call('executeTransaction', req, abi_1.executeTransactionRequestSchema, abi_1.executeTransactionResponseSchema);
    }
    async commit(req) {
        return this._call('commit', req, abi_1.commitRequestSchema, abi_1.commitResponseSchema);
    }
    async revert(req) {
        return this._call('revert', req, abi_1.revertRequestSchema, abi_1.revertResponseSchema);
    }
    async clear(req) {
        return this._call('clear', req, abi_1.clearRequestSchema, abi_1.clearResponseSchema);
    }
    async finalize(req) {
        return this._call('finalize', req, abi_1.finalizeRequestSchema, abi_1.finalizeResponseSchema);
    }
    async getMetadata(req) {
        return this._call('getMetadata', req, abi_1.metadataRequestSchema, abi_1.metadataResponseSchema);
    }
    async query(req) {
        return this._call('query', req, abi_1.queryRequestSchema, abi_1.queryResponseSchema);
    }
    async prove(req) {
        return this._call('prove', req, abi_1.proveRequestSchema, abi_1.proveResponseSchema);
    }
    async _call(method, req, requestSchema, respSchema) {
        const params = Object.keys(requestSchema.properties).length > 0
            ? lisk_codec_1.codec.encode(requestSchema, req)
            : Buffer.alloc(0);
        const requestBody = {
            id: this._globalID,
            method,
            params,
        };
        this._logger.debug({ method: requestBody.method, id: requestBody.id, file: 'abi_client' }, 'Requesting ABI server');
        const encodedRequest = lisk_codec_1.codec.encode(abi_1.ipcRequestSchema, requestBody);
        await this._dealer.send([encodedRequest]);
        const response = defer();
        this._pendingRequests[this._globalID.toString()] = response;
        this._globalID += BigInt(1);
        if (this._globalID >= MAX_UINT64) {
            this._globalID = BigInt(0);
        }
        const resp = await Promise.race([
            response.promise,
            timeout(DEFAULT_TIMEOUT, `Response not received in ${DEFAULT_TIMEOUT}ms`),
        ]);
        this._logger.debug({ method: requestBody.method, id: requestBody.id, file: 'abi_client' }, 'Received response from ABI server');
        const decodedResp = Object.keys(respSchema.properties).length > 0 ? lisk_codec_1.codec.decode(respSchema, resp) : {};
        return decodedResp;
    }
    async _listenToRPCResponse() {
        for await (const [message] of this._dealer) {
            let response;
            try {
                response = lisk_codec_1.codec.decode(abi_1.ipcResponseSchema, message);
            }
            catch (error) {
                this._logger.debug({ err: error }, 'Failed to decode ABI response');
                continue;
            }
            const deferred = this._pendingRequests[response.id.toString()];
            if (!deferred) {
                continue;
            }
            if (!response.success) {
                deferred.reject(new Error(response.error.message));
            }
            else {
                deferred.resolve(response.result);
            }
            delete this._pendingRequests[response.id.toString()];
        }
    }
}
exports.ABIClient = ABIClient;
//# sourceMappingURL=abi_client.js.map