Friday, August 14, 2015

Building an ethereum ÐApp, part IV: The Frontier

What is ethereum and ÐApps? Check here  or search
This is part IV of a series. Part I

Welcome to explore what's behind the Frontier!

The first real release of Ethereum is out and it mostly works! First, let's get out some updates to previous blog posts.

Some updates

  • You can now open the JavaScript console using geth attach which will connect to geth you've already started on your machine. But on Windows, this is still not working very well. A fix is underway. See more here.
  • You may want to use the eth.contract interface to create and manipulate your contract
  • Of course it's always a good idea to keep in sync with the JavaScript API reference!
  • eth.sendTransaction() now returns the tx hash. To get the contract address if you've sent some code, use eth.getTransactionReceipt(tx hash).contractAddress

An update on running a private chain

This is the commandline I use for development:

geth.exe --rpc --rpccorsdomain="*" --datadir geth_private --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --nodiscover --networkid 7938 --genesis private_genesis.json --solc "your/path/to/solc.exe" --unlock 0

and my genesis file is in . Actually all you need for a private dev chain is there.

Note that:
  • the difficulty is set to 4 so that you can create blocks immediately and even the DAG is tiny
  • the command above enables ALL management APIs to the RPC which would be a totally unsafe thing to do on the livenet.
  • change your path to solc.exe (can be downloaded with the cpp-ethereum or eth++ package)
  • for fake test ether, you can either just mine or edit the genesis file to assign some balance to one account. You just need to have a private and public key for that account in advance. You can create them on the live net first.

Back to coding

I've come to the stage where I need to implement payouts in my Roboth.web3 dapp based on which user has the most upvotes. In a few words, this app lets user post a problem (a job) and ask the crowd to provide solutions. Users up/down vote solutions and after a fixed amount of time, the highest rated solution gets selected and paid the amount initially offered with the problem. There are a number of problems with that, two of them I'm going to discuss.

Timed automatic payouts

Payout to the highest rated user should occur at a certain time, ideally automatically. Ethereum by itself doesn't support auto-triggering function calls. In this case, the solution is simple: let the supposed receiver of the payout ask for it themselves. After the contract verifies he is indeed the correct receiver, it can send out the payment.
To make it even better, our centralized server or the JS application can handle this automatically so that the human does not need to think about it and can instead focus on whatever thing humans like to do. The JS side of the dapp can query our contract if user is eligible for a payout using a const function in the contract - one that only reads data and is free to execute.
I haven't implemented this in my dapp yet, wait for next blog post to see how it turns out.

Finding highest rated solution

Each solution can be up or down voted by any user, much like this happens on StackExchange. That means the top position can change dynamically. When payout time comes, we need to find the top player for that particular job. Depending on what data structure is used, this can be time consuming and time equals gas equals money. If you have all solutions in one list, finding the max is just a linear operation and could be fine if you don't expect too many of them. In my case, solutions for a single job are not located together so to find it, I would have to iterate over all solutions for all jobs which would be very costly. 
The top rated solution can be cached so that it can be retrieved immediately. Since the top solution can come to the top and leave it again when downvoted, we need to use a heap data structure to perform such changes efficiently. A heap can be implemented using a simple array so the lack of pointers in Solidity should not be an issue.
Another factor to weigh is the gas price of storage. Having too many repeated storage slots can be costly. Writing new item to storage is priced at 20k gas, reading is at 5k and deleting that item (by setting it to 0) actually refunds 10k.
Again, implementation is pending so check out my next blog post :)