Skip to content

Commit 251c933

Browse files
committed
Fix require statement detection inside loops and add tests for it
1 parent 4b12a4d commit 251c933

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

packages/cashscript/src/debugging.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,12 @@ const debugSingleScenario = (
7575
const lockingScriptDebugResult = fullDebugSteps.slice(findLastIndex(fullDebugSteps, (state) => state.ip === 0));
7676

7777
// The controlStack determines whether the current debug step is in the executed branch
78+
// It also tracks loop / function usage, but for the purpose of determining whether a step was executed,
79+
// we only need to check that there are no 'false' items in the control stack.
7880
// https://libauth.org/types/AuthenticationProgramStateControlStack.html
81+
// https://github.com/bitjson/bch-loops#control-stack
7982
const executedDebugSteps = lockingScriptDebugResult
80-
.filter((debugStep) => debugStep.controlStack.every(item => item === true));
83+
.filter((debugStep) => debugStep.controlStack.every(item => item !== false));
8184

8285
// P2PKH inputs do not have an artifact, so we skip the console.log handling
8386
if (artifact) {

packages/cashscript/test/debugging.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
artifactTestSingleFunction,
1414
artifactTestMultilineRequires,
1515
artifactTestZeroHandling,
16+
artifactTestRequireInsideLoop,
1617
} from './fixture/debugging/debugging_contracts.js';
1718
import { sha256 } from '@cashscript/utils';
1819

@@ -167,6 +168,10 @@ describe('Debugging tests', () => {
167168
const contractTestMultiLineRequiresUtxo = randomUtxo();
168169
provider.addUtxo(contractTestMultiLineRequires.address, contractTestMultiLineRequiresUtxo);
169170

171+
const contractTestRequireInsideLoop = new Contract(artifactTestRequireInsideLoop, [], { provider });
172+
const contractTestRequireInsideLoopUtxo = randomUtxo();
173+
provider.addUtxo(contractTestRequireInsideLoop.address, contractTestRequireInsideLoopUtxo);
174+
170175
// test_require
171176
it('should fail with error message when require statement fails in a multi-function contract', async () => {
172177
const transaction = new TransactionBuilder({ provider })
@@ -450,6 +455,17 @@ describe('Debugging tests', () => {
450455
])
451456
);`);
452457
});
458+
459+
it('should fail a require statement inside a loop', async () => {
460+
const transaction = new TransactionBuilder({ provider })
461+
.addInput(contractTestRequireInsideLoopUtxo, contractTestRequireInsideLoop.unlock.test_require_inside_loop())
462+
.addOutput({ to: contractTestRequireInsideLoop.address, amount: 10000n });
463+
464+
expect(transaction).toFailRequireWith('Test.cash:7 Require statement failed at input 0 in contract Test.cash at line 7 with the following message: i should be less than 6.');
465+
expect(transaction).toFailRequireWith('Failing statement: require(i < 6, \'i should be less than 6\')');
466+
});
467+
468+
it.todo('should fail correct require statement inside nested loops');
453469
});
454470

455471
describe('Non-require error messages', () => {

packages/cashscript/test/fixture/debugging/debugging_contracts.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ contract Test() {
9494
}
9595
`;
9696

97+
const CONTRACT_TEST_REQUIRE_INSIDE_LOOP = `
98+
contract Test() {
99+
function test_require_inside_loop() {
100+
int i = 0;
101+
do {
102+
i = i + 1;
103+
require(i < 6, 'i should be less than 6');
104+
} while (i < 10);
105+
}
106+
}
107+
`;
108+
97109
const CONTRACT_TEST_REQUIRE_SINGLE_FUNCTION = `
98110
contract Test() {
99111
function test_require_single_function() {
@@ -321,3 +333,4 @@ export const artifactTestLogs = compileString(CONTRACT_TEST_LOGS);
321333
export const artifactTestConsecutiveLogs = compileString(CONTRACT_TEST_CONSECUTIVE_LOGS);
322334
export const artifactTestMultipleLogs = compileString(CONTRACT_TEST_MULTIPLE_LOGS);
323335
export const artifactTestMultipleConstructorParameters = compileString(CONTRACT_TEST_MULTIPLE_CONSTRUCTOR_PARAMETERS);
336+
export const artifactTestRequireInsideLoop = compileString(CONTRACT_TEST_REQUIRE_INSIDE_LOOP);

0 commit comments

Comments
 (0)