Usually, every day I practice programming using TDD (Test-Driven Development) workflow: few minutes adding a minimal feature to one of my personal projects. One of them is writing a blockchain in Java. Based on ideas from Ethereum blockchain, it has a virtual machine to execute smart contracts. Today, I implemented subroutines in that virtual, adding three opcodes and their behavior, according Ethereum Improving Proposal 2315.
The relevant commits:
- Execute simple subroutine in VirtualMachine
- Error on walk into a subroutine
- JUMPDEST gas cost; execute subroutine at end of code
- Error on shallow return stack
- Invalid jumps to subroutines
You can see the incremental coding, adding new expected behavior, writing test in red, then adding code to make the tests pass.
The main additions were:
- Add a return stack to virtual machine implementation, that it is not exposed and don’t have any influence in consensus.
- Add three opcodes: JUMPSUB to jump to a subroutine altering the program counter and saving the return address into the return stack; BEGINSUB to mark the beginning of a subroutine (a never executed opcode); RETURNSUB retrieving the return program counter from return stack
- Add gas costs to those new opcodes
- Check the expected behavior in normal use and then, also in edge cases
It was easy to add this feature: using TDD, the initial code is simple and it can be tested by code without much effort (previous virtual machine tests were available to serve as a basis for the new tests); and writing explicitly each expected behavior tests facilitated the write of the corresponding production code.
Pending work: add some additional tests about executing nested subroutines, and minor refactors.
Angel “Java” Lopez