Commit fd5108c8 authored by Cédric Moreau's avatar Cédric Moreau
Browse files

[enh] Upgrading to LevelDB for MIndex

parent f302be99
......@@ -71,7 +71,6 @@ import {HttpSource, HttpUD} from "../../modules/bma/lib/dtos"
import {GenericDAO} from "./indexDAL/abstract/GenericDAO"
import {LokiDAO} from "./indexDAL/loki/LokiDAO"
import {MonitorExecutionTime} from "../debug/MonitorExecutionTime"
import {SqliteMIndex} from "./indexDAL/sqlite/SqliteMIndex"
import {LevelDBDividend} from "./indexDAL/leveldb/LevelDBDividend"
import {LevelDBBindex} from "./indexDAL/leveldb/LevelDBBindex"
......@@ -83,6 +82,7 @@ import {SqlitePeers} from "./indexDAL/sqlite/SqlitePeers"
import {LevelDBWallet} from "./indexDAL/leveldb/LevelDBWallet"
import {LevelDBCindex} from "./indexDAL/leveldb/LevelDBCindex"
import {LevelDBIindex} from "./indexDAL/leveldb/LevelDBIindex"
import {LevelDBMindex} from "./indexDAL/leveldb/LevelDBMindex"
const readline = require('readline')
const indexer = require('../indexer').Indexer
......@@ -165,7 +165,7 @@ export class FileDAL {
this.peerDAL = new SqlitePeers(getSqliteDB)
this.walletDAL = new LevelDBWallet(getLevelDB)
this.bindexDAL = new LevelDBBindex(getLevelDB)
this.mindexDAL = new SqliteMIndex(getSqliteDB)
this.mindexDAL = new LevelDBMindex(getLevelDB)
this.iindexDAL = new LevelDBIindex(getLevelDB)
this.sindexDAL = new LevelDBSindex(getLevelDB)
this.cindexDAL = new LevelDBCindex(getLevelDB)
......@@ -761,8 +761,8 @@ export class FileDAL {
i.pubkey = i.pub
return i
}));
return await Promise.all<DBIdentity>(found.map(async (f:any) => {
const ms = await this.mindexDAL.getReducedMSForImplicitRevocation(f.pub);
return await Promise.all<DBIdentity>(found.map(async (f) => {
const ms = await this.mindexDAL.getReducedMSForImplicitRevocation(f.pubkey);
if (ms) {
f.revoked_on = null;
if (ms.revoked_on) {
......@@ -770,7 +770,7 @@ export class FileDAL {
f.revoked_on = blockOfRevocation.medianTime
}
f.revoked = !!f.revoked_on;
f.revocation_sig = ms.revocation || null;
f.revocation_sig = f.revocation_sig || ms.revocation || null;
}
return f;
}))
......
......@@ -9,9 +9,9 @@ export interface MIndexDAO extends ReduceableDAO<MindexEntry> {
findByPubAndChainableOnGt(pub:string, medianTime:number): Promise<MindexEntry[]>
findRevokesOnLteAndRevokedOnIsNull(medianTime:number): Promise<MindexEntry[]>
findRevokesOnLteAndRevokedOnIsNull(medianTime:number): Promise<string[]>
findExpiresOnLteAndRevokesOnGt(medianTime:number): Promise<MindexEntry[]>
findExpiresOnLteAndRevokesOnGt(medianTime:number): Promise<string[]>
getReducedMS(pub:string): Promise<FullMindexEntry|null>
......
import {MonitorExecutionTime} from "../../../debug/MonitorExecutionTime"
import {FullMindexEntry, MindexEntry, reduce, reduceForDBTrimming, reduceOrNull} from "../../../indexer"
import {LevelUp} from 'levelup'
import {LevelDBTable} from "./LevelDBTable"
import {Underscore} from "../../../common-libs/underscore"
import {pint} from "../../../common-libs/pint"
import {reduceConcat, reduceGroupBy} from "../../../common-libs/reduce"
import {LevelDBWrittenOnIndexer} from "./indexers/LevelDBWrittenOnIndexer"
import {MIndexDAO} from "../abstract/MIndexDAO"
import {LevelMIndexRevokesOnIndexer} from "./indexers/LevelMIndexRevokesOnIndexer"
import {LevelMIndexExpiresOnIndexer} from "./indexers/LevelMIndexExpiresOnIndexer"
export class LevelDBMindex extends LevelDBTable<MindexEntry[]> implements MIndexDAO {
private indexForExpiresOn: LevelMIndexExpiresOnIndexer
private indexForRevokesOn: LevelMIndexRevokesOnIndexer
private indexForWrittenOn: LevelDBWrittenOnIndexer<MindexEntry>
constructor(protected getLevelDB: (dbName: string)=> Promise<LevelUp>) {
super('level_mindex', getLevelDB)
}
/**
* TECHNICAL
*/
async init(): Promise<void> {
await super.init()
this.indexForExpiresOn = new LevelMIndexExpiresOnIndexer('level_mindex/expiresOn', this.getLevelDB)
this.indexForRevokesOn = new LevelMIndexRevokesOnIndexer('level_mindex/revokesOn', this.getLevelDB)
this.indexForWrittenOn = new LevelDBWrittenOnIndexer('level_mindex/writtenOn', this.getLevelDB, i => i.pub)
await this.indexForExpiresOn.init()
await this.indexForRevokesOn.init()
await this.indexForWrittenOn.init()
}
async close(): Promise<void> {
await super.close()
await this.indexForExpiresOn.close()
await this.indexForRevokesOn.close()
await this.indexForWrittenOn.close()
}
/**
* INSERT
*/
@MonitorExecutionTime()
async insert(record: MindexEntry): Promise<void> {
await this.insertBatch([record])
}
@MonitorExecutionTime()
async insertBatch(records: MindexEntry[]): Promise<void> {
// Database insertion
let prevRecords: MindexEntry[] = []
const recordsByPub = reduceGroupBy(records, 'pub')
await Promise.all(Underscore.keys(recordsByPub).map(async pub => {
const existing = (await this.getOrNull(pub)) || []
prevRecords = prevRecords.concat(existing)
await this.put(pub, existing.concat(recordsByPub[pub]))
}))
// Indexation
await this.indexForExpiresOn.onInsert(records, prevRecords)
await this.indexForRevokesOn.onInsert(records, prevRecords)
await this.indexForWrittenOn.onInsert(records)
}
/**
* Reduceable DAO
*/
async trimRecords(belowNumber: number): Promise<void> {
// Trim writtenOn: we remove from the index the blocks below `belowNumber`, and keep track of the deleted values
const pubkeys: string[] = Underscore.uniq((await this.indexForWrittenOn.deleteBelow(belowNumber)))
// For each entry, we trim the records of our INDEX
await Promise.all(pubkeys.map(async pub => {
const oldEntries = await this.get(pub)
const newEntries = reduceForDBTrimming(oldEntries, belowNumber)
await this.put(pub, newEntries)
}))
await this.indexForExpiresOn.onTrimming(belowNumber)
await this.indexForRevokesOn.onTrimming(belowNumber)
}
/**
* Generic DAO
*/
async findRawWithOrder(criterion: { pub?: string }, sort: (string | (string | boolean)[])[]): Promise<MindexEntry[]> {
const rows: MindexEntry[] = (await this.findAllValues()).reduce(reduceConcat, [])
return Underscore.sortBy(rows, r => `${String(r.writtenOn).padStart(10, '0')}-${r.pub}`)
}
async getWrittenOn(blockstamp: string): Promise<MindexEntry[]> {
const ids = (await this.indexForWrittenOn.getWrittenOnKeys(pint(blockstamp))) || []
return (await Promise.all(ids.map(id => this.get(id)))).reduce(reduceConcat, []).filter(e => e.written_on === blockstamp)
}
async removeBlock(blockstamp: string): Promise<void> {
// Trim writtenOn: we remove from the index the blocks below `belowNumber`, and keep track of the deleted values
let newStateRecords: MindexEntry[] = []
const writteOn = pint(blockstamp)
const pubkeys: string[] = Underscore.uniq((await this.indexForWrittenOn.deleteAt(writteOn)))
let removedRecords: MindexEntry[] = []
// For each entry, we trim the records of our INDEX
await Promise.all(pubkeys.map(async pub => {
const records = await this.get(pub)
const keptRecords = records.filter(e => e.written_on !== blockstamp)
removedRecords = removedRecords.concat(records.filter(e => e.written_on === blockstamp))
newStateRecords = newStateRecords.concat(keptRecords)
await this.put(pub, keptRecords)
}))
// Update indexes
await this.indexForExpiresOn.onRemove(removedRecords, newStateRecords)
await this.indexForRevokesOn.onRemove(removedRecords, newStateRecords)
}
//------------- DAO QUERIES --------------
async findByPubAndChainableOnGt(pub: string, medianTime: number): Promise<MindexEntry[]> {
return (await this.reducable(pub)).filter(e => e.chainable_on && e.chainable_on > medianTime)
}
async findExpiresOnLteAndRevokesOnGt(medianTime: number): Promise<string[]> {
return this.indexForExpiresOn.findExpiresOnLte(medianTime)
}
async findPubkeysThatShouldExpire(medianTime: number): Promise<{ pub: string; created_on: string }[]> {
const results: { pub: string; created_on: string }[] = []
const pubkeys = await this.findExpiresOnLteAndRevokesOnGt(medianTime)
for (const pub of pubkeys) {
const MS = await this.getReducedMS(pub) as FullMindexEntry // We are sure because `memberships` already comes from the MINDEX
const hasRenewedSince = MS.expires_on > medianTime;
if (!MS.expired_on && !hasRenewedSince) {
results.push({
pub: MS.pub,
created_on: MS.created_on,
})
}
}
return results
}
async findRevokesOnLteAndRevokedOnIsNull(medianTime: number): Promise<string[]> {
return this.indexForRevokesOn.findRevokesOnLte(medianTime)
}
async getReducedMS(pub: string): Promise<FullMindexEntry | null> {
const reducable = await this.reducable(pub)
return reduceOrNull(reducable) as FullMindexEntry
}
async getReducedMSForImplicitRevocation(pub: string): Promise<FullMindexEntry | null> {
return this.getReducedMS(pub)
}
async getRevokedPubkeys(): Promise<string[]> {
return this.findWhereTransform(v => !!reduce(v).revoked_on, kv => kv.key)
}
async reducable(pub: string): Promise<MindexEntry[]> {
return (await this.getOrNull(pub)) || []
}
}
......@@ -33,7 +33,6 @@ export class LevelDBTable<T> {
}
public async getOrNull(k: string): Promise<T|null> {
try {
const data = await this.db.get(k)
return JSON.parse(String(data)) as any
......
......@@ -2,9 +2,9 @@ import {LevelDBTable} from "../LevelDBTable"
export abstract class LevelDBDataIndex<T, R> extends LevelDBTable<T> {
public abstract onInsert(records: R[]): Promise<void>
public abstract onInsert(records: R[], newState: R[]): Promise<void>
public abstract onRemove(records: R[]): Promise<void>
public abstract onRemove(records: R[], newState: R[]): Promise<void>
public async onTrimming(belowNumber: number): Promise<void> {}
}
import {LevelDBDataIndex} from "../generic/LevelDBDataIndex"
import {MindexEntry, reduce} from "../../../../indexer"
import {reduceConcat, reduceGroupBy} from "../../../../common-libs/reduce"
import {pint} from "../../../../common-libs/pint"
import {Underscore} from "../../../../common-libs/underscore"
export type Pubkey = string
export class LevelMIndexExpiresOnIndexer extends LevelDBDataIndex<Pubkey[], MindexEntry> {
async onInsert(records: MindexEntry[], prevState: MindexEntry[]): Promise<void> {
const prevStateByPub = reduceGroupBy(prevState, 'pub')
// Case 1: expires_on change (when MS JOIN|RENEW)
const byExpiresOn = reduceGroupBy(records.filter(e => e.expires_on), "expires_on")
await Promise.all(Underscore.keys(byExpiresOn)
.map(async expiresOn => {
const pubkeys = byExpiresOn[expiresOn].map(e => e.pub)
// 1. If the key had a previous revokes_on, we remove it
const reducedWhosExpiresOnChanges = pubkeys.filter(p => prevStateByPub[p])
.map(p => reduce(prevStateByPub[p]))
.filter(r => r.expires_on && !r.expired_on)
for (const reduced of reducedWhosExpiresOnChanges) {
await this.removeAllKeysFromExpiresOn(reduced.expires_on as number, [reduced.pub])
}
// 2. We put the new value
await this.addAllKeysToExpiresOn(pint(expiresOn), byExpiresOn[expiresOn].map(e => e.pub))
})
)
// Case 2: expiration occurs
const pubkeysToexpire = Underscore.uniq(records.filter(e => e.expired_on).map(r => r.pub))
const prevStateFM = Underscore.values(prevStateByPub).map(reduce)
const byExpiresOnPrevState = reduceGroupBy(prevStateFM.filter(r => pubkeysToexpire.includes(r.pub)), 'expires_on')
await Promise.all(Underscore.keys(byExpiresOnPrevState)
.map(async expiresOn => this.removeAllKeysFromExpiresOn(pint(expiresOn), byExpiresOnPrevState[expiresOn].map(e => e.pub)))
)
}
async onRemove(records: MindexEntry[], newState: MindexEntry[]): Promise<void> {
const newStateByPub = reduceGroupBy(newState, 'pub')
// Case 1: expires_on change REVERT
const byExpiresOn = reduceGroupBy(records.filter(e => e.expires_on), "expires_on")
await Promise.all(Underscore.keys(byExpiresOn)
.map(async expiresOn => {
const pubkeys = byExpiresOn[expiresOn].map(e => e.pub)
// 1. Remove the existing value
await this.removeAllKeysFromExpiresOn(pint(expiresOn), pubkeys)
// 2. Put back the old one if it exists
const reduced = pubkeys
.filter(p => newStateByPub[p])
.map(p => newStateByPub[p])
.map(reduce)
.filter(r => r.expires_on)
for (const r of reduced) {
await this.addAllKeysToExpiresOn(r.expires_on as number, [r.pub])
}
})
)
// Case 2: expiration REVERT
const values: MindexEntry[] = Underscore.values(newStateByPub).map(entries => reduce(entries))
const byExpiredOn = reduceGroupBy(values, "expired_on")
await Promise.all(Underscore.keys(byExpiredOn)
.map(async expiresOn => this.addAllKeysToExpiresOn(pint(expiresOn), byExpiredOn[expiresOn].map(e => e.pub)))
)
}
async addAllKeysToExpiresOn(expiresOn: number, pubkeys: Pubkey[]): Promise<void> {
const key = LevelMIndexExpiresOnIndexer.trimKey(expiresOn)
let entry = await this.getOrNull(key)
if (!entry) {
entry = []
}
for (const pub of pubkeys) {
entry.push(pub)
}
await this.put(key, entry)
}
async removeAllKeysFromExpiresOn(expiresOn: number, pubkeys: Pubkey[]): Promise<void> {
// We remove the "expires_on" indexed values
const key = LevelMIndexExpiresOnIndexer.trimKey(expiresOn)
const entry = await this.get(key)
for (const pub of pubkeys) {
if (entry.includes(pub)) {
entry.splice(entry.indexOf(pub), 1)
}
}
if (entry.length) {
// Some expirations left
await this.put(key, entry) // TODO: test this, can occur, probably not covered
} else {
// No more expirations left
await this.del(key)
}
}
async findExpiresOnLte(medianTime: number) {
return (await this.findAllValues({ lte: LevelMIndexExpiresOnIndexer.trimKey(medianTime) })).reduce(reduceConcat, [])
}
private static trimKey(expiresOn: number) {
return String(expiresOn).padStart(10, '0')
}
}
import {LevelDBDataIndex} from "../generic/LevelDBDataIndex"
import {MindexEntry, reduce} from "../../../../indexer"
import {reduceConcat, reduceGroupBy} from "../../../../common-libs/reduce"
import {Underscore} from "../../../../common-libs/underscore"
import {pint} from "../../../../common-libs/pint"
export type Pubkey = string
export class LevelMIndexRevokesOnIndexer extends LevelDBDataIndex<Pubkey[], MindexEntry> {
async onInsert(records: MindexEntry[], prevState: MindexEntry[]): Promise<void> {
const prevStateByPub = reduceGroupBy(prevState, 'pub')
// Case 1: revokes_on change (when MS JOIN|RENEW)
const byRevokesOn = reduceGroupBy(records.filter(e => e.revokes_on), "revokes_on")
await Promise.all(Underscore.keys(byRevokesOn)
.map(async revokesOn => {
const pubkeys = byRevokesOn[revokesOn].map(e => e.pub)
// 1. If the key had a previous revokes_on, we remove it
const reducedWhosRevokesOnChanges = pubkeys.filter(p => prevStateByPub[p])
.map(p => reduce(prevStateByPub[p]))
.filter(r => r.revokes_on && !r.revoked_on)
for (const reduced of reducedWhosRevokesOnChanges) {
await this.removeAllKeysFromRevokesOn(reduced.revokes_on as number, [reduced.pub])
}
// 2. We put the new value
await this.addAllKeysToRevokesOn(pint(revokesOn), byRevokesOn[revokesOn].map(e => e.pub))
})
)
// Case 2: revocation occurs
const pubkeysToRevoke = Underscore.uniq(records.filter(e => e.revoked_on).map(r => r.pub))
const prevStateFM = Underscore.values(prevStateByPub).map(reduce)
const byRevokesOnPrevState = reduceGroupBy(prevStateFM.filter(r => pubkeysToRevoke.includes(r.pub)), 'revokes_on')
await Promise.all(Underscore.keys(byRevokesOnPrevState)
.map(async revokesOn => this.removeAllKeysFromRevokesOn(pint(revokesOn), byRevokesOnPrevState[revokesOn].map(e => e.pub)))
)
}
async onRemove(records: MindexEntry[], newState: MindexEntry[]): Promise<void> {
const newStateByPub = reduceGroupBy(newState, 'pub')
// Case 1: revokes_on change REVERT
const byRevokesOn = reduceGroupBy(records.filter(e => e.revokes_on), "revokes_on")
await Promise.all(Underscore.keys(byRevokesOn)
.map(async revokesOn => {
const pubkeys = byRevokesOn[revokesOn].map(e => e.pub)
// 1. Remove the existing value
await this.removeAllKeysFromRevokesOn(pint(revokesOn), pubkeys)
// 2. Put back the old one if it exists
const reduced = pubkeys
.filter(p => newStateByPub[p])
.map(p => newStateByPub[p])
.map(reduce)
.filter(r => r.revokes_on)
for (const r of reduced) {
await this.addAllKeysToRevokesOn(r.revokes_on as number, [r.pub])
}
})
)
// Case 2: revocation REVERT
const values: MindexEntry[] = Underscore.values(newStateByPub).map(entries => reduce(entries))
const byExpiredOn = reduceGroupBy(values, "revoked_on")
await Promise.all(Underscore.keys(byExpiredOn)
.map(async revokesOn => this.addAllKeysToRevokesOn(pint(revokesOn), byExpiredOn[revokesOn].map(e => e.pub)))
)
}
async addAllKeysToRevokesOn(revokesOn: number, pubkeys: Pubkey[]): Promise<void> {
const key = LevelMIndexRevokesOnIndexer.trimKey(revokesOn)
let entry = await this.getOrNull(key)
if (!entry) {
entry = []
}
for (const pub of pubkeys) {
entry.push(pub)
}
await this.put(key, entry)
}
async removeAllKeysFromRevokesOn(revokesOn: number, pubkeys: Pubkey[]): Promise<void> {
// We remove the "revokes_on" indexed values
const key = LevelMIndexRevokesOnIndexer.trimKey(revokesOn)
const entry = await this.get(key)
for (const pub of pubkeys) {
if (entry.includes(pub)) {
entry.splice(entry.indexOf(pub), 1)
}
}
if (entry.length) {
// Some revocations left
await this.put(key, entry) // TODO: test this, can occur, probably not covered
} else {
// No more revocations left
await this.del(key)
}
}
async findRevokesOnLte(revokesOn: number): Promise<Pubkey[]> {
return (await this.findAllValues({ lte: LevelMIndexRevokesOnIndexer.trimKey(revokesOn) })).reduce(reduceConcat, [])
}
private static trimKey(revokesOn: number) {
return String(revokesOn).padStart(10, '0')
}
}
import {FullMindexEntry, Indexer, MindexEntry, reduceBy} from "../../../indexer"
import {FullMindexEntry, Indexer, MindexEntry} from "../../../indexer"
import {MIndexDAO} from "../abstract/MIndexDAO"
import {LokiPubkeySharingIndex} from "./LokiPubkeySharingIndex"
import {MonitorExecutionTime} from "../../../debug/MonitorExecutionTime"
......@@ -21,7 +21,7 @@ export class LokiMIndex extends LokiPubkeySharingIndex<MindexEntry> implements M
}
@MonitorExecutionTime()
async findExpiresOnLteAndRevokesOnGt(medianTime: number): Promise<MindexEntry[]> {
async findExpiresOnLteAndRevokesOnGt(medianTime: number): Promise<string[]> {
return this.collection
.find({
$and: [
......@@ -29,10 +29,11 @@ export class LokiMIndex extends LokiPubkeySharingIndex<MindexEntry> implements M
{ revokes_on: { $gt: medianTime } },
]
})
.map(e => e.pub)
}
@MonitorExecutionTime()
async findRevokesOnLteAndRevokedOnIsNull(medianTime: number): Promise<MindexEntry[]> {
async findRevokesOnLteAndRevokedOnIsNull(medianTime: number): Promise<string[]> {
return this.collection
.find({
$and: [
......@@ -40,6 +41,7 @@ export class LokiMIndex extends LokiPubkeySharingIndex<MindexEntry> implements M
{ revoked_on: null },
]
})
.map(e => e.pub)
}
@MonitorExecutionTime()
async getReducedMS(pub: string): Promise<FullMindexEntry | null> {
......@@ -70,9 +72,9 @@ export class LokiMIndex extends LokiPubkeySharingIndex<MindexEntry> implements M
async findPubkeysThatShouldExpire(medianTime: number): Promise<{ pub: string; created_on: string }[]> {
const results: { pub: string; created_on: string }[] = []
const memberships: MindexEntry[] = reduceBy(await this.findExpiresOnLteAndRevokesOnGt(medianTime), ['pub'])
for (const POTENTIAL of memberships) {
const MS = await this.getReducedMS(POTENTIAL.pub) as FullMindexEntry // We are sure because `memberships` already comes from the MINDEX
const pubkeys = await this.findExpiresOnLteAndRevokesOnGt(medianTime)
for (const pub of pubkeys) {
const MS = await this.getReducedMS(pub) as FullMindexEntry // We are sure because `memberships` already comes from the MINDEX
const hasRenewedSince = MS.expires_on > medianTime;
if (!MS.expired_on && !hasRenewedSince) {
results.push({
......
......@@ -205,8 +205,9 @@ export class SqliteMIndex extends SqliteTable<MindexEntry> implements MIndexDAO
}
@MonitorExecutionTime()
async findRevokesOnLteAndRevokedOnIsNull(medianTime: number): Promise<MindexEntry[]> {
return this.find('SELECT * FROM mindex WHERE revokes_on <= ? AND revoked_on IS NULL', [medianTime])
async findRevokesOnLteAndRevokedOnIsNull(medianTime: number): Promise<string[]> {
return (await this.find('SELECT * FROM mindex WHERE revokes_on <= ? AND revoked_on IS NULL', [medianTime]))
.map(e => e.pub)
}
@MonitorExecutionTime()
......@@ -271,7 +272,7 @@ export class SqliteMIndex extends SqliteTable<MindexEntry> implements MIndexDAO
return this.findEntities('SELECT * FROM mindex WHERE pub = ? order by writtenOn ASC', [pub])
}
async findExpiresOnLteAndRevokesOnGt(medianTime: number): Promise<MindexEntry[]> {
async findExpiresOnLteAndRevokesOnGt(medianTime: number): Promise<string[]> {
return []
}
......
......@@ -807,9 +807,9 @@ export class Indexer {
if (HEAD.number > 0) {
await Promise.all(mindex.map(async (ENTRY: MindexEntry) => {
if (ENTRY.revocation === null) {
const rows = await dal.mindexDAL.findByPubAndChainableOnGt(ENTRY.pub, HEAD_1.medianTime)
// This rule will be enabled on
if (HEAD.medianTime >= 1498860000) {
const rows = await dal.mindexDAL.findByPubAndChainableOnGt(ENTRY.pub, HEAD_1.medianTime)
ENTRY.unchainables = count(rows);
}
}
......@@ -1837,12 +1837,12 @@ export class Indexer {
static async ruleIndexGenImplicitRevocation(HEAD: DBHead, dal:FileDAL) {
const revocations = [];
const pending = await dal.mindexDAL.findRevokesOnLteAndRevokedOnIsNull(HEAD.medianTime)
for (const MS of pending) {
const REDUCED = (await dal.mindexDAL.getReducedMSForImplicitRevocation(MS.pub)) as FullMindexEntry
for (const pub of pending) {
const REDUCED = (await dal.mindexDAL.getReducedMSForImplicitRevocation(pub)) as FullMindexEntry
if (REDUCED.revokes_on <= HEAD.medianTime && !REDUCED.revoked_on) {
revocations.push({
op: 'UPDATE',
pub: MS.pub,
pub: pub,
created_on: REDUCED.created_on,
written_on: [HEAD.number, HEAD.hash].join('-'),
writtenOn: HEAD.number,
......
......@@ -118,7 +118,7 @@ export const MemFS = (initialTree:{ [folder:string]: { [file:string]: string }}
export const Directory = {
DATA_FILES: ['mindex.db', 'c_mindex.db', 'iindex.db', 'cindex.db', 'sindex.db', 'wallet.db', 'dividend.db', 'txs.db', 'peers.db'],
DATA_DIRS: ['level_dividend', 'level_bindex', 'level_blockchain'