@activeledger/activeprotocol 2.15.6 → 4.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/protocol/interfaces/vm.interface.d.ts +9 -5
- package/es/protocol/interfaces/vm.interface.d.ts.map +1 -1
- package/es/protocol/permissionsChecker.d.ts +5 -3
- package/es/protocol/permissionsChecker.d.ts.map +1 -1
- package/es/protocol/permissionsChecker.js +149 -120
- package/es/protocol/permissionsChecker.js.map +1 -1
- package/es/protocol/process.d.ts +10 -9
- package/es/protocol/process.d.ts.map +1 -1
- package/es/protocol/process.js +281 -214
- package/es/protocol/process.js.map +1 -1
- package/es/protocol/shared.d.ts +6 -2
- package/es/protocol/shared.d.ts.map +1 -1
- package/es/protocol/shared.js +41 -29
- package/es/protocol/shared.js.map +1 -1
- package/es/protocol/streamUpdater.d.ts +1 -6
- package/es/protocol/streamUpdater.d.ts.map +1 -1
- package/es/protocol/streamUpdater.js +80 -109
- package/es/protocol/streamUpdater.js.map +1 -1
- package/es/protocol/vm.d.ts +12 -5
- package/es/protocol/vm.d.ts.map +1 -1
- package/es/protocol/vm.js +212 -138
- package/es/protocol/vm.js.map +1 -1
- package/es/protocol/vmscript.js +23 -10
- package/es/protocol/vmscript.js.map +1 -1
- package/lib/protocol/interfaces/vm.interface.d.ts +9 -5
- package/lib/protocol/interfaces/vm.interface.d.ts.map +1 -1
- package/lib/protocol/permissionsChecker.d.ts +5 -3
- package/lib/protocol/permissionsChecker.d.ts.map +1 -1
- package/lib/protocol/permissionsChecker.js +149 -120
- package/lib/protocol/permissionsChecker.js.map +1 -1
- package/lib/protocol/process.d.ts +10 -9
- package/lib/protocol/process.d.ts.map +1 -1
- package/lib/protocol/process.js +281 -240
- package/lib/protocol/process.js.map +1 -1
- package/lib/protocol/shared.d.ts +6 -2
- package/lib/protocol/shared.d.ts.map +1 -1
- package/lib/protocol/shared.js +41 -29
- package/lib/protocol/shared.js.map +1 -1
- package/lib/protocol/streamUpdater.d.ts +1 -6
- package/lib/protocol/streamUpdater.d.ts.map +1 -1
- package/lib/protocol/streamUpdater.js +80 -109
- package/lib/protocol/streamUpdater.js.map +1 -1
- package/lib/protocol/vm.d.ts +12 -5
- package/lib/protocol/vm.d.ts.map +1 -1
- package/lib/protocol/vm.js +211 -137
- package/lib/protocol/vm.js.map +1 -1
- package/lib/protocol/vmscript.js +23 -9
- package/lib/protocol/vmscript.js.map +1 -1
- package/package.json +9 -9
package/es/protocol/process.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import { VirtualMachine } from "./vm";
|
|
4
4
|
import { ActiveOptions } from "@activeledger/activeoptions";
|
|
@@ -6,9 +6,41 @@ import { ActiveLogger } from "@activeledger/activelogger";
|
|
|
6
6
|
import { Shared } from "./shared";
|
|
7
7
|
import { StreamUpdater } from "./streamUpdater";
|
|
8
8
|
import { PermissionsChecker } from "./permissionsChecker";
|
|
9
|
-
|
|
10
|
-
const
|
|
9
|
+
const BROADCAST_TIMEOUT_EARLY = 60 * 1000;
|
|
10
|
+
const BROADCAST_TIMEOUT_VOTE = 60 * 1000;
|
|
11
|
+
const BROADCAST_TIMEOUT_COMMIT = 60 * 1000;
|
|
11
12
|
export class Process extends EventEmitter {
|
|
13
|
+
entry;
|
|
14
|
+
selfHost;
|
|
15
|
+
reference;
|
|
16
|
+
right;
|
|
17
|
+
db;
|
|
18
|
+
dbe;
|
|
19
|
+
dbev;
|
|
20
|
+
secured;
|
|
21
|
+
static networkNodeLength = 0;
|
|
22
|
+
static generalContractVM;
|
|
23
|
+
isDefault = false;
|
|
24
|
+
inputs;
|
|
25
|
+
outputs;
|
|
26
|
+
nodeResponse;
|
|
27
|
+
contractLocation;
|
|
28
|
+
contractId;
|
|
29
|
+
commiting = false;
|
|
30
|
+
voting = true;
|
|
31
|
+
storeSingleError = false;
|
|
32
|
+
errorOut = {
|
|
33
|
+
code: 0,
|
|
34
|
+
reason: "",
|
|
35
|
+
priority: 0,
|
|
36
|
+
};
|
|
37
|
+
broadcastTimeout;
|
|
38
|
+
currentTrueVotes;
|
|
39
|
+
securityCache;
|
|
40
|
+
shared;
|
|
41
|
+
permissionChecker;
|
|
42
|
+
willEmit;
|
|
43
|
+
willEmitData;
|
|
12
44
|
constructor(entry, selfHost, reference, right, db, dbe, dbev, secured) {
|
|
13
45
|
super();
|
|
14
46
|
this.entry = entry;
|
|
@@ -19,18 +51,9 @@ export class Process extends EventEmitter {
|
|
|
19
51
|
this.dbe = dbe;
|
|
20
52
|
this.dbev = dbev;
|
|
21
53
|
this.secured = secured;
|
|
22
|
-
this.isDefault = false;
|
|
23
|
-
this.checkRevs = true;
|
|
24
|
-
this.commiting = false;
|
|
25
|
-
this.voting = true;
|
|
26
|
-
this.storeSingleError = false;
|
|
27
|
-
this.errorOut = {
|
|
28
|
-
code: 0,
|
|
29
|
-
reason: "",
|
|
30
|
-
priority: 0,
|
|
31
|
-
};
|
|
32
54
|
this.shared = new Shared(this.storeSingleError, this.entry, this.dbe, this);
|
|
33
55
|
this.nodeResponse = entry.$nodes[reference];
|
|
56
|
+
Process.networkNodeLength = ActiveOptions.get("neighbourhood", []).length;
|
|
34
57
|
try {
|
|
35
58
|
if (!Process.generalContractVM) {
|
|
36
59
|
Process.generalContractVM = new VirtualMachine(this.selfHost, this.secured, this.db, this.dbev);
|
|
@@ -40,23 +63,21 @@ export class Process extends EventEmitter {
|
|
|
40
63
|
catch (error) {
|
|
41
64
|
throw new Error(error);
|
|
42
65
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
this.permissionChecker = new PermissionsChecker(this.entry, this.db, this.checkRevs, this.securityCache, this.shared);
|
|
66
|
+
this.securityCache = ActiveOptions.get("security", null);
|
|
67
|
+
this.permissionChecker = new PermissionsChecker(this.entry, this.db, this.securityCache, this.shared);
|
|
47
68
|
}
|
|
48
69
|
destroy(umid) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
70
|
+
if (this.entry.$broadcast) {
|
|
71
|
+
clearTimeout(this.broadcastTimeout);
|
|
72
|
+
Process.generalContractVM.destroy(umid);
|
|
73
|
+
delete this.entry;
|
|
53
74
|
}
|
|
54
75
|
else {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
Process.generalContractVM.destroy(umid);
|
|
78
|
+
delete this.entry;
|
|
79
|
+
}, 60000);
|
|
58
80
|
}
|
|
59
|
-
delete this.entry;
|
|
60
81
|
}
|
|
61
82
|
sortVersions(a, b) {
|
|
62
83
|
const padSorting = (v) => {
|
|
@@ -69,80 +90,98 @@ export class Process extends EventEmitter {
|
|
|
69
90
|
};
|
|
70
91
|
return padSorting(a).localeCompare(padSorting(b));
|
|
71
92
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
93
|
+
static contractPathCache = {};
|
|
94
|
+
static clearContractPathCache(contractId) {
|
|
95
|
+
if (contractId) {
|
|
96
|
+
for (const key of Object.keys(Process.contractPathCache)) {
|
|
97
|
+
if (key === contractId || Process.contractPathCache[key].includes(contractId)) {
|
|
98
|
+
delete Process.contractPathCache[key];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
Process.contractPathCache = {};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async start(contractVersion, contractData) {
|
|
107
|
+
ActiveLogger.debug(`New TX : ${this.entry.$umid}`);
|
|
108
|
+
const setupDefaultLocation = async () => {
|
|
75
109
|
this.isDefault = true;
|
|
76
|
-
|
|
110
|
+
if (await fs.stat(`${process.cwd()}/default_contracts/_LOCK.${this.entry.$tx.$contract}`).catch(() => false)) {
|
|
111
|
+
throw new Error("Contract Global Lock");
|
|
112
|
+
}
|
|
113
|
+
this.contractLocation = await fs.realpath(`${process.cwd()}/default_contracts/${this.entry.$tx.$contract}.js`);
|
|
77
114
|
};
|
|
78
|
-
const setupLocation = () => {
|
|
79
|
-
var _a;
|
|
115
|
+
const setupLocation = async () => {
|
|
80
116
|
let contract = this.entry.$tx.$contract;
|
|
117
|
+
this.contractId = contract.split("@")[0];
|
|
81
118
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
119
|
+
if (!Process.contractPathCache[this.entry.$tx.$contract] ||
|
|
120
|
+
(contractVersion && !Process.contractPathCache[this.entry.$tx.$contract].endsWith(`${contractVersion}.js`))) {
|
|
121
|
+
let namespacePath = "";
|
|
122
|
+
try {
|
|
123
|
+
namespacePath = await fs.realpath(`${process.cwd()}/contracts/${this.entry.$tx.$namespace}/`);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
throw new Error("Namespace not found");
|
|
90
127
|
}
|
|
91
|
-
}
|
|
92
|
-
catch (_b) {
|
|
93
|
-
throw new Error("Contract or Namespace not found");
|
|
94
|
-
}
|
|
95
|
-
this.contractId = contractId;
|
|
96
|
-
if (this.entry.$tx.$contract.indexOf("@") === -1) {
|
|
97
128
|
if (contractVersion) {
|
|
98
129
|
contract = contractVersion;
|
|
99
130
|
}
|
|
100
131
|
else {
|
|
101
|
-
|
|
102
|
-
contract =
|
|
103
|
-
((_a = fs
|
|
104
|
-
.readdirSync(namespacePath)
|
|
105
|
-
.filter((fn) => fn.includes(`${this.contractId}@`))
|
|
106
|
-
.sort(this.sortVersions)
|
|
107
|
-
.pop()) === null || _a === void 0 ? void 0 : _a.replace(".js", "")) || this.contractId;
|
|
108
|
-
this.emit("contractLatestVersion", {
|
|
109
|
-
contract: this.entry.$tx.$contract,
|
|
110
|
-
file: contract,
|
|
111
|
-
});
|
|
132
|
+
if (this.entry.$tx.$contract.indexOf("@=") !== -1) {
|
|
133
|
+
contract = this.entry.$tx.$contract.replace("@=", "@");
|
|
112
134
|
}
|
|
113
|
-
|
|
114
|
-
|
|
135
|
+
else {
|
|
136
|
+
try {
|
|
137
|
+
contract = ((await fs
|
|
138
|
+
.readdir(namespacePath))
|
|
139
|
+
.filter((fn) => fn.includes(this.entry.$tx.$contract))
|
|
140
|
+
.sort(this.sortVersions)
|
|
141
|
+
.pop() || "notfound.404").replace(".js", "");
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
throw new Error("Contract not found");
|
|
145
|
+
}
|
|
115
146
|
}
|
|
116
147
|
}
|
|
148
|
+
if (!(await fs.stat(`${namespacePath}/${contract}.js`).catch(() => false))) {
|
|
149
|
+
throw new Error("Contract not found");
|
|
150
|
+
}
|
|
151
|
+
if (!contractVersion) {
|
|
152
|
+
this.emit("contractLatestVersion", {
|
|
153
|
+
contract: this.entry.$tx.$contract,
|
|
154
|
+
file: contract,
|
|
155
|
+
refresh: false,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (await fs.stat(`${namespacePath}/_LOCK.${this.contractId}`).catch(() => false)) {
|
|
159
|
+
throw new Error("Contract Global Lock");
|
|
160
|
+
}
|
|
161
|
+
if (await fs.stat(`${namespacePath}/_LOCK.${contract}`).catch(() => false)) {
|
|
162
|
+
throw new Error(`Contract Version Lock ${contract.substring(contract.indexOf("@") + 1)}`);
|
|
163
|
+
}
|
|
164
|
+
Process.contractPathCache[this.entry.$tx.$contract] = await fs.realpath(`${namespacePath}/${contract}.js`);
|
|
117
165
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
if (fs.existsSync(`${namespacePath}/_LOCK.${contract}`)) {
|
|
122
|
-
throw new Error(`Contract Version Lock ${contract.substring(contract.indexOf("@") + 1)}`);
|
|
123
|
-
}
|
|
124
|
-
this.contractLocation = fs.realpathSync(`${namespacePath}/${contract}.js`);
|
|
166
|
+
this.contractLocation =
|
|
167
|
+
Process.contractPathCache[this.entry.$tx.$contract];
|
|
125
168
|
}
|
|
126
169
|
catch (e) {
|
|
127
170
|
throw e;
|
|
128
171
|
}
|
|
129
172
|
};
|
|
130
173
|
try {
|
|
131
|
-
this.entry.$tx.$namespace === "default"
|
|
174
|
+
await (this.entry.$tx.$namespace === "default"
|
|
132
175
|
? setupDefaultLocation()
|
|
133
|
-
: setupLocation();
|
|
176
|
+
: setupLocation());
|
|
134
177
|
}
|
|
135
178
|
catch (error) {
|
|
136
|
-
this.entry.$nodes[this.reference].error = `Init Contract Error - ${error.message}`;
|
|
179
|
+
this.entry.$nodes[this.reference].error = `Init Contract Error - ${error.message || error}`;
|
|
137
180
|
this.emit("commited", { instant: true });
|
|
138
181
|
return;
|
|
139
182
|
}
|
|
140
|
-
const virtualMachine =
|
|
141
|
-
|
|
142
|
-
: this.contractRef
|
|
143
|
-
? Process.singleContractVMHolder[this.contractRef]
|
|
144
|
-
: Process.generalContractVM;
|
|
145
|
-
if (fs.existsSync(this.contractLocation)) {
|
|
183
|
+
const virtualMachine = Process.generalContractVM;
|
|
184
|
+
if (await fs.stat(this.contractLocation).catch(() => false)) {
|
|
146
185
|
this.inputs = Object.keys(this.entry.$tx.$i || {});
|
|
147
186
|
if (this.inputs.length) {
|
|
148
187
|
this.labelOrKey();
|
|
@@ -152,7 +191,6 @@ export class Process extends EventEmitter {
|
|
|
152
191
|
this.labelOrKey(true);
|
|
153
192
|
}
|
|
154
193
|
if (!this.entry.$revs) {
|
|
155
|
-
this.checkRevs = false;
|
|
156
194
|
this.entry.$revs = {
|
|
157
195
|
$i: {},
|
|
158
196
|
$o: {},
|
|
@@ -162,28 +200,24 @@ export class Process extends EventEmitter {
|
|
|
162
200
|
try {
|
|
163
201
|
const inputStreams = await this.permissionChecker.process(this.inputs);
|
|
164
202
|
const outputStreams = await this.permissionChecker.process(this.outputs, false);
|
|
165
|
-
|
|
166
|
-
if (!this.isDefault) {
|
|
167
|
-
try {
|
|
168
|
-
const contractDataStreams = await this.permissionChecker.process([`${this.contractId}:data`], false);
|
|
169
|
-
if (contractDataStreams.length > 0) {
|
|
170
|
-
contractData = contractDataStreams[0]
|
|
171
|
-
.state;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
catch (e) {
|
|
175
|
-
if (e.code === 1200) {
|
|
176
|
-
throw e;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
this.process(inputStreams, outputStreams, contractData);
|
|
203
|
+
this.process(inputStreams, outputStreams, await this.getContractDate(contractData));
|
|
181
204
|
}
|
|
182
205
|
catch (error) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
206
|
+
const reason = error.reason || error.message || error;
|
|
207
|
+
if (this.entry.$unanimous &&
|
|
208
|
+
!this.entry.$broadcast &&
|
|
209
|
+
!this.entry.$spiRetry &&
|
|
210
|
+
(reason.indexOf("Position Incorrect") !== -1 ||
|
|
211
|
+
reason === "Stream(s) not found")) {
|
|
212
|
+
this.entry.$nodes[this.reference].error = reason;
|
|
213
|
+
this.emitFailed({ status: error.code || 1200, error: reason, entry: this.entry }, true);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.postVote(virtualMachine, {
|
|
217
|
+
code: error.code,
|
|
218
|
+
reason,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
187
221
|
}
|
|
188
222
|
}
|
|
189
223
|
else {
|
|
@@ -211,15 +245,29 @@ export class Process extends EventEmitter {
|
|
|
211
245
|
}
|
|
212
246
|
}
|
|
213
247
|
}
|
|
248
|
+
else {
|
|
249
|
+
return this.shared.raiseLedgerError(1260, new Error("Self signed - Must have inputs"));
|
|
250
|
+
}
|
|
214
251
|
try {
|
|
215
252
|
const outputStreams = await this.permissionChecker.process(this.outputs, false);
|
|
216
|
-
this.process([], outputStreams,
|
|
253
|
+
this.process([], outputStreams, await this.getContractDate(contractData));
|
|
217
254
|
}
|
|
218
255
|
catch (error) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
256
|
+
const reason = error.reason || error.message || error;
|
|
257
|
+
if (this.entry.$unanimous &&
|
|
258
|
+
!this.entry.$broadcast &&
|
|
259
|
+
!this.entry.$spiRetry &&
|
|
260
|
+
(reason === "Stream(s) not found" ||
|
|
261
|
+
reason.indexOf("Position Incorrect") !== -1)) {
|
|
262
|
+
this.entry.$nodes[this.reference].error = reason;
|
|
263
|
+
this.emitFailed({ status: error.code || 1200, error: reason, entry: this.entry }, true);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
this.postVote(virtualMachine, {
|
|
267
|
+
code: error.code,
|
|
268
|
+
reason,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
223
271
|
}
|
|
224
272
|
}
|
|
225
273
|
}
|
|
@@ -234,10 +282,13 @@ export class Process extends EventEmitter {
|
|
|
234
282
|
if (this.isCommiting()) {
|
|
235
283
|
return;
|
|
236
284
|
}
|
|
285
|
+
if (node[this.reference]) {
|
|
286
|
+
delete node[this.reference];
|
|
287
|
+
}
|
|
237
288
|
this.entry.$nodes = Object.assign(this.entry.$nodes, node);
|
|
238
289
|
if (this.willEmit) {
|
|
239
290
|
const nodes = Object.keys(this.entry.$nodes);
|
|
240
|
-
if (!this.hasOutstandingVotes(
|
|
291
|
+
if (!(this.hasOutstandingVotes()) && !this.canCommit()) {
|
|
241
292
|
this.emitFailed(this.willEmitData);
|
|
242
293
|
}
|
|
243
294
|
else {
|
|
@@ -251,42 +302,62 @@ export class Process extends EventEmitter {
|
|
|
251
302
|
}
|
|
252
303
|
else {
|
|
253
304
|
if (!this.isCommiting() && !this.voting) {
|
|
254
|
-
this.
|
|
255
|
-
this.isDefault
|
|
256
|
-
? this.commit(Process.defaultContractsVM)
|
|
257
|
-
: this.contractRef
|
|
258
|
-
? this.commit(Process.singleContractVMHolder[this.contractRef])
|
|
259
|
-
: this.commit(Process.generalContractVM);
|
|
305
|
+
this.commit(Process.generalContractVM);
|
|
260
306
|
}
|
|
261
307
|
}
|
|
262
308
|
}
|
|
263
309
|
isCommiting() {
|
|
264
310
|
return this.commiting;
|
|
265
311
|
}
|
|
266
|
-
|
|
267
|
-
if (!
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
312
|
+
async getContractDate(contractData) {
|
|
313
|
+
if (!contractData && !this.isDefault) {
|
|
314
|
+
if (await this.db.exists(`${this.contractId}:data`)) {
|
|
315
|
+
try {
|
|
316
|
+
const contractDataStreams = await this.permissionChecker.process([`${this.contractId}:data`], false, 5);
|
|
317
|
+
if (contractDataStreams.length > 0) {
|
|
318
|
+
contractData = contractDataStreams[0]
|
|
319
|
+
.state;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch (e) {
|
|
323
|
+
if (e.code === 1200) {
|
|
324
|
+
this.emit("contractData", {
|
|
325
|
+
contract: this.contractId,
|
|
326
|
+
data: {},
|
|
327
|
+
});
|
|
328
|
+
throw e;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
271
331
|
}
|
|
272
|
-
|
|
273
|
-
|
|
332
|
+
else {
|
|
333
|
+
contractData = { _id: "", data: {} };
|
|
274
334
|
}
|
|
335
|
+
this.emit("contractData", {
|
|
336
|
+
contract: this.contractId,
|
|
337
|
+
data: contractData,
|
|
338
|
+
});
|
|
275
339
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
340
|
+
else {
|
|
341
|
+
if (contractData && this.contractId) {
|
|
342
|
+
const rev = `0-context:${contractData._rev}`;
|
|
343
|
+
if (this.entry.$revs.$o[`${this.contractId}:data`]) {
|
|
344
|
+
if (this.entry.$revs.$o[`${this.contractId}:data`] !== rev) {
|
|
345
|
+
this.emit("contractData", {
|
|
346
|
+
contract: this.contractId,
|
|
347
|
+
data: {},
|
|
348
|
+
});
|
|
349
|
+
throw {
|
|
350
|
+
code: 1200,
|
|
351
|
+
reason: "Output Stream Position Incorrect",
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
this.entry.$revs.$o[`${this.contractId}:data`] = rev;
|
|
357
|
+
}
|
|
287
358
|
}
|
|
288
359
|
}
|
|
289
|
-
|
|
360
|
+
return contractData;
|
|
290
361
|
}
|
|
291
362
|
async handleVM(virtualMachine, payload, contractName) {
|
|
292
363
|
const handleVoteError = async (error) => {
|
|
@@ -294,7 +365,7 @@ export class Process extends EventEmitter {
|
|
|
294
365
|
ActiveLogger.debug(this.nodeResponse.error, `Handle Vote Error ${payload.umid}`);
|
|
295
366
|
ActiveLogger.debug(`Calling Contract Return Data - ${payload.umid}`);
|
|
296
367
|
this.nodeResponse.return = virtualMachine.getReturnContractData(this.entry.$umid);
|
|
297
|
-
this.postVote(virtualMachine);
|
|
368
|
+
this.postVote(virtualMachine, this.nodeResponse.error);
|
|
298
369
|
};
|
|
299
370
|
let continueProcessing = true;
|
|
300
371
|
try {
|
|
@@ -319,7 +390,12 @@ export class Process extends EventEmitter {
|
|
|
319
390
|
try {
|
|
320
391
|
if (continueProcessing)
|
|
321
392
|
ActiveLogger.debug(`Calling Contract Vote - ${payload.umid}`);
|
|
322
|
-
await virtualMachine.vote(this.entry.$nodes, payload.umid);
|
|
393
|
+
const vote = await virtualMachine.vote(this.entry.$nodes, payload.umid);
|
|
394
|
+
if (typeof vote !== "boolean" && vote.leader) {
|
|
395
|
+
this.nodeResponse.vote = this.nodeResponse.leader = true;
|
|
396
|
+
this.commit(virtualMachine);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
323
399
|
}
|
|
324
400
|
catch (error) {
|
|
325
401
|
handleVoteError(error);
|
|
@@ -327,6 +403,7 @@ export class Process extends EventEmitter {
|
|
|
327
403
|
}
|
|
328
404
|
if (continueProcessing) {
|
|
329
405
|
this.nodeResponse.vote = true;
|
|
406
|
+
this.nodeResponse.early = false;
|
|
330
407
|
ActiveLogger.debug(`Calling Contract INC - ${payload.umid}`);
|
|
331
408
|
this.nodeResponse.incomms = virtualMachine.getInternodeCommsFromVM(payload.umid);
|
|
332
409
|
ActiveLogger.debug(`Calling Contract Return Data - ${payload.umid}`);
|
|
@@ -342,6 +419,7 @@ export class Process extends EventEmitter {
|
|
|
342
419
|
}
|
|
343
420
|
catch (error) {
|
|
344
421
|
this.nodeResponse.error = "Read Error - " + JSON.stringify(error);
|
|
422
|
+
this.nodeResponse.early = false;
|
|
345
423
|
}
|
|
346
424
|
this.nodeResponse.commit = true;
|
|
347
425
|
this.emit("commited");
|
|
@@ -349,8 +427,10 @@ export class Process extends EventEmitter {
|
|
|
349
427
|
}
|
|
350
428
|
async process(inputs, outputs = [], contractData = undefined) {
|
|
351
429
|
try {
|
|
352
|
-
if (this.entry.$broadcast) {
|
|
353
|
-
this.
|
|
430
|
+
if (this.entry.$broadcast && !this.entry.$wait) {
|
|
431
|
+
if (this.entry.$origin === this.reference) {
|
|
432
|
+
this.emit("broadcast", true);
|
|
433
|
+
}
|
|
354
434
|
}
|
|
355
435
|
const readonly = await this.getReadOnlyStreams();
|
|
356
436
|
const contractName = this.contractLocation.substring(this.contractLocation.lastIndexOf("/") + 1);
|
|
@@ -374,46 +454,10 @@ export class Process extends EventEmitter {
|
|
|
374
454
|
inputs,
|
|
375
455
|
outputs,
|
|
376
456
|
readonly,
|
|
377
|
-
key:
|
|
378
|
-
contractData,
|
|
457
|
+
key: 0,
|
|
458
|
+
contractData: contractData ? contractData : { _id: "", data: {} },
|
|
379
459
|
};
|
|
380
|
-
|
|
381
|
-
this.securityCache = ActiveOptions.get("security", null);
|
|
382
|
-
}
|
|
383
|
-
if (payload.transaction.$namespace === "default") {
|
|
384
|
-
this.processDefaultContracts(payload, contractName);
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
if (this.securityCache &&
|
|
388
|
-
this.securityCache.namespace &&
|
|
389
|
-
this.securityCache.namespace[payload.transaction.$namespace]) {
|
|
390
|
-
const builtin = [];
|
|
391
|
-
const external = [];
|
|
392
|
-
const mocks = [];
|
|
393
|
-
const namespaceExtras = this.securityCache.namespace[payload.transaction.$namespace];
|
|
394
|
-
if (namespaceExtras) {
|
|
395
|
-
if (namespaceExtras.std) {
|
|
396
|
-
namespaceExtras.std.forEach((item) => {
|
|
397
|
-
builtin.push(item);
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
if (namespaceExtras.external) {
|
|
401
|
-
namespaceExtras.external.forEach((item) => {
|
|
402
|
-
external.push(item);
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
if (namespaceExtras.mock) {
|
|
406
|
-
namespaceExtras.mock.forEach((item) => {
|
|
407
|
-
mocks.push(item);
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
this.processUnsafeContracts(payload, payload.transaction.$namespace, contractName, builtin, external, mocks);
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
this.handleVM(Process.generalContractVM, payload, contractName);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
460
|
+
this.handleVM(Process.generalContractVM, payload, contractName);
|
|
417
461
|
}
|
|
418
462
|
catch (error) {
|
|
419
463
|
this.shared.raiseLedgerError(1210, new Error("Read Only Stream Error"));
|
|
@@ -422,6 +466,8 @@ export class Process extends EventEmitter {
|
|
|
422
466
|
}
|
|
423
467
|
postVote(virtualMachine, error = false) {
|
|
424
468
|
this.voting = false;
|
|
469
|
+
this.nodeResponse.early = false;
|
|
470
|
+
delete this.nodeResponse.early;
|
|
425
471
|
if (!this.entry) {
|
|
426
472
|
ActiveLogger.debug(`postVote entry is missing?`);
|
|
427
473
|
return;
|
|
@@ -432,25 +478,32 @@ export class Process extends EventEmitter {
|
|
|
432
478
|
}
|
|
433
479
|
if (this.entry.$broadcast) {
|
|
434
480
|
if (error) {
|
|
435
|
-
this.entry.$nodes[this.reference].error = error.reason
|
|
481
|
+
this.entry.$nodes[this.reference].error = error.reason
|
|
482
|
+
? error.reason
|
|
483
|
+
: error;
|
|
484
|
+
if (error.code === 950) {
|
|
485
|
+
this.shared.raiseLedgerError(error.code, error.reason);
|
|
486
|
+
}
|
|
436
487
|
}
|
|
437
|
-
this.
|
|
438
|
-
|
|
439
|
-
this.commit(virtualMachine);
|
|
488
|
+
if (!this.nodeResponse.leader) {
|
|
489
|
+
this.emit("broadcast");
|
|
440
490
|
}
|
|
491
|
+
this.commit(virtualMachine);
|
|
441
492
|
}
|
|
442
493
|
else {
|
|
443
494
|
if (this.right.reference != this.entry.$origin) {
|
|
444
|
-
ActiveLogger.debug("Attempting commit with too early commit callback (to send right");
|
|
495
|
+
ActiveLogger.debug("Attempting commit with too early commit callback (to send right)");
|
|
445
496
|
this.commit(virtualMachine, async () => {
|
|
446
497
|
try {
|
|
447
498
|
const response = await this.initRightKnock();
|
|
448
499
|
if (!this.nodeResponse.commit) {
|
|
449
|
-
|
|
450
|
-
this.entry.$
|
|
500
|
+
const data = response.data;
|
|
501
|
+
this.entry.$territoriality =
|
|
502
|
+
data.$territoriality ?? this.entry.$territoriality;
|
|
503
|
+
this.entry.$nodes = data.$nodes ?? this.entry.$nodes;
|
|
451
504
|
this.nodeResponse = this.entry.$nodes[this.reference];
|
|
452
505
|
if (error) {
|
|
453
|
-
this.shared.raiseLedgerError(error.code, error.reason, true, 10);
|
|
506
|
+
this.shared.raiseLedgerError(error.code || 1000, error.reason || error, true, 10);
|
|
454
507
|
}
|
|
455
508
|
ActiveLogger.debug("Sending Commit without callback");
|
|
456
509
|
this.commit(virtualMachine);
|
|
@@ -467,15 +520,16 @@ export class Process extends EventEmitter {
|
|
|
467
520
|
else {
|
|
468
521
|
ActiveLogger.debug("Origin is next (Sending Back)");
|
|
469
522
|
error
|
|
470
|
-
? this.shared.raiseLedgerError(error.code, error.reason)
|
|
523
|
+
? this.shared.raiseLedgerError(error.code || 1000, error.reason || error)
|
|
471
524
|
: this.commit(virtualMachine);
|
|
472
525
|
}
|
|
473
526
|
}
|
|
474
527
|
}
|
|
475
|
-
emitFailed(data) {
|
|
476
|
-
|
|
528
|
+
emitFailed(data, noWait) {
|
|
529
|
+
this.commiting = false;
|
|
530
|
+
if (this.willEmit || noWait) {
|
|
477
531
|
clearTimeout(this.willEmit);
|
|
478
|
-
this.emit("failed", this.willEmitData);
|
|
532
|
+
this.emit("failed", this.willEmitData || data);
|
|
479
533
|
}
|
|
480
534
|
else {
|
|
481
535
|
if (this.entry &&
|
|
@@ -491,14 +545,23 @@ export class Process extends EventEmitter {
|
|
|
491
545
|
}
|
|
492
546
|
}
|
|
493
547
|
}
|
|
494
|
-
hasOutstandingVotes(
|
|
495
|
-
|
|
496
|
-
|
|
548
|
+
hasOutstandingVotes() {
|
|
549
|
+
return !!(Process.networkNodeLength - this.countOutstandingVotes());
|
|
550
|
+
}
|
|
551
|
+
countOutstandingVotes() {
|
|
552
|
+
const nodes = Object.keys(this.entry.$nodes);
|
|
553
|
+
let votedNodes = 0;
|
|
554
|
+
for (let i = nodes.length; i--;) {
|
|
555
|
+
if (!this.entry.$nodes[nodes[i]].early) {
|
|
556
|
+
votedNodes++;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return votedNodes;
|
|
497
560
|
}
|
|
498
561
|
async initRightKnock(retries = 0) {
|
|
499
562
|
try {
|
|
500
563
|
ActiveLogger.debug(`Sending -> ${this.right.reference} - ${this.entry.$umid}`);
|
|
501
|
-
return await this.right.knock("init", this.entry);
|
|
564
|
+
return await this.right.knock("init-legacy", this.entry);
|
|
502
565
|
}
|
|
503
566
|
catch (e) {
|
|
504
567
|
if (retries <= 2) {
|
|
@@ -516,22 +579,27 @@ export class Process extends EventEmitter {
|
|
|
516
579
|
}
|
|
517
580
|
canCommit() {
|
|
518
581
|
let networkNodes = Object.keys(this.entry.$nodes);
|
|
519
|
-
this.
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
this.
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
100 >=
|
|
530
|
-
|
|
582
|
+
this.currentTrueVotes = 0;
|
|
583
|
+
if (networkNodes) {
|
|
584
|
+
for (let i = networkNodes.length; i--;) {
|
|
585
|
+
if (!this.entry.$nodes[networkNodes[i]].early &&
|
|
586
|
+
this.entry.$nodes[networkNodes[i]].vote)
|
|
587
|
+
this.currentTrueVotes++;
|
|
588
|
+
}
|
|
589
|
+
const percent = this.entry.$unanimous
|
|
590
|
+
? 100
|
|
591
|
+
: ActiveOptions.get("consensus", {}).reached;
|
|
592
|
+
const reached = (this.currentTrueVotes / Process.networkNodeLength) * 100 >= percent;
|
|
593
|
+
return reached;
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
531
598
|
}
|
|
532
599
|
async commit(virtualMachine, earlyCommit) {
|
|
533
600
|
if (!this.nodeResponse.commit && !this.isCommiting()) {
|
|
534
|
-
if (this.
|
|
601
|
+
if (this.nodeResponse.vote &&
|
|
602
|
+
(this.nodeResponse.leader || this.canCommit())) {
|
|
535
603
|
this.commiting = true;
|
|
536
604
|
clearTimeout(this.broadcastTimeout);
|
|
537
605
|
try {
|
|
@@ -542,15 +610,8 @@ export class Process extends EventEmitter {
|
|
|
542
610
|
this.nodeResponse.incomms = virtualMachine.getInternodeCommsFromVM(this.entry.$umid);
|
|
543
611
|
ActiveLogger.debug(`Calling Contract Return Data X2 - ${this.entry.$umid}`);
|
|
544
612
|
this.nodeResponse.return = virtualMachine.getReturnContractData(this.entry.$umid);
|
|
545
|
-
this.entry = this.shared.clearAllComms(virtualMachine, this.nodeResponse.incomms);
|
|
546
|
-
let throws = virtualMachine.getThrowsFromVM(this.entry.$umid);
|
|
547
|
-
if (throws && throws.length) {
|
|
548
|
-
this.emit("throw", { locations: throws });
|
|
549
|
-
}
|
|
550
613
|
const streamUpdater = new StreamUpdater(this.entry, virtualMachine, this.reference, this.nodeResponse, this.db, this.dbev, this, this.shared, this.contractId);
|
|
551
|
-
earlyCommit
|
|
552
|
-
? streamUpdater.updateStreams(earlyCommit)
|
|
553
|
-
: streamUpdater.updateStreams();
|
|
614
|
+
await streamUpdater.updateStreams(earlyCommit);
|
|
554
615
|
}
|
|
555
616
|
catch (error) {
|
|
556
617
|
if (earlyCommit)
|
|
@@ -575,7 +636,7 @@ export class Process extends EventEmitter {
|
|
|
575
636
|
if (reconciled) {
|
|
576
637
|
ActiveLogger.info("Self Reconcile Successful");
|
|
577
638
|
const streamUpdater = new StreamUpdater(this.entry, virtualMachine, this.reference, this.nodeResponse, this.db, this.dbev, this, this.shared, this.contractId);
|
|
578
|
-
streamUpdater.updateStreams();
|
|
639
|
+
await streamUpdater.updateStreams();
|
|
579
640
|
}
|
|
580
641
|
else {
|
|
581
642
|
if (this.errorOut.code === 1505) {
|
|
@@ -607,9 +668,8 @@ export class Process extends EventEmitter {
|
|
|
607
668
|
this.shared.raiseLedgerError(1510, new Error("Failed Network Voting Round - Non Broadcast"));
|
|
608
669
|
}
|
|
609
670
|
else {
|
|
610
|
-
const neighbours = ActiveOptions.get("neighbourhood", []).length;
|
|
611
671
|
const consensusNeeded = ActiveOptions.get("consensus", {}).reached;
|
|
612
|
-
const outstandingVoters =
|
|
672
|
+
const outstandingVoters = Process.networkNodeLength - this.countOutstandingVotes();
|
|
613
673
|
if (!outstandingVoters) {
|
|
614
674
|
clearTimeout(this.broadcastTimeout);
|
|
615
675
|
if (this.nodeResponse.error) {
|
|
@@ -626,12 +686,17 @@ export class Process extends EventEmitter {
|
|
|
626
686
|
}
|
|
627
687
|
else {
|
|
628
688
|
clearTimeout(this.broadcastTimeout);
|
|
629
|
-
if (((this.
|
|
689
|
+
if (((this.currentTrueVotes + outstandingVoters) / Process.networkNodeLength) *
|
|
690
|
+
100 >=
|
|
630
691
|
consensusNeeded) {
|
|
631
692
|
this.broadcastTimeout = setTimeout(() => {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
693
|
+
if (!this.isCommiting()) {
|
|
694
|
+
ActiveLogger.debug("VM Commit Failure, NETWORK Timeout");
|
|
695
|
+
return this.shared.raiseLedgerError(1510, new Error("Failed Network Voting Timeout - Voters Timed Out"));
|
|
696
|
+
}
|
|
697
|
+
}, this.isCommiting()
|
|
698
|
+
? BROADCAST_TIMEOUT_COMMIT
|
|
699
|
+
: this.currentTrueVotes === 0 ? BROADCAST_TIMEOUT_EARLY : BROADCAST_TIMEOUT_VOTE);
|
|
635
700
|
}
|
|
636
701
|
else {
|
|
637
702
|
if (this.nodeResponse.error) {
|
|
@@ -699,9 +764,11 @@ export class Process extends EventEmitter {
|
|
|
699
764
|
let streamId = txIO[streams[i]].$stream || streams[i];
|
|
700
765
|
map[streamId] = streams[i];
|
|
701
766
|
streams[i] = streamId;
|
|
767
|
+
if (!outputs && txIO[map[streamId]].$sigOnly) {
|
|
768
|
+
this.shared.sigOnly[streams[i]] = true;
|
|
769
|
+
}
|
|
702
770
|
}
|
|
703
771
|
}
|
|
704
772
|
}
|
|
705
773
|
}
|
|
706
|
-
Process.singleContractVMHolder = {};
|
|
707
774
|
//# sourceMappingURL=process.js.map
|