@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 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.invalidRemoteDataErrorMessage = exports.noRemoteData = void 0;
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.invalidRemoteDataErrorMessage = `Remote data settings not properly setup in Clarinet.toml! To use remote data, please provide the "api_url", "initial_height", and "enabled" fields under the "repl.remote_data" section in the Clarinet.toml file.`;
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
- if (remoteDataUserSettings !== undefined &&
63
- (!(remoteDataUserSettings === null || remoteDataUserSettings === void 0 ? void 0 : remoteDataUserSettings["api_url"]) ||
64
- !(remoteDataUserSettings === null || remoteDataUserSettings === void 0 ? void 0 : remoteDataUserSettings["enabled"]) ||
65
- !(remoteDataUserSettings === null || remoteDataUserSettings === void 0 ? void 0 : remoteDataUserSettings["initial_height"]))) {
66
- throw new Error(exports.invalidRemoteDataErrorMessage);
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
- return remoteDataUserSettings || exports.noRemoteData;
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 ignored, there's
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
- if (!invariantCallResultJson.value) {
250
- throw new Error(`Invariant failed for ${targetContractName} contract: "${r.selectedInvariant.name}" returned ${invariantCallResultJson.value}`);
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
- // Handle both negative results from the invariant function and
255
- // general runtime failures. Focus is on capturing the invariant
256
- // function's result, including any runtime errors it caused.
257
- radio.emit("logMessage", (0, ansicolor_1.red)(`₿ ${simnet.burnBlockHeight.toString().padStart(8)} ` +
258
- `Ӿ ${simnet.blockHeight.toString().padStart(8)} ` +
259
- `${invariantCallerWallet} ` +
260
- `[FAIL] ` +
261
- `${targetContractName} ` +
262
- `${(0, ansicolor_1.underline)(r.selectedInvariant.name)} ` +
263
- printedInvariantArgs));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stacks/rendezvous",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Meet your contract's vulnerabilities head-on.",
5
5
  "main": "app.js",
6
6
  "bin": {
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
- const displayedError = (0, transactions_1.cvToString)(testFunctionCallResult);
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stacks/rendezvous",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Meet your contract's vulnerabilities head-on.",
5
5
  "main": "app.js",
6
6
  "bin": {