Skip to content
Snippets Groups Projects
Commit 04910e5f authored by tykayn's avatar tykayn
Browse files

formatting all

parent b3996857
No related branches found
No related tags found
1 merge request!1294Husky linting hooks
Showing
with 1225 additions and 677 deletions
This diff is collapsed.
{ {
"parserOptions": { "parserOptions": {
"ecmaVersion": 8 "ecmaVersion": 8,
"sourceType": "module"
}, },
"plugins": [ "plugins": [
"mocha" "mocha"
......
...@@ -11,84 +11,88 @@ ...@@ -11,84 +11,88 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
const SAMPLING_PERIOD = 150 // milliseconds const SAMPLING_PERIOD = 150; // milliseconds
const MAX_SAMPLES_DISTANCE = 20 * 1000000 // seconds const MAX_SAMPLES_DISTANCE = 20 * 1000000; // seconds
export function getMicrosecondsTime() { export function getMicrosecondsTime() {
const [ seconds, nanoseconds ] = process.hrtime() const [seconds, nanoseconds] = process.hrtime();
return seconds * 1000000 + nanoseconds / 1000 return seconds * 1000000 + nanoseconds / 1000;
} }
export function getNanosecondsTime() { export function getNanosecondsTime() {
const [ seconds, nanoseconds ] = process.hrtime() const [seconds, nanoseconds] = process.hrtime();
return seconds * 1000000 + nanoseconds return seconds * 1000000 + nanoseconds;
} }
export function getDurationInMicroSeconds(before: number) { export function getDurationInMicroSeconds(before: number) {
return parseInt(String(getMicrosecondsTime() - before)) return parseInt(String(getMicrosecondsTime() - before));
} }
interface CpuUsage { interface CpuUsage {
user: number user: number;
system:number system: number;
} }
interface CpuUsageAt { interface CpuUsageAt {
usage:number usage: number;
at:number // microseconds timestamp at: number; // microseconds timestamp
elapsed:number // microseconds elapsed for this result elapsed: number; // microseconds elapsed for this result
} }
export class ProcessCpuProfiler { export class ProcessCpuProfiler {
private cumulatedUsage: CpuUsage;
private cumulatedUsage: CpuUsage private startedAt: number; // microseconds timestamp
private startedAt:number // microseconds timestamp private samples: CpuUsageAt[] = [];
private samples:CpuUsageAt[] = []
constructor(samplingPeriod = SAMPLING_PERIOD) { constructor(samplingPeriod = SAMPLING_PERIOD) {
// Initial state // Initial state
const start = getMicrosecondsTime() const start = getMicrosecondsTime();
this.startedAt = start this.startedAt = start;
this.cumulatedUsage = process.cpuUsage() this.cumulatedUsage = process.cpuUsage();
this.samples.push({ usage: 0, at: start, elapsed: 1 }) this.samples.push({ usage: 0, at: start, elapsed: 1 });
// Periodic sample // Periodic sample
setInterval(() => { setInterval(() => {
const newSampleAt = getMicrosecondsTime() const newSampleAt = getMicrosecondsTime();
const newUsage:CpuUsage = process.cpuUsage() const newUsage: CpuUsage = process.cpuUsage();
const elapsed = newSampleAt - this.lastSampleAt const elapsed = newSampleAt - this.lastSampleAt;
const userDiff = newUsage.user - this.cumulatedUsage.user const userDiff = newUsage.user - this.cumulatedUsage.user;
const usagePercent = userDiff / elapsed // The percent of time consumed by the process since last sample const usagePercent = userDiff / elapsed; // The percent of time consumed by the process since last sample
this.samples.push({ usage: usagePercent, at: newSampleAt, elapsed }) this.samples.push({ usage: usagePercent, at: newSampleAt, elapsed });
while (this.samplesDistance > MAX_SAMPLES_DISTANCE) { while (this.samplesDistance > MAX_SAMPLES_DISTANCE) {
this.samples.shift() this.samples.shift();
} }
this.cumulatedUsage = newUsage this.cumulatedUsage = newUsage;
// console.log('Time elapsed: %s microseconds, = %s %CPU', elapsed, (usagePercent*100).toFixed(2)) // console.log('Time elapsed: %s microseconds, = %s %CPU', elapsed, (usagePercent*100).toFixed(2))
}, samplingPeriod) }, samplingPeriod);
} }
private get lastSampleAt() { private get lastSampleAt() {
return this.samples[this.samples.length - 1].at return this.samples[this.samples.length - 1].at;
} }
private get samplesDistance() { private get samplesDistance() {
return this.samples[this.samples.length - 1].at - this.samples[0].at return this.samples[this.samples.length - 1].at - this.samples[0].at;
} }
cpuUsageOverLastMilliseconds(elapsedMilliseconds: number) { cpuUsageOverLastMilliseconds(elapsedMilliseconds: number) {
return this.cpuUsageOverLastX(elapsedMilliseconds * 1000) return this.cpuUsageOverLastX(elapsedMilliseconds * 1000);
} }
private cpuUsageOverLastX(nbMicrosecondsElapsed: number) { private cpuUsageOverLastX(nbMicrosecondsElapsed: number) {
return this.getSamplesResult(getMicrosecondsTime() - nbMicrosecondsElapsed) return this.getSamplesResult(getMicrosecondsTime() - nbMicrosecondsElapsed);
} }
private getSamplesResult(minTimestamp: number) { private getSamplesResult(minTimestamp: number) {
const matchingSamples = this.samples.filter(s => s.at >= minTimestamp - SAMPLING_PERIOD * 1000) const matchingSamples = this.samples.filter(
const cumulativeElapsed = matchingSamples.reduce((sum, s) => sum + s.elapsed, 0) (s) => s.at >= minTimestamp - SAMPLING_PERIOD * 1000
);
const cumulativeElapsed = matchingSamples.reduce(
(sum, s) => sum + s.elapsed,
0
);
return matchingSamples.reduce((cumulated, percent) => { return matchingSamples.reduce((cumulated, percent) => {
const weight = percent.elapsed / cumulativeElapsed const weight = percent.elapsed / cumulativeElapsed;
return cumulated + percent.usage * weight return cumulated + percent.usage * weight;
}, 0) }, 0);
} }
} }
...@@ -11,30 +11,30 @@ ...@@ -11,30 +11,30 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
const Command = require('commander').Command; const Command = require("commander").Command;
const pjson = require('../package.json'); const pjson = require("../package.json");
export const ExecuteCommand = () => { export const ExecuteCommand = () => {
const options: any = []; const options: any = [];
const commands: any = []; const commands: any = [];
return { return {
addOption: (optFormat: string, optDesc: string, optParser: any) =>
options.push({ optFormat, optDesc, optParser }),
addOption: (optFormat:string, optDesc:string, optParser:any) => options.push({ optFormat, optDesc, optParser }), addCommand: (command: any, executionCallback: any) =>
commands.push({ command, executionCallback }),
addCommand: (command:any, executionCallback:any) => commands.push({ command, executionCallback }),
// To execute the provided command // To execute the provided command
execute: async (programArgs: string[]) => { execute: async (programArgs: string[]) => {
const program = new Command(); const program = new Command();
// Callback for command success // Callback for command success
let onResolve: any; let onResolve: any;
// Callback for command rejection // Callback for command rejection
let onReject:any = () => Promise.reject(Error("Uninitilized rejection throw")); let onReject: any = () =>
Promise.reject(Error("Uninitilized rejection throw"));
// Command execution promise // Command execution promise
const currentCommand = new Promise((resolve, reject) => { const currentCommand = new Promise((resolve, reject) => {
...@@ -44,43 +44,84 @@ export const ExecuteCommand = () => { ...@@ -44,43 +44,84 @@ export const ExecuteCommand = () => {
program program
.version(pjson.version) .version(pjson.version)
.usage('<command> [options]') .usage("<command> [options]")
.option('--home <path>', 'Path to Duniter HOME (defaults to "$HOME/.config/duniter").') .option(
.option('-d, --mdb <name>', 'Database name (defaults to "duniter_default").') "--home <path>",
'Path to Duniter HOME (defaults to "$HOME/.config/duniter").'
.option('--autoconf', 'With `config` and `init` commands, will guess the best network and key options witout asking for confirmation') )
.option('--addep <endpoint>', 'With `config` command, add given endpoint to the list of endpoints of this node') .option(
.option('--remep <endpoint>', 'With `config` command, remove given endpoint to the list of endpoints of this node') "-d, --mdb <name>",
'Database name (defaults to "duniter_default").'
.option('--cpu <percent>', 'Percent of CPU usage for proof-of-work computation', parsePercent) )
.option('--nb-cores <number>', 'Number of cores uses for proof-of-work computation', parseInt)
.option('--prefix <nodeId>', 'Prefix node id for the first character of nonce', parseInt) .option(
"--autoconf",
.option('-c, --currency <name>', 'Name of the currency managed by this node.') "With `config` and `init` commands, will guess the best network and key options witout asking for confirmation"
)
.option('--nostdout', 'Disable stdout printing for `export-bc` command') .option(
.option('--noshuffle', 'Disable peers shuffling for `sync` command') "--addep <endpoint>",
"With `config` command, add given endpoint to the list of endpoints of this node"
.option('--socks-proxy <host:port>', 'Use Socks Proxy') )
.option('--tor-proxy <host:port>', 'Use Tor Socks Proxy') .option(
.option('--reaching-clear-ep <clear|tor|none>', 'method for reaching an clear endpoint') "--remep <endpoint>",
.option('--force-tor', 'force duniter to contact endpoint tor (if you redirect the traffic to tor yourself)') "With `config` command, remove given endpoint to the list of endpoints of this node"
.option('--rm-proxies', 'Remove all proxies') )
.option('--timeout <milliseconds>', 'Timeout to use when contacting peers', parseInt) .option(
.option('--httplogs', 'Enable HTTP logs') "--cpu <percent>",
.option('--nohttplogs', 'Disable HTTP logs') "Percent of CPU usage for proof-of-work computation",
.option('--isolate', 'Avoid the node to send peering or status informations to the network') parsePercent
.option('--forksize <size>', 'Maximum size of fork window', parseInt) )
.option('--notrim', 'Disable the INDEX trimming.') .option(
.option('--notrimc', 'Disable the C_INDEX trimming specifically.') "--nb-cores <number>",
.option('--memory', 'Memory mode') "Number of cores uses for proof-of-work computation",
; parseInt
)
.option(
"--prefix <nodeId>",
"Prefix node id for the first character of nonce",
parseInt
)
.option(
"-c, --currency <name>",
"Name of the currency managed by this node."
)
.option("--nostdout", "Disable stdout printing for `export-bc` command")
.option("--noshuffle", "Disable peers shuffling for `sync` command")
.option("--socks-proxy <host:port>", "Use Socks Proxy")
.option("--tor-proxy <host:port>", "Use Tor Socks Proxy")
.option(
"--reaching-clear-ep <clear|tor|none>",
"method for reaching an clear endpoint"
)
.option(
"--force-tor",
"force duniter to contact endpoint tor (if you redirect the traffic to tor yourself)"
)
.option("--rm-proxies", "Remove all proxies")
.option(
"--timeout <milliseconds>",
"Timeout to use when contacting peers",
parseInt
)
.option("--httplogs", "Enable HTTP logs")
.option("--nohttplogs", "Disable HTTP logs")
.option(
"--isolate",
"Avoid the node to send peering or status informations to the network"
)
.option("--forksize <size>", "Maximum size of fork window", parseInt)
.option("--notrim", "Disable the INDEX trimming.")
.option("--notrimc", "Disable the C_INDEX trimming specifically.")
.option("--memory", "Memory mode");
for (const opt of options) { for (const opt of options) {
program program.option(opt.optFormat, opt.optDesc, opt.optParser);
.option(opt.optFormat, opt.optDesc, opt.optParser);
} }
for (const cmd of commands) { for (const cmd of commands) {
...@@ -90,7 +131,10 @@ export const ExecuteCommand = () => { ...@@ -90,7 +131,10 @@ export const ExecuteCommand = () => {
.action(async function () { .action(async function () {
const args = Array.from(arguments); const args = Array.from(arguments);
try { try {
const resOfExecution = await cmd.executionCallback.apply(null, [program].concat(args)); const resOfExecution = await cmd.executionCallback.apply(
null,
[program].concat(args)
);
onResolve(resOfExecution); onResolve(resOfExecution);
} catch (e) { } catch (e) {
onReject(e); onReject(e);
...@@ -98,19 +142,21 @@ export const ExecuteCommand = () => { ...@@ -98,19 +142,21 @@ export const ExecuteCommand = () => {
}); });
} }
program program.on("*", function (cmd: any) {
.on('*', function (cmd:any) { console.log(
console.log("Unknown command '%s'. Try --help for a listing of commands & options.", cmd); "Unknown command '%s'. Try --help for a listing of commands & options.",
cmd
);
onResolve(); onResolve();
}); });
program.parse(programArgs); program.parse(programArgs);
if (programArgs.length <= 2) { if (programArgs.length <= 2) {
onReject('No command given.'); onReject("No command given.");
} }
return currentCommand; return currentCommand;
} },
}; };
}; };
......
This diff is collapsed.
...@@ -11,75 +11,92 @@ ...@@ -11,75 +11,92 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
import {BlockDTO} from "../dto/BlockDTO" import { BlockDTO } from "../dto/BlockDTO";
import {Underscore} from "../common-libs/underscore" import { Underscore } from "../common-libs/underscore";
export interface SwitchBlock { export interface SwitchBlock {
number: number;
number:number hash: string;
hash:string previousHash: string;
previousHash:string medianTime: number;
medianTime:number
} }
export interface SwitcherDao<T extends SwitchBlock> { export interface SwitcherDao<T extends SwitchBlock> {
getCurrent(): Promise<T | null>;
getCurrent(): Promise<T|null> getPotentials(
getPotentials(numberStart:number, timeStart:number, maxNumber:number): Promise<T[]> numberStart: number,
getBlockchainBlock(number:number, hash:string): Promise<T|null> timeStart: number,
getAbsoluteBlockInForkWindow(number:number, hash:string): Promise<T|null> maxNumber: number
revertTo(number:number): Promise<T[]> ): Promise<T[]>;
addBlock(block:T): Promise<T> getBlockchainBlock(number: number, hash: string): Promise<T | null>;
getAbsoluteBlockInForkWindow(number: number, hash: string): Promise<T | null>;
revertTo(number: number): Promise<T[]>;
addBlock(block: T): Promise<T>;
} }
export class Switcher<T extends SwitchBlock> { export class Switcher<T extends SwitchBlock> {
constructor( constructor(
private dao: SwitcherDao<T>, private dao: SwitcherDao<T>,
private invalidForks: string[], private invalidForks: string[],
private avgGenTime: number, private avgGenTime: number,
private forkWindowSize: number, private forkWindowSize: number,
private switchOnHeadAdvance: number, private switchOnHeadAdvance: number,
private logger:any = undefined) {} private logger: any = undefined
) {}
/** /**
* Looks at known blocks in the sandbox and try to follow the longest resulting chain that has at least both 3 blocks of * Looks at known blocks in the sandbox and try to follow the longest resulting chain that has at least both 3 blocks of
* advance and 3 * avgGenTime of medianTime advancce. * advance and 3 * avgGenTime of medianTime advancce.
*/ */
async tryToFork() { async tryToFork() {
const current = await this.dao.getCurrent() const current = await this.dao.getCurrent();
if (current) { if (current) {
const numberStart = current.number + this.switchOnHeadAdvance const numberStart = current.number + this.switchOnHeadAdvance;
const timeStart = current.medianTime + this.switchOnHeadAdvance * this.avgGenTime const timeStart =
current.medianTime + this.switchOnHeadAdvance * this.avgGenTime;
// Phase 1: find potential chains // Phase 1: find potential chains
const suites = await this.findPotentialSuites(numberStart, timeStart) const suites = await this.findPotentialSuites(numberStart, timeStart);
if (suites.length) { if (suites.length) {
this.logger && this.logger.info("Fork resolution: %s potential suite(s) found...", suites.length) this.logger &&
this.logger.info(
"Fork resolution: %s potential suite(s) found...",
suites.length
);
} }
// Phase 2: select the best chain // Phase 2: select the best chain
let longestChain:null|T[] = await this.findLongestChain(current, suites) let longestChain: null | T[] = await this.findLongestChain(
current,
suites
);
// Phase 3: a best exist? // Phase 3: a best exist?
if (longestChain) { if (longestChain) {
const chainHEAD = longestChain[longestChain.length - 1] const chainHEAD = longestChain[longestChain.length - 1];
// apply it if it respects the 3-3 rule // apply it if it respects the 3-3 rule
if (chainHEAD.number >= numberStart && chainHEAD.medianTime >= timeStart) { if (
await this.switchOnChain(longestChain) chainHEAD.number >= numberStart &&
return await this.dao.getCurrent() chainHEAD.medianTime >= timeStart
) {
await this.switchOnChain(longestChain);
return await this.dao.getCurrent();
} }
} }
} }
return null return null;
} }
/** /**
* Find all the suites' HEAD that we could potentially fork on, in the current fork window. * Find all the suites' HEAD that we could potentially fork on, in the current fork window.
* @param current * @param current
*/ */
async findPotentialSuitesHeads(current:{ number:number, medianTime:number }) { async findPotentialSuitesHeads(current: {
const numberStart = current.number - this.forkWindowSize number: number;
const timeStart = current.medianTime - this.forkWindowSize * this.avgGenTime medianTime: number;
const suites = await this.findPotentialSuites(numberStart, timeStart) }) {
return suites.map(suite => suite[suite.length - 1]) const numberStart = current.number - this.forkWindowSize;
const timeStart =
current.medianTime - this.forkWindowSize * this.avgGenTime;
const suites = await this.findPotentialSuites(numberStart, timeStart);
return suites.map((suite) => suite[suite.length - 1]);
} }
/** /**
...@@ -90,51 +107,85 @@ export class Switcher<T extends SwitchBlock> { ...@@ -90,51 +107,85 @@ export class Switcher<T extends SwitchBlock> {
* @returns {SwitchBlock[][]} The suites found. * @returns {SwitchBlock[][]} The suites found.
*/ */
private async findPotentialSuites(numberStart: number, timeStart: number) { private async findPotentialSuites(numberStart: number, timeStart: number) {
const suites:T[][] = [] const suites: T[][] = [];
const potentials:T[] = Underscore.sortBy(await this.dao.getPotentials(numberStart, timeStart, numberStart + this.forkWindowSize), element => -element.number) const potentials: T[] = Underscore.sortBy(
const knownForkBlocks:{ [k:string]: boolean } = {} await this.dao.getPotentials(
numberStart,
timeStart,
numberStart + this.forkWindowSize
),
(element) => -element.number
);
const knownForkBlocks: { [k: string]: boolean } = {};
for (const candidate of potentials) { for (const candidate of potentials) {
knownForkBlocks[BlockDTO.fromJSONObject(candidate).blockstamp] = true knownForkBlocks[BlockDTO.fromJSONObject(candidate).blockstamp] = true;
} }
const invalids: { [hash:string]: T } = {} const invalids: { [hash: string]: T } = {};
if (potentials.length) { if (potentials.length) {
this.logger && this.logger.info("Fork resolution: %s potential block(s) found...", potentials.length) this.logger &&
this.logger.info(
"Fork resolution: %s potential block(s) found...",
potentials.length
);
} }
for (const candidate of potentials) { for (const candidate of potentials) {
const suite:T[] = [] const suite: T[] = [];
// Do not process the block if it is already known as invalid (has no fork point with current blockchain or misses // Do not process the block if it is already known as invalid (has no fork point with current blockchain or misses
// some blocks) or is already contained in a valid chain. // some blocks) or is already contained in a valid chain.
if (!invalids[candidate.hash] && !Switcher.suitesContains(suites, candidate)) { if (
!invalids[candidate.hash] &&
!Switcher.suitesContains(suites, candidate)
) {
// Tries to build up a full chain that is linked to current chain by a fork point. // Tries to build up a full chain that is linked to current chain by a fork point.
let previous:T|null = candidate, commonRootFound = false let previous: T | null = candidate,
let previousNumber:number = previous.number - 1 commonRootFound = false;
let previousHash:string = previous.previousHash let previousNumber: number = previous.number - 1;
while (previous && previous.number > candidate.number - this.forkWindowSize) { let previousHash: string = previous.previousHash;
suite.push(previous) while (
previousNumber = previous.number - 1 previous &&
previousHash = previous.previousHash previous.number > candidate.number - this.forkWindowSize
previous = null ) {
const previousBlockstamp = [previousNumber, previousHash].join('-') suite.push(previous);
previousNumber = previous.number - 1;
previousHash = previous.previousHash;
previous = null;
const previousBlockstamp = [previousNumber, previousHash].join("-");
// We try to look at blockchain if, of course, it is not already known as a fork block // We try to look at blockchain if, of course, it is not already known as a fork block
// Otherwise it cost a useless DB access // Otherwise it cost a useless DB access
if (!knownForkBlocks[previousBlockstamp]) { if (!knownForkBlocks[previousBlockstamp]) {
previous = await this.dao.getBlockchainBlock(previousNumber, previousHash) previous = await this.dao.getBlockchainBlock(
previousNumber,
previousHash
);
} }
if (previous) { if (previous) {
// Stop the loop: common block has been found // Stop the loop: common block has been found
previous = null previous = null;
suites.push(suite) suites.push(suite);
commonRootFound = true commonRootFound = true;
} else { } else {
// Have a look in sandboxes // Have a look in sandboxes
previous = await this.dao.getAbsoluteBlockInForkWindow(previousNumber, previousHash) previous = await this.dao.getAbsoluteBlockInForkWindow(
previousNumber,
previousHash
);
if (previous) { if (previous) {
knownForkBlocks[BlockDTO.fromJSONObject(previous).blockstamp] = true knownForkBlocks[
const alreadyKnownInvalidBlock = this.invalidForks.indexOf([previous.number, previous.hash].join('-')) !== -1 BlockDTO.fromJSONObject(previous).blockstamp
] = true;
const alreadyKnownInvalidBlock =
this.invalidForks.indexOf(
[previous.number, previous.hash].join("-")
) !== -1;
if (alreadyKnownInvalidBlock) { if (alreadyKnownInvalidBlock) {
// Incorrect = not found // Incorrect = not found
this.logger && this.logger.info("Fork resolution: block #%s-%s is known as incorrect. Skipping.", previous.number, previous.hash.substr(0, 8)) this.logger &&
previous = null this.logger.info(
"Fork resolution: block #%s-%s is known as incorrect. Skipping.",
previous.number,
previous.hash.substr(0, 8)
);
previous = null;
} }
} }
} }
...@@ -142,18 +193,32 @@ export class Switcher<T extends SwitchBlock> { ...@@ -142,18 +193,32 @@ export class Switcher<T extends SwitchBlock> {
// Forget about invalid blocks // Forget about invalid blocks
if (!commonRootFound) { if (!commonRootFound) {
if (!previous) { if (!previous) {
this.logger && this.logger.debug("Suite -> %s-%s missing block#%s-%s", candidate.number, candidate.hash.substr(0, 8), previousNumber, previousHash.substr(0, 8)) this.logger &&
this.logger.debug(
"Suite -> %s-%s missing block#%s-%s",
candidate.number,
candidate.hash.substr(0, 8),
previousNumber,
previousHash.substr(0, 8)
);
for (const b of suite) { for (const b of suite) {
invalids[b.hash] = b invalids[b.hash] = b;
} }
} else { } else {
// The chain would be too long, we could not revert correctly the chain. // The chain would be too long, we could not revert correctly the chain.
this.logger && this.logger.debug("Suite #%s-%s -> %s-%s out of fork window", previousNumber, previousHash.substr(0, 8), candidate.number, candidate.hash.substr(0, 8)) this.logger &&
this.logger.debug(
"Suite #%s-%s -> %s-%s out of fork window",
previousNumber,
previousHash.substr(0, 8),
candidate.number,
candidate.hash.substr(0, 8)
);
} }
} }
} }
} }
return suites return suites;
} }
/** /**
...@@ -165,54 +230,90 @@ export class Switcher<T extends SwitchBlock> { ...@@ -165,54 +230,90 @@ export class Switcher<T extends SwitchBlock> {
*/ */
private async findLongestChain(current: T, suites: T[][]) { private async findLongestChain(current: T, suites: T[][]) {
if (suites.length) { if (suites.length) {
this.logger && this.logger.info("Fork resolution: HEAD = block#%s", current.number) this.logger &&
this.logger.info("Fork resolution: HEAD = block#%s", current.number);
} }
let longestChain:null|T[] = null let longestChain: null | T[] = null;
let j = 0 let j = 0;
for (const s of suites) { for (const s of suites) {
j++ j++;
s.reverse() s.reverse();
// Revert current blockchain to fork point // Revert current blockchain to fork point
const forkPoint = s[0].number - 1 const forkPoint = s[0].number - 1;
const forkHead = s[s.length - 1] const forkHead = s[s.length - 1];
this.logger && this.logger.info("Fork resolution: suite %s/%s (-> #%s-%s) revert to fork point block#%s", j, suites.length, forkHead.number, forkHead.hash.substr(0, 6), forkPoint) this.logger &&
const reverted = await this.dao.revertTo(s[0].number - 1) this.logger.info(
"Fork resolution: suite %s/%s (-> #%s-%s) revert to fork point block#%s",
j,
suites.length,
forkHead.number,
forkHead.hash.substr(0, 6),
forkPoint
);
const reverted = await this.dao.revertTo(s[0].number - 1);
// Try to add a maximum of blocks // Try to add a maximum of blocks
let added = true, i = 0, successfulBlocks:T[] = [] let added = true,
i = 0,
successfulBlocks: T[] = [];
while (added && i < s.length) { while (added && i < s.length) {
try { try {
await this.dao.addBlock(s[i]) await this.dao.addBlock(s[i]);
this.logger && this.logger.info("Fork resolution: suite %s/%s added block#%s-%s", j, suites.length, s[i].number, s[i].hash) this.logger &&
successfulBlocks.push(s[i]) this.logger.info(
"Fork resolution: suite %s/%s added block#%s-%s",
j,
suites.length,
s[i].number,
s[i].hash
);
successfulBlocks.push(s[i]);
} catch (e) { } catch (e) {
this.invalidForks.push([s[i].number, s[i].hash].join('-')) this.invalidForks.push([s[i].number, s[i].hash].join("-"));
this.logger && this.logger.info("Fork resolution: suite %s/%s REFUSED block#%s: %s", j, suites.length, s[0].number + i, e && e.message) this.logger &&
added = false this.logger.info(
} "Fork resolution: suite %s/%s REFUSED block#%s: %s",
i++ j,
suites.length,
s[0].number + i,
e && e.message
);
added = false;
}
i++;
} }
// Pop the successfuly added blocks // Pop the successfuly added blocks
if (successfulBlocks.length) { if (successfulBlocks.length) {
for (const b of successfulBlocks) { for (const b of successfulBlocks) {
this.invalidForks.push([b.number, b.hash].join('-')) this.invalidForks.push([b.number, b.hash].join("-"));
} }
const addedToHeadLevel = successfulBlocks[successfulBlocks.length-1].number - current.number const addedToHeadLevel =
this.logger && this.logger.info("Fork resolution: suite %s/%s reached HEAD + %s. Now rolling back.", j, suites.length, addedToHeadLevel) successfulBlocks[successfulBlocks.length - 1].number - current.number;
await this.dao.revertTo(forkPoint) this.logger &&
this.logger.info(
"Fork resolution: suite %s/%s reached HEAD + %s. Now rolling back.",
j,
suites.length,
addedToHeadLevel
);
await this.dao.revertTo(forkPoint);
} }
// Push back the initial blocks that were temporarily reverted // Push back the initial blocks that were temporarily reverted
reverted.reverse() reverted.reverse();
for (const b of reverted) { for (const b of reverted) {
await this.dao.addBlock(b) await this.dao.addBlock(b);
} }
// Remember the chain if it is the longest (highest HEAD) among tested chains // Remember the chain if it is the longest (highest HEAD) among tested chains
const longestHEAD = longestChain && longestChain[longestChain.length - 1] const longestHEAD = longestChain && longestChain[longestChain.length - 1];
const successHEAD = successfulBlocks && successfulBlocks[successfulBlocks.length - 1] const successHEAD =
if ((!longestHEAD && successHEAD) || (longestHEAD && successHEAD && longestHEAD.number < successHEAD.number)) { successfulBlocks && successfulBlocks[successfulBlocks.length - 1];
longestChain = successfulBlocks if (
(!longestHEAD && successHEAD) ||
(longestHEAD && successHEAD && longestHEAD.number < successHEAD.number)
) {
longestChain = successfulBlocks;
} }
} }
return longestChain return longestChain;
} }
/** /**
...@@ -220,9 +321,9 @@ export class Switcher<T extends SwitchBlock> { ...@@ -220,9 +321,9 @@ export class Switcher<T extends SwitchBlock> {
* @param {SwitchBlock[]} chain * @param {SwitchBlock[]} chain
*/ */
private async switchOnChain(chain: T[]) { private async switchOnChain(chain: T[]) {
await this.dao.revertTo(chain[0].number - 1) await this.dao.revertTo(chain[0].number - 1);
for (const b of chain) { for (const b of chain) {
await this.dao.addBlock(b) await this.dao.addBlock(b);
} }
} }
...@@ -235,10 +336,10 @@ export class Switcher<T extends SwitchBlock> { ...@@ -235,10 +336,10 @@ export class Switcher<T extends SwitchBlock> {
for (const suite of suites) { for (const suite of suites) {
for (const b of suite) { for (const b of suite) {
if (b.number === block.number && b.hash === block.hash) { if (b.number === block.number && b.hash === block.hash) {
return true return true;
} }
} }
} }
return false return false;
} }
} }
export function uniqFilter<T>(value: T, index: number, self: T[]) { export function uniqFilter<T>(value: T, index: number, self: T[]) {
return self.indexOf(value) === index return self.indexOf(value) === index;
} }
export function arrayPruneAll<T>(array: T[], value: T) { export function arrayPruneAll<T>(array: T[], value: T) {
if (!array || array.length === 0) { if (!array || array.length === 0) {
return return;
} }
let index let index;
do { do {
index = array.indexOf(value) index = array.indexOf(value);
if (index !== -1) { if (index !== -1) {
array.splice(index, 1) array.splice(index, 1);
} }
} while (index !== -1) } while (index !== -1);
} }
/** /**
...@@ -17,13 +17,13 @@ export function arrayPruneAll<T>(array: T[], value: T) { ...@@ -17,13 +17,13 @@ export function arrayPruneAll<T>(array: T[], value: T) {
* @param value The value we don't want to see in our copy array. * @param value The value we don't want to see in our copy array.
*/ */
export function arrayPruneAllCopy<T>(original: T[], value: T) { export function arrayPruneAllCopy<T>(original: T[], value: T) {
const array = original.slice() const array = original.slice();
let index let index;
do { do {
index = array.indexOf(value) index = array.indexOf(value);
if (index !== -1) { if (index !== -1) {
array.splice(index, 1) array.splice(index, 1);
} }
} while (index !== -1) } while (index !== -1);
return array return array;
} }
...@@ -16,34 +16,32 @@ const BLOCK_UID = /^(0|[1-9]\d{0,18})-[A-F0-9]{64}$/; ...@@ -16,34 +16,32 @@ const BLOCK_UID = /^(0|[1-9]\d{0,18})-[A-F0-9]{64}$/;
const buidFunctions: any = function (number: number, hash: string) { const buidFunctions: any = function (number: number, hash: string) {
if (arguments.length === 2) { if (arguments.length === 2) {
return [number, hash].join('-'); return [number, hash].join("-");
} }
if (arguments[0]) { if (arguments[0]) {
return [arguments[0].number, arguments[0].hash].join('-'); return [arguments[0].number, arguments[0].hash].join("-");
}
return '0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855';
} }
return "0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855";
};
buidFunctions.fromTS = (line: string) => { buidFunctions.fromTS = (line: string) => {
const match = line.match(/TS:(.*)/) const match = line.match(/TS:(.*)/);
return (match && match[1]) || "" return (match && match[1]) || "";
} };
buidFunctions.fromIdty = (idty: any) => { buidFunctions.fromIdty = (idty: any) => {
return buidFunctions(idty.ts_number, idty.ts_hash) return buidFunctions(idty.ts_number, idty.ts_hash);
} };
export const Buid = { export const Buid = {
format: { format: {
isBuid: (value: any) => { isBuid: (value: any) => {
return (typeof value === 'string') && value.match(BLOCK_UID) ? true : false; return typeof value === "string" && value.match(BLOCK_UID) ? true : false;
}, },
buid: buidFunctions buid: buidFunctions,
}, },
getBlockstamp: (block:{ number:number, hash:string }) => { getBlockstamp: (block: { number: number; hash: string }) => {
return [block.number, block.hash].join('-') return [block.number, block.hash].join("-");
} },
}; };
This diff is collapsed.
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
const bs58 = require('bs58') const bs58 = require("bs58");
export const Base58encode = (bytes: Buffer) => bs58.encode(bytes) export const Base58encode = (bytes: Buffer) => bs58.encode(bytes);
export const Base58decode = (data:any) => new Uint8Array(bs58.decode(data)) export const Base58decode = (data: any) => new Uint8Array(bs58.decode(data));
...@@ -11,19 +11,17 @@ ...@@ -11,19 +11,17 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
import {Base58decode, Base58encode} from "./base58" import { Base58decode, Base58encode } from "./base58";
import {decodeBase64, decodeUTF8, encodeBase64} from "./nacl-util" import { decodeBase64, decodeUTF8, encodeBase64 } from "./nacl-util";
const nacl = require('tweetnacl'); const nacl = require("tweetnacl");
const seedrandom = require('seedrandom'); const seedrandom = require("seedrandom");
const naclBinding = require('naclb'); const naclBinding = require("naclb");
const crypto_sign_BYTES = 64; const crypto_sign_BYTES = 64;
export class Key { export class Key {
constructor(readonly pub: string, readonly sec: string) {}
constructor(readonly pub:string, readonly sec:string) {
}
/***************************** /*****************************
* *
...@@ -32,26 +30,26 @@ export class Key { ...@@ -32,26 +30,26 @@ export class Key {
*****************************/ *****************************/
get publicKey() { get publicKey() {
return this.pub return this.pub;
} }
get secretKey() { get secretKey() {
return this.sec return this.sec;
} }
private rawSec() { private rawSec() {
return Base58decode(this.secretKey) return Base58decode(this.secretKey);
} }
json() { json() {
return { return {
pub: this.publicKey, pub: this.publicKey,
sec: this.secretKey sec: this.secretKey,
} };
} }
signBuggy(msg: string) { signBuggy(msg: string) {
return Promise.resolve(this.signSyncBuggy(msg)) return Promise.resolve(this.signSyncBuggy(msg));
} }
signSyncBuggy(msg: string) { signSyncBuggy(msg: string) {
...@@ -61,11 +59,11 @@ export class Key { ...@@ -61,11 +59,11 @@ export class Key {
for (let i = 0; i < sig.length; i++) { for (let i = 0; i < sig.length; i++) {
sig[i] = signedMsg[i]; sig[i] = signedMsg[i];
} }
return encodeBase64(sig) return encodeBase64(sig);
}; }
sign(msg: string) { sign(msg: string) {
return Promise.resolve(this.signSync(msg)) return Promise.resolve(this.signSync(msg));
} }
signSync(msg: string) { signSync(msg: string) {
...@@ -75,24 +73,24 @@ export class Key { ...@@ -75,24 +73,24 @@ export class Key {
for (let i = 0; i < sig.length; i++) { for (let i = 0; i < sig.length; i++) {
sig[i] = signedMsg[i]; sig[i] = signedMsg[i];
} }
return encodeBase64(sig) return encodeBase64(sig);
}; }
} }
export function randomKey() { export function randomKey() {
const byteseed = new Uint8Array(32) const byteseed = new Uint8Array(32);
for (let i = 0; i < 32; i++) { for (let i = 0; i < 32; i++) {
byteseed[i] = Math.floor(seedrandom()() * 255) + 1 byteseed[i] = Math.floor(seedrandom()() * 255) + 1;
} }
const keypair = nacl.sign.keyPair.fromSeed(byteseed) const keypair = nacl.sign.keyPair.fromSeed(byteseed);
return new Key( return new Key(
Base58encode(new Buffer(keypair.publicKey)), Base58encode(new Buffer(keypair.publicKey)),
Base58encode(new Buffer(keypair.secretKey)) Base58encode(new Buffer(keypair.secretKey))
) );
} }
export function KeyGen(pub: string, sec: string) { export function KeyGen(pub: string, sec: string) {
return new Key(pub, sec) return new Key(pub, sec);
} }
/** /**
......
export interface Map<T> { export interface Map<T> {
[k:string]: T [k: string]: T;
} }
...@@ -15,33 +15,42 @@ declare function escape(s:string): string; ...@@ -15,33 +15,42 @@ declare function escape(s:string): string;
declare function unescape(s: string): string; declare function unescape(s: string): string;
export const decodeUTF8 = function (s: string) { export const decodeUTF8 = function (s: string) {
let i, d = unescape(encodeURIComponent(s)), b = new Uint8Array(d.length); let i,
d = unescape(encodeURIComponent(s)),
b = new Uint8Array(d.length);
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i); for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i);
return b; return b;
} };
export const encodeUTF8 = function (arr: any[]) { export const encodeUTF8 = function (arr: any[]) {
let i, s = []; let i,
s = [];
for (i = 0; i < arr.length; i++) s.push(String.fromCharCode(arr[i])); for (i = 0; i < arr.length; i++) s.push(String.fromCharCode(arr[i]));
return decodeURIComponent(escape(s.join(''))) return decodeURIComponent(escape(s.join("")));
} };
export const encodeBase64 = function (arr: Uint8Array) { export const encodeBase64 = function (arr: Uint8Array) {
if (typeof btoa === 'undefined' || !window) { if (typeof btoa === "undefined" || !window) {
return (new Buffer(arr)).toString('base64'); return new Buffer(arr).toString("base64");
} else { } else {
let i, s = [], len = arr.length; let i,
s = [],
len = arr.length;
for (i = 0; i < len; i++) s.push(String.fromCharCode(arr[i])); for (i = 0; i < len; i++) s.push(String.fromCharCode(arr[i]));
return btoa(s.join('')); return btoa(s.join(""));
}
} }
};
export const decodeBase64 = function (s: string) { export const decodeBase64 = function (s: string) {
if (typeof atob === 'undefined' || !window) { if (typeof atob === "undefined" || !window) {
return new Uint8Array(Array.prototype.slice.call(new Buffer(s, 'base64'), 0)); return new Uint8Array(
Array.prototype.slice.call(new Buffer(s, "base64"), 0)
);
} else { } else {
let i, d = atob(s), b = new Uint8Array(d.length); let i,
d = atob(s),
b = new Uint8Array(d.length);
for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i); for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i);
return b; return b;
} }
} };
\ No newline at end of file
...@@ -12,5 +12,5 @@ ...@@ -12,5 +12,5 @@
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
export function dos2unix(str: string) { export function dos2unix(str: string) {
return str.replace(/\r\n/g, '\n') return str.replace(/\r\n/g, "\n");
} }
...@@ -31,5 +31,5 @@ export enum DataErrors { ...@@ -31,5 +31,5 @@ export enum DataErrors {
CANNOT_REVERT_NO_CURRENT_BLOCK, CANNOT_REVERT_NO_CURRENT_BLOCK,
BLOCK_TO_REVERT_NOT_FOUND, BLOCK_TO_REVERT_NOT_FOUND,
MEMBER_NOT_FOUND, MEMBER_NOT_FOUND,
MILESTONE_BLOCK_NOT_FOUND MILESTONE_BLOCK_NOT_FOUND,
} }
export async function filterAsync<T>(arr: T[], filter: (t: T) => Promise<boolean>) { export async function filterAsync<T>(
const filtered: T[] = [] arr: T[],
await Promise.all(arr.map(async t => { filter: (t: T) => Promise<boolean>
) {
const filtered: T[] = [];
await Promise.all(
arr.map(async (t) => {
if (await filter(t)) { if (await filter(t)) {
filtered.push(t) filtered.push(t);
} }
})) })
return filtered );
return filtered;
} }
...@@ -11,19 +11,14 @@ ...@@ -11,19 +11,14 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
import * as rawer from './rawer' import * as rawer from "./rawer";
import {Base58decode, Base58encode} from "./crypto/base58" import { Base58decode, Base58encode } from "./crypto/base58";
import {unlock as txunlock} from "./txunlock" import { unlock as txunlock } from "./txunlock";
import { hashf } from "../common"; import { hashf } from "../common";
const base58 = { const base58 = {
decode: Base58decode, decode: Base58decode,
encode: Base58encode encode: Base58encode,
} };
export { export { rawer, base58, txunlock, hashf };
rawer,
base58,
txunlock,
hashf
}
import {Querable} from "./querable" import { Querable } from "./querable";
const querablePromise = require('querablep'); const querablePromise = require("querablep");
export interface ManualPromise<T> extends Querable<T> { export interface ManualPromise<T> extends Querable<T> {
resolve: (data: T) => void resolve: (data: T) => void;
reject: (error: Error) => void reject: (error: Error) => void;
} }
/** /**
...@@ -12,14 +12,14 @@ export interface ManualPromise<T> extends Querable<T> { ...@@ -12,14 +12,14 @@ export interface ManualPromise<T> extends Querable<T> {
* @returns {ManualPromise<T>} * @returns {ManualPromise<T>}
*/ */
export function newManualPromise<T>() { export function newManualPromise<T>() {
let resolveCb: (data: T) => void = () => {} let resolveCb: (data: T) => void = () => {};
let rejectCb: (error: Error) => void = () => {} let rejectCb: (error: Error) => void = () => {};
const p = new Promise((res, rej) => { const p = new Promise((res, rej) => {
resolveCb = res resolveCb = res;
rejectCb = rej rejectCb = rej;
}) });
const q: ManualPromise<T> = querablePromise(p) const q: ManualPromise<T> = querablePromise(p);
q.resolve = resolveCb q.resolve = resolveCb;
q.reject = rejectCb q.reject = rejectCb;
return q return q;
} }
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
const _moment_ = require("moment") const _moment_ = require("moment");
export const moment = _moment_ export const moment = _moment_;
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment