How is Chia Coin Disk Plotting Done?

You will be able to learn how to plot the Chia Coin disc in this article.

First of all, to be able to farm (mining) Chia Coin, you need disk, namely hdd and sdd, headlight.

The first thing to do is to download and install the original programs from the Chia site. You need to download the Windows, MacOs or linux based program by clicking this link. (From now on, we will continue with the Windows-based program.)

After downloading and installing the program, it will ask you to create a wallet first. Click on the button that says “Create A New Private Key”.

Then you down i will give a 24 word units as in the picture. You definitely need to save these words somewhere. You can take a screen shot, take a phone or write somewhere.

(If you don’t save these words, you won’t be able to find them again, and you will need them to enter your wallet later.)

Types of Timelords

There are two primary types of Timelords: Regular and Blueboxes.

The first is the core Timelord that takes in Proofs of Space and uses a single fastest core to doing squaring in a class group of unknown order as fast as possible. Beside each running VDF (referred to as a vdf_client in the application and source) is a set of proof generation threads that accumulate the proof that the time calculation’s number of iterations was done correctly.

The second are Bluebox Timelords. Blueboxes are most any machine – especially things like old servers or gaming machines – that scour the historical chain looking for uncompressed proofs of time. So that the chain moves quickly, the regular Timelords use a faster method of generating proofs of time but the proofs are larger and take your Raspberry Pi that you’re trying to sync up a lot more time and effort to validate and sync the blockchain. A Bluebox picks up an uncompressed Proof of Time and recreates it, but this time with the slower and more compact proofs generated at the end. Those are then gossiped around to everyone so they can replace the large and slow to verify Proofs of Time with the compact and much quicker to validate version of exactly the same thing.

The Fastest Timelords

There are three known fastest Timelords seen so far. The fastest known and seen on the testnet blockchain was in approximately September of 2020 where it was generating VDF iterations at about 360,000 iterations per second (or ips.) It disappeared after a few weeks. We speculate that it was an Intel cloud customer playing with pre-release Rocket Lake CPUs that have two channels of AVX-512 IFMA support. The Timelord source code has an implementation of IFMA but it’s not enabled by default as the very few CPUs that do have one channel of IFMA don’t gain much speed from it – primarily because they’re mostly found in power saving laptops. The second “known” fast Timelord is an academic research project. They and we speculate that it may be in the 400k-500k ips range once modified to run our 1024 bit width version. They used the TSMC 28-nm CMOS technology for their prototype. Until Rocket Lake is generally available (which is soon as of this writing in early March) the fastest Timelord is a water cooled Intel Core i9-10900K running un-overclocked with 16 GiB or RAM. Sooner or later we will overclock it… It maintains about 200k-210k ips.

Running a Timelord

First of all, the network only requires one running Timelord to keep moving (liveness.) The way Timelords race is like they are on a series of 100 meter dashes. Each one takes off with the last good Proof of Space and tries to get to the total number of iterations required to complete a given Proof of Space. Better Proofs of Space require less iterations to prove. When the fastest Timelord announces the Proof of Time for this Proof of Space all of the other Timelords stop racing and are magically teleported to the starting line of the next 100 meter dash to start it all over again.

It’s good to have a few Timelords out there. There can be things like routing flaps or the overzealous backhoe that takes large swaths of the internet offline. If the fastest Timelord was just about to win the current dash when its internet blinked off in a fury of construction misadventure, then the second fastest will win that dash and the next dashes – until the fastest returns. One of the key things about Proofs of Time is that given the same Proof of Space, their output and proof are always the same (though the proofs can be larger or smaller and harder or easier to validate – they all end up with the same outcome.)

The Company plans to run a few Timelords around the world – and some backups too – just to make sure that all Farmers and nodes can hear the beat that the Timelords are calling.

Installing a Timelord

Regular Timelords

Due to restrictions on how MSVC handles 128 bit numbers and how Python relies upon MSVC, it is not possible to build and run Timelords of all types on Windows – yet. We have a plan to use GCC and some tools to enable vdf_client on Windows in a way that will be compatible with a Windows install of chia-blockchain. However it’s a bit convoluted to get it working right. On MacOS x86_64 and all Linux distributions, building a Timelord is as easy as running sh in the venv of a git clone style chia-blockchain install. Try ./vdf_bench square_asm 400000 once you’ve built Timelord to give you a sense of your optimal and unloaded ips. Each run of vdf_bench can be surprisingly variable and, in production, the actual ips you will obtain will usually be about 20% lower due to load of creating proofs. The default configuration for Timelords is good enough to just let you start it up. Set your log level to INFO and then grep for “Estimated IPS:” to get a sense of what actual ips your Timelord is achieving. We will shortly modify the Timelord build process to support MacOS ARM64 as well – which is a cakewalk compared to Windows…

Bluebox Timelords

For now, Blueboxes are also restricted to basically anything but Windows. Our plans to port to Windows will make Blueboxes available there as well though. Once you build the Timelord with sh in the venv, you will need to make two changes to ~/.chia/VERSION/config.yaml. In the timelord: section you will want to set sanitizer_mode: to True. Then you need to proceed to the full_node: section and set send_uncompact_interval: to something greater than 0. We recommend 300 seconds there so that your Bluebox has some time to prove through a lot of the un-compacted Proofs of Time before the node drops more into its lap. The default settings may otherwise work but if the total effort is a little too much for whatever machine you are on you can also lower the process_count: from 3 to 2, or even 1, in the timelord_launcher: section. You know it is working if you see VDF Client: Sent proof in your logs at INFO level.

The Future of Timelords

Having an open source ASIC Timelord that everyone can buy inexpensively is the Company’s goal. We had originally expected that we would proceed from general purpose CPUs to FPGAs and then ASICs. It turns out that squaring in class groups of unknown order at 1024 bit widths is both FPGA hard and slightly ASIC hard. It also was a pleasant surprise that Intel’s AVX-512 IFMA was almost perfectly created for this application. As such we will be fostering ASIC efforts over the medium term. We are happy to lose money on an ongoing project to create and enhance an open source PCI card that would be available for say $250 for anyone who wishes to run the fastest Timelords in the world too.

Timelords and Attacks

One of the things that is great about the Chia new consensus is that it makes it almost impossible for a Farmer with a maliciously faster Timelord to selfishly Farm. Due to the way new consensus works, a Farmer with a faster Timelord is basically compelled to prove time for all the farmers winning blocks around him also. Having an “evil” faster Timelord can give a benefit when attempting to 51% attack the network, so it is still important that over time we push the Timelord speeds as close to the maximum speeds of the silicon processes available. We expect to have the time and the resources to do that right and make open source hardware versions widely available.


  • VDF: verifiable delay function, another way to say “proof of time”
  • Timelord launcher: a small program which launches “vdf client” processes over and over, to perform the actual vdf calculations.
  • VDF client: a c++ process which performs a VDF computation and then shuts down
  • Timelord: The timelord is communicates with the node, and is what decides which VDF tasks to assign to which clients. The vdf clients connect through HTTP to the timelord. So you can have the timelord in a separate machine as the timelord launcher

Chialisp Documentation


Chialisp is a powerful and secure LISP-like language for encumbering and releasing funds with smart-contract capabilities. This website is a consolidated place to learn about Chialisp, CLVM and the conditions language.

Here’s a sample:

