@activeledger/activeprotocol 2.15.7 → 4.3.4
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 +6 -4
- 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 +276 -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 -137
- 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 +6 -4
- 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 +276 -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 -136
- 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 +10 -10
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 {
|
|
@@ -320,7 +391,7 @@ export class Process extends EventEmitter {
|
|
|
320
391
|
if (continueProcessing)
|
|
321
392
|
ActiveLogger.debug(`Calling Contract Vote - ${payload.umid}`);
|
|
322
393
|
const vote = await virtualMachine.vote(this.entry.$nodes, payload.umid);
|
|
323
|
-
if (typeof
|
|
394
|
+
if (typeof vote !== "boolean" && vote.leader) {
|
|
324
395
|
this.nodeResponse.vote = this.nodeResponse.leader = true;
|
|
325
396
|
this.commit(virtualMachine);
|
|
326
397
|
return;
|
|
@@ -332,6 +403,7 @@ export class Process extends EventEmitter {
|
|
|
332
403
|
}
|
|
333
404
|
if (continueProcessing) {
|
|
334
405
|
this.nodeResponse.vote = true;
|
|
406
|
+
this.nodeResponse.early = false;
|
|
335
407
|
ActiveLogger.debug(`Calling Contract INC - ${payload.umid}`);
|
|
336
408
|
this.nodeResponse.incomms = virtualMachine.getInternodeCommsFromVM(payload.umid);
|
|
337
409
|
ActiveLogger.debug(`Calling Contract Return Data - ${payload.umid}`);
|
|
@@ -347,6 +419,7 @@ export class Process extends EventEmitter {
|
|
|
347
419
|
}
|
|
348
420
|
catch (error) {
|
|
349
421
|
this.nodeResponse.error = "Read Error - " + JSON.stringify(error);
|
|
422
|
+
this.nodeResponse.early = false;
|
|
350
423
|
}
|
|
351
424
|
this.nodeResponse.commit = true;
|
|
352
425
|
this.emit("commited");
|
|
@@ -354,8 +427,10 @@ export class Process extends EventEmitter {
|
|
|
354
427
|
}
|
|
355
428
|
async process(inputs, outputs = [], contractData = undefined) {
|
|
356
429
|
try {
|
|
357
|
-
if (this.entry.$broadcast) {
|
|
358
|
-
this.
|
|
430
|
+
if (this.entry.$broadcast && !this.entry.$wait) {
|
|
431
|
+
if (this.entry.$origin === this.reference) {
|
|
432
|
+
this.emit("broadcast", true);
|
|
433
|
+
}
|
|
359
434
|
}
|
|
360
435
|
const readonly = await this.getReadOnlyStreams();
|
|
361
436
|
const contractName = this.contractLocation.substring(this.contractLocation.lastIndexOf("/") + 1);
|
|
@@ -379,46 +454,10 @@ export class Process extends EventEmitter {
|
|
|
379
454
|
inputs,
|
|
380
455
|
outputs,
|
|
381
456
|
readonly,
|
|
382
|
-
key:
|
|
383
|
-
contractData,
|
|
457
|
+
key: 0,
|
|
458
|
+
contractData: contractData ? contractData : { _id: "", data: {} },
|
|
384
459
|
};
|
|
385
|
-
|
|
386
|
-
this.securityCache = ActiveOptions.get("security", null);
|
|
387
|
-
}
|
|
388
|
-
if (payload.transaction.$namespace === "default") {
|
|
389
|
-
this.processDefaultContracts(payload, contractName);
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
if (this.securityCache &&
|
|
393
|
-
this.securityCache.namespace &&
|
|
394
|
-
this.securityCache.namespace[payload.transaction.$namespace]) {
|
|
395
|
-
const builtin = [];
|
|
396
|
-
const external = [];
|
|
397
|
-
const mocks = [];
|
|
398
|
-
const namespaceExtras = this.securityCache.namespace[payload.transaction.$namespace];
|
|
399
|
-
if (namespaceExtras) {
|
|
400
|
-
if (namespaceExtras.std) {
|
|
401
|
-
namespaceExtras.std.forEach((item) => {
|
|
402
|
-
builtin.push(item);
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
if (namespaceExtras.external) {
|
|
406
|
-
namespaceExtras.external.forEach((item) => {
|
|
407
|
-
external.push(item);
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
if (namespaceExtras.mock) {
|
|
411
|
-
namespaceExtras.mock.forEach((item) => {
|
|
412
|
-
mocks.push(item);
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
this.processUnsafeContracts(payload, payload.transaction.$namespace, contractName, builtin, external, mocks);
|
|
417
|
-
}
|
|
418
|
-
else {
|
|
419
|
-
this.handleVM(Process.generalContractVM, payload, contractName);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
460
|
+
this.handleVM(Process.generalContractVM, payload, contractName);
|
|
422
461
|
}
|
|
423
462
|
catch (error) {
|
|
424
463
|
this.shared.raiseLedgerError(1210, new Error("Read Only Stream Error"));
|
|
@@ -427,6 +466,8 @@ export class Process extends EventEmitter {
|
|
|
427
466
|
}
|
|
428
467
|
postVote(virtualMachine, error = false) {
|
|
429
468
|
this.voting = false;
|
|
469
|
+
this.nodeResponse.early = false;
|
|
470
|
+
delete this.nodeResponse.early;
|
|
430
471
|
if (!this.entry) {
|
|
431
472
|
ActiveLogger.debug(`postVote entry is missing?`);
|
|
432
473
|
return;
|
|
@@ -437,25 +478,32 @@ export class Process extends EventEmitter {
|
|
|
437
478
|
}
|
|
438
479
|
if (this.entry.$broadcast) {
|
|
439
480
|
if (error) {
|
|
440
|
-
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
|
+
}
|
|
441
487
|
}
|
|
442
|
-
this.
|
|
443
|
-
|
|
444
|
-
this.commit(virtualMachine);
|
|
488
|
+
if (!this.nodeResponse.leader) {
|
|
489
|
+
this.emit("broadcast");
|
|
445
490
|
}
|
|
491
|
+
this.commit(virtualMachine);
|
|
446
492
|
}
|
|
447
493
|
else {
|
|
448
494
|
if (this.right.reference != this.entry.$origin) {
|
|
449
|
-
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)");
|
|
450
496
|
this.commit(virtualMachine, async () => {
|
|
451
497
|
try {
|
|
452
498
|
const response = await this.initRightKnock();
|
|
453
499
|
if (!this.nodeResponse.commit) {
|
|
454
|
-
|
|
455
|
-
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;
|
|
456
504
|
this.nodeResponse = this.entry.$nodes[this.reference];
|
|
457
505
|
if (error) {
|
|
458
|
-
this.shared.raiseLedgerError(error.code, error.reason, true, 10);
|
|
506
|
+
this.shared.raiseLedgerError(error.code || 1000, error.reason || error, true, 10);
|
|
459
507
|
}
|
|
460
508
|
ActiveLogger.debug("Sending Commit without callback");
|
|
461
509
|
this.commit(virtualMachine);
|
|
@@ -472,15 +520,16 @@ export class Process extends EventEmitter {
|
|
|
472
520
|
else {
|
|
473
521
|
ActiveLogger.debug("Origin is next (Sending Back)");
|
|
474
522
|
error
|
|
475
|
-
? this.shared.raiseLedgerError(error.code, error.reason)
|
|
523
|
+
? this.shared.raiseLedgerError(error.code || 1000, error.reason || error)
|
|
476
524
|
: this.commit(virtualMachine);
|
|
477
525
|
}
|
|
478
526
|
}
|
|
479
527
|
}
|
|
480
|
-
emitFailed(data) {
|
|
481
|
-
|
|
528
|
+
emitFailed(data, noWait) {
|
|
529
|
+
this.commiting = false;
|
|
530
|
+
if (this.willEmit || noWait) {
|
|
482
531
|
clearTimeout(this.willEmit);
|
|
483
|
-
this.emit("failed", this.willEmitData);
|
|
532
|
+
this.emit("failed", this.willEmitData || data);
|
|
484
533
|
}
|
|
485
534
|
else {
|
|
486
535
|
if (this.entry &&
|
|
@@ -496,14 +545,23 @@ export class Process extends EventEmitter {
|
|
|
496
545
|
}
|
|
497
546
|
}
|
|
498
547
|
}
|
|
499
|
-
hasOutstandingVotes(
|
|
500
|
-
|
|
501
|
-
|
|
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;
|
|
502
560
|
}
|
|
503
561
|
async initRightKnock(retries = 0) {
|
|
504
562
|
try {
|
|
505
563
|
ActiveLogger.debug(`Sending -> ${this.right.reference} - ${this.entry.$umid}`);
|
|
506
|
-
return await this.right.knock("init", this.entry);
|
|
564
|
+
return await this.right.knock("init-legacy", this.entry);
|
|
507
565
|
}
|
|
508
566
|
catch (e) {
|
|
509
567
|
if (retries <= 2) {
|
|
@@ -521,22 +579,27 @@ export class Process extends EventEmitter {
|
|
|
521
579
|
}
|
|
522
580
|
canCommit() {
|
|
523
581
|
let networkNodes = Object.keys(this.entry.$nodes);
|
|
524
|
-
this.
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
this.
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
100 >=
|
|
535
|
-
|
|
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
|
+
}
|
|
536
598
|
}
|
|
537
599
|
async commit(virtualMachine, earlyCommit) {
|
|
538
600
|
if (!this.nodeResponse.commit && !this.isCommiting()) {
|
|
539
|
-
if (this.nodeResponse.vote &&
|
|
601
|
+
if (this.nodeResponse.vote &&
|
|
602
|
+
(this.nodeResponse.leader || this.canCommit())) {
|
|
540
603
|
this.commiting = true;
|
|
541
604
|
clearTimeout(this.broadcastTimeout);
|
|
542
605
|
try {
|
|
@@ -547,15 +610,8 @@ export class Process extends EventEmitter {
|
|
|
547
610
|
this.nodeResponse.incomms = virtualMachine.getInternodeCommsFromVM(this.entry.$umid);
|
|
548
611
|
ActiveLogger.debug(`Calling Contract Return Data X2 - ${this.entry.$umid}`);
|
|
549
612
|
this.nodeResponse.return = virtualMachine.getReturnContractData(this.entry.$umid);
|
|
550
|
-
this.entry = this.shared.clearAllComms(virtualMachine, this.nodeResponse.incomms);
|
|
551
|
-
let throws = virtualMachine.getThrowsFromVM(this.entry.$umid);
|
|
552
|
-
if (throws && throws.length) {
|
|
553
|
-
this.emit("throw", { locations: throws });
|
|
554
|
-
}
|
|
555
613
|
const streamUpdater = new StreamUpdater(this.entry, virtualMachine, this.reference, this.nodeResponse, this.db, this.dbev, this, this.shared, this.contractId);
|
|
556
|
-
earlyCommit
|
|
557
|
-
? streamUpdater.updateStreams(earlyCommit)
|
|
558
|
-
: streamUpdater.updateStreams();
|
|
614
|
+
await streamUpdater.updateStreams(earlyCommit);
|
|
559
615
|
}
|
|
560
616
|
catch (error) {
|
|
561
617
|
if (earlyCommit)
|
|
@@ -580,7 +636,7 @@ export class Process extends EventEmitter {
|
|
|
580
636
|
if (reconciled) {
|
|
581
637
|
ActiveLogger.info("Self Reconcile Successful");
|
|
582
638
|
const streamUpdater = new StreamUpdater(this.entry, virtualMachine, this.reference, this.nodeResponse, this.db, this.dbev, this, this.shared, this.contractId);
|
|
583
|
-
streamUpdater.updateStreams();
|
|
639
|
+
await streamUpdater.updateStreams();
|
|
584
640
|
}
|
|
585
641
|
else {
|
|
586
642
|
if (this.errorOut.code === 1505) {
|
|
@@ -612,9 +668,8 @@ export class Process extends EventEmitter {
|
|
|
612
668
|
this.shared.raiseLedgerError(1510, new Error("Failed Network Voting Round - Non Broadcast"));
|
|
613
669
|
}
|
|
614
670
|
else {
|
|
615
|
-
const neighbours = ActiveOptions.get("neighbourhood", []).length;
|
|
616
671
|
const consensusNeeded = ActiveOptions.get("consensus", {}).reached;
|
|
617
|
-
const outstandingVoters =
|
|
672
|
+
const outstandingVoters = Process.networkNodeLength - this.countOutstandingVotes();
|
|
618
673
|
if (!outstandingVoters) {
|
|
619
674
|
clearTimeout(this.broadcastTimeout);
|
|
620
675
|
if (this.nodeResponse.error) {
|
|
@@ -631,12 +686,17 @@ export class Process extends EventEmitter {
|
|
|
631
686
|
}
|
|
632
687
|
else {
|
|
633
688
|
clearTimeout(this.broadcastTimeout);
|
|
634
|
-
if (((this.
|
|
689
|
+
if (((this.currentTrueVotes + outstandingVoters) / Process.networkNodeLength) *
|
|
690
|
+
100 >=
|
|
635
691
|
consensusNeeded) {
|
|
636
692
|
this.broadcastTimeout = setTimeout(() => {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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);
|
|
640
700
|
}
|
|
641
701
|
else {
|
|
642
702
|
if (this.nodeResponse.error) {
|
|
@@ -704,9 +764,11 @@ export class Process extends EventEmitter {
|
|
|
704
764
|
let streamId = txIO[streams[i]].$stream || streams[i];
|
|
705
765
|
map[streamId] = streams[i];
|
|
706
766
|
streams[i] = streamId;
|
|
767
|
+
if (!outputs && txIO[map[streamId]].$sigOnly) {
|
|
768
|
+
this.shared.sigOnly[streams[i]] = true;
|
|
769
|
+
}
|
|
707
770
|
}
|
|
708
771
|
}
|
|
709
772
|
}
|
|
710
773
|
}
|
|
711
|
-
Process.singleContractVMHolder = {};
|
|
712
774
|
//# sourceMappingURL=process.js.map
|