Building a Lottery, Part 3

Or: How not to deploy a contract

So here we have the penultimate piece on building a simple lottery. The contracts are written, the tests are done… All that remains is to deploy it and let the world have at it.

Right?

The world needs better tools

I mentioned earlier that I was using the framework embark, which actually comes with a deployment pipeline for deploying your contracts to any number of environments, including the main Ethereum network.

You might also recall, in my previous episode, I mentioned needing to make some tweaks to embark, to better support complex deployment needs. Turns out I hadn’t figured out how to make this work for deploying outside of the test environment.

Finally, you might recall from the first part that I mentioned I was using Remix as my compilation environment. This was due to embark not providing good feedback when compilation of contracts would fail. When I would make a change and go to test, my only feedback that compilation had failed was that the global object named after the contract simply would not exist. This led to a process of copying the contracts verbatim into Remix, fixing errors there, and then copying them back into my editor.

The conflux of these circumstances led to a less than ideal solution: Pasting the bytecode of the compiled contracts into a simple deploy script, using that to generate the proper deployment code, and then deploying the contracts via Ethereum Wallet.

Of scripts and hacks

You might notice from the deploy script that three contracts required deployment, in a specific order, along with a few handings-off of control between them. The gist of the deployment went:

Deploy the LotteryRoundFactory

Grab the address of the deployed LotteryRoundFactory and the address of the deployer

Deploy the LotteryGameLogic, providing the address of the factory and the address of the deployer

Grab the address of the LotteryGameLogic contract

Call LotteryRoundFactory.transferOwnership, passing in the address of the LotteryGameLogic contract

Deploy the Lotto contract, giving it the address of the LotteryGameLogic contract

Grab the address of the Lotto contract

Call LotteryGameLogic.transferOwnership, passing in the address of the Lotto contract

Not exactly the most straightforward pipeline, but at it’s core, quite simple, the sort of thing a build pipeline ought to be able to handle. Sadly, it wasn’t clear to me how to configure embark to do so, if it could even get back the deployment issues I was having in test.

Unfortunately, these sort of hacked-together solutions tend to lead to errors.

Third time is the charm

The first time I deployed the Lotto contract, I immediately went to etherscan.io and attempted to verify the code of the contracts. This, too, was not the most straightforward process. I develop contracts one-per-file, but etherscan requires all dependencies to be concatenated.

However, when it came time to verify LotteryRoundFactory, it appeared that etherscan was rejecting the code I was giving it, as the compilation was resulting in a bytecode mismatch.

I spent some time fiddling with it, double-checking all my work, and still getting nowhere, when it finally dawned on me: I had deployed these contracts from the bytecode Remix had provided me — but I was attempting to verify these contracts with code copied from my editor.

Turns out the code in Remix was an older version.

So, I went about redeploying again. This time I ensured that all the code in Remix was up-to-date, and then followed the process again. This time, I was able to successfully verify all of the deployed contracts.

However, I shortly after realized that I didn’t like the RNG. It turns out the accumulated entropy could be predictably advanced by picking ticket numbers by hand. The picks themselves weren’t incorporated into the RNG, meaning you could pick anything and still achieve the same final outcome in the contract’s internal entropy. If you were someone with the right knowledge (aka the curator), you could predict what the next tick of the PRNG would produce, what winning numbers that would result in, and simply pick those numbers.

So I fixed that bug, and redeployed, again.

Where do we go from here?

Now this is an interesting question.

Originally, I had intended this to be a 4- or 5-part series, documenting creating a smart contract, and then creating the corresponding frontend for it, fleshing it out to become a true DApp (Dapp? dApp? None of these look good…)

However, after some long and thoughtful conversations around the nature of RNGs on the blockchain, I’ve decided to not finish the project. The particular approach works, if you trust the curator (either himself, or to not collude with miners). If you don’t, this is not a good lottery, at all.

However, I might still extend this series, by detailing the various vectors a curator could cheat, should they desire to. I’ll also explore some possible solutions, and why they, too, eventually reduce down to the same core problem: someone with more information than the rest of the group can cheat — either by themselves, or with the help of others.

[Edit] See the follow-up here.