@activeledger/activeprotocol
Version:
Underlying protocol which handles consensus and the smart contract virtual machine of Activeledger
234 lines • 9.89 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamUpdater = void 0;
const activeoptions_1 = require("@activeledger/activeoptions");
const activelogger_1 = require("@activeledger/activelogger");
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_1.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_1.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_1.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_1.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();
}
}
}
exports.StreamUpdater = StreamUpdater;
//# sourceMappingURL=streamUpdater.js.map