I saw vault.sol. It’s about protecting ETH against a stolen private key. A vault key and a recover key are involved. When the vault key is stolen, you can reach your recover key and disable the vault key. For this to work, the vault key can only perform delayed withdrawals, allowing you to notice the theft and use the recovery key. When both keys are stolen, you can even destroy the vault so that nobody can withdraw ETH. That’s supposed to discourage thieves (of course, this doesn’t chase thieves away if they purely want to harm you).

The contract can take three different states. Usual state, UnVaulting state where a vault key is trying to make a withdrawal, and Destroyed state where nobody can ever make any move.

I drew a diagram:

States of vault.sol

It took some amount of human creativity to recover this diagram from the Solidity code, and nothing guarantees that the picture is faithful. I just had a warm, fuzzy feeling that I captured the intension of the code. Nothing backs this warm, fuzzy feeling.

Rant against reliance on warm fuzzy feelings and human creativity

If I really want to confirm this warm feeling, I can try to prove that the EVM code generated from that Solidity code matches the picture. The proof would look very similar to FailOnReentrance.thy.

I’ve been trying to do this exactly, but it’s kind of wasteful to ignore a Solidity source code and to compare the compiled EVM code and a state diagram (or whatever specification). The frustrating thing is that I cannot directly compare the Solidity code and the state diagram. There is no way to bring Solidity code into Isabelle or Coq. It has no specification. By the time I could finish specifying the language, say, in five years, the language will have changed so much that the catching up would take another ten years. Nobody has defined C++ in these theorem provers. You can still translate a Solidity program into Why or F*, but that translation has to be tested. Otherwise you are relying on the warm, fuzzy feeling that you know Solidity. I don’t buy my own warm, fuzzy feeling.

It feels wrong that human creativity is needed to recover a state diagram from an Ethereum contract. From the state variables in Solidity, one needs to pick up the most important. One has to figure out which combination of values cannot occur. You can try to develop a nice heuristic that works automatically to draw a state diagram for a Solidity program. Good luck on that. You might not need much luck because AI is making a great advance, but I avoid number-counting AI’s whenever I can. Lispers are welcome.

I’m developing a programming language called Bamboo whose syntax looks like a state diagram. I like it when syntax guarantees correctness (I found my liking when I heard about the natural deduction rules canceling with each other). In case of state transition, the way to go is to make the code look like the state diagram.

Vault in Bamboo

The vault makes a perfect example of a Bamboo program, I thought. Bamboo is designed for this kind of phase-changes. The states correspond to Bamboo contracts because a Bamboo contract can become another Bamboo contract.

In contract Vault {...} you will find become UnVaulting(...) . That corresponds to an arrow in the state diagram. You see no state variables. Instead, there are arguments to contracts.

Compare the code with the state diagram. Find a “contract” for each box and a “then become” for each arrow.

The code is boxes and arrows turned into textual form, and it’s executable.

Refactoring into nested states?

Now I’ve implemented it, I don’t like the repetition in Usual::destroy() and UnVaulting::destroy() . How can I fix it? One way is to extend Bamboo with states and substates. Then the diagram would become

Refactored State diagram. Now destroy() appears only once. Should Bamboo support this or not?

where, instead of two destroy() arrows, you see only one. Two substates Usual and UnVaulting belong to a superstate Alive . Now one arrow originates from the single superstate, replacing two arrows from two states. The code would become a bit shorter:

A refactored code with no duplicated `destroy()` and `recover()`. Do you want this nesting in Bamboo?

It was fun to invent syntax like become Alive(...).UnVaulting(...) , but I think it’s too confusing. The nesting boxes with links going in and out remind me of Robin Milner’s bigraphs. This can go intractable very quickly. One merit of learning computer science is the realization that very simple elements can form a huge, confusing structure. In order to see whatever can happen from a certain state, you will need to scan all parent blocks. That’s bad (wait, I belong to the C++ team, don’t I?).

So I don’t do the nested states, at least for now. Algebraic data types would also solve the duplication, perhaps. Anyway, I don’t extend the language whenever I can afford to. I should write more tests on the vault program first and then prove it correct with eth-isabelle.

Warnings

Warning: now I notice the Bamboo programs and the state diagrams do not match. There are slight differences. I’m glad to see that. The Bamboo syntax certainly made the difference more visible. I’m too lazy to fix the pictures.

Warning: don’t use any code shown here. Let me first test it, prove it, put my own money on it and invite attackers. I did it once, putting some ETH on a proven-correct program, but the program was very simple that time.