> not Turing-complete programs with race conditions.
I know it's common, but please stop calling reentrancy bugs "race conditions". Smart contracts don't observe concurrent modification of state by other contracts and aren't internally concurrent. Solidity and the EVM object model have way too much implicit behavior, which can lead to unexpected control flows, but these unexpected flows aren't the result of other threads coming in and mucking up state.
Calling a simple reentrancy bug or spookily unexpected control flow a race condition lets the Solidity and EVM designers off too easily. Concurrency with shared mutable state is always difficult, but Solidity makes even simple single-threaded reentrancy difficult to get right. (On a side note, I'm a big fan of Actors/shared-nothing concurrency and think raw threads are almost always the wrong abstraction to expose to application-level developers.)
I also totally agree that Turing completeness is overkill for 99% of use cases, leading to bugs in simple contracts and makes analysis very difficult. If you really need Turing completeness, you could still explicitly construct it within a sufficiently expressive declarative non-Turing complete execution model via externally triggering repeated contract invocation. (For instance, a Brainfuck interpreter that advances one program step per contract execution.) The ecosystem would be Turing complete without contracts being Turing complete.
I know it's common, but please stop calling reentrancy bugs "race conditions". Smart contracts don't observe concurrent modification of state by other contracts and aren't internally concurrent. Solidity and the EVM object model have way too much implicit behavior, which can lead to unexpected control flows, but these unexpected flows aren't the result of other threads coming in and mucking up state.
Calling a simple reentrancy bug or spookily unexpected control flow a race condition lets the Solidity and EVM designers off too easily. Concurrency with shared mutable state is always difficult, but Solidity makes even simple single-threaded reentrancy difficult to get right. (On a side note, I'm a big fan of Actors/shared-nothing concurrency and think raw threads are almost always the wrong abstraction to expose to application-level developers.)
I also totally agree that Turing completeness is overkill for 99% of use cases, leading to bugs in simple contracts and makes analysis very difficult. If you really need Turing completeness, you could still explicitly construct it within a sufficiently expressive declarative non-Turing complete execution model via externally triggering repeated contract invocation. (For instance, a Brainfuck interpreter that advances one program step per contract execution.) The ecosystem would be Turing complete without contracts being Turing complete.