What if simply being connected to a LAN or even the Internet gave you access to any application ever run on any other computer? What if your computer could automatically retrieve and launch those applications, no matter how complex, using a simple hashed-based identifier? What if the right software just arrived at the right time?
Answering these questions is part of our goal with Skynet1 and Spin, the distributed programming language on which Skynet is built. When a user needs a new Spin application, Skynet seamlessly retrieves it from a peer on the local network or the Internet.
To make this possible, applications written in Spin are structured a little differently.
Hash everything
To start with, every part of a Spin application is identified by its SHA-1 digest. We refer to these identifiers as uuids.2 These uuids let Skynet locate and download parts of applications over our peer-to-peer network and trust the results without needing to trust other peers.
Portrait of a fluid application
A Spin application is broken into several chunks. The most important of these is the application’s descriptor. This descriptor is, in some sense, the head of the application. In order to spawn an application, the spawning process must have a copy of the application’s descriptor.
However, the descriptor doesn’t contain any code. Instead, it contains information such as the name and version. It can even include a description or icon. Most importantly, it contains a list of required dependencies specified by uuid.
An application will not start unless all of its dependencies are available. These dependencies may be any kind of resource. One of them will be its own code segment.
The uuid of the descriptor itself uniquely identifies the entire application.
Save space, save bandwidth
Like dynamically linked native code, our dependency system saves space by storing each library or resource at most once, no matter how many applications depend on it. Just as importantly, each dependency will only ever be downloaded once.
Dependable dependency resolution
Like a statically linked executable, a Spin application will always use the exact dependencies it was compiled against. A library cannot be updated out from under an application and introduce unexpected behavior (or new bugs). If an application depends on a buggy library, it must be re-released in order to take advantage of a patched version.
Using exact dependencies was a difficult decision. Tight and loose coupling both have advantages. In general, modern operating systems encourage dynamic linking. This can help them conserve space and RAM while making system updates easier for conventional software.
Our hash-based distribution model already provided those benefits. In the end, we chose exact dependencies because it made our software easier to reason about and seemed to produce more reliable applications.3
Hello world as a fluid application
The simplest Spin application is a folder containing two .spin source files.
hello-world/
main.spin
metadata.spin
First metadata.spin is compiled and then run, returning a partial application descriptor. Then, all spin files except metadata.spin are compiled and included in the code segment.
Creating the descriptor
Here’s a simple metadata.spin file:
'{ type: 'application }
As you can see, you don’t have to specify much.4 The compiler automatically adds other basic fields. It infers the application name from the directory and calculates the dependency uuids during compilation. The dependencies are stored under the “required-uuids” key and the “data-uuid” key specifies which of them is the code segment.
All applications have a spawn entry point that defaults to “main.” That is, when spawned, execution begins at the top of the main.spin file.
Log.as('green, "Hello distributed world.")
And that’s the simplest fluid application.5 Like all Spin applications, this version of the “hello-world” application is uniquely identifiable by its uuid.
3bd42a425d8b3d45d569527b88ec87f040db6257
Those 40 characters describe a complete application, waiting to be fetched from the network and launched on any computer running Skynet.
Skynet is peer-to-peer desktop software designed to connect computers directly to each other so that their owners can seamlessly share media with friends and collaborate with colleagues. ↩
This differs from IETF definition. Unlike IETF Version 5 UUIDs, we do not truncate the value to 128 bits. In addition, we will be transitioning to SHA-256 in the future. To distinguish the two definitions, we write ours as “uuid” in all lowercase. ↩
Of course, not all relationships are suitable for exact linking. For example, communication with system services happens over loosely coupled messaging. These relationships must be declared and versioned to allow system upgrades. Applications whose service version requirements cannot be met, cannot be run. ↩
Applications can be spawned, unlike “libraries,” but are always started explicitly, unlike “services.” ↩
Spin does support writing to standard out, but in practice logging is almost always better. Consider that many running Skynet instances have no terminal attached to their standard out, but all support remote log viewing over our peer-to-peer network. ↩