UNPKG

mokka

Version:

Mokka Consensus Algorithm implementation in Javascript

116 lines 5.64 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeApi = void 0; const EventTypes_1 = __importDefault(require("../constants/EventTypes")); const EventTypes_2 = __importDefault(require("../constants/EventTypes")); const MessageTypes_1 = __importDefault(require("../constants/MessageTypes")); const NodeStates_1 = __importDefault(require("../constants/NodeStates")); const NodeModel_1 = require("../models/NodeModel"); const VoteModel_1 = require("../models/VoteModel"); const utils = __importStar(require("../utils/cryptoUtils")); const utils_1 = require("../utils/utils"); const MessageApi_1 = require("./MessageApi"); class NodeApi { constructor(mokka) { this.mokka = mokka; this.messageApi = new MessageApi_1.MessageApi(mokka); } join(multiaddr) { const publicKey = multiaddr.match(/\w+$/).toString(); if (this.mokka.publicKey === publicKey) return; const node = new NodeModel_1.NodeModel(null, multiaddr, 'CFT', NodeStates_1.default.STOPPED); node.write = this.mokka.write.bind(this.mokka); node.once('end', () => this.leave(node.publicKey)); this.mokka.nodes.set(publicKey, node); this.buildPublicKeysRootAndCombinations(); this.mokka.emit(EventTypes_1.default.NODE_JOIN, node); return node; } buildPublicKeysRootAndCombinations() { const sortedPublicKeys = [...this.mokka.nodes.keys(), this.mokka.publicKey].sort(); this.mokka.publicKeysRoot = utils.buildPublicKeysRoot(sortedPublicKeys); this.mokka.publicKeysCombinationsInQuorum = (0, utils_1.getCombinations)(sortedPublicKeys, this.mokka.majority()); } leave(publicKey) { const node = this.mokka.nodes.get(publicKey); this.mokka.nodes.delete(publicKey); this.buildPublicKeysRootAndCombinations(); this.mokka.emit(EventTypes_1.default.NODE_LEAVE, node); } async promote() { if (this.mokka.state === NodeStates_1.default.CANDIDATE) { return; } const nonce = Date.now(); this.mokka.setState(NodeStates_1.default.CANDIDATE, this.mokka.term + 1, ''); const publicKeysRootForTerm = utils.buildPublicKeysRootForTerm(this.mokka.publicKeysRoot, this.mokka.term, nonce, this.mokka.publicKey); const vote = new VoteModel_1.VoteModel(nonce, this.mokka.term, publicKeysRootForTerm); for (const combination of this.mokka.publicKeysCombinationsInQuorum) { if (!combination.includes(this.mokka.publicKey)) { continue; } const sharedPublicKeyPartial = utils.buildSharedPublicKeyX(combination, this.mokka.term, nonce, publicKeysRootForTerm); vote.publicKeyToCombinationMap.set(sharedPublicKeyPartial, combination); } this.mokka.setVote(vote); const votePayload = { nonce, publicKey: this.mokka.publicKey, term: this.mokka.term }; const selfVoteSignature = utils.buildPartialSignature(this.mokka.privateKey, votePayload.term, votePayload.nonce, publicKeysRootForTerm); vote.repliesPublicKeyToSignatureMap.set(this.mokka.publicKey, selfVoteSignature); const packet = this.messageApi.packet(MessageTypes_1.default.VOTE, { nonce }); await Promise.all([...this.mokka.nodes.values()].map((node) => this.messageApi.message(packet, node.publicKey))); await new Promise((res) => { const timeoutHandler = () => { this.mokka.removeListener(EventTypes_2.default.STATE, emitHandler); res(); }; const timeoutId = setTimeout(timeoutHandler, this.mokka.electionTimeout); const emitHandler = () => { clearTimeout(timeoutId); res(); }; this.mokka.once(EventTypes_2.default.STATE, emitHandler); }); if (this.mokka.state === NodeStates_1.default.CANDIDATE) { this.mokka.setState(NodeStates_1.default.FOLLOWER, this.mokka.term, null); } } async pingFromLeader(packet) { if (packet && packet.state === NodeStates_1.default.LEADER) { this.mokka.logger.trace(`accepted ack`); this.mokka.heartbeatCtrl.setNextBeat(this.mokka.heartbeatCtrl.timeout()); this.mokka.emit(EventTypes_2.default.ACK); } return null; } } exports.NodeApi = NodeApi; //# sourceMappingURL=NodeApi.js.map