{"id":13746465,"url":"https://github.com/Chia-Network/pool-reference","last_synced_at":"2025-05-09T07:30:41.422Z","repository":{"id":38789123,"uuid":"367550334","full_name":"Chia-Network/pool-reference","owner":"Chia-Network","description":"Reference python implementation of Chia pool operations for pool operators","archived":false,"fork":false,"pushed_at":"2025-04-17T16:12:33.000Z","size":289,"stargazers_count":436,"open_issues_count":20,"forks_count":197,"subscribers_count":73,"default_branch":"main","last_synced_at":"2025-04-18T06:49:48.330Z","etag":null,"topics":["blockchain","chia","chia-blockchain","chialisp","cryptocurrency","pool","pooling"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Chia-Network.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-05-15T05:46:46.000Z","updated_at":"2025-04-17T16:12:35.000Z","dependencies_parsed_at":"2024-05-30T22:45:42.584Z","dependency_job_id":"591f0029-4622-4c34-a4fd-b2d8357558a2","html_url":"https://github.com/Chia-Network/pool-reference","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chia-Network%2Fpool-reference","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chia-Network%2Fpool-reference/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chia-Network%2Fpool-reference/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Chia-Network%2Fpool-reference/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Chia-Network","download_url":"https://codeload.github.com/Chia-Network/pool-reference/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253209251,"owners_count":21871618,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","chia","chia-blockchain","chialisp","cryptocurrency","pool","pooling"],"created_at":"2024-08-03T06:00:54.068Z","updated_at":"2025-05-09T07:30:41.405Z","avatar_url":"https://github.com/Chia-Network.png","language":"Python","funding_links":[],"categories":["Smart Contract Platforms"],"sub_categories":[],"readme":"## Pool Reference V1\nThis code is provided under the Apache 2.0 license.\nNote: the draft specification is in the SPECIFICATION.md file.\n\n### Summary\nThis repository provides a sample server written in python, which is meant to serve as a basis for a Chia Pool.\nWhile this is a fully functional implementation, it requires some work in scalability and security to run in production.\nAn FAQ is provided here: https://github.com/Chia-Network/chia-blockchain/wiki/Pooling-FAQ\n\n\n### Customizing\nSeveral things are customizable in this pool reference. This includes:\n* How long the timeout is for leaving the pool\n* How difficulty adjustment happens\n* Fees to take, and how much to pay in blockchain fees  \n* How farmers' points are counted when paying (PPS, PPLNS, etc)\n* How farmers receive payouts (XCH, BTC, ETH, etc), and how often\n* What store (DB) is used - by default it's an SQLite db. Users can use their own store implementations, based on \n  `AbstractPoolStore`, by supplying them to `pool_server.start_pool_server`\n* What happens (in terms of response) after a successful login\n\nHowever, some things cannot be changed. These are described in SPECIFICATION.md, and mostly relate to validation,\nprotocol, and the singleton format for smart coins. \n\n### Pool Protocol Benefits\nThe Chia pool protocol has been designed for security, and decentralization, not relying on any 3rd party, closed code,\nor trusted behaviour. \n\n* The farmer can never steal from the pool by double farming\n* The farmer does not need collateral to join a pool, they only need a few cents to create a singleton\n* The farmer can easily and securely change pools if they want to\n* The farmer can run a full node (increasing decentralization)\n* The farmer can log into another computer with only the 24 words, and the pooling configuration is detected, without\nrequiring a central server\n\n### Pool Protocol Summary\nWhen not pooling, farmers receive signage points from full nodes every 9 seconds, and send these signage points to the\nharvester. Each signage point is sent along with the `sub_slot_iters` and `difficulty`, two network-wide parameters\nwhich are adjusted every day (4608 blocks). The `sub_slot_iters` is the number of VDF iterations performed in 10\nminutes for the fastest VDF in the network. This increases if the fastest timelord's speed increases. The difficulty\nis similarly affected by timelord speed (it goes up when timelord speed increases, since blocks come faster), but \nit's also affected by the total amount of space in the network. These two parameters determine how difficult it is\nto \"win\" a block and find a proof.\n\nSince only about 1 farmer worldwide finds a proof every 18.75 seconds, this means the chances of finding one are \nextremely small, with the default `difficulty` and `sub_slot_iters`. For pooling, what we do is we increase the \n`sub_slot_iters` to a constant, but very high number: 37600000000, and then we decrease the difficulty to an\nartificially lower one, so that proofs can be found more frequently.\n\nThe farmer communicates with one or several pools through an HTTPS protocol, and sets their own local difficulty for\neach pool. Then, when sending signage points to the harvester, the pool `difficulty` and `sub_slot_iters` are used. \nThis means that the farmer can find proofs very often, perhaps every 10 minutes, even for small farmers. These proofs,\nhowever, are not sent to the full node to create a block. They are instead only sent to the pool. This means that the \nother full nodes in the network do not have to see and validate everyone else's proofs, and the network can scale to\nmillions of farmers with no issue, as long as the pool scales properly. Since many farmers are part of the pool,\nonly 1 farmer needs to win a block, for the entire pool to be rewarded proportionally to their space.\n\nThe pool then keeps track of how many proofs (partials) each farmer sends, weighing them by difficulty. Occasionally \n(for example every 3 days), the pool can perform a payout to farmers based on how many partials they submitted. Farmers\nwith more space, and thus more points, will get linearly more rewards. \n\nInstead of farmers using a `pool_public_key` when plotting, they now use a puzzle hash, referred to as the \n`p2_singleton_puzzle_hash`, also known as the `pool_contract_address`. These values go into the plot itself, and \ncannot be changed after creating the plot, since they are hashed into the `plot_id`. The pool contract address is the\naddress of a chialisp contract called a singleton. The farmer must first create a singleton on the blockchain, which\nstores the pool information of the pool that that singleton is assigned to. When making a plot, the address of that\nsingleton is used, and therefore that plot is tied to that singleton forever. When a block is found by the farmer, \nthe pool portion of the block rewards (7/8, or 1.75XCH) go into the singleton, and when claimed, \ngo directly to the pool's target address. \n\nThe farmer can also configure their payout instructions, so that the pool knows where to send the occasional rewards\nto.\n\n\n### Receiving partials\nA partial is a proof of space with some additional metadata and authentication info from the farmer, which\nmeets certain minimum difficulty requirements. Partials must be real proofs of space responding to blockchain signage\npoints, and they must be submitted within the blockchain time window (28 seconds after the signage point).\n\nThe pool server works by receiving partials from the users, validating that they are correct and correspond to a valid\nsignage point on the blockchain, and then adding them to a queue. A few minutes later, the pool pulls from the\nqueue, and checks that the signage point for that partial is still in the blockchain. If everything is good, the\npartial is counted as valid, and the points are added for that farmer.\n\n\n### Collecting pool rewards\n![Pool absorbing rewards image](images/absorb.png?raw=true \"Absorbing rewards\")\n\nThe pool periodically searches the blockchain for new pool rewards (1.75 XCH) that go to the various\n`p2_singleton_puzzle_hashes` of each of the farmers. These coins are locked, and can only be spent if they are spent\nalong with the singleton that they correspond to. The singleton is also locked to a `target_puzzle_hash`, which in\nthis diagram is the red pool address. Anyone can spend the singleton and the `p2_singleton_puzzle_hash` coin, as \nlong as it's a block reward, and all the conditions are met. Some of these conditions require that the singleton\nalways create exactly 1 new child singleton with the same launcher id, and that the coinbase funds are sent to the \n`target_puzzle_hash`.\n\n### Calculating farmer rewards\n\nPeriodically (for example once a day), the pool executes the code in `create_payment_loop`. This first sums up all the \nconfirmed funds in the pool that have a certain number of confirmations.\n\nThen, the pool divides the total amount by the points of all pool members, to obtain the `mojo_per_point` (minus the pool fee\nand the blockchain fee). A new coin gets created for each pool member (and for the pool), and the payments are added\nto the pending_payments list. Note that since blocks have a maximum size, we have to limit the size of each transaction.\nThere is a configurable parameter: `max_additions_per_transaction`. After adding the payments to the pending list,\nthe pool members' points are all reset to zero. This logic can be customized.\n\n\n### 1/8 vs 7/8\nNote that the coinbase rewards in Chia are divided into two coins: the farmer coin and the pool coin. The farmer coin\n(1/8) only goes to the puzzle hash signed by the farmer private key, while the pool coin (7/8) goes to the pool.\nThe user transaction fees on the blockchain are included in the farmer coin as well. This split of 7/8 1/8 exists\nto prevent attacks where one pool tries to destroy another by farming partials, but never submitting winning blocks.\n\n### Difficulty\nThe difficulty allows the pool operator to control how many partials per day they are receiving from each farmer.\nThe difficulty can be adjusted separately for each farmer. A reasonable target would be 300 partials per day,\nto ensure frequent feedback to the farmer, and low variability.\nA difficulty of 1 results in approximately 10 partials per day per k32 plot. This is the minimum difficulty that\nthe V1 of the protocol supports is 1. However, a pool may set a higher minimum difficulty for efficiency. When\ncalculating whether a proof is high quality enough for being awarded points, the pool should use\n`sub_slot_iters=37600000000`.\nIf the farmer submits a proof that is not good enough for the current difficulty, the pool should respond by setting\nthe `current_difficulty` in the response.\n\n### Points\nX points are awarded for submitting a partial with difficulty X, which means that points scale linearly with difficulty.\nFor example, 100 TiB of space should yield approximately 10,000 points per day, whether the difficulty is set to\n100 or 200. It should not matter what difficulty is set for a farmer, as long as they are consistently submitting partials.\nThe specification does not require pools to pay out proportionally by points, but the payout scheme should be clear to\nfarmers, and points should be acknowledged and accumulated points returned in the response.\n\n\n### Difficulty adjustment algorithm\nThis is a simple difficulty adjustment algorithm executed by the pool. The pool can also improve this or change it\nhowever they wish. The farmer can provide their own `suggested_difficulty`, and the pool can decide whether or not\nto update that farmer's difficulty. Be careful to only accept the latest authentication_public_key when setting\ndifficulty or pool payout info. The initial reference client and pool do not use the `suggested_difficulty`.\n\n- Obtain the last successful partial for this launcher id\n- If \u003e 3 hours, divide difficulty by 5\n- If \u003e 45 minutes \u003c 6 hours, divide difficulty by 1.5\n- If \u003c 45 minutes:\n   - If have \u003c 300 partials at this difficulty, maintain same difficulty\n   - Else, multiply the difficulty by (24 * 3600 / (time taken for 300 partials))\n\nThe 6 hours is used to handle rare cases where a farmer's storage drops dramatically. The 45 minutes is similar, but\nfor less extreme cases. Finally, the last case of \u003c 45 minutes should properly handle users with increasing space,\nor slightly decreasing space. This targets 300 partials per day, but different numbers can be used based on\nperformance and user preference.\n\n### Making payments\nNote that the payout info is provided with each partial. The user can choose where rewards are paid out to, and this\ndoes not have to be an XCH address. The pool should ONLY update the payout info for successful partials with the\nlatest seen authentication key for that launcher_id.\n\n\n### Install and run (Testnet)\nTo run a pool, you must use this along with the main branch of `chia-blockchain`.\n\n1. Checkout the `main` branch of `chia-blockchain`, and install it. Checkout this repo in another directory next to (not inside) `chia-blockchain`.\nIf you want to connect to testnet, use `export CHIA_ROOT=~/.chia/testnet9`, or whichever testnet you want to join, and\n   run `chia configure -t true`. You can also directly use the `pools.testnet9` branch, although this branch will\n   be removed in the future (or past).\n\n2. Create three keys, one which will be used for the block rewards from the blockchain, one to receive the pool fee that is kept by the pool, and the third to be a wallet that acts as a test user.\n\n3. Change the `wallet_fingerprint` and `wallet_id` in the `config.yaml` config file, using the information from the first\nkey you created in step 2. These can be obtained by doing `chia wallet show`.\n\n4. Do `chia keys show` and get the first address for each of the keys created in step 2. Put these into the `config.yaml`\nconfig file in `default_target_address` and `pool_fee_address` respectively.\n\n5. Change the `pool_url` in `config.yaml` to point to your external ip or hostname.\n   This must match exactly with what the user enters into their UI or CLI, and must start with https://.\n\n6. Start the node using `chia start farmer`, and log in to a different key (not the two keys created for the pool).\nThis will be referred to as the farmer's key here. Sync up your wallet on testnet for the farmer key.\nYou can log in to a key by running `chia wallet show` and then choosing each wallet in turn, to make them start syncing.\n\n7. Create a venv (different from chia-blockchain) and start the pool server using the following commands:\n\n```\ncd pool-reference\npython3 -m venv ./venv\nsource ./venv/bin/activate\npip install ../chia-blockchain/ \nsudo CHIA_ROOT=\"/your/home/dir/.chia/testnet9\" ./venv/bin/python -m pool\n```\n\nYou should see something like this when starting, but no errors:\n```\nINFO:root:Logging in: {'fingerprint': 2164248527, 'success': True}\nINFO:root:Obtaining balance: {'confirmed_wallet_balance': 0, 'max_send_amount': 0, 'pending_change': 0, 'pending_coin_removal_count': 0, 'spendable_balance': 0, 'unconfirmed_wallet_balance': 0, 'unspent_coin_count': 0, 'wallet_id': 1}\n```\n\n8. Create a pool nft (on the farmer key) by doing `chia plotnft create -s pool -u https://127.0.0.1:80`, or whatever host:port you want\nto use for your pool. Approve it and wait for transaction confirmation. This url must match *exactly* with what the\n   pool uses.\n\n9. Do `chia plotnft show` to ensure that your plotnft is created. Now start making some plots for this pool nft.\nYou can make plots by specifying the -c argument in `chia plots create`. Make sure to *not* use the `-p` argument. The\n    value you should use for -c is the `P2 singleton address` from `chia plotnft show` output.\n You can start with small k25 plots and see if partials are submitted from the farmer to the pool server. The output\nwill be the following in the pool if everything is working:\n```\nINFO:root:Returning {'new_difficulty': 1963211364}, time: 0.017535686492919922 singleton: 0x1f8dab79a614a82f9834c8f395f5fe195ae020807169b71a10218b9788a7a573\n```\n\nPlease send a message to @sorgente711 on keybase if you have questions about the 9 steps explained above. All other questions\nshould be sent to the #pools channel in keybase.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChia-Network%2Fpool-reference","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FChia-Network%2Fpool-reference","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FChia-Network%2Fpool-reference/lists"}