(mod (password new_puzhash amount)
  (defconstant CREATE_COIN 51)

  (if (= (sha256 password) (q . 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824))
    (list (list CREATE_COIN new_puzhash amount))

Download Chialisp 0.4 in tar.gz format

1 – CLVM Basics

CLVM is the compiled, minimal version of ChiaLisp that is used by the Chia network. The full set of operators is documented here

This guide will cover the basics of the language and act as an introduction to the structure of programs. You should be able to follow along by running a version of clvm_tools.

Cons Boxes

ChiaLisp is built out of cons boxes and atoms. A cons box is defined as a pair of ChiaLisp objects. The items in a cons box can either be an atom or another cons box.

Cons boxes are represented as a parentheses with two elements separated by a .. For example:

(200 . "hello")

("hello" . ("world" . "!!!"))

Are legal cons boxes, but the following is not.

(200 . 300 . 400)

A cons box is strictly only a pair. However, we can chain cons boxes together to construct lists.


Lists are enclosed by parentheses and each entry in the list is single spaced with no period between values. Lists are much more commonly used than cons boxes as they are more versatile.

(200 300 "hello" "world")

You can also nest lists.

("hello" ("nested" "list") ("world"))

Remember a list is a representation of consecutive cons boxes terminated in a null atom (). The following expressions are equal:

(200 . (300 . (400 . ())))

(200 300 400)


Atoms are either literal binary blobs or variables. A program is actually just a list in polish notation.

There is no distinguishing of atom types in ChiaLisp. This means that (100 0x65 0x68656c6c6f) and (0x64 101 'hello') are equivalent lists. Internally however the blobs can be interpreted in a number of different ways depending on the operator. We will cover this in further detail later.


There are no support for floating point numbers in ChiaLisp, only integers. Internally integers are interpreted as 256 bit signed integers.

The math operators are *+, and -.

$ brun '(- (q . 6) (q . 5))' '()'

$ brun '(* (q . 2) (q . 4) (q . 5))' '()'

$ brun '(+ (q . 10) (q . 20) (q . 30) (q . 40))' '()'

You may have noticed that the multiplication example above takes more than two parameters in the list. This is because many operators can take a variable number of parameters. + and * are commutative so the order of parameters does not matter. For non-commutative operations, (- (q 100) (q 30) (q 20) (q 5)) is equivalent to (- (q 100) (+ (q 30) (q 20) (q 5))). Similarly, (/ 120 5 4 2) is equivalent to (/ 120 (* 5 4 2)).

There is also support for negative values.

$ brun '(- (q . 5) (q . 7))' '()'

$ brun '(+ (q . 3) (q . -8))' '()'

To use hexadecimal numbers, simply prefix them with 0x.

$ brun '(+ (q . 0x000a) (q . 0x000b))' '()'

The final mathematical operator is equal which acts similarly to == in other languages.

$ brun '(= (q . 5) (q . 6))' '()'

$ brun '(= (q . 5) (q . 5))' '()'

As you can see above this language interprets some data as boolean values.


In this language an empty list () evaluate to False. Any other value evaluates to True, though internally True is represented with 1.

$ brun '(= (q . 100) (q . 90))'

$ brun '(= (q . 100) (q . 100))'

The exception to this rule is 0 because 0 is exactly the same as ().

$ brun '(= (q . 0) ())' '()'

$ brun '(+ (q 70) ())' '()'

Flow Control

The i operator takes the form (i A B C) and acts as an if-statement that evaluates to B if A is True and C otherwise.

$ brun '(i (q . 0) (q . 70) (q . 80))' '()'

$ brun '(i (q . 1) (q . 70) (q . 80))' '()'

$ brun '(i (q . 12) (q . 70) (q . 80))' '()'

$ brun '(i (q . ()) (q . 70) (q . 80))' '()'

Note that both B and C are evaluated eagerly, just like all subexpressions. To defer evaluation until after the condition, B and C must be quoted (with q), and then evaluated with (a).

$ brun '(a (i (q . 0) (q . (x (q . 1337) )) (q . 1)) ())'

Now seems like a good time to clarify further about lists and programs.

Lists and Programs

A list is any space-separated, ordered group of one or more elements inside brackets. For example: (70 80 90 100)(0xf00dbabe 48 "hello"), and (90) are all valid lists.

Lists can even contain other lists, such as ("list" "list" ("sublist" "sublist" ("sub-sublist")) "list").

Programs are a subset of lists which can be evaluated using CLVM.

In order for a list to be a valid program:

  • 1. The first item in the list must be a valid operator
  • 2. Every item after the first must be a valid program

This is why literal values and non-program lists must be quoted using q . .

Programs can contain non-program lists, but they also must be quoted, for example:

$ brun '(q . (80 90 100))' '()'
(80 90 100)

And now that we know we can have programs inside programs we can create programs such as:

$ brun '(i (= (q . 50) (q . 50)) (+ (q . 40) (q . 30)) (q . 20))' '()'

Programs in ChiaLisp tend to get built in this fashion. Smaller programs are assembled together to create a larger program. It is recommended that you create your programs in an editor with brackets matching!

List Operators

f returns the first element in a passed list.

$ brun '(f (q . (80 90 100)))' '()'

r returns every element in a list except for the first.

$ brun '(r (q . (80 90 100)))' '()'
(90 100)

c prepends an element to a list

$ brun '(c (q . 70) (q . (80 90 100)))' '()'
(70 80 90 100)

And we can use combinations of these to access or replace any element we want from a list:

$ brun '(c (q . 100) (r (q . (60 110 120))))' '()'
(100 110 120)

$ brun '(f (r (r (q . (100 110 120 130 140)))))' '()'

Solutions and Environment Variables

Up until now our programs have not had any input or variables, however ChiaLisp does have support for a kind of variable which is passed in through a solution.

It’s important to remember that the context for ChiaLisp is for use in locking up coins with a puzzle program. This means that we need to be able to pass some information to the puzzle.

A solution is a list of values passed to the puzzle. The solution can be referenced with 1.

$ brun '1' '("this" "is the" "solution")'
("this" "is the" "solution")

$ brun '(f 1)' '(80 90 100 110)'

$ brun '(r 1)' '(80 90 100 110)'
(90 100 110)

And remember lists can be nested too.

$ brun '(f (f (r 1)))' '((70 80) (90 100) (110 120))'

$ run '(f (f (r 1)))' '((70 80) ((91 92 93 94 95) 100) (110 120))'
(91 92 93 94 95)

These environment variables can be used in combination with all other operators.

$ run '(+ (f 1) (q 5))' '(10)'

$ run '(* (f 1) (f 1))' '(10)'

This program checks that the second variable is equal to the square of the first variable.

$ run '(= (f (r 1)) (* (f 1) (f 1)))' '(5 25)'

$ run '(= (f (r 1)) (* (f 1) (f 1)))' '(5 30)'

Accessing Environmental Variables Through Integers

In the above examples we were using run, calling the higher level language, instead of brun for the lower level language. This is because for the sake of minimalism in the lower level CLVM language, we address the solution with evaluated integers.

Calling 1 accesses the root of the tree and returns the entire solution list.

$ brun '1' '("example" "data" "for" "test")'
("example" "data" "for" "test")

After that, you can imagine a binary tree of f and r, where each node is numbered.

$ brun '2' '("example" "data" "for" "test")'

$ brun '3' '("example" "data" "for" "test")'
("data" "for" "test")

And this is designed to work when there are lists inside lists too.

$ brun '4' '(("deeper" "example") "data" "for" "test")'

$ brun '5' '(("deeper" "example") "data" "for" "test")'

$ brun '6' '(("deeper" "example") "data" "for" "test")'

And so on.

End of Part 1

This marks the end of this section of the guide. In this section we have covered many of the basics of using ChiaLisp. It is recommended you play with using the information presented here for a bit before moving on.

2 – Coins, Spends and Wallets

This section of the guide will cover evaluating a program inside a program, how ChiaLisp relates to transactions and coins on the Chia network, and cover some techniques to create smart transactions using ChiaLisp.


A coin’s ID is constructed from 3 pieces of information.

  1. The ID of its parent
  2. The hash of its puzzle (AKA the puzzlehash)
  3. The amount that it is worth

To construct a coin ID simply take the hash of these 3 pieces of information concatenated in order.

coinID == sha256(parent_ID + puzzlehash + amount)

This means that a coin’s puzzle and amount are intrinsic parts of it. You cannot change a coin’s puzzle or amount, you can only spend a coin.

The body of a coin is also made up of these 3 pieces of information, but instead of being hashed, they are stored in full. Here is the actual code that defines a coin:

class Coin:
    parent_coin_info: "CoinName"
    puzzle_hash: ProgramHash
    amount: uint64


When you spend a coin you destroy it. Unless the behaviour of a puzzle designates what to do with the coin’s value when it is spent, the value of the coin is also destroyed in the spend.

To spend a coin you need 3 pieces of information (and an optional 4th).

  1. The coin’s ID
  2. The full source of the coin’s puzzle
  3. A solution to the coin’s puzzle
  4. (OPTIONAL) A collection of signatures grouped together, called an aggregated signature

Remember the puzzle and solution is the same as we covered in part 1, except the puzzle has already been stored inside the coin and anybody can submit a solution.

The network / ledger-sim has no concept of coin ownership, anybody can attempt to spend any coin on the network. It’s up to the puzzles to prevent coins from being stolen or spent in unintended ways.

If anybody can submit a solution for a coin, you maybe wondering how somebody can “own” a coin. By the end of the next section of the guide, hopefully it should be clear.

Puzzles and Solutions in Practice

So far in part 1 we have covered ChiaLisp programs that will evaluate to some result. Remember the first part represents a puzzle which is committed to locking up a coin, and the second part is a solution anybody can submit:

$ brun '(+ 2 5)' '(40 50)'

$ brun '(c (q 800) 1)' '("some data" 0xdeadbeef)'
(800 "some data" 0xdeadbeef)

These are fun exercises in isolation, but this format can be used to communicate instructions to the blockchain network of how a coin should behave when it is spent. This can be done by having the result of an evaluation be a list of OpCodes.


The OpCodes are split into two categories: “this spend is only valid if X” and “if this spend is valid then X”.

Here is the complete list of OpCodes along with their format and behaviour.

  • AGG_SIG_UNSAFE – [49] – (49 0xpubkey 0xmessage): This spend is only valid if the attached aggregated signature contains a signature from the given public key of the given message. This is labeled unsafe because if you sign a message once, any other coins you have that require that signature may potentially also be unlocked. It’s probably better just to use AGG_SIG_ME because of the natural entropy introduced by the coin ID.
  • AGG_SIG_ME – [50] – (50 0xpubkey 0xmessage): This spend is only valid if the attached aggregated signature contains a signature from the specified public key of that message concatenated with the coin’s ID.
  • CREATE_COIN – [51] – (51 0xpuzzlehash amount): If this spend is valid, then create a new coin with the given puzzlehash and amount.
  • ASSERT_FEE – [52] – (52 amount): This spend is only valid if there is unused value in this transaction equal to amount, which is explicitly to be used as the fee.
  • CREATE_COIN_ANNOUNCEMENT – [60] – (60 message): If this spend is valid, this creates an ephemeral announcement with an ID dependent on the coin that creates it. Other coins can then assert an announcement exists for inter-coin communication inside a block.
  • ASSERT_COIN_ANNOUNCEMENT – [61] – (61 0xannouncementID): This spend is only valid if there was an announcement in this block matching the announcementID. The announcementID is the hash of the message that was announced concatenated with the coin ID of the coin that announced it announcementID == sha256(coinID + message).
  • CREATE_PUZZLE_ANNOUNCEMENT – [62] – (62 message): If this spend is valid, this creates an ephemeral announcement with an ID dependent on the puzzle that creates it. Other coins can then assert an announcement exists for inter-coin communication inside a block.
  • ASSERT_PUZZLE_ANNOUNCEMENT – [63] – (63 0xannouncementID): This spend is only valid if there was an announcement in this block matching the announcementID. The announcementID is the message that was announced concatenated with the puzzle hash of the coin that announced it announcementID == sha256(puzzle_hash + message).
  • ASSERT_MY_COIN_ID – [70] – (70 0xcoinID): This spend is only valid if the presented coin ID is exactly the same as the ID of the coin that contains this puzzle.
  • ASSERT_MY_PARENT_ID – [71] – (71 0xparentID): This spend is only valid if the presented parent coin info is exactly the same as the parent coin info of the coin that contains this puzzle.
  • ASSERT_MY_PUZZLE_HASH – [72] – (72 0xpuzzlehash): This spend is only valid if the presented puzzle hash is exactly the same as the puzzle hash of the coin that contains this puzzle.
  • ASSERT_MY_AMOUNT – [73] – (73 0xamount): This spend is only valid if the presented amount is exactly the same as the amount of the coin that contains this puzzle.
  • ASSERT_SECONDS_RELATIVE – [80] – (80 seconds): This spend is only valid if the given time has passed since this coin was created.
  • ASSERT_SECONDS_ABSOLUTE – [81] – (81 time): This spend is only valid if the timestamp on this block is greater than the specified timestamp.
  • ASSERT_HEIGHT_RELATIVE – [82] – (82 block_age): This spend is only valid if the specified number of blocks have passed since this coin was created.
  • ASSERT_HEIGHT_ABSOLUTE – [83] – (83 block_height): This spend is only valid if the given block_height has been reached.

Conditions are returned as a list of lists in the form:

((51 0xabcd1234 200) (50 0x1234abcd) (53 0xdeadbeef))

Remember: this is what a puzzle should evaluate to when presented with a solution so that a full-node/ledger-sim can understand it.

Let’s create a few examples puzzles and solutions to demonstrate how this is used in practice.

Example 1: Password Locked Coin

Let’s create a coin that can be spent by anybody as long as they know the password.

To implement this we would have the hash of the password committed into the puzzle and, if presented with the correct password, the puzzle will return instructions to create a new coin with a puzzlehash given in the solution. For the following example the password is “hello” which has the hash value 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824. The implementation for the above coin would be thus:

(i (= (sha256 2) (q 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (c (q . 51) (c 5 (c (q . 100) ()))) (q "wrong password"))

This program takes the hash, with (sha256 ), of the first element in the solution, with 2, and compares that value with the already committed. If the password is correct it will return (c (q . 51) (c 5 (c (q . 100) (q ()))) which evaluates to (51 0xmynewpuzzlehash 100). Remember, 51 is the OpCode to create a new coin using the puzzlehash presented in the solution, and 5 is equivalent to (f (r 1)).

If the password is incorrect it will return the string “wrong password”.

The format for a solution to this is expected to be formatted as (password newpuzzlehash). Remember, anybody can attempt to spend this coin as long as they know the coin’s ID and the full puzzle code.

Let’s test it out using clvm_tools.

$ brun '(i (= (sha256 2) (q 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (c (c (q 51) (c 5 (c (q 100) (q ())))) (q ())) (q "wrong password"))' '("let_me_in" 0xdeadbeef)'
"wrong password"

$ brun '(i (= (sha256 2) (q 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (c (q 51) (c 5 (c (q 100) (q ())))) (q "wrong password"))' '("incorrect" 0xdeadbeef)'
"wrong password"

$ brun '(i (= (sha256 2) (q 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (c (q 51) (c 5 (c (q 100) (q ())))) (q "wrong password"))' '("hello" 0xdeadbeef)'
((51 0xdeadbeef 100))

There is one final change we need to make before this is a complete smart transaction.

If you want to invalidate a spend then you need to raise an exception using x. Otherwise you just have a valid spend that isn’t returning any OpCodes, and that would destroy our coin and not create a new one! So we need to change the fail condition to be (x (q . "wrong password")) which means the transaction fails and the coin is not spent.

If we’re doing this then we should also change the (i A B C) pattern to (a (i A (q . B) (q . C)) 1). The reason for this is explained in part 3. For now don’t worry about why.

Here is our completed password protected coin:

(a (i (= (sha256 2) (q . 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (q . (c (c (q . 51) (c 5 (c (q . 100) ()))) ())) (q . (x (q . "wrong password")))) 1)

Let’s test it out using clvm_tools:

$ brun '(a (i (= (sha256 2) (q . 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (q . (c (c (q . 51) (c 5 (c (q . 100) ()))) ())) (q . (x (q . "wrong password")))) 1)' '("let_me_in" 0xdeadbeef)'
FAIL: clvm raise ("wrong password")

$ brun '(a (i (= (sha256 2) (q . 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)) (q . (c (c (q . 51) (c 5 (c (q . 100) ()))) ())) (q . (x (q . "wrong password")))) 1)' '("hello" 0xdeadbeef)'
((51 0xdeadbeef 100))

Generating OpCodes from the Puzzle vs. from the Solution

Let’s take a moment to consider the balance of power between the send and the spender. Another way of phrasing this is “how much control over the output should the solution have?”

Suppose we lock a coin up using the following puzzle:

(q . ((51 0x365bdd80582fcc2e4868076ab9f24b482a1f83f6d88fd795c362c43544380e7a 100)))

Regardless of what solution is passed this puzzle will always return instructions to create a new coin with the puzzlehash 0x365bdd80582fcc2e4868076ab9f24b482a1f83f6d88fd795c362c43544380e7a and the amount 100.

$ brun '(q . ((51 0x365bdd80582fcc2e4868076ab9f24b482a1f83f6d88fd795c362c43544380e7a 100)))' '(80 90 "hello")'
((51 0x365bdd80582fcc2e4868076ab9f24b482a1f83f6d88fd795c362c43544380e7a 100))

$ brun '(q . ((51 0x365bdd80582fcc2e4868076ab9f24b482a1f83f6d88fd795c362c43544380e7a 100)))' '("it doesn't matter what we put here")'
((51 0x365bdd80582fcc2e4868076ab9f24b482a1f83f6d88fd795c362c43544380e7a 100))

In this example the result of spending the coin is entirely determined from the puzzle. Even though anybody could initiate the spend of the coin, the person that locked the coin up has all the power in the way that the coin is spent as the solution doesn’t matter at all.

Conversely lets consider a coin locked up with the following puzzle:


This example may look a little weird, because most ChiaLisp programs are lists, and this is just an atom, but it is still a valid program. This puzzle simply returns the entire solution to the blockchain. You can think about this in terms of power and control. The person that locked the coin up has given all the power to the person who provides the solution.

$ brun '1' '((51 0xf00dbabe 50) (51 0xfadeddab 50))'
((51 0xf00dbabe 50) (51 0xfadeddab 50))

$ brun '1' '((51 0xf00dbabe 75) (51 0xfadeddab 15) (51 0x1234abcd 10))'
((51 0xf00dbabe 75) (51 0xfadeddab 15) (51 0x1234abcd 10))

In this situation, not only can anybody can spend the coin, they can spend it however they like! This balance of power determines a lot of how puzzles are designed in ChiaLisp.

For example, let’s create a puzzle that lets the spender choose the output, but with one stipulation.

  (c (q . (51 0xcafef00d 200)) 1)

This will let the spender return any conditions and OpCodes they want via the solution but will always add the condition to create a coin with the puzzlehash 0xcafef00d and value 200.

$ brun '(c (q . (51 0xcafef00d 200)) 1)' '((51 0xf00dbabe 75) (51 0xfadeddab 15) (51 0x1234abcd 10))'
((51 0xcafef00d 200) (51 0xf00dbabe 75) (51 0xfadeddab 15) (51 0x1234abcd 10))

This section is intended to demonstrate the point that OpCodes can come from both the recipient’s solution and from the sender’s puzzle, and how that represents trust and the balance of power.

In the next exercise we will put everything we know together and create the “standard” transaction in Chia that underpins how wallets are able to send money to each other.

Example: Signature Locked Coin

To ‘send a coin to somebody’ you simply create a puzzle that requires the recipients signature, but then allows them to return any other OpCodes that they like. This means that the coin cannot be spent by anybody else, but the outputs are entirely decided by the recipient.

We can construct the following smart transaction where AGGSIG is 50 and the recipient’s pubkey is 0xfadedcab.

(c (c (q . 50) (c (q . 0xfadedcab) (c (sha256 2) (q . ())))) 3)

This puzzle forces the resultant evaluation to contain (50 0xpubkey *hash_of_first_solution_arg*) but then adds on all of the conditions presented in the solution.

Let’s test it out in clvm_tools – for this example the recipient’s pubkey will be represented as 0xdeadbeef. The recipient wants to spend the coin to create a new coin which is locked up with the puzzle 0xfadeddab.

$ brun '(c (c (q . 50) (c (q . 0xfadedcab) (c (sha256 2) (q . ())))) 3)' '("hello" (51 0xcafef00d 200))'
((50 0xfadedcab 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824) (51 0xcafef00d 200))


Let’s pull back and add some context here.


A wallet is some software that has several features that make it easy for a user to interact with coins.

  • A wallet keeps track of public and private keys
  • A wallet can generate puzzles and solutions
  • A wallet can sign things with its keys
  • A wallet can identify and remember what coins that the user ‘owns’
  • A wallet can spend coins

You may be wondering how a wallet is able to identify what coins that the user ‘owns’ if any person can attempt to spend a coin. This is because all wallets already know and agree on what the standard format for sending a coin to somebody is. They know what their own pubkeys are, so when a new coin is created a wallet can check if the puzzle inside that coin is a ‘standard send puzzle’ to one of their pubkeys. If it is, then that coin can be considered to be owned by that ‘wallet’ as nobody else can spend it.

If the wallet that ‘owns’ the coin then wanted to send that coin on again to somebody else, they would generate a ‘standard send puzzle’ but with the new recipient’s pubkey. They could then spend the coin that they own, destroying it, and creating a new coin that is locked up with the new recipients pubkey in the process. The new recipient can then identify that it ‘owns’ the coin and can send it on as they wish later.

Change Making

Change making is simple. If a wallet spends less than the total value of a coin, they can create another coin with the remaining portion of value, and lock it up with the standard puzzle for themselves again. You can split a coin up into as many new coins with fractions of the original value as you’d like.

You cannot create two coins of the same value, with the same puzzlehash, from the same parent as this will lead to an ID collision and the spend will be rejected.

Coin Aggregation and Spend Bundles

You can aggregate a bunch of smaller coins together into one large coin. To do this, you can create a SpendBundle which groups together one or more spends so that they cannot be split. The SpendBundle also contains an Aggregated Signature object which is how the AGGSIG condition can check if a value has been signed.

You can also further tighten the link between them by using ASSERT_COIN_CONSUMED. Suppose you have a 20 coin and an 80 coin. In the 20 coin you can make it return (CREATE_COIN 0xnewpuzhash 100) in the spend. Then in the 80 coin you can make it return (ASSERT_COIN_CONSUMED 0xcoinID). The coupling inside the SpendBundle and the 80 value asserting its relationship to the 20 means that the value from the 80 coin is channeled into the creation of the new value 100 coin.

Standard Transaction

We can construct an even more powerful version of the signature locked coin to use as our standard transaction.

(c (c (q . 50) (c (q . 0xfadedcab) (c (sha256 2) (q . ())))) (a 5 11))

The first part is mostly the same, the puzzle always returns an AGGSIG check for the pubkey 0xfadedcab. However it only checks for the first element of the solution. This is because instead of the solution for this puzzle being a list of OpConditions to be printed out, the solution is a program/solution pair. This means that the recipient can run their own program as part of the solution generation, or sign a puzzle and let somebody else provide the solution.

The new program and solution inside the solution are evaluated and the result of that is added to the OpCode output. We will cover in more detail how this works in the next part of this guide.

A basic solution for this standard transaction might look like:

("hello" (q . ((51 0xmynewpuzzlehash 50) (51 0xanothernewpuzzlehash 50))) (q . ()))

Running that in the clvm_tools looks like this:

$ brun '(c (c (q . 50) (c (q . 0xfadedcab) (c (sha256 2) (q . ())))) (a 5 11))' '("hello" (q . ((51 0xdeadbeef 50) (51 0xf00dbabe 50))) (q . ()))'

((50 0xfadeddab 0x1f82d4d4c6a32459143cf8f8d27ca04be337a59f07238f1f2c31aaf0cd51d153) (51 0xdeadbeef 50) (51 0xf00dbabe 50))


Coin ownership refers to the concept of creating a coin with a puzzle that means it can only be spent when signed by the private key of the coin’s “owner”. The goal of wallet software is to generate, interpret and manage these kinds of coins and puzzles.

The next part of this guide will go further in depth in ChiaLisp, and cover how to write more complex puzzles. If any of the material in this part of the guide has got you confused, try returning to it after the next part.

3 – Deeper into CLVM

This section of the guide will cover how ChiaLisp relates to transactions and coins on the Chia network.

Lazy Evaluation in ChiaLisp

As we saw in part 1, programs are often structured around (i A B C) to control flow. ChiaLisp evaluates programs as trees, where the leaves are evaluated first. This can cause unexpected problems if you are not aware of it. Consider the following program which uses x which immediately halts and throws an error if it is evaluated.

$ brun '(i (q . 1) (q . 100) (x (q . "still being evaluated")))'
FAIL: clvm raise (0x7374696c6c206265696e67206576616c7561746564)

This is because ChiaLisp evaluates both of the leaves even though it will only follow the path of one.

To get around this we can use the following design pattern to replace (i A B C).

(a (i (A) (q B) (q C)) (a))

Applying this to our above example looks like this:

$ brun '(a (i (q . 1) (q . (q . 100)) (q . (x (q . "still being evaluated")))) 1)'

It is worth keeping this in mind whenever you write an (i A B C).

If you’re wondering how this works (and how the standard transaction from part 2 worked), then allow me to introduce Evaluate.

Introduction to Evaluate

In Part 1 we mentioned that a program is usually a list where the first element is an operator, and every subsequent element is a valid program. We can also run programs with new arguments inside a program.

This looks like this:

(a *(puzzle)* (*solution)*)

Let’s put this into practice.

Here is a program that evaluates the program (+ 2 (q 5))) and uses the list (70 80 90) or (80 90 100) as the solution.

$ brun '(a (q . (+ 2 (q . 5))) (q . (70 80 90)))' '(20 30 40)'

$ brun '(a (q . (+ 2 (q . 5))) (q . (80 90 100)))' '(20 30 40)'

Notice how the original solution (20 30 40) does not matter for the new evaluation environment. In this example we use q . to quote both the new puzzle and the new solution to prevent them from being prematurely evaluated.

A neat trick that we can pull is that we can define the new solution in terms of the outer solution. In this next example we will add the first element of the old solution to our new solution.

$ brun '(a (q . (+ 2 (q . 5))) (c 2 (q . (70 80 90))))' '(20 30 40)'

However it’s not just the new solution that we can affect using this, we can also pass programs as parameters.

Programs as Parameters

The core CLVM does not have an operator for creating user defined functions. It does, however, allow programs to be passed as parameters, which can be used for similar results.

Here is a puzzle that executes the program contained in 2 (the first solution argument) with the solution (12).

$ brun '(a 2 (q . (12)))' '((* 2 (q . 2)))'

Taking this further we can make the puzzle run a new evaluation that only uses parameters from its old solution:

$ brun '(a 2 1)' '((* 5 (q . 2)) 10)'

We can use this technique to implement recursive programs.

4 – The High Level Language, Compiler, and Functions

This guide assumes that you have already read the previous parts. It is highly recommended that you do so as the higher level language is built directly on top of the lower level language.


The first difference you need to be aware of for the higher level language is that you should call run instead of brun. This lets the runtime know that it should be including higher level features.

The first higher level feature you should be aware of is that it is no longer necessary to quote atoms!

Compare brun and run here:

$ brun '(+ 200 200)'
FAIL: first of non-cons ()
$ run '(+ 200 200)'

Run also gives us access to a number of convenient high level operators, which we will cover now.


list takes any number of parameters and returns them put inside a list. This saves us from having to manually create nested (c (A) (c (B) (q ()))) calls, which can get messy quickly.

$ run '(list 100 "test" 0xdeadbeef)'
(100 "test" 0xdeadbeef)


if automatically puts our i statement into the lazy evaluation form so we do not need to worry about the unused code path being evaluated.

$ run '(if 1 (q . "success") (x))' '(100)'

$ run '(if 0 (q . "success") (x))' '(100)'
FAIL: clvm raise ()

qq unquote

qq allows us to quote something with selected portions being evaluated inside by using unquote. The advantages of this may not be immediately obvious but are extremely useful in practice as it allows us to substitute out sections of predetermined code.

Suppose we are writing a program that returns another coin’s puzzle. We know that a puzzle takes the form: (c (c (q . 50) (c (q . 0xpubkey) (c (sha256 2) (q . ())))) (a 5 11)) However we will want to change 0xpubkey to a value passed to us through our solution.

Note: @ allows us to access the arguments in the higher level language

$ run '(qq (c (c (q 50) (c (q (unquote (f @))) (c (sha256 2) (q ())))) (a 5 11)))' '(0xdeadbeef)'

(c (c (q 50) (c (q 0xdeadbeef) (c (sha256 2) (q ())))) (a 5 11))

Compiling to CLVM with Mod

It is important to remember that in practice smart contracts will run using the lower level language, so none of the above operators will work on the network. What we can do however is compile them down to the lower level language. This is where mod comes in. mod is an operator that lets the runtime know that it needs to be compiling the code rather than actually running it.

(mod A B) takes two or more parameters. The first is used to name parameters that are passed in, and the last is the higher level script which is to be compiled.

Below we name our arguments arg_one and arg_two and then access arg_one inside our main program

$ run '(mod (arg_one arg_two) (list arg_one))'
(c 2 (q ()))

As you can see it returns our program in compiled lower level form.

$ brun '(c 2 (q ()))' '(100 200 300)'

You may be wondering what other parameters mod takes, between variable names and source code.

Functions, Macros and Constants

In the higher level language we can define functions, macros, and constants before our program by using defundefmacro and defconstant.

We can define as many of these as we like before the main source code. Usually a program will be structured like this:

(mod (arg_one arg_two)
  (defconstant const_name value)
  (defun function_name (parameter_one parameter_two) (*function_code*))
  (defun another_function (param_one param_two param_three) (*function_code*))
  (defmacro macro_name (param_one param_two) (*macro_code*))

  (main *program*)

A few things to note:

  • Functions can reference themselves in their code but macros cannot as they are inserted at compile time, similar to inline functions.
  • Both functions and macros can reference other functions, macros and constants.
  • Macros that refer to their parameters must be quasiquoted with the parameters unquoted
  • Be careful of infinite loops in macros that reference other macros.
  • Comments can be written with semicolons

Now lets look at some example programs using functions.


(mod (arg_one)
  ; function definitions
  (defun factorial (input)
    (if (= input 1) 1 (* (factorial (- input 1)) input))

  ; main
  (factorial arg_one)

We can save these files to .clvm files which can be run from the command line. Saving the above example as factorial.clvm allows us to do the following.

$ run factorial.clvm
(a (q 2 2 (c 2 (c 5 ()))) (c (q 2 (i (= 5 (q . 1)) (q 1 . 1) (q 18 (a 2 (c 2 (c (- 5 (q . 1)) ()))) 5)) 1) 1))

$ brun '(a (q 2 2 (c 2 (c 5 ()))) (c (q 2 (i (= 5 (q . 1)) (q 1 . 1) (q 18 (a 2 (c 2 (c (- 5 (q . 1)) ()))) 5)) 1) 1))' '(5)'

Squaring a List

Now lets do an example which uses macros as well. When writing a macro it must be quasiquoted with the parameters being unquoted.

We can also take this time to show another feature of the compiler. You can name each parameter in a list or you can name the list itself. This works at any place where you name parameters, and allows you to handle lists where you aren’t sure of the size.

Here we define a macro to square a parameter and then a function to square a list.

(mod args

  (defmacro square (input)
    (qq (* (unquote input) (unquote input)))

  (defun sqre_list (my_list)
    (if my_list
      (c (square (f my_list)) (sqre_list (r my_list)))

  (sqre_list args)

Compiling and running this code results in this:

$ run square_list.clvm
(a (q 2 2 (c 2 (c 3 ()))) (c (q 2 (i 5 (q 4 (* 9 9) (a 2 (c 2 (c 13 ())))) (q . 5)) 1) 1))

$ brun '(a (q 2 2 (c 2 (c 3 ()))) (c (q 2 (i 5 (q 4 (* 9 9) (a 2 (c 2 (c 13 ())))) (q . 5)) 1) 1))' '(10 9 8 7)'
(100 81 64 49)


You should now have the context and knowledge needed to write your own chialisp programs. Remember from part 2 that these programs run on the blockchain and instruct the blockchain what to do with the coin’s value

The Great Chia Glossary

This guide will act as a glossary for many of the concepts utilized in Chia. If you are familiar with how Bitcoin transactions work, a lot of this will be familiar.

  • Coin (TXO/transaction output) – A coin stores value. All coins are generated as the output of a transaction or a coinbase reward or fee target. A coin is spent exactly once, allowing its value to go into other coins, and is then permanently destroyed. Each unspent coin is locked with a ChiaLisp program which is that coin’s puzzle, and whoever has the information to solve that puzzle is the person who can spend that coin. The most basic puzzle has a public key and accepts a solution which contains a list of conditions signed by the corresponding private key, so only the owner of the private key can unlock the coin and spend it.
  • Unspent Coin (UTXO/unspent transaction output) – A coin which has been created but not yet spent and hence is storing value. Unspents (UTXO set/unspent transaction output set) – This is the set of all unspent coins on the network. It is used to check if a transaction is valid, acting as a lookup for the puzzles. It maps a coin ID to a birthdate in blockheight. A transaction must contain a reveal of the information used to calculate the ID in order for it to be possible to validate because the unspents doesn’t contain that information, only hashes which can be used to validate it.
  • Coin ID/CoinName (TXO ID/transaction output ID) – The ID of a coin in Chia is generated by hashing the primary input ID, puzzle hash, and amount concatenated in that order. This is very different from Bitcoin which uses much more data to form the TXO ID, restricting what smart contracts are capable of.
  • Primary Input/Parent – When a coin is created the coin that was used as input in the transaction is designated as the primary input. This is used to create the coin ID. If more that one coin is used up as an input in a transaction then one of the coins is designated the primary input, and the others simply reinforce the transaction.
  • Spend/CoinSolution – A spend is a reveal of a coin’s ID, along with the full puzzle code, and a solution to be ran with the puzzle. The result of a spend is determined by the returned Op Constraints after running the puzzle with the solution.
  • Spend Bundle – A spend bundle is a collection of spends grouped together with an aggregated signature to be sent to the network.
  • ChiaLisp – ChiaLisp is the Turing-complete functional language which the puzzles for spending coin are programmed in.
  • Puzzle (Scriptpubkey) – A ChiaLisp program which specifies the behaviour of a coin when it is spent. A puzzle can either reject a solution or output a set of constraints.
  • Solution (Scriptsig) – This is some ChiaLisp which is passed to the puzzle for evaluation when a transaction is submitted.
  • CLVM – The CLVM is the ChiaLisp Virtual Machine which is the sandboxed environment that puzzles and solutions are run in. The CLVM only runs the compiled minimal version of ChiaLisp, though a compiler can convert the higher level ChiaLisp to the compiled minimal version.
  • Aggregated Signature/AggSig – Aggregated Signatures allow us to condense multiple signatures into a single aggregated signature, such that if we know a public key and value we can verify if it exists inside of the single aggregate. This uses BLS non-interactive aggregation.
  • Prepend Signature – Prepend signatures are used so that we can retain metadata about the structure of an aggregated signature. TODO: Expand
  • Op Constraints/Conditions – Constraints are returned by the puzzle when it’s passed the solution. If all of the returned conditions are met then a transaction is valid.
  • Wallet – Software written to interact with transactions. Chia uses Hierarchical Deterministic Wallets (HD Wallets). This means that they can generate many different public keys that are all valid and verifiable as unique to that wallet. A wallet contains a coin if it possesses the information necessary to unlock that coin and create a transaction which spends it.
  • Puzzle Generator – A wallet will use a Puzzle Generator to define how it wants to receive transactions. Most wallets will want to generate the standard transaction, however by storing a ChiaLisp program that generate a puzzle, all a Sending Wallet needs to do is ask the Recipient Wallet what its Program Generator is and then run that to create the puzzle to lock the coin up with.
  • Puzzle Generator ID – This is the hash of a wallet’s puzzle generator. A wallet can do a hash-lookup and see if it already knows the source code for that puzzle generator. If not, it will request the full source code and store that information in its lookup table.
  • Smart Contract – A smart contract is a specialised ChiaLisp puzzle which locks a coin up and enables complex blockchain interactions.
  • Coloured Coins – Coloured Coins are a special kind of chia coin which are created by users. A coloured coin is a uniquely marked subset of chia which can’t be forged and can be linked to other assets.
  • Authorized Payees – Authorized Payees is a smart contract that means that Wallet A can give Wallet B some money, but Wallet B is only allowed to spend that money in ways that Wallet A has explicitly authorised.
  • Decentralised ID – A decentralised ID is a smart contract that enables a wallet to act as an ID which can create messages to other IDs.

Good Security Practices on Many Machines

Keep Your Keys Separate

In other words, only use the keys specific to your machine’s purpose.

  • Your master/farming key should not be in your plotting machine(s).
  • Your master/farming key should not be in your harvester machine(s).

Farming On Multiple Machines

Plotting On Multiple Machines

Buried in the Farming on many machines wiki page is this relevant tidbit:

When creating plots on the other harvesters, use chia plots create -f farmer_key -p pool_key, inserting the farmer and pool keys from your main machine. Alternatively, you could copy your private keys over by using chia keys add, but this is less secure.

Harvesting On Multiple Machines

Follow the instructions on setting up certificates on harvesters on the Farming on many machines wiki page.

Keep Your Wallet Separate

One way to not get your wallet hacked is to not have it accessible to the internet. Here is how to do this: Chia Keys Management

Your reward address for chia rewards should be a separate key as well, kept in an offline machine. You can generate an address on a different computer, and put this address in the config.yaml (farmer.xch_target_address and pool.xch_target_address), so if your farming machine gets hacked, you don't lose past rewards. (Source)

How to Find Your Keys

Use the following command in a safe place. Your private and public keys will be visible.

You’ll need to use the CLI. Use this command to list all your keys: chia keys show

Farming On Many Machines

How to harvest on other machines that are not your main machine

This guide allows you to run a harvester on each machine, without having to run a full node, wallet, and farmer on each one. This keeps your system simpler, uses less bandwidth, space, CPU, and also keeps your keys safer. It also makes your overall farm quicker and more efficient when replying to challenges.

The architecture is composed of one main machine which runs the farmer, full node, and wallet, and other machines which run only the harvester. Only your main machine will connect to the Chia network.

To secure communication between your harvester and main machine, TLS is used where your main machine will be the private Certification Authority (CA) that signs all certificates. Each harvester must have its own signed certificate to properly communicate with your main machine.

                                       _____  Harvester 1 (certificate A)
other network peers  --------   Main machine (CA) ------  Harvester 2 (certificate B)
                                      \_____  Harvester 3 (certificate C)


  • First, make sure Chia is installed on all machines and initialized by running the CLI chia init.
  • When creating plots on the other harvesters, use chia plots create -f farmer_key -p pool_key, inserting the farmer and pool keys from your main machine. Alternatively, you could copy your private keys over by using chia keys add, but this is less secure. After creating a plot, run chia plots check to ensure everything is working correctly.
  • Make a copy of your main machine CA directory located in ~/.chia/mainnet/config/ssl/ca to be accessible by your harvester machines; you can share the ssl/ca directory on a network drive, USB key, or do a network copy to each harvester. Be aware that major updates might need you to copy the new ca contents. Verify that the harvester does not report SSL errors on connections attempts.

Setup Steps

Then for each harvester, follow these steps:

NOTE: For step 4, you are using a copy of your /ca directory from your main machine temporarily. DO NOT replace the /ca folder on your harvester. Put the /ca directory into a temp folder on your harvester. You’re going to show your harvester these files temporarily and then you can delete the /ca directory in your temp folder.

  1. Make sure your main machines IP address on port 8447 is accessible by your harvester machines
  2. Shut down all chia daemon processes with chia stop all -d
  3. Make a backup of any settings in your harvester
  4. Run chia init -c [directory] on your harvester, where [directory] is the copy of your main machine /ca directory that you put in a temp folder. This command creates a new certificate signed by your main machine’s CA.
  5. Open the ~/.chia/mainnet/config/config.yaml file in each harvester, and enter your main machine’s IP address in the remote harvester‘s farmer_peer section (NOT full_node).
    crt: config/ssl/ca/chia_ca.crt
    key: config/ssl/ca/chia_ca.key
    host: Main.Machine.IP
    port: 8447
  1. Launch the harvester by running CLI chia start harvester -r and you should see a new connection on your main machine in your INFO level logs.
  2. To stop the harvester, you run CLI chia stop harvester


You cannot copy the entire config/ssl directory from one machine to another. Each harvester must have a different set of TLS certificates for your main machine to recognize it as different harvesters. Unintended bugs can occur, including harvesters failing to work properly when the same certificates are shared among different machines.

Security Concern:

Since beta27, the CA files are copied to each harvester, as the daemon currently needs it to startup correctly. This is not ideal, and a new way to distribute certificates will be implemented in a subsequent release post mainnet launch. Please be careful when running your harvester that is accessible from the open internet.


Currently (mainnet), the GUI doesn’t show harvester plots. The best way to see if it’s working is shut down Chia full node and set your logging level to INFO in your config.yaml on your main machine and restart Chia full node. Now you can check the log ~/.chia/mainnet/log/debug.log and see if you get messages like the following:

[time stamp] farmer farmer_server   : INFO   -> new_signage_point_harvester to peer [harvester IP address] [peer id - 64 char hexadecimal]
[time stamp] farmer farmer_server   : INFO   <- farming_info from peer [peer id - 64 char hexadecimal] [harvester IP address]
[time stamp] farmer farmer_server   : INFO   <- new_proof_of_space from peer [peer id - 64 char hexadecimal] [harvester IP address]

The outgoing new_signage_point_harvester message states the farmer sent a challenge to your harvester and the incoming farming_info message indicates a response. The new_proof_of_space message states the harvester found a proof for the challenge. You will get more new_signage_point and farming_info messages than new_proof_of_space messages.

Here’s how to find your logs: Where to Find Things

If you are running the GUI on the main farmer and want to run multiple Harvesters from the CLI

  • Shut down Chia on main computer
  • Find your IP address on computer
  • Make a copy of your main machine CA directory located in c:\users\(your user name)\.chia\mainnet\config\ssl – copy the CA file; you can share the ssl/ca directory on a network drive, USB key, or do a network copy to each harvester. You must copy the new ssl/ca directory with each version of chia-blockchain— copy the CA file to the harvester machine — know its location
  • In new Harvester – follow steps below
  • Load Chia and use your regular 24 word mnemonic key to see that it works. Then shut down Chia
  • In c:\users(your user name).chia\mainnet\config file– open it with notepad
  • Change enable_upnp: true– change that to false
  • Locate harvester: farmer_peer: host: localhost– change only this location– type in your main pc ip address (ex 192.192.x.x)
  • Locate the CA folder you copied from main computer– know its network location.
  • Go to command prompt. Type in or copy *cd C:\Users(your username)\AppData\Local\Chia-Blockchain\app-1.1.1\resources\app.asar.unpacked\daemon*
  • Make sure the (app-1.1.1) is the current version– this is when version 1.1.1 is active
  • Run chia init -c [directory] on your harvester, where [directory] is the copy of your main machine CA directory and its network location. This command creates a new certificate signed by your main machine’s CA.
  • [directory] this is where you type the link to where your CA folder is stored– if on the c drive then type for example c:\ca. The full line would look like chia init -c c:\ca
  • Then press enter. Once that process is complete *Start both your main pc and the new harvester
  • The new harvester may take a 10-20 minutes to start the sync procees- it will be a little bit slower- but should start to sync and will make a full copy of the blockchain to get to normal sync. You can create plots on that machine or copy plots over. It will only farm once full sync is completed.

To know its working

  • On your main pc under Farm tab- at the bottom select “Hide Advanced Options”- scroll down and ” Your Harvester Network” wil now show (2) Node ID– (1) your main pc and (2) your harvester
  • also under farm tab under “Last Attempted Proof” your qty of plots on your harvester will also show up there


  • Chia does upgrades- if you are finding your harvester is not sync with blockchain or wallet– you may have to re-copy the CA files again from main pc
  • Run chia init -c [directory] on your harvester, where [directory] is the copy of your main machine CA directory and its network location. This command creates a new certificate signed by your main machine’s CA.

Reference Farming Hardware

The farming process is very lightweight and can be run with minimal CPU and DRAM resources. The goal of a good farming platform is to have the maximum amount of capacity in the least amount of space, using as little power as possible. In other words, the priority for a farming platform, independent of obtaining storage for the lowest cost possible, is to have the highest amount of TB/W in a small space.

DIY Farms

Building your own rig as illustrated below requires solid IT skills and knowledge of how to safely handle electrical components. In some places these builds are not lawful without being a licensed electrician. Replicate at your own risk! Keep this far away from kids!

Farming productively (03/19/2021 through 04/04/2021), 163 blocks / 326 XCH at network space 120 ~ 200 PiB.

There are many unique DIY builds in the farming hardware channel that find unique uses for repurposing existing hardware to mount drives. Here a build from early community user that houses 32 drives farming off a RockPi4 and Sabrent USB hubs for an average power consumption of ~250W & ~5.6kWh per day (last 30 days) – easily making it one of the most power-efficient farms built so far!

Parts list (prices change constantly):

  • 32x Hard drives, different sizes and models from sizes 3 to 16 TB
  • 32x USB3/SATA PCB boards, re-used from shucking external hard drives but can also be ordered online
  • 32x 12V DC power cables, re-used from shucking external hard drives
  • 1x MEAN WELL RSP-500-12 DC Power Supply 500W/12V/42A
  • 1x Replacement Power Cable, 3 Pin Connector
  • 2x Sabrent 16-Port USB 3.0 Data HUB
  • 1x SMAKN 4 USB Car Charger Power Supply Step Down Module DC 9-40V to 5V 6A
  • 0.1x 8 AWG Copper Wire (this wire is used to connect power dist. bank with power supply)
  • 2x Power Distribution Banks
  • 2x Single Shelf Upright
  • a handful of metal screws and nuts
  • 1x Rock Pi 4A 4GB
  • 1x Aluminum Heat Sink for Rock Pi 4
  • 1x and optional Kasa Smart HS300 Plug Power Strip

Farming over 2200 x K32 plots in mostly under 1 second..

With the new consensus plots are probed very regularly. No issue for the RockPi4 to keep up with.

Plots with proofs for submission are found on a regular basis with over 2250x K32, providing the proof still no more than one second, with currently 22 PiB of total netspace.

Desktop Farming

A desktop in a full tower can house between 12-16 drives. This is a great setup for small farmers as desktops are the easiest to build and manage for PC enthusiasts. A full tower case that houses many drives can be found from many different vendors at a low cost. Typical desktop motherboards contain between 6-10 SATA ports, so expanding past that will also require a SAS HBA. Pros – cheap, easy to configure and customize Cons – need to build yourself and source


A desktop board can be put into an easily obtainable Rosewill 4U Server Chassis Case. This case features up to 16 drives and 7 fans included, and just needs a standard desktop PSU to get going.

JBOD, DAS (direct-attached storage)

A JBOD, or “Just a bunch of disks” is a device dedicated to housing a large number of hard disk drives, and does not contain any integrated compute resources. A JBOD is typically made up of an enclosure, enclosure slots that identify each drive individually, a SAS expander and backplane, fans, and power supplies. All the disks in a JBOD can be accessed by a single SAS cable connected to a host server or desktop through a HBA (host bus adapter) which converts a PCIe slot to SAS.


Mainstream JBOD – 45 disks in 4U chassis. Referred to in the farming channel as the SM45, this can be found on eBay for $300-400 making it very cost-efficient for medium to large size farms Supermicro SuperChassis 847E16-RJBOD1

Recommended HBAs to attach to host – LSI 9200-8e (ebay), 9200-16e (ebay) along with SFF-8088 to SFF-8088 1M External SAS Cable, or 9300 (ebay) or 9400-8e (ebay) with SAS SFF-8644 to SFF-8088 cable

High drive count – 90 disks in 4U chassis. highest density on the market, but typically goes for $1200-2000 used. Supermicro SuperChassis 946ED-R2KJBOD

Pros High number of slots. Fully integrated power supplies and fans. Uses SAS enclosure management to identify slots in software and identify a failed device with an LED locate function. Can use SAS or SATA drives.

Cons Fans can be loud. Heavy. Requires data center rack to be mounted correctly.

NAS Farming

A NAS, or networked attached storage, is a device dedicated to having hard drives included in a backplane and a lightweight CPU and DRAM. NAS serves storage through the network (as opposed to DAS, or direct-attached storage)


Synology DiskStation DS1821+

Pros – high number of drives in small space, extremely power efficient

Cons – expensive compared to other options, plugin required for farmer or harvester (not complete yet), typically setup with redundancy for data protection which is not required for farming. SATA drives only (which is fine for most)

Reference Plotting Hardware

These are machines that work well to quickly create plots in parallel. These serve as starting points to think about acquiring or modifying existing systems to be good plotting machines on a TBs of plots created per day basis. You don’t need this level of hardware to then farm plots that have been generated however. For that a Raspberry Pi is enough.

Plotting can be done on consumer systems (laptops), but is much faster done on high-end desktops, workstations, and servers. Plotting takes scaling for CPU cores to improve the parallelism (this is -r number of threads, or number of parallel processes), scaling in DRAM per process, and fast SSDs or many small 10k hard drives for temporary storage space.

The amount of DRAM and temp space changed in 1.0.4. The new table below reflects the values in the GUI. You need at least one CPU core (but you can use r to increase thread count speeding up phase 1), and the DRAM and temp space below per plot. The easy math for a system is to take the number of cores and use that as the target for number of processes to run in parallel, the multiply the temp space and DRAM requirements by that to find the minimum amount.

K-valueDRAM (MiB)Temp Space (GiB)Temp Space (GB)

The goal of a plotting machine is to create the highest TiB per day of plots, with the lowest system cost. There are many unique combinations of consumer, data center, and enterprise hardware at many different price points that are adequate for plotting. 

Chia Plotting Performance by Device

UserSystem NameOSMotherboard / SAS Adapter (Server)CPUCPU Perf
DRAM (Size, Type, MHz, etc)Temp DriveTime
Phase 1 (s)
Total Time
per Plot (s)
GiB/minParallel PlotsTiB/day
(all // Plots)
MiB/day/CPU PassmarkTotal Price
BucketsStaggerStripe Size-e
(Bitfield Disabled)
@toyFinal SpaceWindows 10Asus Prime TRX40-Pro SThreadripper 3970X/Mod. NH-U14S @4.264229256GB DDR4 @ 32007x 2TB NVME 980pro/mp510 1x 3,8TB NVME Micron 9200Series12,24529,571.00492.98.21101.330.20564212.14198.25$6,500.00$535.281.1.345000128yesdefaultno
@storage_jmIntel Wolf Pass ServerUbuntu Server 20.04.2Intel® Server System R2208WFTZSR2x Intel® Xeon® Gold 6130 Processor36970256GB DD4 2666 ECC RDIMM2 Intel SSD DC P4608 6.4TB, 4x 3.2TB in RAID 012,72243,156.10719.311.99101.330.1409469.11258.48$5,400.00$592.531.0.553400128yesdefaultno
@kiwihaitchMy BossUbuntu 20.04MSI TRX40 Pro 10GThreadripper 3970X64229256GB DDR4 @ 32006 x Intel P4600 3.2TB21,00049,900.00831.713.86101.330.1218457.71125.871.0.533400128noDefaultno
@trivonusKiloUbuntu Server 20.04.1Supermicro X10DRU-i+2x Intel Xeon E5-2690 v4 14 core 2.6 Ghz34169192GB DDR4 ECC2x Intel P4618 6.4TB PCIE NVME (4x 3.2TB in mdadm RAID 0)25,12757,675.00961.316.02101.330.1054487.12218.36$4,600.00$646.481.0.523300128yesDefaultno
@storage_jmIntel Wolf Pass ServerUbuntu Server 20.04.2Intel® Server System R2208WFTZSR2x Intel® Xeon® Gold 6130 Processor36970128GB DD4 2666 ECC RDIMMIntel SSD DC P4608 6.4TB, 2x 3.2TB in RAID 012,72232,790.10546.59.11101.330.1854266.78192.29$4,000.00$590.021.0.553400128yesdefaultno
@vexrUbuntu 20.04.2 LTSSupermicro X10-DRi2x Intel Xeon E5-2680 v325043192GB DDR4 ECC 2133P-R45 x WD 8TB – WD80EMAZ-00WJTA024,96463,348.861,055.817.60101.330.0960456.07254.301.1.223400128yesDefaultno
@kotarou3Debian testing (bullseye)MSI TRX40 Pro WifiThreadripper 3960X w/PBO+NH-U12S54963128GB DDR4 @32002× 2TB MP600 Force (btrfs RAID0 noatime,discard=async) + 2× 1TB MP600 Force (ditto)9,93031,000.00516.78.61101.330.1961215.79110.49$3,800.00$656.111.1.584000128yesdefaultno
@kotarou3Debian testing (bullseye)MSI TRX40 Pro WifiThreadripper 3960X w/PBO+NH-U12S54963128GB DDR4 @32002× 2TB MP600 Force (btrfs RAID0 noatime,discard=async) + 2× 1TB MP600 Force (ditto)10,49032,600.00543.39.06101.330.1865225.77110.07$3,800.00$658.611.1.584000128yesdefaultno
@kotarou3Debian testing (bullseye)MSI TRX40 Pro WifiThreadripper 3960X w/PBO+NH-U12S54963128GB DDR4 @32003× 2TB MP600 Force (btrfs RAID0 noatime,discard)16,15044,800.00746.712.44101.330.1357264.9694.66$3,800.00$765.841.1.543389128yesdefaultno
@kotarou3Debian testing (bullseye)MSI TRX40 Pro WifiThreadripper 3960X w/PBO+NH-U12S54963128GB DDR4 @32003× 2TB MP600 Force (btrfs RAID0 noatime,discard)9,19028,700.00478.37.97101.330.2118154.4785.25$3,800.00$850.401.1.583400128yesdefaultno
@toddsbythe monolithUbuntu Desktop 20.04.2Asus PRIME X570-PROAMD Ryzen 5900x w/ NZXT K53 AIO3947364GB DDR4 2666MHz (2x32GB)4x 2TB m.2 Inland (mdadm RAID-0)11,19632,328.30538.88.98101.330.1881184.76126.461.1.527700128yesdefaultno
@fiveanglechachachaUbuntu 21.04 serverDell R420 pizzabox2x Intel® Xeon® Processor E5-2470 v22313896GB DDR3 1600 ECC2x Nytro Warpdrives: BLP-1600 + XP6210-4A2048 in R015,00038,000.00633.310.56101.330.1600194.27193.73$
@technovioletRyzen Test 1Ubuntu 20.04.2 LTS Diskless (PXE)ASRock Taichi X570Ryzen 5950x4609764GB DDR4 @36004 x 1TB Inland Premium (MDADM R-0, XFS), 2 x 250GB EVO850 Destination5,43316,149.30269.24.49101.330.376584.2496.34$1,973.00$465.84124096128yesdefaultno
@storage_jmbrother in law buildWindows 10 2H20GIGABYTE Z590 AORUS EliteIntel® Core™ i9-10850K Processor2337764GB DDR4 32002x Corsair MP600 2TB NVMe M.2 80mm5,38916,981.00283.04.72101.330.358084.03180.67$2,000.00$496.541.0.584000128yesDefaultno
@technoviolet2667v3 Test 1Ubuntu 20.04.2 LTS Diskless (PXE)Supermicro SYS-1028R-TDW2 x Intel Xeon E5-2667v321642512GB DDR4 @18668 x EVO850 500GB (MDADM R-0, XFS, ZRAM LOG), 1 x Micron 9100 2.4TB NVME Destination10,52726,674.16444.67.41101.330.2279123.85186.36$1,738.00$451.8668192128yesdefaultno
@technoviolet2640v3 Test 2Ubuntu 20.04.2 LTS Diskless (PXE)Supermicro SYS-1028R-TDW2 x Intel Xeon E5-2640v31809464GB DDR4 @186618 x HUSMH8020BSS204 200GB SAS-12K (MDADM R-0, XFS) 2 x 250GB EVO850 Destination9,14826,824.00447.17.45101.330.2267123.82221.65$1,442.00$377.0186138128yesdefaultno
@trivonusEchoUbuntu Server 20.04.1MSI B550 GAMING PLUSRyzen 9 3950X 16-Core Processor39231128GB DDR4 3200 Mhz1x Intel P4608 6.4TB PCIE NVME (2x 3.2TB in mdadm RAID 0)16,20444,850.00747.512.46101.330.1356203.81101.90$2,900.00$760.641.0.535000128yesDefaultno
@trivonusIndiaUbuntu Server 20.04.1Supermicro X9DRi-LN4F+2x Intel Xeon E5-2650 v2 8 core 2.6 Ghz17588128GB DDR3 1333 Mhz ECC1x Intel P4608 6.4TB PCIE NVME (2x 3.2TB in mdadm RAID 0)18,69447,510.00791.813.20101.330.1280203.60214.58$2,350.00$652.941.0.534500128yesDefaultno
@trivonusBerthaUbuntu Server 20.04.1MSI MEG X570 ACERyzen 3900x @4.1GHZ3290164GB 2×32,DDR4 36002x Sabrent Rcoket 2TB w/ heatsink12,14233,600.00560.09.33101.330.1809143.56113.54$2,642.00$741.641.0.543400128YesDefaultno
@trivonusAlphaUbuntu Server 20.04.1MSI MAG B550 TomahawkAMD Ryzen 9 3900XT 12-Core Processor3298564GB DDR4 3600Intel DC P4510 4TB PCIE 3.1 x4 NVME11,10230,055.00500.98.35101.330.2023123.41108.52$2,211.00$647.701.0.544500128yesDefaultno
@storage_jmbrother in law buildWindows 10 2H20GIGABYTE Z590 AORUS EliteIntel® Core™ i9-10850K Processor2337764GB DDR4 32002x Corsair MP600 2TB NVMe M.2 80mm8,63325,692.27428.27.14101.330.2366103.33149.27$2,000.00$601.011.1.283400128yesDefaultno
@trivonusGolfUbuntu Server 20.04.1Supermicro X9DRi-LN4F+2x Intel Xeon E5-2650 v2 8 core 2.6 Ghz1758864GB DDR3 1333Mhz ECC1x Intel P4608 6.4TB PCIE NVME (2x 3.2TB in mdadm RAID 0)17,77448,909.00815.213.59101.330.1243183.15187.59$2,100.00$667.401.0.542900128yesDefualtno
@trivonusDeltaUbuntu Server 20.04.1ASUS TUF Gaming X570 Plus-WIFIAMD Ryzen 7 5800x 8-Core Processor1927564GB, 2x32GB, DDR4 36001x Intel P4610 3.2 TB10,21427,400.00456.77.61101.330.2219103.12169.75$2,150.00$689.031.0.545500128yesDefaultno
@trivonusCharlieUbuntu server 20.04.1MSI Z490-A ProIntel Core i7-10700 2.9ghz1735664GB, 2×32, DDR4 32002x Sabrent Rocket 2TB w/ heatsink12,16630,700.00511.78.53101.330.1980102.78168.25$2,050.00$736.111.0.544000128yesDefaultno
@technoviolet2640v3 Test 1Ubuntu 20.04.2 LTS Diskless (PXE)Supermicro SYS-1028R-TDW2 x Intel Xeon E5-2640v31809464GB DDR4 @18662 x 960GB Samsung PM983 (MDADM R-0, XFS), 1 x 500GB EVO850 Destination10,49726,423.00440.47.34101.330.230182.59150.01$1,088.00$420.3164096128yesdefaultno
@fiveanglepedotFedora 34 Server betaHP DL380 G7/HP 410i/LSI 9201-16e2x Intel® Xeon® Processor X56501045796GB DDR3 1333 ECC5x Nytro Warpdrive/Oracle F40 (20x100GB) in LVM 4x5R014,00041,000.00683.311.39101.330.1483122.50250.92$
@eastcoastserversSupermicro 216Server 2019Supermicro X9Dri-f LSI 9400-8iDual Xeon E5-2697 V224139128GB DDR3 160024 x Seagate ST600MM000627,75684,767.001,412.823.55101.330.0717242.42105.15$2,750.00$1,136.051024000128nodefault
@thecryptodrewNeedleUbuntu 20.04.2ASUS ROG STRIX B550-iAMD Ryzen 9 5900X / CM Hyper 2123947332GB DDR4 3200MHz2x 2TB Inland m.2 NVMe (mdadm raid-0, XFS)11,19628,044.00467.47.79101.330.216872.1356.69$1,650.00$773.171.1.523200128yesDefaultno
@flamingoi9-9900Ubuntu LTS 20.04.2Asus rog strix z390-i gamingi9-99001709732GB DDR4 @32002 x WD Black SN750 M.2 NVMe SSD – 1TB9,96925,033.00417.26.95101.330.242962.05125.68$1,200.00$585.5944000128nodefaultno
@technoviolet2640v3 Test 3Ubuntu 20.04.2 LTS Diskless (PXE)Supermicro SYS-1028R-TDW2 x Intel Xeon E5-2640v31809464GB DDR4 @18662 x 960GB Samsung PM983 (MDADM R-0, XFS, ZRAM LOG), 1 x 500GB EVO850 Destination10,40025,623.00427.17.12101.330.237362.00116.02$1,088.00$543.4564096128yesdefaultno
@rs967MSI Z490 + i7Windows 10 HomeMSI Z490-A ProIntel i7-10700K 8-Core 16-Thread OC 4.2GHzNA32GB DDR4 36001x Inland Premium 2TB m.2 NVMe SSD11,74727,388.72456.57.61101.330.222061.870.00$2,500.00$1,334.781.0.535000128noDefaultno
@Crypt4lifeVulkanWindows 10Asus TUF GAMING B550-PLUSAMD Ryzen 7 5800x 8-Core1927532GB DDR4 @ 30001 X 1TB SSD NVME10,33324,044.00400.76.67101.330.252951.7896.85$1,450.00$814.471.1.358000128yesdefaultno
@toyBudget buildUbuntu 20.04.2Asus Gaming B550 PlusRyzen 2700x OC @ 4.15 GHZ1759764GB DDR4 @ 32002x 2TB NVME 1x 3,8TB NVME8,45725,202.00420.07.00101.330.241251.70101.08$1,500.00$884.311.1.343408128yesdefaultno
@eparrotLenovo ThinkStation (mini)Ubuntu Server 20.04.1Lenovo 314FIntel i7 9700 (8 core, 8 thread)1348632GB DDR4Inland Premium 2TB NVMe10,65025,300.00421.77.03101.330.240351.69131.38$700.00$414.271.0.423400128yesdefaultno
@fiveanglehyperiaFedora 34 Server betaMSI B450 Gaming AC PlusAMD Ryzen™ 5 36001786516/32GB DDR4 3200 MT/s2x 900GB (Samsung PM953 2TB, Micron 5210 4TB) R0, 1x Micron M500DC13,50037,000.00616.710.28101.330.164361.3981.38$650.00$468.831.1.559750128yesdefaultno
@syolConsumer gamingUbuntu Desktop 20.04.1Asus P8Z77-V DELUXEi7-3770k OC 3.9GHzNA32GB DDR3 1600Samsung 970 EVO Plus 1TB NVMe XFS 2x500GB & WD Bleu SN550 1 TB NVMe XFS 2x500GB14,00032,090.00534.88.91101.330.189541.
@guiserNUC i7Ubuntu Server 20.04.1NUC10i7FNHCIntel i7-10710U 6-Core 12-Thread1010332GB DDR4 2666 SO-DIMM1x 1TB Seagate Firecuda 520 NVMe8,91624,807.00413.56.89101.330.245131.03107.31$1,500.00$1,450.751.0.426000128noDefaultyes
@maggelWorkstationWindows 10 Pro WSL2 Ubuntu 20.04Pro WS X570-ACEAMD Ryzen 5900X39473128GB DDR4 3200Intel P3600 XFS14,97041,500.00691.711.53101.330.146530.6216.42
@n418ASRockWindows 10 ProASRock B550M Steel LegendAMD Ryzen 9 5900X 12-Core Processor39473128GB DDR4 3200Sabrent 2TB PCIe 4.0×4 NVMe SSD20,82069,500.001,158.319.31429.870.371110.5213.86264noDefault
@eparrotCyberpower GamemasterWindows 10 HomeASRock B360M Xtremei5-9400F 2.90GHz954016GB DDR4Inland Premium 1TB SSD NVMe6,84318,184.00303.15.05101.330.334410.4751.68$1,000.00$2,126.791.0.443400128YesDefaultno
@guiserNUC i7Ubuntu Server 20.04.1NUC10i7FNHCIntel i7-10710U 6-Core 12-Thread1010332GB DDR4 2666 SO-DIMM1x 1TB Seagate Firecuda 520 NVMe7,77719,388.22323.15.39101.330.313610.4445.77$1,500.00$3,401.551.0.424000128noDefaultno
@DattJCMsi X570Windows 10 2H20MSI X570 MAGRyzen 9 3900X 12-Core 24-Threads329012x 16, 32GB DDR4 @36001 x SN850 1TB M.27,05621,664.65361.16.02101.330.280610.3912.58$3,300.00$8,362.071.1.5126750128nodefaultno
@rs967Basic Rig 2Ubuntu LTS 20.04.1Gigabyte Ultra-Durable 3Intel i5-2400 2-Core 4-Thread38168GB DDR3 13331x WD Green 500GB Hard Drive20,00076,000.001,266.721.11101.330.080010.1130.91$150.00$1,333.381.0.536000128noDefaultno
@toyTimegimpUbuntu 21.04MSI B550 UnifyRyzen 5950x /Noctua NH-D15 @4.646097128GB DDR4 @ 36004x 2TB NVME mp510 1x 3,8TB NVME Micron 9200Series9,21222,184.00369.76.16101.330.2741249.25210.4025000128yesDefaultno
@technovioletRyzen Test 1Ubuntu 20.04.2 LTS Diskless (PXE)ASRock Taichi X570Ryzen 5950x4609764GB DDR4 @36004 x 1TB Inland Premium (MDADM R-0, XFS), 2 x 250GB EVO850 Destination00.000.00.00101.330.0000120.000.00$1,973.00124096128yesdefaultno
@technovioletRyzen Test 2Ubuntu 20.04.2 LTS Diskless (PXE)ASRock Taichi X570Ryzen 5950x4609764GB DDR4 @360018 x HUSMH8020BSS204 200GB SAS-12K (MDADM R-0, XFS) 2 x 250GB EVO850 Destinationgathering data for 24hr101.330.00000.000.00$2,087.0064096128yesdefaultno
@toyUbuntu 21.04MSI B550 UnifyRyzen 5900x /Noctua NH-D1539473128GB DDR4 @ 36004x 2TB NVME mp5107,92419,542.00325.75.43101.330.3111187.88209.2025000128yesDefaultno
@zignzign-desk01Windows 10AsRock Z370i9 9900kNA32GB DDR4 @ 36001x ADATA SX8100NP 2TB + Seagate FireCuda 510 SSD 1TB11,19334,748.00579.19.65101.330.175092.
(user)Chia Plotting Performance

SSD Endurance

Estimated SSD wear out, endurance table

There are various approaches to picking a great plotting SSD, and a lot will depend on the physical system it is going into for form factor and interface compatibility (NVMe/PCIe, SATA, or SAS). The one thing in common will be that you need high endurance, due to the fact that it take almost ~1.8TB of writes using the -e flag or 1.6TB without that option to create a single K=32 plot.

Endurance is how much data can be written to the SSD before it wears out. In Chia this is important because a plotting SSD will generally be at 100% duty cycle and writing all day.

A mixed use or high endurance data center or enterprise SSD is the best choice for plotting. Used SSDs with plenty of endurance can be found for a good value on eBay, Craigslist, or similar.

Consumer NVMe SSDs are generally not recommended due to the lower endurance, and they often employ caching algorithms to faster media (SLC, or single level cell) for great bursty performance. They do not perform well under heavy workload sustained IO. There are very high performance consumer NVMe SSDs that will offer great plotting performance, but the lower rated endurance in TBW will result in a faster wearout.

VendorModelForm FactorInterfaceClass$ASP$/GBUser Capacity (GB):usable GiB in OSSpec sheet rated TBWtotal plots, worst, (TiB)total plots, best, (TiB)$/TiB, worst$/TiB, best
IntelP3700U.2 & AICNVMeenterprise mixed use$250.00$0.1616001455.54380019532930$0.13$0.09
IntelP3600U.2 & AICNVMeenterprise mixed use$140.00$0.0916001455.58760391977$0.36$0.14
IntelP4600U.2 & AICNVMeenterprise mixed use$352.00$0.1132002910.91820013562441$0.26$0.14
IntelP3600U.2 & AICNVMeenterprise mixed use$116.00$0.1012001091.66570297742$0.39$0.16
IntelP3600U.2 & AICNVMeenterprise mixed use$115.00$0.1012001091.66570293732$0.39$0.16
IntelP4600U.2 & AICNVMeenterprise mixed use$176.00$0.1116001455.58990407732$0.43$0.24
IntelP4600U.2 & AICNVMeenterprise mixed use$220.00$0.1120001819.311080509916$0.43$0.24
IntelP3700U.2 & AICNVMeenterprise mixed use$120.00$0.30400363.97300332498$0.36$0.24
Micron5300 MaxSATA 2.5inSATAenterprise SATA$307.20$0.1619201746.6175205571270$0.55$0.24
Micron5300 MaxSATA 2.5inSATAenterprise SATA$614.40$0.1638403493.12452811142539$0.55$0.24
IntelS4610SATA 2.5inSATAenterprise mixed use$144.00$0.15960873.35800266586$0.54$0.25
Micron5300 ProSATA 2.5inSATAenterprise SATA$249.60$0.1319201746.652562001000$1.25$0.25
Micron5300 ProSATA 2.5inSATAenterprise SATA$499.20$0.1338403493.184104002000$1.25$0.25
SamsungPM1725bU.2 & AICNVMeenterprise mixed use$267.00$0.1716001455.587604001000$0.67$0.27
Micron9300 ProU.2NVMeenterprise$1,152.00$0.1576806986.3168007274000$1.58$0.29
Micron9300 ProU.2NVMeenterprise$576.00$0.1538403493.184003642000$1.58$0.29
IntelP4610U.2NVMeenterprise mixed use$300.00$0.1916001455.5106134301031$0.70$0.29
SamsungPM983U.2 and M.2NVMedata center$110.00$0.11960873.31366.5663350$1.76$0.31
SamsungPM983U.2 and M.2NVMedata center$225.00$0.1219201746.62733.12125700$1.80$0.32
IntelS3710SATA 2.5inSATAenterprise mixed use$68.00$0.17400363.98300137205$0.50$0.33
ToshibaPX04SVQ2.5in SASSAS 12Gbpsenterprise SAS$380.00$0.2416001455.587603981074$0.96$0.35
InlandInland Premium 1TB SSDM.2NVMeclient mainstream$125.00$0.121024931.5160073350$1.72$0.36
Micron9300U.2NVMedata center$768.00$0.2038403493.184003642000$2.11$0.38
Micron9300 MaxU.2NVMeenterprise$1,600.00$0.2564005821.93730016504125$0.97$0.39
Micron9300 MaxU.2NVMeenterprise$800.00$0.2532002910.9186008252063$0.97$0.39
IntelS4600SATA 2.5inSATAenterprise mixed use$96.00$0.20480436.62950104188$0.92$0.51
IntelP4510U.2NVMedata center$400.00$0.2020001819.32054115516$3.49$0.78
WDSN750M.2NVMeclient mainstream$60.00$0.12500454.83001475$4.40$0.80
WDSN750M.2NVMeclient mainstream$120.00$0.121000909.760027150$4.40$0.80
SeagateNitro 1551SATA 2.5inSATAdata center SATA$255.00$0.27960873.32390102305$2.51$0.84
Samsung970 EvoM.2NVMeclient maintream$163.84$0.161024931.560030150$5.46$1.09
IntelP4800XU.2 & AICNVMeenterprise$2,062.50$2.75750682.34100018311831$1.13$1.13
Samsung970 ProM.2NVMeclient high end$307.20$0.301024931.5120050250$6.14$1.23
Intel905pU.2 and M.2NVMeclinet high end$1,152.00$1.20960873.317520938938$1.23$1.23
Intel665pM.2NVMeclient mainstream$102.40$0.101024931.53001575$6.83$1.37
IntelP4800XU.2 & AICNVMeenterprise$2,062.50$5.50375341.141000916916$2.25$2.25
Intel660pM.2NVMeclient mainstream$122.88$0.121024931.52001050$12.29$2.46

estimated GiB per minute based off class of drives for drives that have yet to be tested, for the drives in the wiki I have added the measured numbers.


  • NAND P/E Cycles = amount of program / erase cycles NAND can do before wearing out. NAND programs (writes) in pages and erases in blocks (contains many pages)
  • Wearing out – SSD no longer meeting UBER (uncorrectable bit error rate), retention (keeping data safe while powered off), failure rate, or user capacity
  • UBER = number of data errors / number of bits read
  • WAF (Write Amplification Factor) = NAND writes / host writes
  • TBW or PBW – amount of host writes to SSD before wearing out
  • TBW = drive capacity * cycles / WAF
  • DWPD (drive writes per day): amount of data you can write to device each day of the warranty (typically 5 years) without wearing out
  • DWPD = TBW/365/5/drive capacity

Monitor Endurance in Linux


Reading endurance with NVMe-CLI – this is the gas gauge that shows total endurance used

sudo nvme smart-log /dev/nvme0 | grep percentage_used

Reading amount of writes that the drive have actually done

sudo nvme smart-log /dev/nvme0 | grep data_units_written

Bytes written = output * 1000 * 512B

TBW = output * 1000 * 512B / (1000^4) or (1024^4)

To find out NAND writes, you will have use the vendor plugins for NVMe-CLI.

sudo nvme <vendor name> help

Example with an Intel SSD

sudo nvme intel smart-log-add /dev/nvme0


In SATA you can use the following commands

sudo apt install smartmontools

sudo smartctl -x /dev/sda | grep Logical

sudo smartctl -a /dev/sda

looking for Media_Wearout_Indicator

note this does also work for NVMe for basic SMART health info

sudo smartctl -a /dev/nvme0


sg_logs /dev/sg1 --page=0x11

look for

Percentage used endurance indicator: 0%

How to Check If Everything is Working (or Not)

This doc assumes you know how to use the CLI. Using the CLI is the best way to troubleshoot (and to do everything Chia too). The Quick Start Guide and CLI Commands Reference have useful info to get you familiar with the CLI.

Where to Find Things

The file structure for Linux, macOS, and Windows versions of Chia are similar.

├─ .chia/
│   └── mainnet/
│      ├─ config/
│      │      ├─ config.yaml
│      │      └─ ssl/
│      │            └─ (and more...)
│      ├─ db/
│      ├─ log/
│      │      └─ debug.log
│      ├─ run/
│      │      └─ (and more...)
│      └─ wallet/
│             └─ (and more...)
└── /chia-blockchain
       └─ (and more...)

Linux & macOS

  • Chia config: ~/.chia/mainnet/config/config.yaml
  • Chia logs: ~/.chia/mainnet/log/


  • Chia config: C:\Users\%USERNAME%\.chia\mainnet\config\config.yaml
  • Chia logs: C:\Users\%USERNAME%\.chia\mainnet\log\


In config.yaml you can set the level of detail for your logs.

Look for this section in config.yaml. It’s useful to change the logger setting log_level from WARNING to INFO to get the detail needed to troubleshoot.

logging: &id001
    log_filename: log/debug.log
    log_level: INFO
    log_stdout: false

You can run grep (LinuxmacOS) or Select-String (Windows) to search through your logs for relevant information.

Is It Working?

If you want to quickly find errors, run this:

  • Linux/macOS: cat ~/.chia/mainnet/log/debug.log | grep -i 'error'
  • Windows: Get-Content -Path "~\.chia\mainnet\log\debug.log" | Select-String -Pattern "error"


The time it takes to do a proof challenge should be below 30 seconds. If you see higher times, something is wrong with your setup.

Here are some commands you can use to examine debug.log for problems.

  • Linux/macOS: tail ~/.chia/mainnet/log/debug.log | grep eligible
  • Windows:
    • Select-String -Path “~\.chia\mainnet\log\debug*” -Pattern “eligible”
    • Select-String -Path “~\.chia\mainnet\log\debug*” -Pattern “Found [^0] proof”
    • Select-String -Path “~\.chia\mainnet\log\debug*” -Pattern “Farmed unfinished_block”
    • Get-Content -Path "~\.chia\mainnet\log\debug.log" -Wait | Select-String -Pattern "found"


You can find the documentation for the check command on the CLI Commands Reference – check page

  • To check all your plots, run chia plots check. This will check all directories you have listed in your config.yaml to contain plots.
  • Use chia plots check -h to see the options for this command

Windows Tips and Tricks

In Windows, you can use the chia CLI from Windows PowerShell, allowing you more flexibility and control. PowerShell is a program where you type commands, press enter, and do things like changing folders, moving files, or running programs, like chia.

1. Parallel plotting using PowerShell

    cd $env:userprofile\AppData\Local\Chia-Blockchain\app-1.1.5\resources\app.asar.unpacked\daemon\
    start-process .\chia.exe -argumentlist "plots create yourParametersGoHere"
    start-process ....

If start-process doesn’t work, try .\chia.exe plots create yourParametersGoHere instead.

Or add the path "%USERPROFILE%\AppData\Local\chia-blockchain\app-1.1.5\resources\app.asar.unpacked\daemon" to the path user variable, this way you can execute chia commands, only using “chia” in a command window.

To add a delay between your parallel processes, you can put a sleep <seconds> between each chia plots create command, e.g. sleep 3600 to delay the next process by an hour.

A specific example:

    cd $env:userprofile\AppData\Local\Chia-Blockchain\app-1.1.5\resources\app.asar.unpacked\daemon\
    start-process ./chia.exe -argumentlist "plots create -k 32 -b 4000 -u 128 -r 4 -t d:\tempdrive1 -2 e:\tempdrive2 -d F:\plots -n 1"

The command above makes one plot (specified by -n 1), to plot in parallel you need to repeat the command (without closing the first one). Increase the -n value for sequential plotting, i.e. once the 1st plot is completed, the next is started.

Reminder: Manually Add logging when plotting in PowerShell

When plotting with the GUI, the plotter will write logs in \mainnet\plotter for each plot. Many third party tools (such as the excellent Chia Plot Status) rely on the logs for their information reporting. One way to have manual logs when plotting from CLI is to use the built in “tee” command like this:

.\chia.exe plots create -k 32 -n 2 -u 128 -t G:\ChiaTemp -d O:\Chia8O -r 2 -n 5 | tee -filepath $env:userprofile\.chia\mainnet\plotter\plots-5-6-2021-B.txt

2. Take a good look at log files

Your configuration and logs are found in ~\.chia\mainnet\log and ~\.chia\mainnet\config. You can tail your logs with Get-Content ~\.chia\mainnet\log\debug.log -wait. To see more of what is going on, set your log level in config\config.yaml to INFO from WARNING and restart. You can also use \.chia.exe configure --set-log-level INFO from the app directory outlined above and then restart for the changes to take effect.

3. Windows (auto) Update can be a pain

Consider going through a Windows Update check and install updates prior to starting a plot process. It can take a while, and updates might initiate a reboot. You can also go into Advanced Options to disable updates for up to 35 days at a time.

4. Disable uPnP when running multiple nodes

If you attempt to run more than one node on your local network, having uPnP on on both will cause both nodes significant confusion. You will need to use powershell to disable uPnP on all but one.

For version 1.0:

    cd $env:userprofile\AppData\Local\Chia-Blockchain\app-1.1.5\resources\app.asar.unpacked\daemon\
    ./chia.exe configure --enable-upnp false

5. Forever “Connecting to wallet”

Sometimes your wallet database can get corrupted. If you get stuck on the “Connecting to wallet” spinner for more than 60 seconds, you will probably want to exit the app, delete your wallet database with Powershell, and then start the app again.

For version 1.0.x:

    del ~\.chia\mainnet\wallet\db\blockchain*

6. Periodic pause during plotting (PowerShell)

If your PowerShell plotting processes seem to pause, you should disable Quick Edit. Powershell -> Properties -> Options: Disable quick edit.

If you are still seeing this symptom it is almost always a problem with your RAM.

7. Leave free space on your drive

If you end up having your HDD or SSD have any issues that require disk repair, you will need to have free space on the disk that is larger than the largest file. For k32 plots, you will need to leave > 101 GB. This way, if your plots ever have errors (as reported by plot check tool), you will at least be able to try to repair them with CHKDSK /r. However, CHKDSK cannot repair files that are larger than the remaining free space on a drive, and will have an error