@vechain/connex.driver-nodejs
Version:
Connex framework driver implementation in NodeJS
229 lines • 18.4 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const LRU = require("lru-cache");
const bloom_1 = require("thor-devkit/dist/bloom");
const bignumber_js_1 = require("bignumber.js");
const WINDOW_LEN = 12;
class Cache {
constructor() {
this.irreversible = {
blocks: new LRU(256),
txs: new LRU(512),
receipts: new LRU(512)
};
this.window = [];
}
handleNewBlock(head, bloom, block) {
while (this.window.length > 0) {
const top = this.window[this.window.length - 1];
if (top.id === head.id) {
return;
}
if (top.id === head.parentID) {
break;
}
this.window.pop();
}
this.window.push(Object.assign({}, head, { bloom: bloom ? new bloom_1.Bloom(bloom.k, Buffer.from(bloom.bits.slice(2), 'hex')) : undefined, block, accounts: new Map(), txs: new Map(), receipts: new Map(), tied: new Map() }));
// shift out old slots and move cached items into frozen cache
while (this.window.length > WINDOW_LEN) {
const bottom = this.window.shift();
bottom.txs.forEach((v, k) => this.irreversible.txs.set(k, v));
bottom.receipts.forEach((v, k) => this.irreversible.receipts.set(k, v));
if (bottom.block) {
this.irreversible.blocks.set(bottom.block.id, bottom.block);
this.irreversible.blocks.set(bottom.block.number, bottom.block);
}
}
}
getBlock(revision, fetch) {
return __awaiter(this, void 0, void 0, function* () {
let block = this.irreversible.blocks.get(revision) || null;
if (block) {
return block;
}
const { slot } = this.findSlot(revision);
if (slot && slot.block) {
return slot.block;
}
block = yield fetch();
if (block) {
if (slot && slot.id === block.id) {
slot.block = block;
}
if (this.isIrreversible(block.number)) {
this.irreversible.blocks.set(block.id, block);
if (block.isTrunk) {
this.irreversible.blocks.set(block.number, block);
}
}
}
return block;
});
}
getTx(txid, fetch) {
return __awaiter(this, void 0, void 0, function* () {
let tx = this.irreversible.txs.get(txid) || null;
if (tx) {
return tx;
}
for (const slot of this.window) {
tx = slot.txs.get(txid) || null;
if (tx) {
return tx;
}
}
tx = yield fetch();
if (tx) {
const { slot } = this.findSlot(tx.meta.blockID);
if (slot) {
slot.txs.set(txid, tx);
}
if (this.isIrreversible(tx.meta.blockNumber)) {
this.irreversible.txs.set(txid, tx);
}
}
return tx;
});
}
getReceipt(txid, fetch) {
return __awaiter(this, void 0, void 0, function* () {
let receipt = this.irreversible.receipts.get(txid) || null;
if (receipt) {
return receipt;
}
for (const slot of this.window) {
receipt = slot.receipts.get(txid) || null;
if (receipt) {
return receipt;
}
}
receipt = yield fetch();
if (receipt) {
const { slot } = this.findSlot(receipt.meta.blockID);
if (slot) {
slot.receipts.set(txid, receipt);
}
if (this.isIrreversible(receipt.meta.blockNumber)) {
this.irreversible.receipts.set(txid, receipt);
}
}
return receipt;
});
}
getAccount(addr, revision, fetch) {
return __awaiter(this, void 0, void 0, function* () {
const found = this.findSlot(revision);
for (let i = found.index; i >= 0; i--) {
const slot = this.window[i];
const acc = slot.accounts.get(addr);
if (acc) {
if (i !== found.index) {
found.slot.accounts.set(addr, acc);
}
return acc.snapshot(found.slot.timestamp);
}
if (!slot.bloom || testBytesHex(slot.bloom, addr)) {
// account might be dirty
break;
}
}
const accObj = yield fetch();
if (found.slot) {
found.slot.accounts.set(addr, new Account(accObj, found.slot.timestamp));
}
return accObj;
});
}
/**
* get cached entry which is tied to a batch of addresses
* @param key the cache key
* @param revision block id where cache bound to
* @param fetch to fetch value when cache missing
* @param ties array of tied addresses, as the gist to invalidate cache key. undefined means the key is always
* invalidated on different revision.
*/
getTied(key, revision, fetch, ties) {
return __awaiter(this, void 0, void 0, function* () {
const found = this.findSlot(revision);
for (let i = found.index; i >= 0; i--) {
const slot = this.window[i];
const v = slot.tied.get(key);
if (v) {
if (i !== found.index) {
found.slot.tied.set(key, v);
}
return v;
}
if (!slot.bloom || !ties) {
break;
}
// if ties.length === 0, never invalidate cache
if (ties.some(t => testBytesHex(slot.bloom, t))) {
// might be dirty
break;
}
}
const value = yield fetch();
if (found.slot) {
found.slot.tied.set(key, value);
}
return value;
});
}
findSlot(revision) {
const index = this.window.findIndex(s => s.id === revision || s.number === revision);
if (index >= 0) {
return { slot: this.window[index], index };
}
return { index };
}
isIrreversible(n) {
if (this.window.length > 0) {
return n < this.window[this.window.length - 1].number - WINDOW_LEN;
}
return false;
}
}
exports.Cache = Cache;
function testBytesHex(bloom, hex) {
let buf = Buffer.from(hex.slice(2), 'hex');
const nzIndex = buf.findIndex(v => v !== 0);
if (nzIndex < 0) {
buf = Buffer.alloc(0);
}
else {
buf = buf.slice(nzIndex);
}
return bloom.test(buf);
}
const ENERGY_GROWTH_RATE = 5000000000;
class Account {
constructor(obj, initTimestamp) {
this.obj = obj;
this.initTimestamp = initTimestamp;
}
snapshot(timestamp) {
return Object.assign({}, this.obj, { energy: this.energyAt(timestamp) });
}
energyAt(timestamp) {
if (timestamp < this.initTimestamp) {
return this.obj.energy;
}
return '0x' + new bignumber_js_1.default(this.obj.balance)
.times(timestamp - this.initTimestamp)
.times(ENERGY_GROWTH_RATE)
.dividedToIntegerBy(1e18)
.plus(this.obj.energy)
.toString(16);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUFBLGlDQUFnQztBQUNoQyxrREFBOEM7QUFDOUMsK0NBQW9DO0FBRXBDLE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQTtBQVlyQixNQUFhLEtBQUs7SUFBbEI7UUFDcUIsaUJBQVksR0FBRztZQUM1QixNQUFNLEVBQUUsSUFBSSxHQUFHLENBQXFDLEdBQUcsQ0FBQztZQUN4RCxHQUFHLEVBQUUsSUFBSSxHQUFHLENBQWtDLEdBQUcsQ0FBQztZQUNsRCxRQUFRLEVBQUUsSUFBSSxHQUFHLENBQThCLEdBQUcsQ0FBQztTQUN0RCxDQUFBO1FBQ2dCLFdBQU0sR0FBVyxFQUFFLENBQUE7SUFzTnhDLENBQUM7SUFwTlUsY0FBYyxDQUNqQixJQUFnQyxFQUNoQyxLQUFtQyxFQUNuQyxLQUF5QjtRQUV6QixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUMzQixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFBO1lBQy9DLElBQUksR0FBRyxDQUFDLEVBQUUsS0FBSyxJQUFJLENBQUMsRUFBRSxFQUFFO2dCQUNwQixPQUFNO2FBQ1Q7WUFDRCxJQUFJLEdBQUcsQ0FBQyxFQUFFLEtBQUssSUFBSSxDQUFDLFFBQVEsRUFBRTtnQkFDMUIsTUFBSzthQUNSO1lBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQTtTQUNwQjtRQUVELElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxtQkFDVCxJQUFJLElBQ1AsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxhQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJ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