Let’s demonstrate this difficulty with a simple example. This is our “Sharing Box.” You can insert anything you want others to use, then set a price and let somebody rent it. But how do you ensure that only users who have paid are able to open it?

Most developers would probably set up a server somewhere in the cloud and run a database to store info regarding who has paid and when. Our small box would then need a good Wi-Fi connection to access this server. Simple, right? However, there are major issues with this centralized solution:

There is a single point of failure: If your server is offline for whatever reason, all sharing boxes stop working. Any hacker could simply attack this server and gain access to all sharing boxes. This would be a nightmare! And please don’t say that your server is safe or that this would never happen; it happens all the time. And if it is not an attacker, your admin may simply be having a bad day.

Scary, isn’t it? So let’s decentralize our Sharing Box! This is where blockchain comes in. Here we have thousands of nodes, and as long as a single node runs, the blockchain works. The more nodes are running, the harder it is for an attacker to overtake the network.

Connecting Devices to the Blockchain

While the blockchain solves a lot of security issues (and it makes payments much easier!), the question remains: How do we connect our small box to the blockchain?

To connect, we usually become a peer and start synchronizing and verifying all the network’s transactions. For a full node on Ethereum, this means we would need about 140 GB of storage and have to constantly synchronize and verify blocks and transactions to be sure we had the correct data. This is way too much for our small box.

To address this issue, smart people optimized storage with the pruned node, which simply tosses older states and reduces the node to only 90 GB. Way better but still too much.

Once the first light client was released, everyone hoped it would finally solve the storage problem. A light client only stores the data it needs, but this comes with a price: It relies on full nodes. However, it’s still able to verify because it constantly syncs with other peers. The light client takes us down to a few hundred MB, which is good, but that still doesn’t fit on a microcontroller. Even syncing requires a constant bandwidth, and if you’re offline for a few days, it takes several minutes to catch up. Bandwidth is very expensive for mobile devices!

That’s why some developers started to use a so-called remote client: a central full node on a server (or even a centralized RPC service like Infura). But this is a bad idea since it means we might as well use the unsecure, centralized server option we mentioned earlier.

Using Incubed

You see, establishing a secure connection to the blockchain on a small loT device isn’t easy, but that’s why we built Incubed, a stateless client that can run with zero storage (except for the code and optional cache). Incubed operates without a single point of failure and is able to verify all data. Just like a light client uses full nodes to fetch data to verify, Incubed relies on a set of distributed full nodes. Anybody can run and register such a node in the registry contract. But other than the light client, we don’t constantly sync within the peer-to-peer network; we only send requests as needed. This is important since it means

We get immediate responses (no need to catch up); and No constant bandwidth reading the blockheaders.

This is crucial not only for IoT devices but also apps and websites connecting securely to the blockchain. However, if anyone can run such a node, we must be able to prove and verify the data. (When we talk about data, we mean all standard JSON-RPC calls, including eth_call.)

Let’s see how this works by looking at our Sharing Box:

Anybody can use the app and pay to open the box. This is done by sending a transaction to a smart contract, which stores the paid amount and checks all requirements (like KYC and conflicting bookings). If all is good, the transaction is confirmed by creating an event with the public address of the user (the one with permission to open the box) and the time range the user paid for. You can even call this contract a digital twin of the Sharing Box since it defines the rules and behavior of the device. If this transaction is successfully executed, the app only needs to store the transaction hash (which is used as an identifier). Now, if the user wants to open the box, the app connects to it using Bluetooth and sends a message, which contains:

- a signature created with the user’s private key, which verifies that the data wasn’t manipulated and that the message was authorized by the user;

- a timestamp to ensure that nobody can replay it; and

- the transaction hash of the previously sent transaction, which tells the box where the payment occurred. Our box receives this data and needs to verify that the user who signed the message has permission to do so. This means we need proof that this transaction — and, as a result, the event — really happened on the blockchain. This verification is done by Incubed.

The Incubed client picks a random public node from a registry contract and requests the proof for the transaction receipt (the result of an Ethereum transaction confirming the paid booking). Since the Sharing Box has no internet connection we let the phone collect the data.

(If you want to know more about how proofs work, watch this video ). Once the box has received the response, Incubed verifies the Merkle proof and the blockheader of the transaction receipt. The receipt must contain an event that tells us that who is allowed access and when. If the signer of this signature is the one, we can accept it and open the door!

Verifying the Blockheader

Incubed is able to verify transactions and even functions calls of smart contracts by using Merkle proofs against a blockheader, but how can we be sure this blockheader is correct? This depends on the consensus mechanism the blockchain uses.

For proof of authority, there is a list of keys allowed to sign the blockheader. To verify the blockheader, we simply check if the signature was created from a key on the list. Since the signature is part of the blockheader, this is all we need. (and the correct set of validators)

For proof of work (like the public Ethereum chain), anybody can create blocks as long as he or she is able to put enough work into it. But to know whether a block is accepted, we ask the registered Incubed nodes to pay a deposit and sign blockhashes (just the hash of the blockheader). If the nodes were to sign a wrong hash, they would lose their deposit because this signed blockhash can be verified by anyone inside a smart contract. All you need is an independent node checking if the signature is correct before our small box receives it. Since anybody is incentivized to find a wrong blockhash and can receive the deposit of the signer, the same node that gave us the proof can check the signature, which reduces the number of requests. Because the client chooses which signature to accept, the server cannot cheat and sign with a different key.

Putting it on a microcontroller

This verification allows us to put everything on a small chip like nRF52840, which only has 256 KB of RAM and 1 MB of flash memory. One of these costs about $3 and enables a completely decentralized, stateless, and verified connection to the blockchain.

Just imagine what else we can build with Incubed!

Simon Jentzsch (CTO, Slock.it)