Module agora.script.ScopeCondition

Keeps track of scopes and their conditions (TRUE or FALSE). This struct can be used to implement conditional (IF/ELSE/ENDIF) logic.

It does this by pushing a new scope for each visited IF opcode, popping a scope for every visited END_IF opcode, and toggling the scope's condition for every visited ELSE opcode.

Unlike C-like programming languages we do not support GOTO and therefore may only increment the program counter one instruction at a time. This constraint makes this ScopeCondition design possible.

This implementation is largely based on Bitcoin's ConditionStack, as it's the most optimal O(1) solution we could think of using.

For a description on how code flow control works (for a previous version),

see

https://building-on-bitcoin.com/docs/slides/Thomas_Kerin_BoB_2018.pdf

Example

ScopeCondition sc;
assert(sc.empty());
assert(sc.isTrue());

// IF
//     DO <- pc
sc.push(true);
assert(!sc.empty());
assert(sc.isTrue());

// IF
//     DO
// ELSE
//     DO <- pc
sc.tryToggle();
assert(!sc.empty());
assert(!sc.isTrue());

// IF
//     IF
//         DO <- pc
//     ENDIF
//     DO
// ENDIF
sc = ScopeCondition.init;
sc.push(true);
sc.push(true);
assert(!sc.empty());
assert(sc.isTrue());

// IF
//     IF
//         DO
//     ENDIF
//     DO  <- pc
// ENDIF
sc.pop();
assert(!sc.empty());
assert(sc.isTrue());

// IF
//     IF
//         DO
//     ENDIF
//     DO
// ENDIF  <- pc
sc.pop();
assert(sc.empty());
assert(sc.isTrue());

// OP_TRUE
// IF -> true
//     DO -> executed
//     OP_0
//     IF
//         DO -> skipped
//         OP_TRUE <- false as previous scope was false
//         IF
//             DO -> skipped
//             OP_TRUE <- false, ditto
//             IF
//                 DO -> skipped
//                 OP_TRUE <- false, ditto
//                 IF
//                      DO -> skipped
//                 ENDIF
//                 DO -> skipped
//             ENDIF
//             DO -> skipped
//         ENDIF
//         DO -> skipped
//     ENDIF
//     DO -> executed (no false scopes left)
// ENDIF
sc = ScopeCondition.init;
sc.push(true);
sc.push(false);
sc.push(true);
sc.push(true);
sc.push(false);
assert(!sc.empty());
assert(!sc.isTrue());
sc.pop();
assert(!sc.empty());
assert(!sc.isTrue());
sc.pop();
assert(!sc.empty());
assert(!sc.isTrue());
sc.pop();
assert(!sc.empty());
assert(!sc.isTrue());
sc.pop();
assert(sc.isTrue());
sc.pop();
assert(sc.empty());
assert(sc.isTrue());

Structs

NameDescription
ScopeCondition