@vechain/connex-driver
Version:
Connex framework driver implementation
242 lines • 20.6 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DriverNoVendor = void 0;
const thor_devkit_1 = require("thor-devkit");
const cache_1 = require("./cache");
const common_1 = require("./common");
const promint_1 = require("./promint");
/** class implements Connex.Driver leaves out Vendor related methods */
class DriverNoVendor {
constructor(net, genesis, initialHead) {
this.net = net;
this.genesis = genesis;
this.headResolvers = [];
this.int = new promint_1.PromInt();
this.cache = new cache_1.Cache();
// to merge concurrent identical remote requests
this.pendingRequests = {};
if (initialHead) {
this.head = initialHead;
}
else {
this.head = {
id: genesis.id,
number: genesis.number,
timestamp: genesis.timestamp,
parentID: genesis.parentID,
txsFeatures: genesis.txsFeatures,
gasLimit: genesis.gasLimit
};
if (genesis.baseFeePerGas) {
this.head.baseFeePerGas = genesis.baseFeePerGas;
}
}
void this.headTrackerLoop();
}
// close the driver to prevent mem leak
close() {
this.int.interrupt();
}
// implementations
pollHead() {
return this.int.wrap(new Promise(resolve => {
this.headResolvers.push(() => resolve(this.head));
}));
}
getBlock(revision) {
return this.cache.getBlock(revision, () => this.httpGet(`blocks/${revision}`));
}
getFeesHistory(newestBlock, blockCount, rewardPercentiles) {
return this.cache.getFeesHistory(newestBlock, blockCount, rewardPercentiles || [], () => {
const params = {
newestBlock: newestBlock.toString(),
blockCount: blockCount.toString()
};
if (rewardPercentiles && rewardPercentiles.length > 0) {
params.rewardPercentiles = rewardPercentiles.join(',');
}
return this.httpGet('fees/history', params);
});
}
getPriorityFeeSuggestion() {
// No cache since we do not have a key for it
return this.httpGet('fees/priority').then(res => res.maxPriorityFeePerGas);
}
getTransaction(id, allowPending) {
return this.cache.getTx(id, () => {
const query = { head: this.head.id };
if (allowPending) {
query.pending = 'true';
}
return this.httpGet(`transactions/${id}`, query);
});
}
getReceipt(id) {
return this.cache.getReceipt(id, () => this.httpGet(`transactions/${id}/receipt`, { head: this.head.id }));
}
getAccount(addr, revision) {
return this.cache.getAccount(addr, revision, () => this.httpGet(`accounts/${addr}`, { revision }));
}
getCode(addr, revision) {
return this.cache.getTied(`code-${addr}`, revision, () => this.httpGet(`accounts/${addr}/code`, { revision }));
}
getStorage(addr, key, revision) {
return this.cache.getTied(`storage-${addr}-${key}`, revision, () => this.httpGet(`accounts/${addr}/storage/${key}`, { revision }));
}
explain(arg, revision, cacheHints) {
const cacheKey = `explain-${(0, thor_devkit_1.blake2b256)(JSON.stringify(arg)).toString('hex')}`;
return this.cache.getTied(cacheKey, revision, () => this.httpPost('accounts/*', arg, { revision }), cacheHints);
}
filterEventLogs(arg, cacheHints) {
const cacheKey = `event-${(0, thor_devkit_1.blake2b256)(JSON.stringify(arg)).toString('hex')}`;
return this.cache.getTied(cacheKey, this.head.id, () => this.httpPost('logs/event', arg), cacheHints);
}
filterTransferLogs(arg, cacheHints) {
const cacheKey = `transfer-${(0, thor_devkit_1.blake2b256)(JSON.stringify(arg)).toString('hex')}`;
return this.cache.getTied(cacheKey, this.head.id, () => this.httpPost('logs/transfer', arg), cacheHints);
}
signTx(msg, options) {
throw new Error('signer not implemented');
}
signCert(msg, options) {
throw new Error('signer not implemented');
}
//////
mergeRequest(req, ...keyParts) {
const key = JSON.stringify(keyParts);
const pending = this.pendingRequests[key];
// eslint-disable-next-line @typescript-eslint/no-misused-promises
if (pending) {
return pending;
}
return this.pendingRequests[key] = (() => __awaiter(this, void 0, void 0, function* () {
try {
return yield req();
}
finally {
delete this.pendingRequests[key];
}
}))();
}
httpGet(path, query) {
return this.mergeRequest(() => {
return this.net.http('GET', path, {
query,
validateResponseHeader: this.headerValidator
});
}, path, query || '');
}
httpPost(path, body, query) {
return this.mergeRequest(() => {
return this.net.http('POST', path, {
query,
body,
validateResponseHeader: this.headerValidator
});
}, path, query || '', body || '');
}
get headerValidator() {
return (headers) => {
const xgid = headers['x-genesis-id'];
if (xgid && xgid !== this.genesis.id) {
throw new Error(`responded 'x-genesis-id' not matched`);
}
};
}
emitNewHead() {
const resolvers = this.headResolvers;
this.headResolvers = [];
resolvers.forEach(r => r());
}
headTrackerLoop() {
return __awaiter(this, void 0, void 0, function* () {
for (;;) {
let attemptWs = false;
try {
const best = yield this.int.wrap(this.httpGet('blocks/best'));
if (best.id !== this.head.id && best.number >= this.head.number) {
this.head = {
id: best.id,
number: best.number,
timestamp: best.timestamp,
parentID: best.parentID,
txsFeatures: best.txsFeatures,
gasLimit: best.gasLimit
};
if (best.baseFeePerGas) {
this.head.baseFeePerGas = best.baseFeePerGas;
}
this.cache.handleNewBlock(this.head, undefined, best);
this.emitNewHead();
if (Date.now() - this.head.timestamp * 1000 < 60 * 1000) {
// nearly synced
attemptWs = true;
}
}
}
catch (err) {
if (err instanceof promint_1.InterruptedError) {
break;
}
}
if (attemptWs) {
try {
yield this.trackWs();
}
catch (err) {
if (err instanceof promint_1.InterruptedError) {
break;
}
}
}
try {
yield this.int.wrap((0, common_1.sleep)(8 * 1000));
}
catch (_a) {
break;
}
}
});
}
trackWs() {
return __awaiter(this, void 0, void 0, function* () {
const wsPath = `subscriptions/beat2?pos=${this.head.parentID}`;
const wsr = this.net.openWebSocketReader(wsPath);
try {
for (;;) {
const data = yield this.int.wrap(wsr.read());
const beat = JSON.parse(data);
if (!beat.obsolete && beat.id !== this.head.id && beat.number >= this.head.number) {
this.head = {
id: beat.id,
number: beat.number,
timestamp: beat.timestamp,
parentID: beat.parentID,
txsFeatures: beat.txsFeatures,
gasLimit: beat.gasLimit
};
if (beat.baseFeePerGas) {
this.head.baseFeePerGas = beat.baseFeePerGas;
}
this.cache.handleNewBlock(this.head, { k: beat.k, bits: beat.bloom });
this.emitNewHead();
}
}
}
finally {
wsr.close();
}
});
}
}
exports.DriverNoVendor = DriverNoVendor;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJpdmVyLW5vLXZlbmRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kcml2ZXItbm8tdmVuZG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLDZDQUF3QztBQUN4QyxtQ0FBK0I7QUFDL0IscUNBQWdDO0FBRWhDLHVDQUFxRDtBQUVyRCx1RUFBdUU7QUFDdkUsTUFBYSxjQUFjO0lBU3ZCLFlBQ3VCLEdBQVEsRUFDbEIsT0FBMEIsRUFDbkMsV0FBd0M7UUFGckIsUUFBRyxHQUFILEdBQUcsQ0FBSztRQUNsQixZQUFPLEdBQVAsT0FBTyxDQUFtQjtRQVIvQixrQkFBYSxHQUFHLEVBQXVCLENBQUE7UUFDOUIsUUFBRyxHQUFHLElBQUksaUJBQU8sRUFBRSxDQUFBO1FBQ25CLFVBQUssR0FBRyxJQUFJLGFBQUssRUFBRSxDQUFBO1FBQ3BDLGdEQUFnRDtRQUMvQixvQkFBZSxHQUFpQyxFQUFFLENBQUE7UUFPL0QsSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNkLElBQUksQ0FBQyxJQUFJLEdBQUcsV0FBVyxDQUFBO1FBQzNCLENBQUM7YUFBTSxDQUFDO1lBQ0osSUFBSSxDQUFDLElBQUksR0FBRztnQkFDUixFQUFFLEVBQUUsT0FBTyxDQUFDLEVBQUU7Z0JBQ2QsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO2dCQUN0QixTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7Z0JBQzVCLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUTtnQkFDMUIsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXO2dCQUNoQyxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7YUFDN0IsQ0FBQTtZQUNELElBQUksT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUN4QixJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFBO1lBQ25ELENBQUM7UUFDTCxDQUFDO1FBQ0QsS0FBSyxJQUFJLENBQUMsZUFBZSxFQUFF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