Luxor Technology

Nick Hansen
2 min readOct 5, 2017

--

To make Luxor work, we had to make a key decision: Do we build everything into siad or should the Stratum server be separate?

We decided that building out the required Stratum RPCs (namely, getblocktemplate) provided a more “industry standard” solution, so that’s what we did.

We are committed to publishing the changes we made to siad. Once the service is fully launched and operational, the code will be made available for public scrutiny. Hopefully, we can help others along the way and continue to strengthen the Sia ecosystem.

Stratum

I love Golang, so we implemented the Stratum from the ground up in Golang with a React front end served by Node, courtesy of @eddiepluswang.

All of the miner statistics are housed in a persistent Redis store, which is housed in a managed VPS. We use Redis PubSub to handle miner affinity changes as well as payout updates. User balances, long-term hashrate stats, block stats and payouts are stored in Postgres.

We have an instance of siad running in each region. We decided on this rather than a singular daemon for a few reasons.

  1. ) Redundancy. If anything were to go wrong with the main siad instance, it can take a long time to restart. We were especially concerned about the possibility of a BoltDB corruption and the subsequent re-scan of the chain.
  2. Latency: There would be an increase in longpool latency. Getting consensus updates to the Stratum quickly is vital in keeping stale rate low, and more importantly, preventing rejects. A rejected share is absolutely unacceptable.

Choosing Golang was a fantastic choice. It is very low overhead and has some great mechanisms for building concurrent applications (like a mining pool!). The below image is an instance of the stratum server (sia-stratum)on a 2CPU, 2Gb droplet with ~30 miners operating.

Low Memory and CPU footprint

Payouts

When a miner submits a share, the difficulty of the shares is added to an array stored in Redis. This share is used for calculating payouts, as well as hashrate.

We have a cronjob which runs periodically to check if we have any unpaid blocks, then gathers up all the submitted shares and updates the user balance equally based on share difficulty ratios. These balances are stored in an SSL-enabled DB asynchronously per user.

We have a cronjob which periodically transfers pool funds to an off-site wallet for security. There is another cron which actually does the payouts to users which meet the balance requirement (500SC at time of writing). Once the payouts are made, the user balance is reset to zero and the miner is notified via a Published message to clear it’s unpaid amounts

Questions?

nick@luxor.tech
@NickHansen600

--

--