The idea for blockclock.live came up when one of our friends received their BlockClock and started tinkering with the API. We realized that we could send messages to the BlockClock and figured it would be fun to build a pay-per-message service using Lightning Network payments.
We bought the domain on Wednesday and built a prototype in a few hours, which was enough to convince the owner to let us use it for the project. The site went live on Thursday afternoon and immediately started receiving messages!
How it works!
This application consist of a few parts:
The general architecture is that the website maintains a database of all messages, interfaces with the Lightning Network via LND, and keeps the state of the current message to display.
The BlockClock, web cam, and Raspi running the daemon are in our office. The daemon interfaces with the website to update the BlockClock's message.
We had a spare cell phone in the office. The Twitch app allows streaming via mobile device, so we pointed the camera at the BlockClock and the streaming part was ready!
The BlockClock is a very cool device. It allows customization of the display via its GUI interface and it has an API that allows you to set internal variables via HTTP. We used this feature to send three variables (one for each line of text) to our BlockClock and configured one of the displays to show those variables. Pretty simple!
The BlockClock internal software allows you to configure up to four screens and rotate between them. We have some other ideas to rotate between other data sets, such as market data from Blocktap.io, but we'll leave that for a future exercise.
With the ability to customize the display of the BlockClock ready to go, we just needed a way to send data to it.
Directly pushing updates to our BlockClock from the website didn't seem like the best idea. Instead we use a script that interfaces between the website and the BlockClock. It connects to https://www.blockclock.live/api/message and calls the BlockClock API when there are changes.
You can check out the Node.js script here. It does not require any dependencies (although the core libs leave something to be desired). This script targets Node.js 10.
The website source code is also available on Github inside the altangent/blockclock repository. Feel free to make improvements to it!
The site started from the altangent/node-react-app template that we use as a base for some of our projects. It provides a quick starting point using the tools we prefer when building web applications:
- Node.js server as the backend
- React app with react-router
- SASS customization of Bootstrap
- Browserify for bundling (we avoid webpack because its an abomination of complexity)
- Watch scripts for restarting the service, rebuilding the React app, and reprocessing the SASS stylesheets
To connect to LND we are using lnd-async, a tool we wrote to wrap the gRPC connection and convert the return to Promises instead of callbacks. We're also using RocksDB to persist state of the application.
For those curious how the we go from a website request to updating the BlockClock, this section is for you.
When a user wants to change the message on the BlockClock, they type a message in the UI and click the button to create an invoice. The UI sends a
POST request to
/api/invoice with the 3 lines of text they want to display. This API will connect to LND and generate an invoice for a 1000 satoshi payment. We store this request in RocksDB for easy lookup at settlement.
We probably could have been a bit more clever with using LND as the datastore until settlement occurs, but using RocksDB gives us some flexibility if we need to switch LND nodes or run multiple LND nodes. It also keeps all of the blockclock.live requests in a single place that we can easily query.
Once the invoice is returned to the user, it's up to them to pay to complete the rest of the process.
When the website first starts, it connects to LND and opens a socket for listening to invoice changes via the SubscribeInvoices API.
When an invoice is settled, the subscription triggers logic to check the state of the invoice in the database. If things are ok, we update the website state with the new message and mark the invoice as completed in the database.
The message is then available via
GET request of
/api/message on blockclock.live. This API simply returns the current message that should be displayed on the BlockClock.
The daemon will pick up this change in value and update the BlockClock!
We've had a few problems so far. We apologize if you sent a message and it didn't display. Here are a few of the issues we experienced in no particular order:
They always say you should build for mobile first. We didn't. After the initial release the first thing we did was refactor and make the site responsive and mobile friendly.
Pretty simple one, the first night was a tad dark until we were able to get a lamp on the BlockClock. Then our lamp burned out so we used a monitor with a blank white screen for light until we got a new bulb.
Just in case you were wondering, the Twitch app stops streaming when a phone call comes in. So our non-webcam based setup worked until phone calls ruined the party.
Disabling cellular and turning on Do not disturb fixed that. We found another USB web cam that we're going to update to once we move to a more permanent location.
Multiple network interruptions hung both the daemon and the BlockClock itself at times. Once we restarted the script and made sure it would time out properly things were resolved. We've had a few other network errors that we resolved by resetting the BlockClock. We suspect these are related to unreliable WiFi connectivity at our office.
Building blockclock.live was a really fun exercise that allowed us to utilize our open-source Lightning Network software tools and directly engage with Bitcoin users all over the world. We had some good laughs at all the silly messages and were inspired by the response of the community. We're always looking for contributors for our open-source projects to help our industry grow.