UNPKG

@activeledger/activeprotocol

Version:

Underlying protocol which handles consensus and the smart contract virtual machine of Activeledger

230 lines 9.68 kB
import { ActiveOptions } from "@activeledger/activeoptions"; import { ActiveLogger } from "@activeledger/activelogger"; export class StreamUpdater { constructor(entry, virtualMachine, reference, nodeResponse, db, dbev, emitter, shared, contractId) { this.entry = entry; this.virtualMachine = virtualMachine; this.reference = reference; this.nodeResponse = nodeResponse; this.db = db; this.dbev = dbev; this.emitter = emitter; this.shared = shared; this.contractId = contractId; this.collisions = []; this.skip = []; this.nhkpCheck = ActiveOptions.get("security", {}) .hardenedKeys; this.refStreams = { new: [], updated: [], }; this.streams = this.virtualMachine.getActivityStreamsFromVM(this.entry.$umid); this.inputs = this.virtualMachine.getInputs(this.entry.$umid); } updateStreams(earlyCommit) { if (earlyCommit) this.earlyCommit = earlyCommit; this.streams.length ? this.processStreams() : this.processNoStreams(); } async processNoStreams() { if (!this.entry.$territoriality) { this.entry.$territoriality = this.reference; } try { this.nodeResponse.post = await this.virtualMachine.postProcess(this.entry.$territoriality === this.reference, this.entry.$territoriality, this.entry.$umid); this.nodeResponse.incomms = this.virtualMachine.getInternodeCommsFromVM(this.entry.$umid); this.nodeResponse.return = this.virtualMachine.getReturnContractData(this.entry.$umid); this.entry = this.shared.clearAllComms(this.virtualMachine, this.nodeResponse.incomms); if (this.earlyCommit) this.earlyCommit(); this.emitter.emit("commited"); } catch (error) { if (this.earlyCommit) this.earlyCommit(); this.emitter.emit("commited"); } } processStreams() { this.docs = []; this.buildReferenceStreams(); if (this.inputs && this.inputs.length) this.handleInputs(); this.docs.push({ _id: this.entry.$umid + ":umid", umid: this.compactTxEntry(), streams: this.refStreams, }); this.detectCollisions(); } compactTxEntry() { return { $umid: this.entry.$umid, $tx: this.entry.$tx, $sigs: this.entry.$sigs, $revs: this.entry.$revs, $selfsign: this.entry.$selfsign ? this.entry.$selfsign : false, $datetime: this.entry.$datetime, }; } handleInputs() { const notInSkip = (index) => this.skip.indexOf(this.inputs[index].meta._id) === -1; let i = this.inputs.length; while (i--) { if (notInSkip(i) && this.inputs[i].meta.txs && this.inputs[i].meta.txs.length) { this.inputs[i].meta.txs.push(this.entry.$umid); if (this.inputs[i].state._id && this.nhkpCheck) { this.handleNHPK(this.inputs[i]); } this.docs.push(this.inputs[i].meta); } } } handleNHPK(input) { const inputLabel = this.shared.getLabelIOMap(true, input.state._id); const nhpk = this.entry.$tx.$i[inputLabel].$nhpk; const txSigAuthKeys = Object.keys(this.entry.$sigs[input.state._id]); const authorities = input.meta.authorities; const keys = Object.keys(authorities); let i = keys.length; while (i--) { const authority = authorities[keys[i]]; const txSigAuthKey = txSigAuthKeys.indexOf(authority.hash); if (txSigAuthKey === -1) { authority.public = nhpk[txSigAuthKeys[txSigAuthKey]]; } } } handleContractDataStream(contractData) { const [contract, suffix] = contractData._id.split(":"); if (contract.length < 64) { contractData._id = `${this.contractId}:${suffix}`; } this.docs.push(contractData); } buildReferenceStreams() { var _a; let i = this.streams.length; while (i--) { if (((_a = this.streams[i]._id) === null || _a === void 0 ? void 0 : _a.indexOf(":data")) > -1) { this.handleContractDataStream(this.streams[i]); continue; } if (!this.streams[i].meta._rev) { if (!this.streams[i].meta._id) { this.streams[i].state._id = this.entry.$umid + i; this.streams[i].meta._id = this.streams[i].state._id + ":stream"; this.streams[i].volatile._id = this.streams[i].state._id + ":volatile"; } this.streams[i].meta.txs = [this.entry.$umid]; this.streams[i].meta.$constructor = true; delete this.streams[i].state._rev; delete this.streams[i].meta._rev; delete this.streams[i].volatile._rev; if (this.streams[i].meta.umid !== this.entry.$umid) { this.collisions.push(this.streams[i].meta._id); } this.refStreams.new.push({ id: this.shared.assumedVirtualPrefix + this.streams[i].state._id, name: this.streams[i].meta.name, }); } else { if (this.streams[i].meta.txs && this.streams[i].meta.txs.length) { this.streams[i].meta.txs.push(this.entry.$umid); this.skip.push(this.streams[i].meta._id); } if (this.streams[i].state._id && this.nhkpCheck) { let nhpk = this.entry.$tx.$i[this.shared.getLabelIOMap(true, this.streams[i].state._id)].$nhpk; let txSigAuthsKeys = Object.keys(this.entry.$sigs[this.streams[i].state._id]); this.streams[i].meta.authorities.forEach((authority) => { const txSigAuthKey = txSigAuthsKeys.indexOf(authority.hash); if (txSigAuthKey !== -1) { authority.public = nhpk[txSigAuthsKeys[txSigAuthKey]]; } }); } this.refStreams.updated.push({ id: this.shared.filterPrefix(this.streams[i].state._id), name: this.streams[i].meta.name, }); } if (this.streams[i].state._id) this.docs.push(this.streams[i].state); if (this.streams[i].meta._id) this.docs.push(this.streams[i].meta); if (this.streams[i].volatile && this.streams[i].volatile._id) this.docs.push(this.streams[i].volatile); } } async append() { let continueProcessing = true, emit = true; try { await Promise.all([ this.db.bulkDocs(this.docs), this.dbev.post({ _id: `umid:${new Date(this.entry.$datetime).getTime()},${this.entry.$umid}`, }), ]); } catch (error) { continueProcessing = emit = false; ActiveLogger.debug(error, "Datastore Failure"); this.shared.raiseLedgerError(1510, new Error("Failed to save")); } if (continueProcessing) { this.nodeResponse.datetime = new Date(); if (!this.entry.$territoriality) { this.entry.$territoriality = this.reference; } if (this.reference === this.entry.$origin) { this.entry.$streams = this.refStreams; } this.nodeResponse.streams = this.refStreams; try { const post = await this.virtualMachine.postProcess(this.entry.$territoriality === this.reference, this.entry.$territoriality, this.entry.$umid); this.nodeResponse.post = post; this.nodeResponse.incomms = this.virtualMachine.getInternodeCommsFromVM(this.entry.$umid); this.nodeResponse.return = this.virtualMachine.getReturnContractData(this.entry.$umid); this.entry = this.shared.clearAllComms(this.virtualMachine, this.nodeResponse.incomms); } catch (error) { continueProcessing = false; } } this.emitter.emit("broadcast"); if (this.earlyCommit) this.earlyCommit(); if (emit) { this.emitter.emit("commited"); } } async detectCollisions() { if (this.collisions.length) { ActiveLogger.info("Deterministic streams to be checked"); let streamColCheck = []; let i = this.collisions.length; while (i--) { const streamId = this.collisions[i]; streamColCheck.push(this.db.get(streamId)); } try { const streams = await Promise.all(streamColCheck); ActiveLogger.debug(streams, "Deterministic Stream Name Exists"); this.nodeResponse.commit = false; this.shared.raiseLedgerError(1530, new Error("Deterministic Stream Name Exists")); } catch (error) { this.append(); } } else { this.append(); } } } //# sourceMappingURL=streamUpdater.js.map