@stacks/rendezvous 0.6.0 → 0.6.2
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/README.md +6 -0
- package/dist/app.js +18 -9
- package/dist/invariant.js +53 -18
- package/dist/package.json +1 -1
- package/dist/property.js +6 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,4 +106,10 @@ rv example counter invariant
|
|
|
106
106
|
|
|
107
107
|
---
|
|
108
108
|
|
|
109
|
+
### Documentation
|
|
110
|
+
|
|
111
|
+
For full documentation, see the official [Rendezvous Book](https://stacks-network.github.io/rendezvous/).
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
109
115
|
[^1]: Hughes, J. (2004). _Testing the Hard Stuff and Staying Sane_. In Proceedings of the ACM SIGPLAN Workshop on Haskell (Haskell '04).
|
package/dist/app.js
CHANGED
|
@@ -13,7 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
14
|
};
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.tryParseRemoteDataSettings = exports.getManifestFileName = exports.
|
|
16
|
+
exports.tryParseRemoteDataSettings = exports.getManifestFileName = exports.invalidRemoteDataWarningMessage = exports.noRemoteData = void 0;
|
|
17
17
|
exports.main = main;
|
|
18
18
|
const path_1 = require("path");
|
|
19
19
|
const events_1 = require("events");
|
|
@@ -38,7 +38,13 @@ exports.noRemoteData = {
|
|
|
38
38
|
api_url: "",
|
|
39
39
|
initial_height: 1,
|
|
40
40
|
};
|
|
41
|
-
exports.
|
|
41
|
+
exports.invalidRemoteDataWarningMessage = `\nRemote data settings existing in Clarinet.toml, but remote data feature will not be used! To use remote data, please make sure the following fields are set:
|
|
42
|
+
|
|
43
|
+
- enabled = true
|
|
44
|
+
- api_url = <stacks-api-url>
|
|
45
|
+
- initial_height = <stacks-block-height-to-fork-from>
|
|
46
|
+
|
|
47
|
+
under the "repl.remote_data" section in the Clarinet.toml file.`;
|
|
42
48
|
/**
|
|
43
49
|
* Gets the manifest file name for a Clarinet project.
|
|
44
50
|
* If a custom manifest exists (`Clarinet-<contract-name>.toml`), it is used.
|
|
@@ -59,16 +65,19 @@ const tryParseRemoteDataSettings = (manifestPath, radio) => {
|
|
|
59
65
|
var _a, _b;
|
|
60
66
|
const clarinetToml = toml_1.default.parse((0, fs_1.readFileSync)((0, path_1.resolve)(manifestPath), "utf-8"));
|
|
61
67
|
const remoteDataUserSettings = (_b = (_a = clarinetToml.repl) === null || _a === void 0 ? void 0 : _a["remote_data"]) !== null && _b !== void 0 ? _b : undefined;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
const invalidRemoteDataSetup = !(remoteDataUserSettings === null || remoteDataUserSettings === void 0 ? void 0 : remoteDataUserSettings["api_url"]) ||
|
|
69
|
+
!(remoteDataUserSettings === null || remoteDataUserSettings === void 0 ? void 0 : remoteDataUserSettings["enabled"]) ||
|
|
70
|
+
!(remoteDataUserSettings === null || remoteDataUserSettings === void 0 ? void 0 : remoteDataUserSettings["initial_height"]);
|
|
71
|
+
if (remoteDataUserSettings !== undefined && invalidRemoteDataSetup) {
|
|
72
|
+
radio.emit("logMessage", (0, ansicolor_1.yellow)(exports.invalidRemoteDataWarningMessage));
|
|
67
73
|
}
|
|
68
|
-
if (remoteDataUserSettings) {
|
|
74
|
+
else if (remoteDataUserSettings) {
|
|
69
75
|
radio.emit("logMessage", (0, ansicolor_1.yellow)("\nUsing remote data. Setting up the environment can take up to a minute..."));
|
|
70
76
|
}
|
|
71
|
-
|
|
77
|
+
if (!remoteDataUserSettings || invalidRemoteDataSetup) {
|
|
78
|
+
return exports.noRemoteData;
|
|
79
|
+
}
|
|
80
|
+
return remoteDataUserSettings;
|
|
72
81
|
};
|
|
73
82
|
exports.tryParseRemoteDataSettings = tryParseRemoteDataSettings;
|
|
74
83
|
const helpMessage = `
|
package/dist/invariant.js
CHANGED
|
@@ -169,18 +169,26 @@ const checkInvariants = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
169
169
|
try {
|
|
170
170
|
const functionCall = simnet.callPublicFn(r.rendezvousContractId, selectedFunction.name, selectedFunctionsArgsCV[index], sutCallerAddress);
|
|
171
171
|
const functionCallResultJson = (0, transactions_1.cvToJSON)(functionCall.result);
|
|
172
|
+
// Reaching this point means the function call went through, but it
|
|
173
|
+
// may still have returned an error result. Get the result, convert
|
|
174
|
+
// it to Clarity string format, and report it to improve the user
|
|
175
|
+
// experiance by providing important information about the function
|
|
176
|
+
// call during the run.
|
|
177
|
+
const selectedFunctionClarityResult = (0, transactions_1.cvToString)(functionCall.result);
|
|
172
178
|
if (functionCallResultJson.success) {
|
|
173
179
|
localContext[r.rendezvousContractId][selectedFunction.name]++;
|
|
174
180
|
simnet.callPublicFn(r.rendezvousContractId, "update-context", [
|
|
175
181
|
transactions_1.Cl.stringAscii(selectedFunction.name),
|
|
176
182
|
transactions_1.Cl.uint(localContext[r.rendezvousContractId][selectedFunction.name]),
|
|
177
183
|
], simnet.deployer);
|
|
184
|
+
// Function call passed.
|
|
178
185
|
radio.emit("logMessage", `₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
|
|
179
186
|
`Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
|
|
180
187
|
(0, ansicolor_1.dim)(`${sutCallerWallet} `) +
|
|
181
188
|
`${targetContractName} ` +
|
|
182
189
|
`${(0, ansicolor_1.underline)(selectedFunction.name)} ` +
|
|
183
|
-
printedFunctionArgs
|
|
190
|
+
`${printedFunctionArgs} ` +
|
|
191
|
+
(0, ansicolor_1.green)(selectedFunctionClarityResult));
|
|
184
192
|
try {
|
|
185
193
|
if (dialerRegistry !== undefined) {
|
|
186
194
|
yield dialerRegistry.executePostDialers({
|
|
@@ -195,12 +203,14 @@ const checkInvariants = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
195
203
|
}
|
|
196
204
|
}
|
|
197
205
|
else {
|
|
206
|
+
// Function call failed.
|
|
198
207
|
radio.emit("logMessage", (0, ansicolor_1.dim)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
|
|
199
208
|
`Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
|
|
200
209
|
`${sutCallerWallet} ` +
|
|
201
210
|
`${targetContractName} ` +
|
|
202
211
|
`${(0, ansicolor_1.underline)(selectedFunction.name)} ` +
|
|
203
|
-
printedFunctionArgs
|
|
212
|
+
`${printedFunctionArgs} ` +
|
|
213
|
+
(0, ansicolor_1.red)(selectedFunctionClarityResult)));
|
|
204
214
|
}
|
|
205
215
|
}
|
|
206
216
|
catch (error) {
|
|
@@ -209,15 +219,21 @@ const checkInvariants = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
209
219
|
throw error;
|
|
210
220
|
}
|
|
211
221
|
else {
|
|
222
|
+
const displayedError = error &&
|
|
223
|
+
typeof error === "string" &&
|
|
224
|
+
error.toLowerCase().includes("runtime")
|
|
225
|
+
? "(runtime)"
|
|
226
|
+
: "(unknown)";
|
|
212
227
|
// If the function call fails with a runtime error, log a dimmed
|
|
213
|
-
// message. Since the public function result is
|
|
214
|
-
// no need to throw an error.
|
|
228
|
+
// message. Since the public function result is only logged and
|
|
229
|
+
// does not affect the run, there's no need to throw an error.
|
|
215
230
|
radio.emit("logMessage", (0, ansicolor_1.dim)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
|
|
216
231
|
`Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
|
|
217
232
|
`${sutCallerWallet} ` +
|
|
218
233
|
`${targetContractName} ` +
|
|
219
234
|
`${(0, ansicolor_1.underline)(selectedFunction.name)} ` +
|
|
220
|
-
printedFunctionArgs
|
|
235
|
+
`${printedFunctionArgs} ` +
|
|
236
|
+
(0, ansicolor_1.red)(displayedError)));
|
|
221
237
|
}
|
|
222
238
|
}
|
|
223
239
|
}
|
|
@@ -237,6 +253,7 @@ const checkInvariants = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
237
253
|
try {
|
|
238
254
|
const { result: invariantCallResult } = simnet.callReadOnlyFn(r.rendezvousContractId, r.selectedInvariant.name, selectedInvariantArgsCV, invariantCallerAddress);
|
|
239
255
|
const invariantCallResultJson = (0, transactions_1.cvToJSON)(invariantCallResult);
|
|
256
|
+
const invariantCallClarityResult = (0, transactions_1.cvToString)(invariantCallResult);
|
|
240
257
|
if (invariantCallResultJson.value === true) {
|
|
241
258
|
radio.emit("logMessage", `₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
|
|
242
259
|
`Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
|
|
@@ -244,23 +261,36 @@ const checkInvariants = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
244
261
|
`${(0, ansicolor_1.green)("[PASS]")} ` +
|
|
245
262
|
`${targetContractName} ` +
|
|
246
263
|
`${(0, ansicolor_1.underline)(r.selectedInvariant.name)} ` +
|
|
247
|
-
printedInvariantArgs
|
|
264
|
+
`${printedInvariantArgs} ` +
|
|
265
|
+
(0, ansicolor_1.green)(invariantCallClarityResult));
|
|
248
266
|
}
|
|
249
|
-
|
|
250
|
-
|
|
267
|
+
else {
|
|
268
|
+
radio.emit("logMessage", (0, ansicolor_1.red)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
|
|
269
|
+
`Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
|
|
270
|
+
`${invariantCallerWallet} ` +
|
|
271
|
+
`[FAIL] ` +
|
|
272
|
+
`${targetContractName} ` +
|
|
273
|
+
`${(0, ansicolor_1.underline)(r.selectedInvariant.name)} ` +
|
|
274
|
+
`${printedInvariantArgs} ` +
|
|
275
|
+
(0, ansicolor_1.red)(invariantCallClarityResult)));
|
|
276
|
+
// Invariant call went through, but returned something other than
|
|
277
|
+
// `true`. Create a custom error to distinguish this case from
|
|
278
|
+
// runtime errors.
|
|
279
|
+
throw new FalsifiedInvariantError(`Invariant failed for ${targetContractName} contract: "${r.selectedInvariant.name}" returned ${invariantCallClarityResult}`);
|
|
251
280
|
}
|
|
252
281
|
}
|
|
253
282
|
catch (error) {
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
283
|
+
// Log errors that aren't already handled as falsified invariants.
|
|
284
|
+
// This prevents duplicate error messages for the same failure.
|
|
285
|
+
if (!(error instanceof FalsifiedInvariantError)) {
|
|
286
|
+
radio.emit("logMessage", (0, ansicolor_1.red)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
|
|
287
|
+
`Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
|
|
288
|
+
`${invariantCallerWallet} ` +
|
|
289
|
+
`[FAIL] ` +
|
|
290
|
+
`${targetContractName} ` +
|
|
291
|
+
`${(0, ansicolor_1.underline)(r.selectedInvariant.name)} ` +
|
|
292
|
+
printedInvariantArgs));
|
|
293
|
+
}
|
|
264
294
|
// Re-throw the error for fast-check to catch and process.
|
|
265
295
|
throw error;
|
|
266
296
|
}
|
|
@@ -318,3 +348,8 @@ const filterInvariantFunctions = (allFunctionsMap) => new Map(Array.from(allFunc
|
|
|
318
348
|
contractId,
|
|
319
349
|
functions.filter((f) => f.access === "read_only" && f.name.startsWith("invariant-")),
|
|
320
350
|
]));
|
|
351
|
+
class FalsifiedInvariantError extends Error {
|
|
352
|
+
constructor(message) {
|
|
353
|
+
super(message);
|
|
354
|
+
}
|
|
355
|
+
}
|
package/dist/package.json
CHANGED
package/dist/property.js
CHANGED
|
@@ -147,6 +147,7 @@ const checkProperties = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
147
147
|
const { result: testFunctionCallResult } = simnet.callPublicFn(r.testContractId, r.selectedTestFunction.name, selectedTestFunctionArgs, testCallerAddress);
|
|
148
148
|
const testFunctionCallResultJson = (0, transactions_1.cvToJSON)(testFunctionCallResult);
|
|
149
149
|
const discardedInPlace = (0, exports.isTestDiscardedInPlace)(testFunctionCallResultJson);
|
|
150
|
+
const testFunctionCallClarityResult = (0, transactions_1.cvToString)(testFunctionCallResult);
|
|
150
151
|
if (discardedInPlace) {
|
|
151
152
|
radio.emit("logMessage", `₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
|
|
152
153
|
`Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
|
|
@@ -154,7 +155,8 @@ const checkProperties = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
154
155
|
`${(0, ansicolor_1.yellow)("[WARN]")} ` +
|
|
155
156
|
`${targetContractName} ` +
|
|
156
157
|
`${(0, ansicolor_1.underline)(r.selectedTestFunction.name)} ` +
|
|
157
|
-
(0, ansicolor_1.dim)(printedTestFunctionArgs)
|
|
158
|
+
`${(0, ansicolor_1.dim)(printedTestFunctionArgs)} ` +
|
|
159
|
+
(0, ansicolor_1.yellow)(testFunctionCallClarityResult));
|
|
158
160
|
}
|
|
159
161
|
else if (!discardedInPlace &&
|
|
160
162
|
testFunctionCallResultJson.success &&
|
|
@@ -165,7 +167,8 @@ const checkProperties = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
165
167
|
`${(0, ansicolor_1.green)("[PASS]")} ` +
|
|
166
168
|
`${targetContractName} ` +
|
|
167
169
|
`${(0, ansicolor_1.underline)(r.selectedTestFunction.name)} ` +
|
|
168
|
-
printedTestFunctionArgs
|
|
170
|
+
`${printedTestFunctionArgs} ` +
|
|
171
|
+
(0, ansicolor_1.green)(testFunctionCallClarityResult));
|
|
169
172
|
if (r.canMineBlocks) {
|
|
170
173
|
simnet.mineEmptyBurnBlocks(r.burnBlocks);
|
|
171
174
|
}
|
|
@@ -174,8 +177,7 @@ const checkProperties = (simnet, targetContractName, rendezvousList, rendezvousA
|
|
|
174
177
|
// The function call did not result in (ok true) or (ok false).
|
|
175
178
|
// Either the test failed or the test function returned an
|
|
176
179
|
// unexpected value i.e. `(ok 1)`.
|
|
177
|
-
|
|
178
|
-
throw new PropertyTestError(`Test failed for ${targetContractName} contract: "${r.selectedTestFunction.name}" returned ${displayedError}`, displayedError);
|
|
180
|
+
throw new PropertyTestError(`Test failed for ${targetContractName} contract: "${r.selectedTestFunction.name}" returned ${testFunctionCallClarityResult}`, testFunctionCallClarityResult);
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
catch (error) {
|