spartan-farmer

A proof-of-concept farmer for the Subspace Network Blockchain
## Overview **Notes:** The code is un-audited and not production ready, use it at your own risk. This repo is an implementation of a Farmer, designed to work with a seperate Client that implements [Spartan Proof-of-Capacity (PoC) consensus](https://github.com/subspace/substrate/blob/w3f-spartan-ms-1/frame/spartan/design.md). PoC is a generic term for consensus based on disk space, including proofs of space, storage, space-time, and replication. A farmer is similar to a miner in a proof-of-work blockchain, but instead of wasting CPU cycles, it wastes disk space. Much of this code is based on our earlier implementation, [subspace-core-rust](https://www.github.com/subspace/subspace-core-rust). This work is supported by a [Web 3 Foundation grant](https://github.com/w3f/Open-Grants-Program/blob/master/applications/spartan_poc_consensus_module.md) to develop PoC consensus for the Substrate framework. It is specifically designed to work with [spartan-client](https://github.com/subspace/substrate/tree/w3f-spartan-ms-1/bin/node-template-spartan), a substrate client based on the substrate-node-template. Spartan is a stepping stone towards the larger goal of deploying [Subspace](https://www.subspace.network/) as a parachain on the Polkadot Network. Subspace is a proof-of-storage blockchain that resolves the farmer's dilemma, to learn more read our white paper. ## Some Notes on Plotting ### Time to Plot Plotting time is roughly linear with respect to number of cores and clock speed of the host system. On average, it takes ~ 1 minute to create a 1GB plot or 18 hours to to create a 1TB plot, though these numbers will depend on the system used. This is largely independent of the storage media used (i.e. HDD, SATA SSD, NVME SSD) as it is largely a CPU-bound task. ### Disk Wear and Tear Some PoC protocols require several passes over the disk in order to plot. For example, a 100GB plot might actually consume several TB of writes and reduce the expected lifetime of the disk. This is not the case with Spartan. The plot is created in a single pass on startup. ### Storage Overhead In addition the plot, a small Binary Search Tree (BST) is also stored on disk using RocksDB. This adds roughly 1% storage overhead. So creating a 1GB plot will actually consume about 1.01 GB of storage. ## Run with Docker The simplest way to use spartan-farmer is to use container image: ```bash docker volume create spartan-farmer docker run --rm -it --mount source=spartan-farmer,target=/var/spartan subspacelabs/spartan-farmer --help ``` `spartan-farmer` is the volume where plot and identity will be stored, it only needs to be created once. ## Install and Run Manually Instead of Docker you can also install spartan-farmer natively by compiling it using cargo. **Notes:** This will currently only work on Mac and Linux, not Windows. If you have not previously installed the `gmp_mpfr_sys` crate, follow these [instructions](https://docs.rs/gmp-mpfr-sys/1.3.0/gmp_mpfr_sys/index.html#building-on-gnulinux). RocksDB on Linux needs LLVM/Clang: ```bash sudo apt-get install llvm clang ``` Then install the framer using Cargo: ``` cargo +nightly install spartan-farmer ``` NOTE: Above command requires nightly compiler for now, make sure to install it if you don't have one yet: ``` rustup toolchain install nightly ``` ## Usage Commands here assume you installed native binary, but you can also easily adapt them to using with Docker. Use `--help` to find out all available commands and their options: ``` spartan-farmer --help ``` ### Create a New Plot ``` spartan-farmer plot ``` This will create a 1 GB plot: ``` spartan-farmer plot 256000 test ``` For all supported options check help: ``` spartan-farmer plot --help ``` By default, plots are written to the OS-specific users local data directory. ``` Linux $XDG_DATA_HOME or /home/alice/.local/share $HOME/.local/share macOS $HOME/Library/Application Support /Users/Alice/Library/Application Support Windows {FOLDERID_LocalAppData} C:\Users\Alice\AppData\Local ``` ### Start the farmer ``` RUST_LOG=debug spartan-farmer farm ``` This will connect to local node and will try to solve on every slot notification. *NOTE: You need to have a spartan-client node running before starting farmer, otherwise it will not be able to start* ## Design The farmer has two modes: plotting and farming. ### Plotting 1. A genesis piece is created from a short seed. 2. A new Schnorr key pair is generated, and the farmer ID is derived from the public key. 3. New encodings are created by applying the time-asymmetric SLOTH permutation as `encode(genesis_piece, farmer_id, plot_index)` 4. Each encoding is written directly to disk. 5. A commitment, or tag, to each encoding is created as `hmac(encoding, salt)` and stored within a binary search tree (BST). This process currently takes ~ 36 hours per TiB on a quad-core machine, but for 1 GiB plotting should take between a few seconds and a few minutes. ### Solving Once plotting is complete the farmer may join the network and participate in consensus. 1. Connect to a client and subscribe to `slot_notifications` via JSON-RPC. 2. Given a global challenge as `hash(epoch_randomness || slot_index)` and `SOLUTION_RANGE`. 3. Derive local challenge as `hash(global_challenge || farmer_id)`. 4. Query the BST for the nearest tag to the local challenge. 5. If it within `SOLUTION_RANGE` return a `SOLUTION` else return `None`