diff --git a/book/src/.gitbook/assets/consensus.svg b/book/src/.gitbook/assets/consensus.svg
deleted file mode 100644
index 70a3235081..0000000000
--- a/book/src/.gitbook/assets/consensus.svg
+++ /dev/null
@@ -1,159 +0,0 @@
-
-
diff --git a/book/src/.gitbook/assets/economic_design_infl_230719.png b/book/src/.gitbook/assets/economic_design_infl_230719.png
deleted file mode 100644
index 2ce0958cc4..0000000000
Binary files a/book/src/.gitbook/assets/economic_design_infl_230719.png and /dev/null differ
diff --git a/book/src/.gitbook/assets/p_ex_schedule (1).png b/book/src/.gitbook/assets/p_ex_schedule (1).png
new file mode 100644
index 0000000000..beb4c0cc5c
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_schedule (1).png differ
diff --git a/book/src/.gitbook/assets/p_ex_schedule (2).png b/book/src/.gitbook/assets/p_ex_schedule (2).png
new file mode 100644
index 0000000000..beb4c0cc5c
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_schedule (2).png differ
diff --git a/book/src/.gitbook/assets/p_ex_schedule (3).png b/book/src/.gitbook/assets/p_ex_schedule (3).png
new file mode 100644
index 0000000000..beb4c0cc5c
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_schedule (3).png differ
diff --git a/book/src/.gitbook/assets/p_ex_schedule (4).png b/book/src/.gitbook/assets/p_ex_schedule (4).png
new file mode 100644
index 0000000000..beb4c0cc5c
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_schedule (4).png differ
diff --git a/book/src/.gitbook/assets/p_ex_supply (1).png b/book/src/.gitbook/assets/p_ex_supply (1).png
new file mode 100644
index 0000000000..3779849368
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_supply (1).png differ
diff --git a/book/src/.gitbook/assets/p_ex_supply (2).png b/book/src/.gitbook/assets/p_ex_supply (2).png
new file mode 100644
index 0000000000..3779849368
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_supply (2).png differ
diff --git a/book/src/.gitbook/assets/p_ex_supply (3).png b/book/src/.gitbook/assets/p_ex_supply (3).png
new file mode 100644
index 0000000000..3779849368
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_supply (3).png differ
diff --git a/book/src/.gitbook/assets/p_ex_supply (4).png b/book/src/.gitbook/assets/p_ex_supply (4).png
new file mode 100644
index 0000000000..3779849368
Binary files /dev/null and b/book/src/.gitbook/assets/p_ex_supply (4).png differ
diff --git a/book/src/.gitbook/assets/porep_reward.png b/book/src/.gitbook/assets/porep_reward.png
deleted file mode 100644
index 501cf29e1d..0000000000
Binary files a/book/src/.gitbook/assets/porep_reward.png and /dev/null differ
diff --git a/book/src/.gitbook/assets/validation_client_interest_rates.png b/book/src/.gitbook/assets/validation_client_interest_rates.png
deleted file mode 100644
index b17fdf0d39..0000000000
Binary files a/book/src/.gitbook/assets/validation_client_interest_rates.png and /dev/null differ
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index b1b92fade6..8a4827c376 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -1,93 +1,81 @@
-# Solana Architecture
+# Table of contents
-- [Introduction](introduction.md)
+* [Introduction](introduction.md)
+* [Terminology](terminology.md)
+* [Getting Started](getting-started/README.md)
+ * [Testnet Participation](getting-started/testnet-participation.md)
+ * [Example Client: Web Wallet](getting-started/webwallet.md)
+* [Programming Model](programs/README.md)
+ * [Example: Tic-Tac-Toe](programs/tictactoe.md)
+ * [Drones](programs/drones.md)
+* [A Solana Cluster](cluster/README.md)
+ * [Synchronization](cluster/synchronization.md)
+ * [Leader Rotation](cluster/leader-rotation.md)
+ * [Fork Generation](cluster/fork-generation.md)
+ * [Managing Forks](cluster/managing-forks.md)
+ * [Turbine Block Propagation](cluster/turbine-block-propagation.md)
+ * [Ledger Replication](cluster/ledger-replication.md)
+ * [Secure Vote Signing](cluster/vote-signing.md)
+ * [Stake Delegation and Rewards](cluster/stake-delegation-and-rewards.md)
+ * [Performance Metrics](cluster/performance-metrics.md)
+* [Anatomy of a Validator](validator/README.md)
+ * [TPU](validator/tpu.md)
+ * [TVU](validator/tvu/README.md)
+ * [Blocktree](validator/tvu/blocktree.md)
+ * [Gossip Service](validator/gossip.md)
+ * [The Runtime](validator/runtime.md)
+* [Anatomy of a Transaction](transaction.md)
+* [Running a Validator](running-validator/README.md)
+ * [Hardware Requirements](running-validator/validator-hardware.md)
+ * [Choosing a Testnet](running-validator/validator-testnet.md)
+ * [Installing the Validator Software](running-validator/validator-software.md)
+ * [Starting a Validator](running-validator/validator-start.md)
+ * [Staking](running-validator/validator-stake.md)
+ * [Monitoring a Validator](running-validator/validator-monitor.md)
+ * [Publishing Validator Info](running-validator/validator-info.md)
+ * [Troubleshooting](running-validator/validator-troubleshoot.md)
+ * [FAQ](running-validator/validator-faq.md)
+* [Running a Replicator](running-replicator.md)
+* [API Reference](api-reference/README.md)
+ * [Transaction](api-reference/transaction-api.md)
+ * [Instruction](api-reference/instruction-api.md)
+ * [Blockstreamer](api-reference/blockstreamer.md)
+ * [JSON RPC API](api-reference/jsonrpc-api.md)
+ * [JavaScript API](api-reference/javascript-api.md)
+ * [solana CLI](api-reference/cli.md)
+* [Accepted Design Proposals](proposals/README.md)
+ * [Ledger Replication](proposals/ledger-replication-to-implement.md)
+ * [Secure Vote Signing](proposals/vote-signing-to-implement.md)
+ * [Staking Rewards](proposals/staking-rewards.md)
+ * [Cluster Economics](proposals/ed_overview/README.md)
+ * [Validation-client Economics](proposals/ed_overview/ed_validation_client_economics/README.md)
+ * [State-validation Protocol-based Rewards](proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md)
+ * [State-validation Transaction Fees](proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md)
+ * [Replication-validation Transaction Fees](proposals/ed_overview/ed_validation_client_economics/ed_vce_replication_validation_transaction_fees.md)
+ * [Validation Stake Delegation](proposals/ed_overview/ed_validation_client_economics/ed_vce_validation_stake_delegation.md)
+ * [Replication-client Economics](proposals/ed_overview/ed_replication_client_economics/README.md)
+ * [Storage-replication Rewards](proposals/ed_overview/ed_replication_client_economics/ed_rce_storage_replication_rewards.md)
+ * [Replication-client Reward Auto-delegation](proposals/ed_overview/ed_replication_client_economics/ed_rce_replication_client_reward_auto_delegation.md)
+ * [Economic Sustainability](proposals/ed_overview/ed_economic_sustainability.md)
+ * [Attack Vectors](proposals/ed_overview/ed_attack_vectors.md)
+ * [Economic Design MVP](proposals/ed_overview/ed_mvp.md)
+ * [References](proposals/ed_overview/ed_references.md)
+ * [Cluster Test Framework](proposals/cluster-test-framework.md)
+ * [Validator](proposals/validator-proposal.md)
+ * [Simple Payment and State Verification](proposals/simple-payment-and-state-verification.md)
+ * [Cross-Program Invocation](proposals/cross-program-invocation.md)
+* [Implemented Design Proposals](implemented-proposals/README.md)
+ * [Blocktree](implemented-proposals/blocktree.md)
+ * [Cluster Software Installation and Updates](implemented-proposals/installer.md)
+ * [Deterministic Transaction Fees](implemented-proposals/transaction-fees.md)
+ * [Tower BFT](implemented-proposals/tower-bft.md)
+ * [Leader-to-Leader Transition](implemented-proposals/leader-leader-transition.md)
+ * [Leader-to-Validator Transition](implemented-proposals/leader-validator-transition.md)
+ * [Passive Stake Delegation and Rewards](implemented-proposals/passive-stake-delegation-and-rewards.md)
+ * [Persistent Account Storage](implemented-proposals/persistent-account-storage.md)
+ * [Reliable Vote Transmission](implemented-proposals/reliable-vote-transmission.md)
+ * [Repair Service](implemented-proposals/repair-service.md)
+ * [Testing Programs](implemented-proposals/testing-programs.md)
+ * [Credit-only Accounts](implemented-proposals/credit-only-credit-debit-accounts.md)
+ * [Embedding the Move Langauge](implemented-proposals/embedding-move.md)
-- [Terminology](terminology.md)
-
-- [Getting Started](getting-started.md)
- - [Testnet Participation](testnet-participation.md)
- - [Example Client: Web Wallet](webwallet.md)
-
-- [Programming Model](programs.md)
- - [Example: Tic-Tac-Toe](tictactoe.md)
- - [Drones](drones.md)
-
-- [A Solana Cluster](cluster.md)
- - [Synchronization](synchronization.md)
- - [Leader Rotation](leader-rotation.md)
- - [Fork Generation](fork-generation.md)
- - [Managing Forks](managing-forks.md)
- - [Turbine Block Propagation](turbine-block-propagation.md)
- - [Ledger Replication](ledger-replication.md)
- - [Secure Vote Signing](vote-signing.md)
- - [Stake Delegation and Rewards](stake-delegation-and-rewards.md)
- - [Performance Metrics](performance-metrics.md)
-
-- [Anatomy of a Validator](validator.md)
- - [TPU](tpu.md)
- - [TVU](tvu.md)
- - [Blocktree](blocktree.md)
- - [Gossip Service](gossip.md)
- - [The Runtime](runtime.md)
-
-- [Anatomy of a Transaction](transaction.md)
-
-- [Running a Validator](running-validator.md)
- - [Hardware Requirements](validator-hardware.md)
- - [Choosing a Testnet](validator-testnet.md)
- - [Installing the Validator Software](validator-software.md)
- - [Starting a Validator](validator-start.md)
- - [Staking](validator-stake.md)
- - [Monitoring a Validator](validator-monitor.md)
- - [Publishing Validator Info](validator-info.md)
- - [Troubleshooting](validator-troubleshoot.md)
- - [FAQ](validator-faq.md)
-
-- [Running a Replicator](running-replicator.md)
-
-- [API Reference](api-reference.md)
- - [Transaction](transaction-api.md)
- - [Instruction](instruction-api.md)
- - [Blockstreamer](blockstreamer.md)
- - [JSON RPC API](jsonrpc-api.md)
- - [JavaScript API](javascript-api.md)
- - [solana CLI](cli.md)
-
-- [Accepted Design Proposals](proposals.md)
- - [Ledger Replication](ledger-replication-to-implement.md)
- - [Secure Vote Signing](vote-signing-to-implement.md)
- - [Staking Rewards](staking-rewards.md)
- - [Cluster Test Framework](cluster-test-framework.md)
- - [Validator](validator-proposal.md)
- - [Simple Payment and State Verification](simple-payment-and-state-verification.md)
- - [Cross-Program Invocation](cross-program-invocation.md)
- - [Rent](rent.md)
- - [Inter-chain Transaction Verification](interchain-transaction-verification.md)
- - [Snapshot Verification](snapshot-verification.md)
-
-- [Implemented Design Proposals](implemented-proposals.md)
- - [Blocktree](blocktree.md)
- - [Cluster Software Installation and Updates](installer.md)
- - [Cluster Economics](ed_overview.md)
- - [Validation-client Economics](ed_validation_client_economics.md)
- - [State-validation Protocol-based Rewards](ed_vce_state_validation_protocol_based_rewards.md)
- - [State-validation Transaction Fees](ed_vce_state_validation_transaction_fees.md)
- - [Replication-validation Transaction Fees](ed_vce_replication_validation_transaction_fees.md)
- - [Validation Stake Delegation](ed_vce_validation_stake_delegation.md)
- - [Replication-client Economics](ed_replication_client_economics.md)
- - [Storage-replication Rewards](ed_rce_storage_replication_rewards.md)
- - [Replication-client Reward Auto-delegation](ed_rce_replication_client_reward_auto_delegation.md)
- - [Economic Sustainability](ed_economic_sustainability.md)
- - [Attack Vectors](ed_attack_vectors.md)
- - [Economic Design MVP](ed_mvp.md)
- - [References](ed_references.md)
- - [Deterministic Transaction Fees](transaction-fees.md)
- - [Tower BFT](tower-bft.md)
- - [Leader-to-Leader Transition](leader-leader-transition.md)
- - [Leader-to-Validator Transition](leader-validator-transition.md)
- - [Persistent Account Storage](persistent-account-storage.md)
- - [Reliable Vote Transmission](reliable-vote-transmission.md)
- - [Repair Service](repair-service.md)
- - [Testing Programs](testing-programs.md)
- - [Credit-only Accounts](credit-only-credit-debit-accounts.md)
- - [Embedding the Move Langauge](embedding-move.md)
diff --git a/book/src/api-reference/README.md b/book/src/api-reference/README.md
new file mode 100644
index 0000000000..583cbd2826
--- /dev/null
+++ b/book/src/api-reference/README.md
@@ -0,0 +1,4 @@
+# API Reference
+
+The following sections contain API references material you may find useful when developing applications utilizing a Solana cluster.
+
diff --git a/book/src/api-reference/blockstreamer.md b/book/src/api-reference/blockstreamer.md
new file mode 100644
index 0000000000..146073efef
--- /dev/null
+++ b/book/src/api-reference/blockstreamer.md
@@ -0,0 +1,28 @@
+# Blockstreamer
+
+Solana supports a node type called an _blockstreamer_. This fullnode variation is intended for applications that need to observe the data plane without participating in transaction validation or ledger replication.
+
+A blockstreamer runs without a vote signer, and can optionally stream ledger entries out to a Unix domain socket as they are processed. The JSON-RPC service still functions as on any other node.
+
+To run a blockstreamer, include the argument `no-signer` and \(optional\) `blockstream` socket location:
+
+```bash
+$ ./multinode-demo/validator-x.sh --no-signer --blockstream
+```
+
+The stream will output a series of JSON objects:
+
+* An Entry event JSON object is sent when each ledger entry is processed, with the following fields:
+ * `dt`, the system datetime, as RFC3339-formatted string
+ * `t`, the event type, always "entry"
+ * `s`, the slot height, as unsigned 64-bit integer
+ * `h`, the tick height, as unsigned 64-bit integer
+ * `entry`, the entry, as JSON object
+* A Block event JSON object is sent when a block is complete, with the following fields:
+ * `dt`, the system datetime, as RFC3339-formatted string
+ * `t`, the event type, always "block"
+ * `s`, the slot height, as unsigned 64-bit integer
+ * `h`, the tick height, as unsigned 64-bit integer
+ * `l`, the slot leader id, as base-58 encoded string
+ * `id`, the block id, as base-58 encoded string
+
diff --git a/book/src/api-reference/cli.md b/book/src/api-reference/cli.md
new file mode 100644
index 0000000000..65bcc8b5c0
--- /dev/null
+++ b/book/src/api-reference/cli.md
@@ -0,0 +1,370 @@
+# solana CLI
+
+The [solana-cli crate](https://crates.io/crates/solana-cli) provides a command-line interface tool for Solana
+
+## Examples
+
+### Get Pubkey
+
+```bash
+// Command
+$ solana address
+
+// Return
+
+```
+
+### Airdrop Lamports
+
+```bash
+// Command
+$ solana airdrop 123
+
+// Return
+"Your balance is: 123"
+```
+
+### Get Balance
+
+```bash
+// Command
+$ solana balance
+
+// Return
+"Your balance is: 123"
+```
+
+### Confirm Transaction
+
+```bash
+// Command
+$ solana confirm
+
+// Return
+"Confirmed" / "Not found" / "Transaction failed with error "
+```
+
+### Deploy program
+
+```bash
+// Command
+$ solana deploy
+
+// Return
+
+```
+
+### Unconditional Immediate Transfer
+
+```bash
+// Command
+$ solana pay 123
+
+// Return
+
+```
+
+### Post-Dated Transfer
+
+```bash
+// Command
+$ solana pay 123 \
+ --after 2018-12-24T23:59:00 --require-timestamp-from
+
+// Return
+{signature: , processId: }
+```
+
+_`require-timestamp-from` is optional. If not provided, the transaction will expect a timestamp signed by this wallet's secret key_
+
+### Authorized Transfer
+
+A third party must send a signature to unlock the lamports.
+
+```bash
+// Command
+$ solana pay 123 \
+ --require-signature-from
+
+// Return
+{signature: , processId: }
+```
+
+### Post-Dated and Authorized Transfer
+
+```bash
+// Command
+$ solana pay 123 \
+ --after 2018-12-24T23:59 --require-timestamp-from \
+ --require-signature-from
+
+// Return
+{signature: , processId: }
+```
+
+### Multiple Witnesses
+
+```bash
+// Command
+$ solana pay 123 \
+ --require-signature-from \
+ --require-signature-from
+
+// Return
+{signature: , processId: }
+```
+
+### Cancelable Transfer
+
+```bash
+// Command
+$ solana pay 123 \
+ --require-signature-from \
+ --cancelable
+
+// Return
+{signature: , processId: }
+```
+
+### Cancel Transfer
+
+```bash
+// Command
+$ solana cancel
+
+// Return
+
+```
+
+### Send Signature
+
+```bash
+// Command
+$ solana send-signature
+
+// Return
+
+```
+
+### Indicate Elapsed Time
+
+Use the current system time:
+
+```bash
+// Command
+$ solana send-timestamp
+
+// Return
+
+```
+
+Or specify some other arbitrary timestamp:
+
+```bash
+// Command
+$ solana send-timestamp --date 2018-12-24T23:59:00
+
+// Return
+
+```
+
+## Usage
+
+```text
+solana 0.12.0
+
+USAGE:
+ solana [FLAGS] [OPTIONS] [SUBCOMMAND]
+
+FLAGS:
+ -h, --help Prints help information
+ --rpc-tls Enable TLS for the RPC endpoint
+ -V, --version Prints version information
+
+OPTIONS:
+ --drone-host Drone host to use [default: same as --host]
+ --drone-port Drone port to use [default: 9900]
+ -n, --host Host to use for both RPC and drone [default: 127.0.0.1]
+ -k, --keypair /path/to/id.json
+ --rpc-host RPC host to use [default: same as --host]
+ --rpc-port RPC port to use [default: 8899]
+
+SUBCOMMANDS:
+ address Get your public key
+ airdrop Request a batch of lamports
+ balance Get your balance
+ cancel Cancel a transfer
+ confirm Confirm transaction by signature
+ deploy Deploy a program
+ get-transaction-count Get current transaction count
+ help Prints this message or the help of the given subcommand(s)
+ pay Send a payment
+ send-signature Send a signature to authorize a transfer
+ send-timestamp Send a timestamp to unlock a transfer
+```
+
+```text
+solana-address
+Get your public key
+
+USAGE:
+ solana address
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+```
+
+```text
+solana-airdrop
+Request a batch of lamports
+
+USAGE:
+ solana airdrop
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ The number of lamports to request
+```
+
+```text
+solana-balance
+Get your balance
+
+USAGE:
+ solana balance
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+```
+
+```text
+solana-cancel
+Cancel a transfer
+
+USAGE:
+ solana cancel
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ The process id of the transfer to cancel
+```
+
+```text
+solana-confirm
+Confirm transaction by signature
+
+USAGE:
+ solana confirm
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ The transaction signature to confirm
+```
+
+```text
+solana-deploy
+Deploy a program
+
+USAGE:
+ solana deploy
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ /path/to/program.o
+```
+
+```text
+solana-fees
+Display current cluster fees
+
+USAGE:
+ solana fees
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+```
+
+```text
+solana-get-transaction-count
+Get current transaction count
+
+USAGE:
+ solana get-transaction-count
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+```
+
+```text
+solana-pay
+Send a payment
+
+USAGE:
+ solana pay [FLAGS] [OPTIONS]
+
+FLAGS:
+ --cancelable
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --after A timestamp after which transaction will execute
+ --require-timestamp-from Require timestamp from this third party
+ --require-signature-from ... Any third party signatures required to unlock the lamports
+
+ARGS:
+ The pubkey of recipient
+ The number of lamports to send
+```
+
+```text
+solana-send-signature
+Send a signature to authorize a transfer
+
+USAGE:
+ solana send-signature
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+ARGS:
+ The pubkey of recipient
+ The process id of the transfer to authorize
+```
+
+```text
+solana-send-timestamp
+Send a timestamp to unlock a transfer
+
+USAGE:
+ solana send-timestamp [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ --date Optional arbitrary timestamp to apply
+
+ARGS:
+ The pubkey of recipient
+ The process id of the transfer to unlock
+```
+
diff --git a/book/src/api-reference/instruction-api.md b/book/src/api-reference/instruction-api.md
new file mode 100644
index 0000000000..e460c9a9f0
--- /dev/null
+++ b/book/src/api-reference/instruction-api.md
@@ -0,0 +1,38 @@
+# Instruction
+
+For the purposes of building a [Transaction](../transaction.md), a more verbose instruction format is used:
+
+* **Instruction:**
+ * **program\_id:** The pubkey of the on-chain program that executes the
+
+ instruction
+
+ * **accounts:** An ordered list of accounts that should be passed to
+
+ the program processing the instruction, including metadata detailing
+
+ if an account is a signer of the transaction and if it is a credit
+
+ only account.
+
+ * **data:** A byte array that is passed to the program executing the
+
+ instruction
+
+A more compact form is actually included in a `Transaction`:
+
+* **CompiledInstruction:**
+ * **program\_id\_index:** The index of the `program_id` in the
+
+ `account_keys` list
+
+ * **accounts:** An ordered list of indices into `account_keys`
+
+ specifying the accounds that should be passed to the program
+
+ processing the instruction.
+
+ * **data:** A byte array that is passed to the program executing the
+
+ instruction
+
diff --git a/book/src/api-reference/javascript-api.md b/book/src/api-reference/javascript-api.md
new file mode 100644
index 0000000000..5f891d0fc0
--- /dev/null
+++ b/book/src/api-reference/javascript-api.md
@@ -0,0 +1,4 @@
+# JavaScript API
+
+See [solana-web3](https://solana-labs.github.io/solana-web3.js/).
+
diff --git a/book/src/api-reference/jsonrpc-api.md b/book/src/api-reference/jsonrpc-api.md
new file mode 100644
index 0000000000..f20a1a0cd5
--- /dev/null
+++ b/book/src/api-reference/jsonrpc-api.md
@@ -0,0 +1,788 @@
+# JSON RPC API
+
+Solana nodes accept HTTP requests using the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification.
+
+To interact with a Solana node inside a JavaScript application, use the [solana-web3.js](https://github.com/solana-labs/solana-web3.js) library, which gives a convenient interface for the RPC methods.
+
+## RPC HTTP Endpoint
+
+**Default port:** 8899 eg. [http://localhost:8899](http://localhost:8899), [http://192.168.1.88:8899](http://192.168.1.88:8899)
+
+## RPC PubSub WebSocket Endpoint
+
+**Default port:** 8900 eg. ws://localhost:8900, [http://192.168.1.88:8900](http://192.168.1.88:8900)
+
+## Methods
+
+* [confirmTransaction](jsonrpc-api.md#confirmtransaction)
+* [getAccountInfo](jsonrpc-api.md#getaccountinfo)
+* [getBalance](jsonrpc-api.md#getbalance)
+* [getClusterNodes](jsonrpc-api.md#getclusternodes)
+* [getEpochInfo](jsonrpc-api.md#getepochinfo)
+* [getGenesisBlockhash](jsonrpc-api.md#getgenesisblockhash)
+* [getLeaderSchedule](jsonrpc-api.md#getleaderschedule)
+* [getProgramAccounts](jsonrpc-api.md#getprogramaccounts)
+* [getRecentBlockhash](jsonrpc-api.md#getrecentblockhash)
+* [getSignatureStatus](jsonrpc-api.md#getsignaturestatus)
+* [getSlot](jsonrpc-api.md#getslot)
+* [getSlotLeader](jsonrpc-api.md#getslotleader)
+* [getSlotsPerSegment](jsonrpc-api.md#getslotspersegment)
+* [getStorageTurn](jsonrpc-api.md#getstorageturn)
+* [getStorageTurnRate](jsonrpc-api.md#getstorageturnrate)
+* [getNumBlocksSinceSignatureConfirmation](jsonrpc-api.md#getnumblockssincesignatureconfirmation)
+* [getTransactionCount](jsonrpc-api.md#gettransactioncount)
+* [getTotalSupply](jsonrpc-api.md#gettotalsupply)
+* [getVersion](jsonrpc-api.md#getversion)
+* [getVoteAccounts](jsonrpc-api.md#getvoteaccounts)
+* [requestAirdrop](jsonrpc-api.md#requestairdrop)
+* [sendTransaction](jsonrpc-api.md#sendtransaction)
+* [startSubscriptionChannel](jsonrpc-api.md#startsubscriptionchannel)
+* [Subscription Websocket](jsonrpc-api.md#subscription-websocket)
+ * [accountSubscribe](jsonrpc-api.md#accountsubscribe)
+ * [accountUnsubscribe](jsonrpc-api.md#accountunsubscribe)
+ * [programSubscribe](jsonrpc-api.md#programsubscribe)
+ * [programUnsubscribe](jsonrpc-api.md#programunsubscribe)
+ * [signatureSubscribe](jsonrpc-api.md#signaturesubscribe)
+ * [signatureUnsubscribe](jsonrpc-api.md#signatureunsubscribe)
+
+## Request Formatting
+
+To make a JSON-RPC request, send an HTTP POST request with a `Content-Type: application/json` header. The JSON request data should contain 4 fields:
+
+* `jsonrpc`, set to `"2.0"`
+* `id`, a unique client-generated identifying integer
+* `method`, a string containing the method to be invoked
+* `params`, a JSON array of ordered parameter values
+
+Example using curl:
+
+```bash
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]}' 192.168.1.88:8899
+```
+
+The response output will be a JSON object with the following fields:
+
+* `jsonrpc`, matching the request specification
+* `id`, matching the request identifier
+* `result`, requested data or success confirmation
+
+Requests can be sent in batches by sending an array of JSON-RPC request objects as the data for a single POST.
+
+## Definitions
+
+* Hash: A SHA-256 hash of a chunk of data.
+* Pubkey: The public key of a Ed25519 key-pair.
+* Signature: An Ed25519 signature of a chunk of data.
+* Transaction: A Solana instruction signed by a client key-pair.
+
+## JSON RPC API Reference
+
+### confirmTransaction
+
+Returns a transaction receipt
+
+#### Parameters:
+
+* `string` - Signature of Transaction to confirm, as base-58 encoded string
+
+#### Results:
+
+* `boolean` - Transaction status, true if Transaction is confirmed
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"confirmTransaction", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":true,"id":1}
+```
+
+### getAccountInfo
+
+Returns all information associated with the account of provided Pubkey
+
+#### Parameters:
+
+* `string` - Pubkey of account to query, as base-58 encoded string
+
+#### Results:
+
+The result field will be a JSON object with the following sub fields:
+
+* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
+* `owner`, array of 32 bytes representing the program this account has been assigned to
+* `data`, array of bytes representing any data associated with the account
+* `executable`, boolean indicating if the account contains a program \(and is strictly read-only\)
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":{"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
+```
+
+### getBalance
+
+Returns the balance of the account of provided Pubkey
+
+#### Parameters:
+
+* `string` - Pubkey of account to query, as base-58 encoded string
+
+#### Results:
+
+* `integer` - quantity, as a signed 64-bit integer
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":0,"id":1}
+```
+
+### getClusterNodes
+
+Returns information about all the nodes participating in the cluster
+
+#### Parameters:
+
+None
+
+#### Results:
+
+The result field will be an array of JSON objects, each with the following sub fields:
+
+* `pubkey` - Node public key, as base-58 encoded string
+* `gossip` - Gossip network address for the node
+* `tpu` - TPU network address for the node
+* `rpc` - JSON RPC network address for the node, or `null` if the JSON RPC service is not enabled
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":[{"gossip":"10.239.6.48:8001","pubkey":"9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ","rpc":"10.239.6.48:8899","tpu":"10.239.6.48:8856"}],"id":1}
+```
+
+### getEpochInfo
+
+Returns information about the current epoch
+
+#### Parameters:
+
+None
+
+#### Results:
+
+The result field will be an object with the following fields:
+
+* `epoch`, the current epoch
+* `slotIndex`, the current slot relative to the start of the current epoch
+* `slotsInEpoch`, the number of slots in this epoch
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":{"epoch":3,"slotIndex":126,"slotsInEpoch":256},"id":1}
+```
+
+### getGenesisBlockhash
+
+Returns the genesis block hash
+
+#### Parameters:
+
+None
+
+#### Results:
+
+* `string` - a Hash as base-58 encoded string
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getGenesisBlockhash"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":"GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC","id":1}
+```
+
+### getLeaderSchedule
+
+Returns the leader schedule for the current epoch
+
+#### Parameters:
+
+None
+
+#### Results:
+
+The result field will be an array of leader public keys \(as base-58 encoded strings\) for each slot in the current epoch
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":[...],"id":1}
+```
+
+### getProgramAccounts
+
+Returns all accounts owned by the provided program Pubkey
+
+#### Parameters:
+
+* `string` - Pubkey of program, as base-58 encoded string
+
+#### Results:
+
+The result field will be an array of arrays. Each sub array will contain:
+
+* `string` - the account Pubkey as base-58 encoded string and a JSON object, with the following sub fields:
+* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
+* `owner`, array of 32 bytes representing the program this account has been assigned to
+* `data`, array of bytes representing any data associated with the account
+* `executable`, boolean indicating if the account contains a program \(and is strictly read-only\)
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getProgramAccounts", "params":["8nQwAgzN2yyUzrukXsCa3JELBYqDQrqJ3UyHiWazWxHR"]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":[["BqGKYtAKu69ZdWEBtZHh4xgJY1BYa2YBiBReQE3pe383", {"executable":false,"owner":[50,28,250,90,221,24,94,136,147,165,253,136,1,62,196,215,225,34,222,212,99,84,202,223,245,13,149,99,149,231,91,96],"lamports":1,"data":[]], ["4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T", {"executable":false,"owner":[50,28,250,90,221,24,94,136,147,165,253,136,1,62,196,215,225,34,222,212,99,84,202,223,245,13,149,99,149,231,91,96],"lamports":10,"data":[]]]},"id":1}
+```
+
+### getRecentBlockhash
+
+Returns a recent block hash from the ledger, and a fee schedule that can be used to compute the cost of submitting a transaction using it.
+
+#### Parameters:
+
+None
+
+#### Results:
+
+An array consisting of
+
+* `string` - a Hash as base-58 encoded string
+* `FeeCalculator object` - the fee schedule for this block hash
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",{"lamportsPerSignature": 0}],"id":1}
+```
+
+### getSignatureStatus
+
+Returns the status of a given signature. This method is similar to [confirmTransaction](jsonrpc-api.md#confirmtransaction) but provides more resolution for error events.
+
+#### Parameters:
+
+* `string` - Signature of Transaction to confirm, as base-58 encoded string
+
+#### Results:
+
+* `null` - Unknown transaction
+* `object` - Transaction status:
+ * `"Ok": null` - Transaction was successful
+ * `"Err": ` - Transaction failed with TransactionError [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatus", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}
+```
+
+### getSlot
+
+Returns the current slot the node is processing
+
+#### Parameters:
+
+None
+
+#### Results:
+
+* `u64` - Current slot
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlot"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":"1234","id":1}
+```
+
+### getSlotLeader
+
+Returns the current slot leader
+
+#### Parameters:
+
+None
+
+#### Results:
+
+* `string` - Node Id as base-58 encoded string
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlotLeader"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":"ENvAW7JScgYq6o4zKZwewtkzzJgDzuJAFxYasvmEQdpS","id":1}
+```
+
+### getSlotsPerSegment
+
+Returns the current storage segment size in terms of slots
+
+#### Parameters:
+
+None
+
+#### Results:
+
+* `u64` - Number of slots in a storage segment
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlotsPerSegment"}' http://localhost:8899
+// Result
+{"jsonrpc":"2.0","result":"1024","id":1}
+```
+
+### getStorageTurn
+
+Returns the current storage turn's blockhash and slot
+
+#### Parameters:
+
+None
+
+#### Results:
+
+An array consisting of
+
+* `string` - a Hash as base-58 encoded string indicating the blockhash of the turn slot
+* `u64` - the current storage turn slot
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurn"}' http://localhost:8899
+ // Result
+{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC", "2048"],"id":1}
+```
+
+### getStorageTurnRate
+
+Returns the current storage turn rate in terms of slots per turn
+
+#### Parameters:
+
+None
+
+#### Results:
+
+* `u64` - Number of slots in storage turn
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStorageTurnRate"}' http://localhost:8899
+ // Result
+{"jsonrpc":"2.0","result":"1024","id":1}
+```
+
+### getNumBlocksSinceSignatureConfirmation
+
+Returns the current number of blocks since signature has been confirmed.
+
+#### Parameters:
+
+* `string` - Signature of Transaction to confirm, as base-58 encoded string
+
+#### Results:
+
+* `integer` - count, as unsigned 64-bit integer
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getNumBlocksSinceSignatureConfirmation", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":8,"id":1}
+```
+
+### getTransactionCount
+
+Returns the current Transaction count from the ledger
+
+#### Parameters:
+
+None
+
+#### Results:
+
+* `integer` - count, as unsigned 64-bit integer
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getTransactionCount"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":268,"id":1}
+```
+
+### getTotalSupply
+
+Returns the current total supply in Lamports
+
+#### Parameters:
+
+None
+
+#### Results:
+
+* `integer` - Total supply, as unsigned 64-bit integer
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getTotalSupply"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":10126,"id":1}
+```
+
+### getVersion
+
+Returns the current solana versions running on the node
+
+#### Parameters:
+
+None
+
+#### Results:
+
+The result field will be a JSON object with the following sub fields:
+
+* `solana-core`, software version of solana-core
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' http://localhost:8899
+// Result
+{"jsonrpc":"2.0","result":{"solana-core": "0.17.2"},"id":1}
+```
+
+### getVoteAccounts
+
+Returns the account info and associated stake for all the voting accounts in the current bank.
+
+#### Parameters:
+
+None
+
+#### Results:
+
+The result field will be a JSON object of `current` and `delinquent` accounts, each containing an array of JSON objects with the following sub fields:
+
+* `votePubkey` - Vote account public key, as base-58 encoded string
+* `nodePubkey` - Node public key, as base-58 encoded string
+* `activatedStake` - the stake, in lamports, delegated to this vote account and active in this epoch
+* `epochVoteAccount` - bool, whether the vote account is staked for this epoch
+* `commission`, an 8-bit integer used as a fraction \(commission/MAX\_U8\) for rewards payout
+* `lastVote` - Most recent slot voted on by this vote account
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":{"current":[{"commission":0,"epochVoteAccount":true,"nodePubkey":"B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD","lastVote":147,"activatedStake":42,"votePubkey":"3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"}],"delinquent":[{"commission":127,"epochVoteAccount":false,"nodePubkey":"6ZPxeQaDo4bkZLRsdNrCzchNQr5LN9QMc9sipXv9Kw8f","lastVote":0,"activatedStake":0,"votePubkey":"CmgCk4aMS7KW1SHX3s9K5tBJ6Yng2LBaC8MFov4wx9sm"}]},"id":1}
+```
+
+### requestAirdrop
+
+Requests an airdrop of lamports to a Pubkey
+
+#### Parameters:
+
+* `string` - Pubkey of account to receive lamports, as base-58 encoded string
+* `integer` - lamports, as a signed 64-bit integer
+
+#### Results:
+
+* `string` - Transaction Signature of airdrop, as base-58 encoded string
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"requestAirdrop", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri", 50]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":"5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW","id":1}
+```
+
+### sendTransaction
+
+Creates new transaction
+
+#### Parameters:
+
+* `array` - array of octets containing a fully-signed Transaction
+
+#### Results:
+
+* `string` - Transaction Signature, as base-58 encoded string
+
+#### Example:
+
+```bash
+// Request
+curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"sendTransaction", "params":[[61, 98, 55, 49, 15, 187, 41, 215, 176, 49, 234, 229, 228, 77, 129, 221, 239, 88, 145, 227, 81, 158, 223, 123, 14, 229, 235, 247, 191, 115, 199, 71, 121, 17, 32, 67, 63, 209, 239, 160, 161, 2, 94, 105, 48, 159, 235, 235, 93, 98, 172, 97, 63, 197, 160, 164, 192, 20, 92, 111, 57, 145, 251, 6, 40, 240, 124, 194, 149, 155, 16, 138, 31, 113, 119, 101, 212, 128, 103, 78, 191, 80, 182, 234, 216, 21, 121, 243, 35, 100, 122, 68, 47, 57, 13, 39, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 40, 240, 124, 194, 149, 155, 16, 138, 31, 113, 119, 101, 212, 128, 103, 78, 191, 80, 182, 234, 216, 21, 121, 243, 35, 100, 122, 68, 47, 57, 11, 12, 106, 49, 74, 226, 201, 16, 161, 192, 28, 84, 124, 97, 190, 201, 171, 186, 6, 18, 70, 142, 89, 185, 176, 154, 115, 61, 26, 163, 77, 1, 88, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]}' http://localhost:8899
+
+// Result
+{"jsonrpc":"2.0","result":"2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b","id":1}
+```
+
+### Subscription Websocket
+
+After connect to the RPC PubSub websocket at `ws:///`:
+
+* Submit subscription requests to the websocket using the methods below
+* Multiple subscriptions may be active at once
+* All subscriptions take an optional `confirmations` parameter, which defines
+
+ how many confirmed blocks the node should wait before sending a notification.
+
+ The greater the number, the more likely the notification is to represent
+
+ consensus across the cluster, and the less likely it is to be affected by
+
+ forking or rollbacks. If unspecified, the default value is 0; the node will
+
+ send a notification as soon as it witnesses the event. The maximum
+
+ `confirmations` wait length is the cluster's `MAX_LOCKOUT_HISTORY`, which
+
+ represents the economic finality of the chain.
+
+### accountSubscribe
+
+Subscribe to an account to receive notifications when the lamports or data for a given account public key changes
+
+#### Parameters:
+
+* `string` - account Pubkey, as base-58 encoded string
+* `integer` - optional, number of confirmed blocks to wait before notification.
+
+ Default: 0, Max: `MAX_LOCKOUT_HISTORY` \(greater integers rounded down\)
+
+#### Results:
+
+* `integer` - Subscription id \(needed to unsubscribe\)
+
+#### Example:
+
+```bash
+// Request
+{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12"]}
+
+{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", 15]}
+
+// Result
+{"jsonrpc": "2.0","result": 0,"id": 1}
+```
+
+#### Notification Format:
+
+```bash
+{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
+```
+
+### accountUnsubscribe
+
+Unsubscribe from account change notifications
+
+#### Parameters:
+
+* `integer` - id of account Subscription to cancel
+
+#### Results:
+
+* `bool` - unsubscribe success message
+
+#### Example:
+
+```bash
+// Request
+{"jsonrpc":"2.0", "id":1, "method":"accountUnsubscribe", "params":[0]}
+
+// Result
+{"jsonrpc": "2.0","result": true,"id": 1}
+```
+
+### programSubscribe
+
+Subscribe to a program to receive notifications when the lamports or data for a given account owned by the program changes
+
+#### Parameters:
+
+* `string` - program\_id Pubkey, as base-58 encoded string
+* `integer` - optional, number of confirmed blocks to wait before notification.
+
+ Default: 0, Max: `MAX_LOCKOUT_HISTORY` \(greater integers rounded down\)
+
+#### Results:
+
+* `integer` - Subscription id \(needed to unsubscribe\)
+
+#### Example:
+
+```bash
+// Request
+{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["9gZbPtbtHrs6hEWgd6MbVY9VPFtS5Z8xKtnYwA2NynHV"]}
+
+{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["9gZbPtbtHrs6hEWgd6MbVY9VPFtS5Z8xKtnYwA2NynHV", 15]}
+
+// Result
+{"jsonrpc": "2.0","result": 0,"id": 1}
+```
+
+#### Notification Format:
+
+* `string` - account Pubkey, as base-58 encoded string
+* `object` - account info JSON object \(see [getAccountInfo](jsonrpc-api.md#getaccountinfo) for field details\)
+
+ ```bash
+ {"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"data":[1,1,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
+ ```
+
+### programUnsubscribe
+
+Unsubscribe from program-owned account change notifications
+
+#### Parameters:
+
+* `integer` - id of account Subscription to cancel
+
+#### Results:
+
+* `bool` - unsubscribe success message
+
+#### Example:
+
+```bash
+// Request
+{"jsonrpc":"2.0", "id":1, "method":"programUnsubscribe", "params":[0]}
+
+// Result
+{"jsonrpc": "2.0","result": true,"id": 1}
+```
+
+### signatureSubscribe
+
+Subscribe to a transaction signature to receive notification when the transaction is confirmed On `signatureNotification`, the subscription is automatically cancelled
+
+#### Parameters:
+
+* `string` - Transaction Signature, as base-58 encoded string
+* `integer` - optional, number of confirmed blocks to wait before notification.
+
+ Default: 0, Max: `MAX_LOCKOUT_HISTORY` \(greater integers rounded down\)
+
+#### Results:
+
+* `integer` - subscription id \(needed to unsubscribe\)
+
+#### Example:
+
+```bash
+// Request
+{"jsonrpc":"2.0", "id":1, "method":"signatureSubscribe", "params":["2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b"]}
+
+{"jsonrpc":"2.0", "id":1, "method":"signatureSubscribe", "params":["2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b", 15]}
+
+// Result
+{"jsonrpc": "2.0","result": 0,"id": 1}
+```
+
+#### Notification Format:
+
+```bash
+{"jsonrpc": "2.0","method": "signatureNotification", "params": {"result": "Confirmed","subscription":0}}
+```
+
+### signatureUnsubscribe
+
+Unsubscribe from signature confirmation notification
+
+#### Parameters:
+
+* `integer` - subscription id to cancel
+
+#### Results:
+
+* `bool` - unsubscribe success message
+
+#### Example:
+
+```bash
+// Request
+{"jsonrpc":"2.0", "id":1, "method":"signatureUnsubscribe", "params":[0]}
+
+// Result
+{"jsonrpc": "2.0","result": true,"id": 1}
+```
+
diff --git a/book/src/api-reference/transaction-api.md b/book/src/api-reference/transaction-api.md
new file mode 100644
index 0000000000..ba74ecc28e
--- /dev/null
+++ b/book/src/api-reference/transaction-api.md
@@ -0,0 +1,63 @@
+# Transaction
+
+## Components of a `Transaction`
+
+* **Transaction:**
+ * **message:** Defines the transaction
+ * **header:** Details the account types of and signatures required by
+
+ the transaction
+
+ * **num\_required\_signatures:** The total number of signatures
+
+ required to make the transaction valid.
+
+ * **num\_credit\_only\_signed\_accounts:** The last
+
+ `num_credit_only_signed_accounts` signatures refer to signing
+
+ credit only accounts. Credit only accounts can be used concurrently
+
+ by multiple parallel transactions, but their balance may only be
+
+ increased, and their account data is read-only.
+
+ * **num\_credit\_only\_unsigned\_accounts:** The last
+
+ `num_credit_only_unsigned_accounts` pubkeys in `account_keys` refer
+
+ to non-signing credit only accounts
+
+ * **account\_keys:** List of pubkeys used by the transaction, including
+
+ by the instructions and for signatures. The first
+
+ `num_required_signatures` pubkeys must sign the transaction.
+
+ * **recent\_blockhash:** The ID of a recent ledger entry. Validators will
+
+ reject transactions with a `recent_blockhash` that is too old.
+
+ * **instructions:** A list of [instructions](https://github.com/solana-labs/solana/tree/6b18db969dd1616eff07de35e7b823c75339fea8/book/src/instruction.md) that are
+
+ run sequentially and committed in one atomic transaction if all
+
+ succeed.
+ * **signatures:** A list of signatures applied to the transaction. The
+
+ list is always of length `num_required_signatures`, and the signature
+
+ at index `i` corresponds to the pubkey at index `i` in `account_keys`.
+
+ The list is initialized with empty signatures \(i.e. zeros\), and
+
+ populated as signatures are added.
+
+## Transaction Signing
+
+A `Transaction` is signed by using an ed25519 keypair to sign the serialization of the `message`. The resulting signature is placed at the index of `signatures` matching the index of the keypair's pubkey in `account_keys`.
+
+## Transaction Serialization
+
+`Transaction`s \(and their `message`s\) are serialized and deserialized using the [bincode](https://crates.io/crates/bincode) crate with a non-standard vector serialization that uses only one byte for the length if it can be encoded in 7 bits, 2 bytes if it fits in 14 bits, or 3 bytes if it requires 15 or 16 bits. The vector serialization is defined by Solana's [short-vec](https://github.com/solana-labs/solana/blob/master/sdk/src/short_vec.rs).
+
diff --git a/book/src/cluster/README.md b/book/src/cluster/README.md
new file mode 100644
index 0000000000..5fe19fe8fe
--- /dev/null
+++ b/book/src/cluster/README.md
@@ -0,0 +1,41 @@
+# A Solana Cluster
+
+A Solana cluster is a set of fullnodes working together to serve client transactions and maintain the integrity of the ledger. Many clusters may coexist. When two clusters share a common genesis block, they attempt to converge. Otherwise, they simply ignore the existence of the other. Transactions sent to the wrong one are quietly rejected. In this chapter, we'll discuss how a cluster is created, how nodes join the cluster, how they share the ledger, how they ensure the ledger is replicated, and how they cope with buggy and malicious nodes.
+
+## Creating a Cluster
+
+Before starting any fullnodes, one first needs to create a _genesis block_. The block contains entries referencing two public keys, a _mint_ and a _bootstrap leader_. The fullnode holding the bootstrap leader's secret key is responsible for appending the first entries to the ledger. It initializes its internal state with the mint's account. That account will hold the number of native tokens defined by the genesis block. The second fullnode then contacts the bootstrap leader to register as a _validator_ or _replicator_. Additional fullnodes then register with any registered member of the cluster.
+
+A validator receives all entries from the leader and submits votes confirming those entries are valid. After voting, the validator is expected to store those entries until replicator nodes submit proofs that they have stored copies of it. Once the validator observes a sufficient number of copies exist, it deletes its copy.
+
+## Joining a Cluster
+
+Validators and replicators enter the cluster via registration messages sent to its _control plane_. The control plane is implemented using a _gossip_ protocol, meaning that a node may register with any existing node, and expect its registration to propagate to all nodes in the cluster. The time it takes for all nodes to synchronize is proportional to the square of the number of nodes participating in the cluster. Algorithmically, that's considered very slow, but in exchange for that time, a node is assured that it eventually has all the same information as every other node, and that that information cannot be censored by any one node.
+
+## Sending Transactions to a Cluster
+
+Clients send transactions to any fullnode's Transaction Processing Unit \(TPU\) port. If the node is in the validator role, it forwards the transaction to the designated leader. If in the leader role, the node bundles incoming transactions, timestamps them creating an _entry_, and pushes them onto the cluster's _data plane_. Once on the data plane, the transactions are validated by validator nodes and replicated by replicator nodes, effectively appending them to the ledger.
+
+## Confirming Transactions
+
+A Solana cluster is capable of subsecond _confirmation_ for up to 150 nodes with plans to scale up to hundreds of thousands of nodes. Once fully implemented, confirmation times are expected to increase only with the logarithm of the number of validators, where the logarithm's base is very high. If the base is one thousand, for example, it means that for the first thousand nodes, confirmation will be the duration of three network hops plus the time it takes the slowest validator of a supermajority to vote. For the next million nodes, confirmation increases by only one network hop.
+
+Solana defines confirmation as the duration of time from when the leader timestamps a new entry to the moment when it recognizes a supermajority of ledger votes.
+
+A gossip network is much too slow to achieve subsecond confirmation once the network grows beyond a certain size. The time it takes to send messages to all nodes is proportional to the square of the number of nodes. If a blockchain wants to achieve low confirmation and attempts to do it using a gossip network, it will be forced to centralize to just a handful of nodes.
+
+Scalable confirmation can be achieved using the follow combination of techniques:
+
+1. Timestamp transactions with a VDF sample and sign the timestamp.
+2. Split the transactions into batches, send each to separate nodes and have
+
+ each node share its batch with its peers.
+
+3. Repeat the previous step recursively until all nodes have all batches.
+
+Solana rotates leaders at fixed intervals, called _slots_. Each leader may only produce entries during its allotted slot. The leader therefore timestamps transactions so that validators may lookup the public key of the designated leader. The leader then signs the timestamp so that a validator may verify the signature, proving the signer is owner of the designated leader's public key.
+
+Next, transactions are broken into batches so that a node can send transactions to multiple parties without making multiple copies. If, for example, the leader needed to send 60 transactions to 6 nodes, it would break that collection of 60 into batches of 10 transactions and send one to each node. This allows the leader to put 60 transactions on the wire, not 60 transactions for each node. Each node then shares its batch with its peers. Once the node has collected all 6 batches, it reconstructs the original set of 60 transactions.
+
+A batch of transactions can only be split so many times before it is so small that header information becomes the primary consumer of network bandwidth. At the time of this writing, the approach is scaling well up to about 150 validators. To scale up to hundreds of thousands of validators, each node can apply the same technique as the leader node to another set of nodes of equal size. We call the technique _data plane fanout_; learn more in the [data plan fanout](https://github.com/solana-labs/solana/tree/6b18db969dd1616eff07de35e7b823c75339fea8/book/src/data-plane-fanout.md) section.
+
diff --git a/book/src/cluster/fork-generation.md b/book/src/cluster/fork-generation.md
new file mode 100644
index 0000000000..3c02df9530
--- /dev/null
+++ b/book/src/cluster/fork-generation.md
@@ -0,0 +1,81 @@
+# Fork Generation
+
+The chapter describes how forks naturally occur as a consequence of [leader rotation](leader-rotation.md).
+
+## Overview
+
+Nodes take turns being leader and generating the PoH that encodes state changes. The cluster can tolerate loss of connection to any leader by synthesizing what the leader _**would**_ have generated had it been connected but not ingesting any state changes. The possible number of forks is thereby limited to a "there/not-there" skip list of forks that may arise on leader rotation slot boundaries. At any given slot, only a single leader's transactions will be accepted.
+
+## Message Flow
+
+1. Transactions are ingested by the current leader.
+2. Leader filters valid transactions.
+3. Leader executes valid transactions updating its state.
+4. Leader packages transactions into entries based off its current PoH slot.
+5. Leader transmits the entries to validator nodes \(in signed blobs\)
+ 1. The PoH stream includes ticks; empty entries that indicate liveness of
+
+ the leader and the passage of time on the cluster.
+
+ 2. A leader's stream begins with the tick entries necessary complete the PoH
+
+ back to the leaders most recently observed prior leader slot.
+6. Validators retransmit entries to peers in their set and to further
+
+ downstream nodes.
+
+7. Validators validate the transactions and execute them on their state.
+8. Validators compute the hash of the state.
+9. At specific times, i.e. specific PoH tick counts, validators transmit votes
+
+ to the leader.
+
+ 1. Votes are signatures of the hash of the computed state at that PoH tick
+
+ count
+
+ 2. Votes are also propagated via gossip
+
+10. Leader executes the votes as any other transaction and broadcasts them to
+
+ the cluster.
+
+11. Validators observe their votes and all the votes from the cluster.
+
+## Partitions, Forks
+
+Forks can arise at PoH tick counts that correspond to a vote. The next leader may not have observed the last vote slot and may start their slot with generated virtual PoH entries. These empty ticks are generated by all nodes in the cluster at a cluster-configured rate for hashes/per/tick `Z`.
+
+There are only two possible versions of the PoH during a voting slot: PoH with `T` ticks and entries generated by the current leader, or PoH with just ticks. The "just ticks" version of the PoH can be thought of as a virtual ledger, one that all nodes in the cluster can derive from the last tick in the previous slot.
+
+Validators can ignore forks at other points \(e.g. from the wrong leader\), or slash the leader responsible for the fork.
+
+Validators vote based on a greedy choice to maximize their reward described in [Tower BFT](../implemented-proposals/tower-bft.md).
+
+### Validator's View
+
+#### Time Progression
+
+The diagram below represents a validator's view of the PoH stream with possible forks over time. L1, L2, etc. are leader slots, and `E`s represent entries from that leader during that leader's slot. The `x`s represent ticks only, and time flows downwards in the diagram.
+
+
+
+Note that an `E` appearing on 2 forks at the same slot is a slashable condition, so a validator observing `E3` and `E3'` can slash L3 and safely choose `x` for that slot. Once a validator commits to a forks, other forks can be discarded below that tick count. For any slot, validators need only consider a single "has entries" chain or a "ticks only" chain to be proposed by a leader. But multiple virtual entries may overlap as they link back to the a previous slot.
+
+#### Time Division
+
+It's useful to consider leader rotation over PoH tick count as time division of the job of encoding state for the cluster. The following table presents the above tree of forks as a time-divided ledger.
+
+| leader slot | L1 | L2 | L3 | L4 | L5 |
+| :--- | :--- | :--- | :--- | :--- | :--- |
+| data | E1 | E2 | E3 | E4 | E5 |
+| ticks since prev | | | | x | xx |
+
+Note that only data from leader L3 will be accepted during leader slot L3. Data from L3 may include "catchup" ticks back to a slot other than L2 if L3 did not observe L2's data. L4 and L5's transmissions include the "ticks to prev" PoH entries.
+
+This arrangement of the network data streams permits nodes to save exactly this to the ledger for replay, restart, and checkpoints.
+
+### Leader's View
+
+When a new leader begins a slot, it must first transmit any PoH \(ticks\) required to link the new slot with the most recently observed and voted slot. The fork the leader proposes would link the current slot to a previous fork that the leader has voted on with virtual ticks.
+
diff --git a/book/src/cluster/leader-rotation.md b/book/src/cluster/leader-rotation.md
new file mode 100644
index 0000000000..8a7f783b3b
--- /dev/null
+++ b/book/src/cluster/leader-rotation.md
@@ -0,0 +1,98 @@
+# Leader Rotation
+
+At any given moment, a cluster expects only one fullnode to produce ledger entries. By having only one leader at a time, all validators are able to replay identical copies of the ledger. The drawback of only one leader at a time, however, is that a malicious leader is capable of censoring votes and transactions. Since censoring cannot be distinguished from the network dropping packets, the cluster cannot simply elect a single node to hold the leader role indefinitely. Instead, the cluster minimizes the influence of a malicious leader by rotating which node takes the lead.
+
+Each validator selects the expected leader using the same algorithm, described below. When the validator receives a new signed ledger entry, it can be certain that entry was produced by the expected leader. The order of slots which each leader is assigned a slot is called a _leader schedule_.
+
+## Leader Schedule Rotation
+
+A validator rejects blocks that are not signed by the _slot leader_. The list of identities of all slot leaders is called a _leader schedule_. The leader schedule is recomputed locally and periodically. It assigns slot leaders for a duration of time called an _epoch_. The schedule must be computed far in advance of the slots it assigns, such that the ledger state it uses to compute the schedule is finalized. That duration is called the _leader schedule offset_. Solana sets the offset to the duration of slots until the next epoch. That is, the leader schedule for an epoch is calculated from the ledger state at the start of the previous epoch. The offset of one epoch is fairly arbitrary and assumed to be sufficiently long such that all validators will have finalized their ledger state before the next schedule is generated. A cluster may choose to shorten the offset to reduce the time between stake changes and leader schedule updates.
+
+While operating without partitions lasting longer than an epoch, the schedule only needs to be generated when the root fork crosses the epoch boundary. Since the schedule is for the next epoch, any new stakes committed to the root fork will not be active until the next epoch. The block used for generating the leader schedule is the first block to cross the epoch boundary.
+
+Without a partition lasting longer than an epoch, the cluster will work as follows:
+
+1. A validator continuously updates its own root fork as it votes.
+2. The validator updates its leader schedule each time the slot height crosses an epoch boundary.
+
+For example:
+
+The epoch duration is 100 slots. The root fork is updated from fork computed at slot height 99 to a fork computed at slot height 102. Forks with slots at height 100,101 were skipped because of failures. The new leader schedule is computed using fork at slot height 102. It is active from slot 200 until it is updated again.
+
+No inconsistency can exist because every validator that is voting with the cluster has skipped 100 and 101 when its root passes 102. All validators, regardless of voting pattern, would be committing to a root that is either 102, or a descendant of 102.
+
+### Leader Schedule Rotation with Epoch Sized Partitions.
+
+The duration of the leader schedule offset has a direct relationship to the likelihood of a cluster having an inconsistent view of the correct leader schedule.
+
+Consider the following scenario:
+
+Two partitions that are generating half of the blocks each. Neither is coming to a definitive supermajority fork. Both will cross epoch 100 and 200 without actually committing to a root and therefore a cluster wide commitment to a new leader schedule.
+
+In this unstable scenario, multiple valid leader schedules exist.
+
+* A leader schedule is generated for every fork whose direct parent is in the previous epoch.
+* The leader schedule is valid after the start of the next epoch for descendant forks until it is updated.
+
+Each partition's schedule will diverge after the partition lasts more than an epoch. For this reason, the epoch duration should be selected to be much much larger then slot time and the expected length for a fork to be committed to root.
+
+After observing the cluster for a sufficient amount of time, the leader schedule offset can be selected based on the median partition duration and its standard deviation. For example, an offset longer then the median partition duration plus six standard deviations would reduce the likelihood of an inconsistent ledger schedule in the cluster to 1 in 1 million.
+
+## Leader Schedule Generation at Genesis
+
+The genesis block declares the first leader for the first epoch. This leader ends up scheduled for the first two epochs because the leader schedule is also generated at slot 0 for the next epoch. The length of the first two epochs can be specified in the genesis block as well. The minimum length of the first epochs must be greater than or equal to the maximum rollback depth as defined in [Tower BFT](../implemented-proposals/tower-bft.md).
+
+## Leader Schedule Generation Algorithm
+
+Leader schedule is generated using a predefined seed. The process is as follows:
+
+1. Periodically use the PoH tick height \(a monotonically increasing counter\) to
+
+ seed a stable pseudo-random algorithm.
+
+2. At that height, sample the bank for all the staked accounts with leader
+
+ identities that have voted within a cluster-configured number of ticks. The
+
+ sample is called the _active set_.
+
+3. Sort the active set by stake weight.
+4. Use the random seed to select nodes weighted by stake to create a
+
+ stake-weighted ordering.
+
+5. This ordering becomes valid after a cluster-configured number of ticks.
+
+## Schedule Attack Vectors
+
+### Seed
+
+The seed that is selected is predictable but unbiasable. There is no grinding attack to influence its outcome.
+
+### Active Set
+
+A leader can bias the active set by censoring validator votes. Two possible ways exist for leaders to censor the active set:
+
+* Ignore votes from validators
+* Refuse to vote for blocks with votes from validators
+
+To reduce the likelihood of censorship, the active set is calculated at the leader schedule offset boundary over an _active set sampling duration_. The active set sampling duration is long enough such that votes will have been collected by multiple leaders.
+
+### Staking
+
+Leaders can censor new staking transactions or refuse to validate blocks with new stakes. This attack is similar to censorship of validator votes.
+
+### Validator operational key loss
+
+Leaders and validators are expected to use ephemeral keys for operation, and stake owners authorize the validators to do work with their stake via delegation.
+
+The cluster should be able to recover from the loss of all the ephemeral keys used by leaders and validators, which could occur through a common software vulnerability shared by all the nodes. Stake owners should be able to vote directly co-sign a validator vote even though the stake is currently delegated to a validator.
+
+## Appending Entries
+
+The lifetime of a leader schedule is called an _epoch_. The epoch is split into _slots_, where each slot has a duration of `T` PoH ticks.
+
+A leader transmits entries during its slot. After `T` ticks, all the validators switch to the next scheduled leader. Validators must ignore entries sent outside a leader's assigned slot.
+
+All `T` ticks must be observed by the next leader for it to build its own entries on. If entries are not observed \(leader is down\) or entries are invalid \(leader is buggy or malicious\), the next leader must produce ticks to fill the previous leader's slot. Note that the next leader should do repair requests in parallel, and postpone sending ticks until it is confident other validators also failed to observe the previous leader's entries. If a leader incorrectly builds on its own ticks, the leader following it must replace all its ticks.
+
diff --git a/book/src/cluster/ledger-replication.md b/book/src/cluster/ledger-replication.md
new file mode 100644
index 0000000000..6d7060303b
--- /dev/null
+++ b/book/src/cluster/ledger-replication.md
@@ -0,0 +1,269 @@
+# Ledger Replication
+
+At full capacity on a 1gbps network solana will generate 4 petabytes of data per year. To prevent the network from centralizing around validators that have to store the full data set this protocol proposes a way for mining nodes to provide storage capacity for pieces of the data.
+
+The basic idea to Proof of Replication is encrypting a dataset with a public symmetric key using CBC encryption, then hash the encrypted dataset. The main problem with the naive approach is that a dishonest storage node can stream the encryption and delete the data as it's hashed. The simple solution is to periodically regenerate the hash based on a signed PoH value. This ensures that all the data is present during the generation of the proof and it also requires validators to have the entirety of the encrypted data present for verification of every proof of every identity. So the space required to validate is `number_of_proofs * data_size`
+
+## Optimization with PoH
+
+Our improvement on this approach is to randomly sample the encrypted segments faster than it takes to encrypt, and record the hash of those samples into the PoH ledger. Thus the segments stay in the exact same order for every PoRep and verification can stream the data and verify all the proofs in a single batch. This way we can verify multiple proofs concurrently, each one on its own CUDA core. The total space required for verification is `1_ledger_segment + 2_cbc_blocks * number_of_identities` with core count equal to `number_of_identities`. We use a 64-byte chacha CBC block size.
+
+## Network
+
+Validators for PoRep are the same validators that are verifying transactions. If a replicator can prove that a validator verified a fake PoRep, then the validator will not receive a reward for that storage epoch.
+
+Replicators are specialized _light clients_. They download a part of the ledger \(a.k.a Segment\) and store it, and provide PoReps of storing the ledger. For each verified PoRep replicators earn a reward of sol from the mining pool.
+
+## Constraints
+
+We have the following constraints:
+
+* Verification requires generating the CBC blocks. That requires space of 2
+
+ blocks per identity, and 1 CUDA core per identity for the same dataset. So as
+
+ many identities at once should be batched with as many proofs for those
+
+ identities verified concurrently for the same dataset.
+
+* Validators will randomly sample the set of storage proofs to the set that
+
+ they can handle, and only the creators of those chosen proofs will be
+
+ rewarded. The validator can run a benchmark whenever its hardware configuration
+
+ changes to determine what rate it can validate storage proofs.
+
+## Validation and Replication Protocol
+
+### Constants
+
+1. SLOTS\_PER\_SEGMENT: Number of slots in a segment of ledger data. The
+
+ unit of storage for a replicator.
+
+2. NUM\_KEY\_ROTATION\_SEGMENTS: Number of segments after which replicators
+
+ regenerate their encryption keys and select a new dataset to store.
+
+3. NUM\_STORAGE\_PROOFS: Number of storage proofs required for a storage proof
+
+ claim to be successfully rewarded.
+
+4. RATIO\_OF\_FAKE\_PROOFS: Ratio of fake proofs to real proofs that a storage
+
+ mining proof claim has to contain to be valid for a reward.
+
+5. NUM\_STORAGE\_SAMPLES: Number of samples required for a storage mining
+
+ proof.
+
+6. NUM\_CHACHA\_ROUNDS: Number of encryption rounds performed to generate
+
+ encrypted state.
+
+7. NUM\_SLOTS\_PER\_TURN: Number of slots that define a single storage epoch or
+
+ a "turn" of the PoRep game.
+
+### Validator behavior
+
+1. Validators join the network and begin looking for replicator accounts at each
+
+ storage epoch/turn boundary.
+
+2. Every turn, Validators sign the PoH value at the boundary and use that signature
+
+ to randomly pick proofs to verify from each storage account found in the turn boundary.
+
+ This signed value is also submitted to the validator's storage account and will be used by
+
+ replicators at a later stage to cross-verify.
+
+3. Every `NUM_SLOTS_PER_TURN` slots the validator advertises the PoH value. This is value
+
+ is also served to Replicators via RPC interfaces.
+
+4. For a given turn N, all validations get locked out until turn N+3 \(a gap of 2 turn/epoch\).
+
+ At which point all validations during that turn are available for reward collection.
+
+5. Any incorrect validations will be marked during the turn in between.
+
+### Replicator behavior
+
+1. Since a replicator is somewhat of a light client and not downloading all the
+
+ ledger data, they have to rely on other validators and replicators for information.
+
+ Any given validator may or may not be malicious and give incorrect information, although
+
+ there are not any obvious attack vectors that this could accomplish besides having the
+
+ replicator do extra wasted work. For many of the operations there are a number of options
+
+ depending on how paranoid a replicator is:
+
+ * \(a\) replicator can ask a validator
+ * \(b\) replicator can ask multiple validators
+ * \(c\) replicator can ask other replicators
+ * \(d\) replicator can subscribe to the full transaction stream and generate
+
+ the information itself \(assuming the slot is recent enough\)
+
+ * \(e\) replicator can subscribe to an abbreviated transaction stream to
+
+ generate the information itself \(assuming the slot is recent enough\)
+
+2. A replicator obtains the PoH hash corresponding to the last turn with its slot.
+3. The replicator signs the PoH hash with its keypair. That signature is the
+
+ seed used to pick the segment to replicate and also the encryption key. The
+
+ replicator mods the signature with the slot to get which segment to
+
+ replicate.
+
+4. The replicator retrives the ledger by asking peer validators and
+
+ replicators. See 6.5.
+
+5. The replicator then encrypts that segment with the key with chacha algorithm
+
+ in CBC mode with `NUM_CHACHA_ROUNDS` of encryption.
+
+6. The replicator initializes a chacha rng with the a signed recent PoH value as
+
+ the seed.
+
+7. The replicator generates `NUM_STORAGE_SAMPLES` samples in the range of the
+
+ entry size and samples the encrypted segment with sha256 for 32-bytes at each
+
+ offset value. Sampling the state should be faster than generating the encrypted
+
+ segment.
+
+8. The replicator sends a PoRep proof transaction which contains its sha state
+
+ at the end of the sampling operation, its seed and the samples it used to the
+
+ current leader and it is put onto the ledger.
+
+9. During a given turn the replicator should submit many proofs for the same segment
+
+ and based on the `RATIO_OF_FAKE_PROOFS` some of those proofs must be fake.
+
+10. As the PoRep game enters the next turn, the replicator must submit a
+
+ transaction with the mask of which proofs were fake during the last turn. This
+
+ transaction will define the rewards for both replicators and validators.
+
+11. Finally for a turn N, as the PoRep game enters turn N + 3, replicator's proofs for
+
+ turn N will be counted towards their rewards.
+
+### The PoRep Game
+
+The Proof of Replication game has 4 primary stages. For each "turn" multiple PoRep games can be in progress but each in a different stage.
+
+The 4 stages of the PoRep Game are as follows:
+
+1. Proof submission stage
+ * Replicators: submit as many proofs as possible during this stage
+ * Validators: No-op
+2. Proof verification stage
+ * Replicators: No-op
+ * Validators: Select replicators and verify their proofs from the previous turn
+3. Proof challenge stage
+ * Replicators: Submit the proof mask with justifications \(for fake proofs submitted 2 turns ago\)
+ * Validators: No-op
+4. Reward collection stage
+ * Replicators: Collect rewards for 3 turns ago
+ * Validators: Collect rewards for 3 turns ago
+
+For each turn of the PoRep game, both Validators and Replicators evaluate each stage. The stages are run as separate transactions on the storage program.
+
+### Finding who has a given block of ledger
+
+1. Validators monitor the turns in the PoRep game and look at the rooted bank
+
+ at turn boundaries for any proofs.
+
+2. Validators maintain a map of ledger segments and corresponding replicator public keys.
+
+ The map is updated when a Validator processes a replicator's proofs for a segment.
+
+ The validator provides an RPC interface to access the this map. Using this API, clients
+
+ can map a segment to a replicator's network address \(correlating it via cluster\_info table\).
+
+ The clients can then send repair requests to the replicator to retrieve segments.
+
+3. Validators would need to invalidate this list every N turns.
+
+## Sybil attacks
+
+For any random seed, we force everyone to use a signature that is derived from a PoH hash at the turn boundary. Everyone uses the same count, so the same PoH hash is signed by every participant. The signatures are then each cryptographically tied to the keypair, which prevents a leader from grinding on the resulting value for more than 1 identity.
+
+Since there are many more client identities then encryption identities, we need to split the reward for multiple clients, and prevent Sybil attacks from generating many clients to acquire the same block of data. To remain BFT we want to avoid a single human entity from storing all the replications of a single chunk of the ledger.
+
+Our solution to this is to force the clients to continue using the same identity. If the first round is used to acquire the same block for many client identities, the second round for the same client identities will force a redistribution of the signatures, and therefore PoRep identities and blocks. Thus to get a reward for replicators need to store the first block for free and the network can reward long lived client identities more than new ones.
+
+## Validator attacks
+
+* If a validator approves fake proofs, replicator can easily out them by
+
+ showing the initial state for the hash.
+
+* If a validator marks real proofs as fake, no on-chain computation can be done
+
+ to distinguish who is correct. Rewards would have to rely on the results from
+
+ multiple validators to catch bad actors and replicators from being denied rewards.
+
+* Validator stealing mining proof results for itself. The proofs are derived
+
+ from a signature from a replicator, since the validator does not know the
+
+ private key used to generate the encryption key, it cannot be the generator of
+
+ the proof.
+
+## Reward incentives
+
+Fake proofs are easy to generate but difficult to verify. For this reason, PoRep proof transactions generated by replicators may require a higher fee than a normal transaction to represent the computational cost required by validators.
+
+Some percentage of fake proofs are also necessary to receive a reward from storage mining.
+
+## Notes
+
+* We can reduce the costs of verification of PoRep by using PoH, and actually
+
+ make it feasible to verify a large number of proofs for a global dataset.
+
+* We can eliminate grinding by forcing everyone to sign the same PoH hash and
+
+ use the signatures as the seed
+
+* The game between validators and replicators is over random blocks and random
+
+ encryption identities and random data samples. The goal of randomization is
+
+ to prevent colluding groups from having overlap on data or validation.
+
+* Replicator clients fish for lazy validators by submitting fake proofs that
+
+ they can prove are fake.
+
+* To defend against Sybil client identities that try to store the same block we
+
+ force the clients to store for multiple rounds before receiving a reward.
+
+* Validators should also get rewarded for validating submitted storage proofs
+
+ as incentive for storing the ledger. They can only validate proofs if they
+
+ are storing that slice of the ledger.
+
diff --git a/book/src/cluster/managing-forks.md b/book/src/cluster/managing-forks.md
new file mode 100644
index 0000000000..fbd8d63535
--- /dev/null
+++ b/book/src/cluster/managing-forks.md
@@ -0,0 +1,35 @@
+# Managing Forks
+
+The ledger is permitted to fork at slot boundaries. The resulting data structure forms a tree called a _blocktree_. When the fullnode interprets the blocktree, it must maintain state for each fork in the chain. We call each instance an _active fork_. It is the responsibility of a fullnode to weigh those forks, such that it may eventually select a fork.
+
+A fullnode selects a fork by submiting a vote to a slot leader on that fork. The vote commits the fullnode for a duration of time called a _lockout period_. The fullnode is not permitted to vote on a different fork until that lockout period expires. Each subsequent vote on the same fork doubles the length of the lockout period. After some cluster-configured number of votes \(currently 32\), the length of the lockout period reaches what's called _max lockout_. Until the max lockout is reached, the fullnode has the option to wait until the lockout period is over and then vote on another fork. When it votes on another fork, it performs a operation called _rollback_, whereby the state rolls back in time to a shared checkpoint and then jumps forward to the tip of the fork that it just voted on. The maximum distance that a fork may roll back is called the _rollback depth_. Rollback depth is the number of votes required to achieve max lockout. Whenever a fullnode votes, any checkpoints beyond the rollback depth become unreachable. That is, there is no scenario in which the fullnode will need to roll back beyond rollback depth. It therefore may safely _prune_ unreachable forks and _squash_ all checkpoints beyond rollback depth into the root checkpoint.
+
+## Active Forks
+
+An active fork is as a sequence of checkpoints that has a length at least one longer than the rollback depth. The shortest fork will have a length exactly one longer than the rollback depth. For example:
+
+
+
+The following sequences are _active forks_:
+
+* {4, 2, 1}
+* {5, 2, 1}
+* {6, 3, 1}
+* {7, 3, 1}
+
+## Pruning and Squashing
+
+A fullnode may vote on any checkpoint in the tree. In the diagram above, that's every node except the leaves of the tree. After voting, the fullnode prunes nodes that fork from a distance farther than the rollback depth and then takes the opportunity to minimize its memory usage by squashing any nodes it can into the root.
+
+Starting from the example above, wth a rollback depth of 2, consider a vote on 5 versus a vote on 6. First, a vote on 5:
+
+
+
+The new root is 2, and any active forks that are not descendants from 2 are pruned.
+
+Alternatively, a vote on 6:
+
+
+
+The tree remains with a root of 1, since the active fork starting at 6 is only 2 checkpoints from the root.
+
diff --git a/book/src/cluster/performance-metrics.md b/book/src/cluster/performance-metrics.md
new file mode 100644
index 0000000000..a97fd08b3e
--- /dev/null
+++ b/book/src/cluster/performance-metrics.md
@@ -0,0 +1,16 @@
+# Performance Metrics
+
+Solana cluster performance is measured as average number of transactions per second that the network can sustain \(TPS\). And, how long it takes for a transaction to be confirmed by super majority of the cluster \(Confirmation Time\).
+
+Each cluster node maintains various counters that are incremented on certain events. These counters are periodically uploaded to a cloud based database. Solana's metrics dashboard fetches these counters, and computes the performance metrics and displays it on the dashboard.
+
+## TPS
+
+Each node's bank runtime maintains a count of transactions that it has processed. The dashboard first calculates the median count of transactions across all metrics enabled nodes in the cluster. The median cluster transaction count is then averaged over a 2 second period and displayed in the TPS time series graph. The dashboard also shows the Mean TPS, Max TPS and Total Transaction Count stats which are all calculated from the median transaction count.
+
+## Confirmation Time
+
+Each validator node maintains a list of active ledger forks that are visible to the node. A fork is considered to be frozen when the node has received and processed all entries corresponding to the fork. A fork is considered to be confirmed when it receives cumulative super majority vote, and when one of its children forks is frozen.
+
+The node assigns a timestamp to every new fork, and computes the time it took to confirm the fork. This time is reflected as validator confirmation time in performance metrics. The performance dashboard displays the average of each validator node's confirmation time as a time series graph.
+
diff --git a/book/src/cluster/stake-delegation-and-rewards.md b/book/src/cluster/stake-delegation-and-rewards.md
new file mode 100644
index 0000000000..ca0a9cde79
--- /dev/null
+++ b/book/src/cluster/stake-delegation-and-rewards.md
@@ -0,0 +1,209 @@
+# Stake Delegation and Rewards
+
+Stakers are rewarded for helping to validate the ledger. They do this by delegating their stake to validator nodes. Those validators do the legwork of replaying the ledger and send votes to a per-node vote account to which stakers can delegate their stakes. The rest of the cluster uses those stake-weighted votes to select a block when forks arise. Both the validator and staker need some economic incentive to play their part. The validator needs to be compensated for its hardware and the staker needs to be compensated for the risk of getting its stake slashed. The economics are covered in [staking rewards](../proposals/staking-rewards.md). This chapter, on the other hand, describes the underlying mechanics of its implementation.
+
+## Basic Design
+
+The general idea is that the validator owns a Vote account. The Vote account tracks validator votes, counts validator generated credits, and provides any additional validator specific state. The Vote account is not aware of any stakes delegated to it and has no staking weight.
+
+A separate Stake account \(created by a staker\) names a Vote account to which the stake is delegated. Rewards generated are proportional to the amount of lamports staked. The Stake account is owned by the staker only. Some portion of the lamports stored in this account are the stake.
+
+## Passive Delegation
+
+Any number of Stake accounts can delegate to a single Vote account without an interactive action from the identity controlling the Vote account or submitting votes to the account.
+
+The total stake allocated to a Vote account can be calculated by the sum of all the Stake accounts that have the Vote account pubkey as the `StakeState::Stake::voter_pubkey`.
+
+## Vote and Stake accounts
+
+The rewards process is split into two on-chain programs. The Vote program solves the problem of making stakes slashable. The Stake account acts as custodian of the rewards pool, and provides passive delegation. The Stake program is responsible for paying out each staker once the staker proves to the Stake program that its delegate has participated in validating the ledger.
+
+### VoteState
+
+VoteState is the current state of all the votes the validator has submitted to the network. VoteState contains the following state information:
+
+* `votes` - The submitted votes data structure.
+* `credits` - The total number of rewards this vote program has generated over its lifetime.
+* `root_slot` - The last slot to reach the full lockout commitment necessary for rewards.
+* `commission` - The commission taken by this VoteState for any rewards claimed by staker's Stake accounts. This is the percentage ceiling of the reward.
+* Account::lamports - The accumulated lamports from the commission. These do not count as stakes.
+* `authorized_vote_signer` - Only this identity is authorized to submit votes. This field can only modified by this identity.
+
+### VoteInstruction::Initialize
+
+* `account[0]` - RW - The VoteState
+
+ `VoteState::authorized_vote_signer` is initialized to `account[0]`
+
+ other VoteState members defaulted
+
+### VoteInstruction::AuthorizeVoteSigner\(Pubkey\)
+
+* `account[0]` - RW - The VoteState
+
+ `VoteState::authorized_vote_signer` is set to to `Pubkey`, the transaction must by
+
+ signed by the Vote account's current `authorized_vote_signer`.
+
+
+ `VoteInstruction::AuthorizeVoter` allows a staker to choose a signing service
+
+ for its votes. That service is responsible for ensuring the vote won't cause
+
+ the staker to be slashed.
+
+### VoteInstruction::Vote\(Vec\)
+
+* `account[0]` - RW - The VoteState
+
+ `VoteState::lockouts` and `VoteState::credits` are updated according to voting lockout rules see [Tower BFT](../implemented-proposals/tower-bft.md)
+
+* `account[1]` - RO - A list of some N most recent slots and their hashes for the vote to be verified against.
+
+### StakeState
+
+A StakeState takes one of three forms, StakeState::Uninitialized, StakeState::Stake and StakeState::RewardsPool.
+
+### StakeState::Stake
+
+StakeState::Stake is the current delegation preference of the **staker** and contains the following state information:
+
+* Account::lamports - The lamports available for staking.
+* `stake` - the staked amount \(subject to warm up and cool down\) for generating rewards, always less than or equal to Account::lamports
+* `voter_pubkey` - The pubkey of the VoteState instance the lamports are delegated to.
+* `credits_observed` - The total credits claimed over the lifetime of the program.
+* `activated` - the epoch at which this stake was activated/delegated. The full stake will be counted after warm up.
+* `deactivated` - the epoch at which this stake will be completely de-activated, which is `cool down` epochs after StakeInstruction::Deactivate is issued.
+
+### StakeState::RewardsPool
+
+To avoid a single network wide lock or contention in redemption, 256 RewardsPools are part of genesis under pre-determined keys, each with std::u64::MAX credits to be able to satisfy redemptions according to point value.
+
+The Stakes and the RewardsPool are accounts that are owned by the same `Stake` program.
+
+### StakeInstruction::DelegateStake\(u64\)
+
+The Stake account is moved from Uninitialized to StakeState::Stake form. This is how stakers choose their initial delegate validator node and activate their stake account lamports.
+
+* `account[0]` - RW - The StakeState::Stake instance. `StakeState::Stake::credits_observed` is initialized to `VoteState::credits`, `StakeState::Stake::voter_pubkey` is initialized to `account[1]`, `StakeState::Stake::stake` is initialized to the u64 passed as an argument above, `StakeState::Stake::activated` is initialized to current Bank epoch, and `StakeState::Stake::deactivated` is initialized to std::u64::MAX
+* `account[1]` - R - The VoteState instance.
+* `account[2]` - R - sysvar::current account, carries information about current Bank epoch
+* `account[3]` - R - stake\_api::Config accoount, carries warmup, cooldown, and slashing configuration
+
+### StakeInstruction::RedeemVoteCredits
+
+The staker or the owner of the Stake account sends a transaction with this instruction to claim rewards.
+
+The Vote account and the Stake account pair maintain a lifetime counter of total rewards generated and claimed. Rewards are paid according to a point value supplied by the Bank from inflation. A `point` is one credit \* one staked lamport, rewards paid are proportional to the number of lamports staked.
+
+* `account[0]` - RW - The StakeState::Stake instance that is redeeming rewards.
+* `account[1]` - R - The VoteState instance, must be the same as `StakeState::voter_pubkey`
+* `account[2]` - RW - The StakeState::RewardsPool instance that will fulfill the request \(picked at random\).
+* `account[3]` - R - sysvar::rewards account from the Bank that carries point value.
+* `account[4]` - R - sysvar::stake\_history account from the Bank that carries stake warmup/cooldown history
+
+Reward is paid out for the difference between `VoteState::credits` to `StakeState::Stake::credits_observed`, multiplied by `sysvar::rewards::Rewards::validator_point_value`. `StakeState::Stake::credits_observed` is updated to`VoteState::credits`. The commission is deposited into the Vote account token balance, and the reward is deposited to the Stake account token balance.
+
+```text
+let credits_to_claim = vote_state.credits - stake_state.credits_observed;
+stake_state.credits_observed = vote_state.credits;
+```
+
+`credits_to_claim` is used to compute the reward and commission, and `StakeState::Stake::credits_observed` is updated to the latest `VoteState::credits` value.
+
+### StakeInstruction::Deactivate
+
+A staker may wish to withdraw from the network. To do so he must first deactivate his stake, and wait for cool down.
+
+* `account[0]` - RW - The StakeState::Stake instance that is deactivating, the transaction must be signed by this key.
+* `account[1]` - R - The VoteState instance to which this stake is delegated, required in case of slashing
+* `account[2]` - R - sysvar::current account from the Bank that carries current epoch
+
+StakeState::Stake::deactivated is set to the current epoch + cool down. The account's stake will ramp down to zero by that epoch, and Account::lamports will be available for withdrawal.
+
+### StakeInstruction::Withdraw\(u64\)
+
+Lamports build up over time in a Stake account and any excess over activated stake can be withdrawn.
+
+* `account[0]` - RW - The StakeState::Stake from which to withdraw, the transaction must be signed by this key.
+* `account[1]` - RW - Account that should be credited with the withdrawn lamports.
+* `account[2]` - R - sysvar::current account from the Bank that carries current epoch, to calculate stake.
+* `account[3]` - R - sysvar::stake\_history account from the Bank that carries stake warmup/cooldown history
+
+## Benefits of the design
+
+* Single vote for all the stakers.
+* Clearing of the credit variable is not necessary for claiming rewards.
+* Each delegated stake can claim its rewards independently.
+* Commission for the work is deposited when a reward is claimed by the delegated stake.
+
+## Example Callflow
+
+
+
+## Staking Rewards
+
+The specific mechanics and rules of the validator rewards regime is outlined here. Rewards are earned by delegating stake to a validator that is voting correctly. Voting incorrectly exposes that validator's stakes to [slashing](https://github.com/solana-labs/solana/tree/6b18db969dd1616eff07de35e7b823c75339fea8/book/src/staking-and-rewards.md).
+
+### Basics
+
+The network pays rewards from a portion of network [inflation](https://github.com/solana-labs/solana/tree/6b18db969dd1616eff07de35e7b823c75339fea8/book/src/inflation.md). The number of lamports available to pay rewards for an epoch is fixed and must be evenly divided among all staked nodes according to their relative stake weight and participation. The weighting unit is called a [point](../terminology.md#point).
+
+Rewards for an epoch are not available until the end of that epoch.
+
+At the end of each epoch, the total number of points earned during the epoch is summed and used to divide the rewards portion of epoch inflation to arrive at a point value. This value is recorded in the bank in a [sysvar](../terminology.md#sysvar) that maps epochs to point values.
+
+During redemption, the stake program counts the points earned by the stake for each epoch, multiplies that by the epoch's point value, and transfers lamports in that amount from a rewards account into the stake and vote accounts according to the vote account's commission setting.
+
+### Economics
+
+Point value for an epoch depends on aggregate network participation. If participation in an epoch drops off, point values are higher for those that do participate.
+
+### Earning credits
+
+Validators earn one vote credit for every correct vote that exceeds maximum lockout, i.e. every time the validator's vote account retires a slot from its lockout list, making that vote a root for the node.
+
+Stakers who have delegated to that validator earn points in proportion to their stake. Points earned is the product of vote credits and stake.
+
+### Stake warmup, cooldown, withdrawal
+
+Stakes, once delegated, do not become effective immediately. They must first pass through a warm up period. During this period some portion of the stake is considered "effective", the rest is considered "activating". Changes occur on epoch boundaries.
+
+The stake program limits the rate of change to total network stake, reflected in the stake program's `config::warmup_rate` \(typically 15% per epoch\).
+
+The amount of stake that can be warmed up each epoch is a function of the previous epoch's total effective stake, total activating stake, and the stake program's configured warmup rate.
+
+Cooldown works the same way. Once a stake is deactivated, some part of it is considered "effective", and also "deactivating". As the stake cools down, it continues to earn rewards and be exposed to slashing, but it also becomes available for withdrawal.
+
+Bootstrap stakes are not subject to warmup.
+
+Rewards are paid against the "effective" portion of the stake for that epoch.
+
+#### Warmup example
+
+Consider the situation of a single stake of 1,000 activated at epoch N, with network warmup rate of 20%, and a quiescent total network stake at epoch N of 2,000.
+
+At epoch N+1, the amount available to be activated for the network is 400 \(20% of 200\), and at epoch N, this example stake is the only stake activating, and so is entitled to all of the warmup room available.
+
+| epoch | effective | activating | total effective | total activating |
+| :--- | ---: | ---: | ---: | ---: |
+| N-1 | | | 2,000 | 0 |
+| N | 0 | 1,000 | 2,000 | 1,000 |
+| N+1 | 400 | 600 | 2,400 | 600 |
+| N+2 | 880 | 120 | 2,880 | 120 |
+| N+3 | 1000 | 0 | 3,000 | 0 |
+
+Were 2 stakes \(X and Y\) to activate at epoch N, they would be awarded a portion of the 20% in proportion to their stakes. At each epoch effective and activating for each stake is a function of the previous epoch's state.
+
+| epoch | X eff | X act | Y eff | Y act | total effective | total activating |
+| :--- | ---: | ---: | ---: | ---: | ---: | ---: |
+| N-1 | | | | | 2,000 | 0 |
+| N | 0 | 1,000 | 0 | 200 | 2,000 | 1,200 |
+| N+1 | 320 | 680 | 80 | 120 | 2,400 | 800 |
+| N+2 | 728 | 272 | 152 | 48 | 2,880 | 320 |
+| N+3 | 1000 | 0 | 200 | 0 | 3,200 | 0 |
+
+### Withdrawal
+
+As rewards are earned lamports can be withdrawn from a stake account. Only lamports in excess of effective+activating stake may be withdrawn at any time. This means that during warmup, effectively no stake can be withdrawn. During cooldown, any tokens in excess of effective stake may be withdrawn \(activating == 0\);
+
diff --git a/book/src/cluster/synchronization.md b/book/src/cluster/synchronization.md
new file mode 100644
index 0000000000..75a0a46d27
--- /dev/null
+++ b/book/src/cluster/synchronization.md
@@ -0,0 +1,27 @@
+# Synchronization
+
+Fast, reliable synchronization is the biggest reason Solana is able to achieve such high throughput. Traditional blockchains synchronize on large chunks of transactions called blocks. By synchronizing on blocks, a transaction cannot be processed until a duration called "block time" has passed. In Proof of Work consensus, these block times need to be very large \(~10 minutes\) to minimize the odds of multiple fullnodes producing a new valid block at the same time. There's no such constraint in Proof of Stake consensus, but without reliable timestamps, a fullnode cannot determine the order of incoming blocks. The popular workaround is to tag each block with a [wallclock timestamp](https://en.bitcoin.it/wiki/Block_timestamp). Because of clock drift and variance in network latencies, the timestamp is only accurate within an hour or two. To workaround the workaround, these systems lengthen block times to provide reasonable certainty that the median timestamp on each block is always increasing.
+
+Solana takes a very different approach, which it calls _Proof of History_ or _PoH_. Leader nodes "timestamp" blocks with cryptographic proofs that some duration of time has passed since the last proof. All data hashed into the proof most certainly have occurred before the proof was generated. The node then shares the new block with validator nodes, which are able to verify those proofs. The blocks can arrive at validators in any order or even could be replayed years later. With such reliable synchronization guarantees, Solana is able to break blocks into smaller batches of transactions called _entries_. Entries are streamed to validators in realtime, before any notion of block consensus.
+
+Solana technically never sends a _block_, but uses the term to describe the sequence of entries that fullnodes vote on to achieve _confirmation_. In that way, Solana's confirmation times can be compared apples to apples to block-based systems. The current implementation sets block time to 800ms.
+
+What's happening under the hood is that entries are streamed to validators as quickly as a leader node can batch a set of valid transactions into an entry. Validators process those entries long before it is time to vote on their validity. By processing the transactions optimistically, there is effectively no delay between the time the last entry is received and the time when the node can vote. In the event consensus is **not** achieved, a node simply rolls back its state. This optimisic processing technique was introduced in 1981 and called [Optimistic Concurrency Control](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.65.4735). It can be applied to blockchain architecture where a cluster votes on a hash that represents the full ledger up to some _block height_. In Solana, it is implemented trivially using the last entry's PoH hash.
+
+## Relationship to VDFs
+
+The Proof of History technique was first described for use in blockchain by Solana in November of 2017. In June of the following year, a similar technique was described at Stanford and called a [verifiable delay function](https://eprint.iacr.org/2018/601.pdf) or _VDF_.
+
+A desirable property of a VDF is that verification time is very fast. Solana's approach to verifying its delay function is proportional to the time it took to create it. Split over a 4000 core GPU, it is sufficiently fast for Solana's needs, but if you asked the authors of the paper cited above, they might tell you \([and have](https://github.com/solana-labs/solana/issues/388)\) that Solana's approach is algorithmically slow and it shouldn't be called a VDF. We argue the term VDF should represent the category of verifiable delay functions and not just the subset with certain performance characteristics. Until that's resolved, Solana will likely continue using the term PoH for its application-specific VDF.
+
+Another difference between PoH and VDFs is that a VDF is used only for tracking duration. PoH's hash chain, on the other hand, includes hashes of any data the application observed. That data is a double-edged sword. On one side, the data "proves history" - that the data most certainly existed before hashes after it. On the side, it means the application can manipulate the hash chain by changing _when_ the data is hashed. The PoH chain therefore does not serve as a good source of randomness whereas a VDF without that data could. Solana's [leader rotation algorithm](synchronization.md#leader-rotation), for example, is derived only from the VDF _height_ and not its hash at that height.
+
+## Relationship to Consensus Mechanisms
+
+Proof of History is not a consensus mechanism, but it is used to improve the performance of Solana's Proof of Stake consensus. It is also used to improve the performance of the data plane and replication protocols.
+
+## More on Proof of History
+
+* [water clock analogy](https://medium.com/solana-labs/proof-of-history-explained-by-a-water-clock-e682183417b8)
+* [Proof of History overview](https://medium.com/solana-labs/proof-of-history-a-clock-for-blockchain-cf47a61a9274)
+
diff --git a/book/src/cluster/turbine-block-propagation.md b/book/src/cluster/turbine-block-propagation.md
new file mode 100644
index 0000000000..3a90b5d742
--- /dev/null
+++ b/book/src/cluster/turbine-block-propagation.md
@@ -0,0 +1,44 @@
+# Turbine Block Propagation
+
+A Solana cluster uses a multi-layer block propagation mechanism called _Turbine_ to broadcast transaction blobs to all nodes with minimal amount of duplicate messages. The cluster divides itself into small collections of nodes, called _neighborhoods_. Each node is responsible for sharing any data it receives with the other nodes in its neighborhood, as well as propagating the data on to a small set of nodes in other neighborhoods. This way each node only has to communicate with a small number of nodes.
+
+During its slot, the leader node distributes blobs between the validator nodes in the first neighborhood \(layer 0\). Each validator shares its data within its neighborhood, but also retransmits the blobs to one node in some neighborhoods in the next layer \(layer 1\). The layer-1 nodes each share their data with their neighborhood peers, and retransmit to nodes in the next layer, etc, until all nodes in the cluster have received all the blobs.
+
+## Neighborhood Assignment - Weighted Selection
+
+In order for data plane fanout to work, the entire cluster must agree on how the cluster is divided into neighborhoods. To achieve this, all the recognized validator nodes \(the TVU peers\) are sorted by stake and stored in a list. This list is then indexed in different ways to figure out neighborhood boundaries and retransmit peers. For example, the leader will simply select the first nodes to make up layer 0. These will automatically be the highest stake holders, allowing the heaviest votes to come back to the leader first. Layer-0 and lower-layer nodes use the same logic to find their neighbors and next layer peers.
+
+To reduce the possibility of attack vectors, each blob is transmitted over a random tree of neighborhoods. Each node uses the same set of nodes representing the cluster. A random tree is generated from the set for each blob using randomness derived from the blob itself. Since the random seed is not known in advance, attacks that try to eclipse neighborhoods from certain leaders or blocks become very difficult, and should require almost complete control of the stake in the cluster.
+
+## Layer and Neighborhood Structure
+
+The current leader makes its initial broadcasts to at most `DATA_PLANE_FANOUT` nodes. If this layer 0 is smaller than the number of nodes in the cluster, then the data plane fanout mechanism adds layers below. Subsequent layers follow these constraints to determine layer-capacity: Each neighborhood contains `DATA_PLANE_FANOUT` nodes. Layer-0 starts with 1 neighborhood with fanout nodes. The number of nodes in each additional layer grows by a factor of fanout.
+
+As mentioned above, each node in a layer only has to broadcast its blobs to its neighbors and to exactly 1 node in some next-layer neighborhoods, instead of to every TVU peer in the cluster. A good way to think about this is, layer-0 starts with 1 neighborhood with fanout nodes, layer-1 adds "fanout" neighborhoods, each with fanout nodes and layer-2 will have `fanout * number of nodes in layer-1` and so on.
+
+This way each node only has to communicate with a maximum of `2 * DATA_PLANE_FANOUT - 1` nodes.
+
+The following diagram shows how the Leader sends blobs with a Fanout of 2 to Neighborhood 0 in Layer 0 and how the nodes in Neighborhood 0 share their data with each other.
+
+
+
+The following diagram shows how Neighborhood 0 fans out to Neighborhoods 1 and 2.
+
+
+
+Finally, the following diagram shows a two layer cluster with a Fanout of 2.
+
+
+
+### Configuration Values
+
+`DATA_PLANE_FANOUT` - Determines the size of layer 0. Subsequent layers grow by a factor of `DATA_PLANE_FANOUT`. The number of nodes in a neighborhood is equal to the fanout value. Neighborhoods will fill to capacity before new ones are added, i.e if a neighborhood isn't full, it _must_ be the last one.
+
+Currently, configuration is set when the cluster is launched. In the future, these parameters may be hosted on-chain, allowing modification on the fly as the cluster sizes change.
+
+## Neighborhoods
+
+The following diagram shows how two neighborhoods in different layers interact. To cripple a neighborhood, enough nodes \(erasure codes +1\) from the neighborhood above need to fail. Since each neighborhood receives blobs from multiple nodes in a neighborhood in the upper layer, we'd need a big network failure in the upper layers to end up with incomplete data.
+
+
+
diff --git a/book/src/cluster/vote-signing.md b/book/src/cluster/vote-signing.md
new file mode 100644
index 0000000000..6cea8d36b4
--- /dev/null
+++ b/book/src/cluster/vote-signing.md
@@ -0,0 +1,67 @@
+# Secure Vote Signing
+
+A validator fullnode receives entries from the current leader and submits votes confirming those entries are valid. This vote submission presents a security challenge, because forged votes that violate consensus rules could be used to slash the validator's stake.
+
+The validator votes on its chosen fork by submitting a transaction that uses an asymmetric key to sign the result of its validation work. Other entities can verify this signature using the validator's public key. If the validator's key is used to sign incorrect data \(e.g. votes on multiple forks of the ledger\), the node's stake or its resources could be compromised.
+
+Solana addresses this risk by splitting off a separate _vote signer_ service that evaluates each vote to ensure it does not violate a slashing condition.
+
+## Validators, Vote Signers, and Stakeholders
+
+When a validator receives multiple blocks for the same slot, it tracks all possible forks until it can determine a "best" one. A validator selects the best fork by submitting a vote to it, using a vote signer to minimize the possibility of its vote inadvertently violating a consensus rule and getting a stake slashed.
+
+A vote signer evaluates the vote proposed by the validator and signs the vote only if it does not violate a slashing condition. A vote signer only needs to maintain minimal state regarding the votes it signed and the votes signed by the rest of the cluster. It doesn't need to process a full set of transactions.
+
+A stakeholder is an identity that has control of the staked capital. The stakeholder can delegate its stake to the vote signer. Once a stake is delegated, the vote signer votes represent the voting weight of all the delegated stakes, and produce rewards for all the delegated stakes.
+
+Currently, there is a 1:1 relationship between validators and vote signers, and stakeholders delegate their entire stake to a single vote signer.
+
+## Signing service
+
+The vote signing service consists of a JSON RPC server and a request processor. At startup, the service starts the RPC server at a configured port and waits for validator requests. It expects the following type of requests: 1. Register a new validator node
+
+* The request must contain validator's identity \(public key\)
+* The request must be signed with the validator's private key
+* The service drops the request if signature of the request cannot be
+
+ verified
+
+* The service creates a new voting asymmetric key for the validator, and
+
+ returns the public key as a response
+
+* If a validator tries to register again, the service returns the public key
+
+ from the pre-existing keypair
+
+ 1. Sign a vote
+
+* The request must contain a voting transaction and all verification data
+* The request must be signed with the validator's private key
+* The service drops the request if signature of the request cannot be
+
+ verified
+
+* The service verifies the voting data
+* The service returns a signature for the transaction
+
+## Validator voting
+
+A validator node, at startup, creates a new vote account and registers it with the cluster by submitting a new "vote register" transaction. The other nodes on the cluster process this transaction and include the new validator in the active set. Subsequently, the validator submits a "new vote" transaction signed with the validator's voting private key on each voting event.
+
+### Configuration
+
+The validator node is configured with the signing service's network endpoint \(IP/Port\).
+
+### Registration
+
+At startup, the validator registers itself with its signing service using JSON RPC. The RPC call returns the voting public key for the validator node. The validator creates a new "vote register" transaction including this public key, and submits it to the cluster.
+
+### Vote Collection
+
+The validator looks up the votes submitted by all the nodes in the cluster for the last voting period. This information is submitted to the signing service with a new vote signing request.
+
+### New Vote Signing
+
+The validator creates a "new vote" transaction and sends it to the signing service using JSON RPC. The RPC request also includes the vote verification data. On success, the RPC call returns the signature for the vote. On failure, RPC call returns the failure code.
+
diff --git a/book/src/getting-started/README.md b/book/src/getting-started/README.md
new file mode 100644
index 0000000000..ddd7315571
--- /dev/null
+++ b/book/src/getting-started/README.md
@@ -0,0 +1,132 @@
+# Getting Started
+
+The Solana git repository contains all the scripts you might need to spin up your own local testnet. Depending on what you're looking to achieve, you may want to run a different variation, as the full-fledged, performance-enhanced multinode testnet is considerably more complex to set up than a Rust-only, singlenode testnode. If you are looking to develop high-level features, such as experimenting with smart contracts, save yourself some setup headaches and stick to the Rust-only singlenode demo. If you're doing performance optimization of the transaction pipeline, consider the enhanced singlenode demo. If you're doing consensus work, you'll need at least a Rust-only multinode demo. If you want to reproduce our TPS metrics, run the enhanced multinode demo.
+
+For all four variations, you'd need the latest Rust toolchain and the Solana source code:
+
+First, install Rust's package manager Cargo.
+
+```bash
+$ curl https://sh.rustup.rs -sSf | sh
+$ source $HOME/.cargo/env
+```
+
+Now checkout the code from github:
+
+```bash
+$ git clone https://github.com/solana-labs/solana.git
+$ cd solana
+```
+
+The demo code is sometimes broken between releases as we add new low-level features, so if this is your first time running the demo, you'll improve your odds of success if you check out the [latest release](https://github.com/solana-labs/solana/releases) before proceeding:
+
+```bash
+$ TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
+$ git checkout $TAG
+```
+
+### Configuration Setup
+
+Ensure important programs such as the vote program are built before any nodes are started
+
+```bash
+$ cargo build --all
+```
+
+The network is initialized with a genesis ledger generated by running the following script.
+
+```bash
+$ ./multinode-demo/setup.sh
+```
+
+### Drone
+
+In order for the fullnodes and clients to work, we'll need to spin up a drone to give out some test tokens. The drone delivers Milton Friedman-style "air drops" \(free tokens to requesting clients\) to be used in test transactions.
+
+Start the drone with:
+
+```bash
+$ ./multinode-demo/drone.sh
+```
+
+### Singlenode Testnet
+
+Before you start a validator, make sure you know the IP address of the machine you want to be the bootstrap leader for the demo, and make sure that udp ports 8000-10000 are open on all the machines you want to test with.
+
+Now start the bootstrap leader in a separate shell:
+
+```bash
+$ ./multinode-demo/bootstrap-leader.sh
+```
+
+Wait a few seconds for the server to initialize. It will print "leader ready..." when it's ready to receive transactions. The leader will request some tokens from the drone if it doesn't have any. The drone does not need to be running for subsequent leader starts.
+
+### Multinode Testnet
+
+To run a multinode testnet, after starting a leader node, spin up some additional validators in separate shells:
+
+```bash
+$ ./multinode-demo/validator-x.sh
+```
+
+To run a performance-enhanced full node on Linux, [CUDA 10.0](https://developer.nvidia.com/cuda-downloads) must be installed on your system:
+
+```bash
+$ ./fetch-perf-libs.sh
+$ SOLANA_CUDA=1 ./multinode-demo/bootstrap-leader.sh
+$ SOLANA_CUDA=1 ./multinode-demo/validator.sh
+```
+
+### Testnet Client Demo
+
+Now that your singlenode or multinode testnet is up and running let's send it some transactions!
+
+In a separate shell start the client:
+
+```bash
+$ ./multinode-demo/client.sh # runs against localhost by default
+```
+
+What just happened? The client demo spins up several threads to send 500,000 transactions to the testnet as quickly as it can. The client then pings the testnet periodically to see how many transactions it processed in that time. Take note that the demo intentionally floods the network with UDP packets, such that the network will almost certainly drop a bunch of them. This ensures the testnet has an opportunity to reach 710k TPS. The client demo completes after it has convinced itself the testnet won't process any additional transactions. You should see several TPS measurements printed to the screen. In the multinode variation, you'll see TPS measurements for each validator node as well.
+
+### Testnet Debugging
+
+There are some useful debug messages in the code, you can enable them on a per-module and per-level basis. Before running a leader or validator set the normal RUST\_LOG environment variable.
+
+For example
+
+* To enable `info` everywhere and `debug` only in the solana::banking\_stage module:
+
+ ```bash
+ $ export RUST_LOG=solana=info,solana::banking_stage=debug
+ ```
+
+* To enable BPF program logging:
+
+ ```bash
+ $ export RUST_LOG=solana_bpf_loader=trace
+ ```
+
+Generally we are using `debug` for infrequent debug messages, `trace` for potentially frequent messages and `info` for performance-related logging.
+
+You can also attach to a running process with GDB. The leader's process is named _solana-validator_:
+
+```bash
+$ sudo gdb
+attach
+set logging on
+thread apply all bt
+```
+
+This will dump all the threads stack traces into gdb.txt
+
+## Public Testnet
+
+In this example the client connects to our public testnet. To run validators on the testnet you would need to open udp ports `8000-10000`.
+
+```bash
+$ ./multinode-demo/client.sh --entrypoint testnet.solana.com:8001 --drone testnet.solana.com:9900 --duration 60 --tx_count 50
+```
+
+You can observe the effects of your client's transactions on our [dashboard](https://metrics.solana.com:3000/d/testnet/testnet-hud?orgId=2&from=now-30m&to=now&refresh=5s&var-testnet=testnet)
+
diff --git a/book/src/getting-started/testnet-participation.md b/book/src/getting-started/testnet-participation.md
new file mode 100644
index 0000000000..64c54a9efc
--- /dev/null
+++ b/book/src/getting-started/testnet-participation.md
@@ -0,0 +1,7 @@
+# Testnet Participation
+
+Participate in our testnet:
+
+* [Running a Validator](../running-validator/)
+* [Running a Replicator](../running-replicator.md)
+
diff --git a/book/src/getting-started/webwallet.md b/book/src/getting-started/webwallet.md
new file mode 100644
index 0000000000..953a6dac3a
--- /dev/null
+++ b/book/src/getting-started/webwallet.md
@@ -0,0 +1,16 @@
+# Example Client: Web Wallet
+
+## Build and run a web wallet locally
+
+First fetch the example code:
+
+```bash
+$ git clone https://github.com/solana-labs/example-webwallet.git
+$ cd example-webwallet
+$ TAG=$(git describe --tags $(git rev-list --tags
+--max-count=1))
+$ git checkout $TAG
+```
+
+Next, follow the steps in the git repository's [README](https://github.com/solana-labs/example-webwallet/blob/master/README.md).
+
diff --git a/book/src/implemented-proposals/README.md b/book/src/implemented-proposals/README.md
new file mode 100644
index 0000000000..f47169fea0
--- /dev/null
+++ b/book/src/implemented-proposals/README.md
@@ -0,0 +1,4 @@
+# Implemented Design Proposals
+
+The following design proposals are fully implemented.
+
diff --git a/book/src/implemented-proposals/blocktree.md b/book/src/implemented-proposals/blocktree.md
new file mode 100644
index 0000000000..302c883b35
--- /dev/null
+++ b/book/src/implemented-proposals/blocktree.md
@@ -0,0 +1,93 @@
+# Blocktree
+
+After a block reaches finality, all blocks from that one on down to the genesis block form a linear chain with the familiar name blockchain. Until that point, however, the validator must maintain all potentially valid chains, called _forks_. The process by which forks naturally form as a result of leader rotation is described in [fork generation](../cluster/fork-generation.md). The _blocktree_ data structure described here is how a validator copes with those forks until blocks are finalized.
+
+The blocktree allows a validator to record every blob it observes on the network, in any order, as long as the blob is signed by the expected leader for a given slot.
+
+Blobs are moved to a fork-able key space the tuple of `leader slot` + `blob index` \(within the slot\). This permits the skip-list structure of the Solana protocol to be stored in its entirety, without a-priori choosing which fork to follow, which Entries to persist or when to persist them.
+
+Repair requests for recent blobs are served out of RAM or recent files and out of deeper storage for less recent blobs, as implemented by the store backing Blocktree.
+
+## Functionalities of Blocktree
+
+1. Persistence: the Blocktree lives in the front of the nodes verification
+
+ pipeline, right behind network receive and signature verification. If the
+
+ blob received is consistent with the leader schedule \(i.e. was signed by the
+
+ leader for the indicated slot\), it is immediately stored.
+
+2. Repair: repair is the same as window repair above, but able to serve any
+
+ blob that's been received. Blocktree stores blobs with signatures,
+
+ preserving the chain of origination.
+
+3. Forks: Blocktree supports random access of blobs, so can support a
+
+ validator's need to rollback and replay from a Bank checkpoint.
+
+4. Restart: with proper pruning/culling, the Blocktree can be replayed by
+
+ ordered enumeration of entries from slot 0. The logic of the replay stage
+
+ \(i.e. dealing with forks\) will have to be used for the most recent entries in
+
+ the Blocktree.
+
+## Blocktree Design
+
+1. Entries in the Blocktree are stored as key-value pairs, where the key is the concatenated slot index and blob index for an entry, and the value is the entry data. Note blob indexes are zero-based for each slot \(i.e. they're slot-relative\).
+2. The Blocktree maintains metadata for each slot, in the `SlotMeta` struct containing:
+ * `slot_index` - The index of this slot
+ * `num_blocks` - The number of blocks in the slot \(used for chaining to a previous slot\)
+ * `consumed` - The highest blob index `n`, such that for all `m < n`, there exists a blob in this slot with blob index equal to `n` \(i.e. the highest consecutive blob index\).
+ * `received` - The highest received blob index for the slot
+ * `next_slots` - A list of future slots this slot could chain to. Used when rebuilding
+
+ the ledger to find possible fork points.
+
+ * `last_index` - The index of the blob that is flagged as the last blob for this slot. This flag on a blob will be set by the leader for a slot when they are transmitting the last blob for a slot.
+ * `is_rooted` - True iff every block from 0...slot forms a full sequence without any holes. We can derive is\_rooted for each slot with the following rules. Let slot\(n\) be the slot with index `n`, and slot\(n\).is\_full\(\) is true if the slot with index `n` has all the ticks expected for that slot. Let is\_rooted\(n\) be the statement that "the slot\(n\).is\_rooted is true". Then:
+
+ is\_rooted\(0\) is\_rooted\(n+1\) iff \(is\_rooted\(n\) and slot\(n\).is\_full\(\)
+3. Chaining - When a blob for a new slot `x` arrives, we check the number of blocks \(`num_blocks`\) for that new slot \(this information is encoded in the blob\). We then know that this new slot chains to slot `x - num_blocks`.
+4. Subscriptions - The Blocktree records a set of slots that have been "subscribed" to. This means entries that chain to these slots will be sent on the Blocktree channel for consumption by the ReplayStage. See the `Blocktree APIs` for details.
+5. Update notifications - The Blocktree notifies listeners when slot\(n\).is\_rooted is flipped from false to true for any `n`.
+
+## Blocktree APIs
+
+The Blocktree offers a subscription based API that ReplayStage uses to ask for entries it's interested in. The entries will be sent on a channel exposed by the Blocktree. These subscription API's are as follows: 1. `fn get_slots_since(slot_indexes: &[u64]) -> Vec`: Returns new slots connecting to any element of the list `slot_indexes`.
+
+1. `fn get_slot_entries(slot_index: u64, entry_start_index: usize, max_entries: Option) -> Vec`: Returns the entry vector for the slot starting with `entry_start_index`, capping the result at `max` if `max_entries == Some(max)`, otherwise, no upper limit on the length of the return vector is imposed.
+
+Note: Cumulatively, this means that the replay stage will now have to know when a slot is finished, and subscribe to the next slot it's interested in to get the next set of entries. Previously, the burden of chaining slots fell on the Blocktree.
+
+## Interfacing with Bank
+
+The bank exposes to replay stage:
+
+1. `prev_hash`: which PoH chain it's working on as indicated by the hash of the last
+
+ entry it processed
+
+2. `tick_height`: the ticks in the PoH chain currently being verified by this
+
+ bank
+
+3. `votes`: a stack of records that contain:
+ 1. `prev_hashes`: what anything after this vote must chain to in PoH
+ 2. `tick_height`: the tick height at which this vote was cast
+ 3. `lockout period`: how long a chain must be observed to be in the ledger to
+
+ be able to be chained below this vote
+
+Replay stage uses Blocktree APIs to find the longest chain of entries it can hang off a previous vote. If that chain of entries does not hang off the latest vote, the replay stage rolls back the bank to that vote and replays the chain from there.
+
+## Pruning Blocktree
+
+Once Blocktree entries are old enough, representing all the possible forks becomes less useful, perhaps even problematic for replay upon restart. Once a validator's votes have reached max lockout, however, any Blocktree contents that are not on the PoH chain for that vote for can be pruned, expunged.
+
+Replicator nodes will be responsible for storing really old ledger contents, and validators need only persist their bank periodically.
+
diff --git a/book/src/implemented-proposals/credit-only-credit-debit-accounts.md b/book/src/implemented-proposals/credit-only-credit-debit-accounts.md
new file mode 100644
index 0000000000..c837fb3db2
--- /dev/null
+++ b/book/src/implemented-proposals/credit-only-credit-debit-accounts.md
@@ -0,0 +1,105 @@
+# Credit-only Accounts
+
+This design covers the handling of credit-only and credit-debit accounts in the [runtime](../validator/runtime.md). Accounts already distinguish themselves as credit-only or credit-debit based on the program ID specified by the transaction's instruction. Programs must treat accounts that are not owned by them as credit-only.
+
+To identify credit-only accounts by program id would require the account to be fetched and loaded from disk. This operation is expensive, and while it is occurring, the runtime would have to reject any transactions referencing the same account.
+
+The proposal introduces a `num_readonly_accounts` field to the transaction structure, and removes the `program_ids` dedicated vector for program accounts.
+
+This design doesn't change the runtime transaction processing rules. Programs still can't write or spend accounts that they do not own, but it allows the runtime to optimistically take the correct lock for each account specified in the transaction before loading the accounts from storage.
+
+Accounts selected as credit-debit by the transaction can still be treated as credit-only by the instructions.
+
+## Runtime handling
+
+credit-only accounts have the following properties:
+
+* Can be deposited into: Deposits can be implemented as a simple `atomic_add`.
+* read-only access to account data.
+
+Instructions that debit or modify the credit-only account data will fail.
+
+## Account Lock Optimizations
+
+The Accounts module keeps track of current locked accounts in the runtime, which separates credit-only accounts from the credit-debit accounts. The credit-only accounts can be cached in memory and shared between all the threads executing transactions.
+
+The current runtime can't predict whether an account is credit-only or credit-debit when the transaction account keys are locked at the start of the transaction processing pipeline. Accounts referenced by the transaction have not been loaded from the disk yet.
+
+An ideal design would cache the credit-only accounts while they are referenced by any transaction moving through the runtime, and release the cache when the last transaction exits the runtime.
+
+## Credit-only accounts and read-only account data
+
+Credit-only account data can be treated as read-only. Credit-debit account data is treated as read-write.
+
+## Transaction changes
+
+To enable the possibility of caching accounts only while they are in the runtime, the Transaction structure should be changed in the following way:
+
+* `program_ids: Vec` - This vector is removed. Program keys can be placed at the end of the `account_keys` vector within the `num_readonly_accounts` number set to the number of programs.
+* `num_readonly_accounts: u8` - The number of keys from the **end** of the transaction's `account_keys` array that is credit-only.
+
+The following possible accounts are present in an transaction:
+
+* paying account
+* RW accounts
+* R accounts
+* Program IDs
+
+The paying account must be credit-debit, and program IDs must be credit-only. The first account in the `account_keys` array is always the account that pays for the transaction fee, therefore it cannot be credit-only. For these reasons the credit-only accounts are all grouped together at the end of the `account_keys` vector. Counting credit-only accounts from the end allow for the default `0` value to still be functionally correct, since a transaction will succeed with all credit-debit accounts.
+
+Since accounts can only appear once in the transaction's `account_keys` array, an account can only be credit-only or credit-debit in a single transaction, not both. The runtime treats a transaction as one atomic unit of execution. If any instruction needs credit-debit access to an account, a copy needs to be made. The write lock is held for the entire time the transaction is being processed by the runtime.
+
+## Starvation
+
+Read locks for credit-only accounts can keep the runtime from executing transactions requesting a write lock to a credit-debit account.
+
+When a request for a write lock is made while a read lock is open, the transaction requesting the write lock should be cached. Upon closing the read lock, the pending transactions can be pushed through the runtime.
+
+While a pending write transaction exists, any additional read lock requests for that account should fail. It follows that any other write lock requests will also fail. Currently, clients must retransmit when a transaction fails because of a pending transaction. This approach would mimic that behavior as closely as possible while preventing write starvation.
+
+## Program execution with credit-only accounts
+
+Before handing off the accounts to program execution, the runtime can mark each account in each instruction as a credit-only account. The credit-only accounts can be passed as references without an extra copy. The transaction will abort on a write to credit-only.
+
+An alternative is to detect writes to credit-only accounts and fail the transactions before commit.
+
+## Alternative design
+
+This design attempts to cache a credit-only account after loading without the use of a transaction-specified credit-only accounts list. Instead, the credit-only accounts are held in a reference-counted table inside the runtime as the transactions are processed.
+
+1. Transaction accounts are locked.
+
+ a. If the account is present in the ‘credit-only' table, the TX does not fail.
+
+ ```text
+ The pending state for this TX is marked NeedReadLock.
+ ```
+
+2. Transaction accounts are loaded.
+
+ a. Transaction accounts that are credit-only increase their reference
+
+ ```text
+ count in the `credit-only` table.
+ ```
+
+ b. Transaction accounts that need a write lock and are present in the
+
+ ```text
+ `credit-only` table fail.
+ ```
+
+3. Transaction accounts are unlocked.
+
+ a. Decrement the `credit-only` lock table reference count; remove if its 0
+
+ b. Remove from the `lock` set if the account is not in the `credit-only`
+
+ ```text
+ table.
+ ```
+
+The downside with this approach is that if the `lock` set mutex is released between lock and load to allow better pipelining of transactions, a request for a credit-only account may fail. Therefore, this approach is not suitable for treating programs as credit-only accounts.
+
+Holding the accounts lock mutex while fetching the account from disk would potentially have a significant performance hit on the runtime. Fetching from disk is expected to be slow, but can be parallelized between multiple disks.
+
diff --git a/book/src/implemented-proposals/embedding-move.md b/book/src/implemented-proposals/embedding-move.md
new file mode 100644
index 0000000000..c948e7dafe
--- /dev/null
+++ b/book/src/implemented-proposals/embedding-move.md
@@ -0,0 +1,36 @@
+# Embedding the Move Langauge
+
+## Problem
+
+Solana enables developers to write on-chain programs in general purpose programming languages such as C or Rust, but those programs contain Solana-specific mechanisms. For example, there isn't another chain that asks developers to create a Rust module with a `process_instruction(KeyedAccounts)` function. Whenever practical, Solana should offer dApp developers more portable options.
+
+Until just recently, no popular blockchain offered a language that could expose the value of Solana's massively parallel [runtime](../validator/runtime.md). Solidity contracts, for example, do not separate references to shared data from contract code, and therefore need to be executed serially to ensure deterministic behavior. In practice we see that the most aggressively optimized EVM-based blockchains all seem to peak out around 1,200 TPS - a small fraction of what Solana can do. The Libra project, on the other hand, designed an on-chain programming language called Move that is more suitable for parallel execution. Like Solana's runtime, Move programs depend on accounts for all shared state.
+
+The biggest design difference between Solana's runtime and Libra's Move VM is how they manage safe invocations between modules. Solana took an operating systems approach and Libra took the domain-specific language approach. In the runtime, a module must trap back into the runtime to ensure the caller's module did not write to data owned by the callee. Likewise, when the callee completes, it must again trap back to the runtime to ensure the callee did not write to data owned by the caller. Move, on the other hand, includes an advanced type system that allows these checks to be run by its bytecode verifier. Because Move bytecode can be verified, the cost of verification is paid just once, at the time the module is loaded on-chain. In the runtime, the cost is paid each time a transaction crosses between modules. The difference is similar in spirit to the difference between a dynamically-typed language like Python versus a statically-typed language like Java. Solana's runtime allows dApps to be written in general purpose programming languages, but that comes with the cost of runtime checks when jumping between programs.
+
+This proposal attempts to define a way to embed the Move VM such that:
+
+* cross-module invocations within Move do not require the runtime's
+
+ cross-program runtime checks
+
+* Move programs can leverage functionality in other Solana programs and vice
+
+ versa
+
+* Solana's runtime parallelism is exposed to batches of Move and non-Move
+
+ transactions
+
+## Proposed Solution
+
+### Move VM as a Solana loader
+
+The Move VM shall be embedded as a Solana loader under the identifier `MOVE_PROGRAM_ID`, so that Move modules can be marked as `executable` with the VM as its `owner`. This will allow modules to load module dependencies, as well as allow for parallel execution of Move scripts.
+
+All data accounts owned by Move modules must set their owners to the loader, `MOVE_PROGRAM_ID`. Since Move modules encapsulate their account data in the same way Solana programs encapsulate theirs, the Move module owner should be embedded in the account data. The runtime will grant write access to the Move VM, and Move grants access to the module accounts.
+
+### Interacting with Solana programs
+
+To invoke instructions in non-Move programs, Solana would need to extend the Move VM with a `process_instruction()` system call. It would work the same as `process_instruction()` Rust BPF programs.
+
diff --git a/book/src/implemented-proposals/installer.md b/book/src/implemented-proposals/installer.md
new file mode 100644
index 0000000000..b3e7b0d698
--- /dev/null
+++ b/book/src/implemented-proposals/installer.md
@@ -0,0 +1,215 @@
+# Cluster Software Installation and Updates
+
+Currently users are required to build the solana cluster software themselves from the git repository and manually update it, which is error prone and inconvenient.
+
+This document proposes an easy to use software install and updater that can be used to deploy pre-built binaries for supported platforms. Users may elect to use binaries supplied by Solana or any other party they trust. Deployment of updates is managed using an on-chain update manifest program.
+
+## Motivating Examples
+
+### Fetch and run a pre-built installer using a bootstrap curl/shell script
+
+The easiest install method for supported platforms:
+
+```bash
+$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.18.0/install/solana-install-init.sh | sh
+```
+
+This script will check github for the latest tagged release and download and run the `solana-install-init` binary from there.
+
+If additional arguments need to be specified during the installation, the following shell syntax is used:
+
+```bash
+$ init_args=.... # arguments for `solana-install-init ...`
+$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.18.0/install/solana-install-init.sh | sh -s - ${init_args}
+```
+
+### Fetch and run a pre-built installer from a Github release
+
+With a well-known release URL, a pre-built binary can be obtained for supported platforms:
+
+```bash
+$ curl -o solana-install-init https://github.com/solana-labs/solana/releases/download/v0.18.0/solana-install-init-x86_64-apple-darwin
+$ chmod +x ./solana-install-init
+$ ./solana-install-init --help
+```
+
+### Build and run the installer from source
+
+If a pre-built binary is not available for a given platform, building the installer from source is always an option:
+
+```bash
+$ git clone https://github.com/solana-labs/solana.git
+$ cd solana/install
+$ cargo run -- --help
+```
+
+### Deploy a new update to a cluster
+
+Given a solana release tarball \(as created by `ci/publish-tarball.sh`\) that has already been uploaded to a publicly accessible URL, the following commands will deploy the update:
+
+```bash
+$ solana-keygen new -o update-manifest.json # <-- only generated once, the public key is shared with users
+$ solana-install deploy http://example.com/path/to/solana-release.tar.bz2 update-manifest.json
+```
+
+### Run a validator node that auto updates itself
+
+```bash
+$ solana-install init --pubkey 92DMonmBYXwEMHJ99c9ceRSpAmk9v6i3RdvDdXaVcrfj # <-- pubkey is obtained from whoever is deploying the updates
+$ export PATH=~/.local/share/solana-install/bin:$PATH
+$ solana-keygen ... # <-- runs the latest solana-keygen
+$ solana-install run solana-validator ... # <-- runs a validator, restarting it as necesary when an update is applied
+```
+
+## On-chain Update Manifest
+
+An update manifest is used to advertise the deployment of new release tarballs on a solana cluster. The update manifest is stored using the `config` program, and each update manifest account describes a logical update channel for a given target triple \(eg, `x86_64-apple-darwin`\). The account public key is well-known between the entity deploying new updates and users consuming those updates.
+
+The update tarball itself is hosted elsewhere, off-chain and can be fetched from the specified `download_url`.
+
+```text
+use solana_sdk::signature::Signature;
+
+/// Information required to download and apply a given update
+pub struct UpdateManifest {
+ pub timestamp_secs: u64, // When the release was deployed in seconds since UNIX EPOCH
+ pub download_url: String, // Download URL to the release tar.bz2
+ pub download_sha256: String, // SHA256 digest of the release tar.bz2 file
+}
+
+/// Userdata of an Update Manifest program Account.
+#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
+pub struct SignedUpdateManifest {
+ pub manifest: UpdateManifest,
+ pub manifest_signature: Signature,
+}
+```
+
+Note that the `manifest` field itself contains a corresponding signature \(`manifest_signature`\) to guard against man-in-the-middle attacks between the `solana-install` tool and the solana cluster RPC API.
+
+To guard against rollback attacks, `solana-install` will refuse to install an update with an older `timestamp_secs` than what is currently installed.
+
+## Release Archive Contents
+
+A release archive is expected to be a tar file compressed with bzip2 with the following internal structure:
+
+* `/version.yml` - a simple YAML file containing the field `"target"` - the
+
+ target tuple. Any additional fields are ignored.
+
+* `/bin/` -- directory containing available programs in the release.
+
+ `solana-install` will symlink this directory to
+
+ `~/.local/share/solana-install/bin` for use by the `PATH` environment
+
+ variable.
+
+* `...` -- any additional files and directories are permitted
+
+## solana-install Tool
+
+The `solana-install` tool is used by the user to install and update their cluster software.
+
+It manages the following files and directories in the user's home directory:
+
+* `~/.config/solana/install/config.yml` - user configuration and information about currently installed software version
+* `~/.local/share/solana/install/bin` - a symlink to the current release. eg, `~/.local/share/solana-update/-/bin`
+* `~/.local/share/solana/install/releases//` - contents of a release
+
+### Command-line Interface
+
+```text
+solana-install 0.16.0
+The solana cluster software installer
+
+USAGE:
+ solana-install [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+ -V, --version Prints version information
+
+OPTIONS:
+ -c, --config Configuration file to use [default: .../Library/Preferences/solana/install.yml]
+
+SUBCOMMANDS:
+ deploy deploys a new update
+ help Prints this message or the help of the given subcommand(s)
+ info displays information about the current installation
+ init initializes a new installation
+ run Runs a program while periodically checking and applying software updates
+ update checks for an update, and if available downloads and applies it
+```
+
+```text
+solana-install-init
+initializes a new installation
+
+USAGE:
+ solana-install init [OPTIONS]
+
+FLAGS:
+ -h, --help Prints help information
+
+OPTIONS:
+ -d, --data_dir Directory to store install data [default: .../Library/Application Support/solana]
+ -u, --url JSON RPC URL for the solana cluster [default: http://testnet.solana.com:8899]
+ -p, --pubkey Public key of the update manifest [default: 9XX329sPuskWhH4DQh6k16c87dHKhXLBZTL3Gxmve8Gp]
+```
+
+```text
+solana-install-info
+displays information about the current installation
+
+USAGE:
+ solana-install info [FLAGS]
+
+FLAGS:
+ -h, --help Prints help information
+ -l, --local only display local information, don't check the cluster for new updates
+```
+
+```text
+solana-install-deploy
+deploys a new update
+
+USAGE:
+ solana-install deploy
+
+FLAGS:
+ -h, --help Prints help information
+
+ARGS:
+ URL to the solana release archive
+ Keypair file for the update manifest (/path/to/keypair.json)
+```
+
+```text
+solana-install-update
+checks for an update, and if available downloads and applies it
+
+USAGE:
+ solana-install update
+
+FLAGS:
+ -h, --help Prints help information
+```
+
+```text
+solana-install-run
+Runs a program while periodically checking and applying software updates
+
+USAGE:
+ solana-install run [program_arguments]...
+
+FLAGS:
+ -h, --help Prints help information
+
+ARGS:
+ program to run
+ ... arguments to supply to the program
+
+The program will be restarted upon a successful software update
+```
+
diff --git a/book/src/implemented-proposals/leader-leader-transition.md b/book/src/implemented-proposals/leader-leader-transition.md
new file mode 100644
index 0000000000..ee84fa3e86
--- /dev/null
+++ b/book/src/implemented-proposals/leader-leader-transition.md
@@ -0,0 +1,54 @@
+# Leader-to-Leader Transition
+
+This design describes how leaders transition production of the PoH ledger between each other as each leader generates its own slot.
+
+## Challenges
+
+Current leader and the next leader are both racing to generate the final tick for the current slot. The next leader may arrive at that slot while still processing the current leader's entries.
+
+The ideal scenario would be that the next leader generated its own slot right after it was able to vote for the current leader. It is very likely that the next leader will arrive at their PoH slot height before the current leader finishes broadcasting the entire block.
+
+The next leader has to make the decision of attaching its own block to the last completed block, or wait to finalize the pending block. It is possible that the next leader will produce a block that proposes that the current leader failed, even though the rest of the network observes that block succeeding.
+
+The current leader has incentives to start its slot as early as possible to capture economic rewards. Those incentives need to be balanced by the leader's need to attach its block to a block that has the most commitment from the rest of the network.
+
+## Leader timeout
+
+While a leader is actively receiving entries for the previous slot, the leader can delay broadcasting the start of its block in real time. The delay is locally configurable by each leader, and can be dynamically based on the previous leader's behavior. If the previous leader's block is confirmed by the leader's TVU before the timeout, the PoH is reset to the start of the slot and this leader produces its block immediately.
+
+The downsides:
+
+* Leader delays its own slot, potentially allowing the next leader more time to
+
+ catch up.
+
+The upsides compared to guards:
+
+* All the space in a block is used for entries.
+* The timeout is not fixed.
+* The timeout is local to the leader, and therefore can be clever. The leader's heuristic can take into account turbine performance.
+* This design doesn't require a ledger hard fork to update.
+* The previous leader can redundantly transmit the last entry in the block to the next leader, and the next leader can speculatively decide to trust it to generate its block without verification of the previous block.
+* The leader can speculatively generate the last tick from the last received entry.
+* The leader can speculatively process transactions and guess which ones are not going to be encoded by the previous leader. This is also a censorship attack vector. The current leader may withhold transactions that it receives from the clients so it can encode them into its own slot. Once processed, entries can be replayed into PoH quickly.
+
+## Alternative design options
+
+### Guard tick at the end of the slot
+
+A leader does not produce entries in its block after the _penultimate tick_, which is the last tick before the first tick of the next slot. The network votes on the _last tick_, so the time difference between the _penultimate tick_ and the _last tick_ is the forced delay for the entire network, as well as the next leader before a new slot can be generated. The network can produce the _last tick_ from the _penultimate tick_.
+
+If the next leader receives the _penultimate tick_ before it produces its own _first tick_, it will reset its PoH and produce the _first tick_ from the previous leader's _penultimate tick_. The rest of the network will also reset its PoH to produce the _last tick_ as the id to vote on.
+
+The downsides:
+
+* Every vote, and therefore confirmation, is delayed by a fixed timeout. 1 tick, or around 100ms.
+* Average case confirmation time for a transaction would be at least 50ms worse.
+* It is part of the ledger definition, so to change this behavior would require a hard fork.
+* Not all the available space is used for entries.
+
+The upsides compared to leader timeout:
+
+* The next leader has received all the previous entries, so it can start processing transactions without recording them into PoH.
+* The previous leader can redundantly transmit the last entry containing the _penultimate tick_ to the next leader. The next leader can speculatively generate the _last tick_ as soon as it receives the _penultimate tick_, even before verifying it.
+
diff --git a/book/src/implemented-proposals/leader-validator-transition.md b/book/src/implemented-proposals/leader-validator-transition.md
new file mode 100644
index 0000000000..1afaf51b17
--- /dev/null
+++ b/book/src/implemented-proposals/leader-validator-transition.md
@@ -0,0 +1,53 @@
+# Leader-to-Validator Transition
+
+A fullnode typically operates as a validator. If, however, a staker delegates its stake to a fullnode, it will occasionally be selected as a _slot leader_. As a slot leader, the fullnode is responsible for producing blocks during an assigned _slot_. A slot has a duration of some number of preconfigured _ticks_. The duration of those ticks are estimated with a _PoH Recorder_ described later in this document.
+
+## BankFork
+
+BankFork tracks changes to the bank state over a specific slot. Once the final tick has been registered the state is frozen. Any attempts to write to are rejected.
+
+## Validator
+
+A validator operates on many different concurrent forks of the bank state until it generates a PoH hash with a height within its leader slot.
+
+## Slot Leader
+
+A slot leader builds blocks on top of only one fork, the one it last voted on.
+
+## PoH Recorder
+
+Slot leaders and validators use a PoH Recorder for both estimating slot height and for recording transactions.
+
+### PoH Recorder when Validating
+
+The PoH Recorder acts as a simple VDF when validating. It tells the validator when it needs to switch to the slot leader role. Every time the validator votes on a fork, it should use the fork's latest block id to re-seed the VDF. Re-seeding solves two problems. First, it synchronizes its VDF to the leader's, allowing it to more accurately determine when its leader slot begins. Second, if the previous leader goes down, all wallclock time is accounted for in the next leader's PoH stream. For example, if one block is missing when the leader starts, the block it produces should have a PoH duration of two blocks. The longer duration ensures the following leader isn't attempting to snip all the transactions from the previous leader's slot.
+
+### PoH Recorder when Leading
+
+A slot leader use the PoH Recorder to record transactions, locking their positions in time. The PoH hash must be derived from a previous leader's last block. If it isn't, its block will fail PoH verification and be rejected by the cluster.
+
+The PoH Recorder also serves to inform the slot leader when its slot is over. The leader needs to take care not to modify its bank if recording the transaction would generate a PoH height outside its designated slot. The leader, therefore, should not commit account changes until after it generates the entry's PoH hash. When the PoH height falls outside its slot any transactions in its pipeline may be dropped or forwarded to the next leader. Forwarding is preferred, as it would minimize network congestion, allowing the cluster to advertise higher TPS capacity.
+
+## Validator Loop
+
+The PoH Recorder manages the transition between modes. Once a ledger is replayed, the validator can run until the recorder indicates it should be the slot leader. As a slot leader, the node can then execute and record transactions.
+
+The loop is synchronized to PoH and does a synchronous start and stop of the slot leader functionality. After stopping, the validator's TVU should find itself in the same state as if a different leader had sent it the same block. The following is pseudocode for the loop:
+
+1. Query the LeaderScheduler for the next assigned slot.
+2. Run the TVU over all the forks.
+ 1. TVU will send votes to what it believes is the "best" fork.
+ 2. After each vote, restart the PoH Recorder to run until the next assigned
+
+ slot.
+3. When time to be a slot leader, start the TPU. Point it to the last fork the
+
+ TVU voted on.
+
+4. Produce entries until the end of the slot.
+ 1. For the duration of the slot, the TVU must not vote on other forks.
+ 2. After the slot ends, the TPU freezes its BankFork. After freezing,
+
+ the TVU may resume voting.
+5. Goto 1.
+
diff --git a/book/src/implemented-proposals/passive-stake-delegation-and-rewards.md b/book/src/implemented-proposals/passive-stake-delegation-and-rewards.md
new file mode 100644
index 0000000000..88a0b7c970
--- /dev/null
+++ b/book/src/implemented-proposals/passive-stake-delegation-and-rewards.md
@@ -0,0 +1,152 @@
+# Passive Stake Delegation and Rewards
+
+This design proposal focuses on the software architecture for the on-chain voting and staking programs. Incentives for staking is covered in [staking rewards](../proposals/staking-rewards.md).
+
+The current architecture requires a vote for each delegated stake from the validator, and therefore does not scale to allow replicator clients to automatically delegate their rewards.
+
+The design proposes a new set of programs for voting and stake delegation, The proposed programs allow many stake accounts to passively earn rewards with a single validator vote without permission or active involvement from the validator.
+
+## Current Design Problems
+
+In the current design each staker creates their own VoteState, and assigns a **delegate** in the VoteState that can submit votes. Since the validator has to actively vote for each stake delegated to it, validators can censor stakes by not voting for them.
+
+The number of votes is equal to the number of stakers, and not the number of validators. Replicator clients are expected to delegate their replication rewards as they are earned, and therefore the number of stakes is expected to be large compared to the number of validators in a long running cluster.
+
+## Proposed changes to the current design.
+
+The general idea is that instead of the staker, the validator will own the VoteState program. In this proposal the VoteState program is there to track validator votes, count validator generated credits and to provide any additional validator specific state. The VoteState program is not aware of any stakes delegated to it, and has no staking weight.
+
+The rewards generated are proportional to the amount of lamports staked. In this proposal stake state is stored as part of the StakeState program. This program is owned by the staker only. Lamports stored in this program are the stake. Unlike the current design, this program contains a new field to indicate which VoteState program the stake is delegated to.
+
+### VoteState
+
+VoteState is the current state of all the votes the **delegate** has submitted to the bank. VoteState contains the following state information:
+
+* votes - The submitted votes data structure.
+* credits - The total number of rewards this vote program has generated over its lifetime.
+* root\_slot - The last slot to reach the full lockout commitment necessary for rewards.
+* commission - The commission taken by this VoteState for any rewards claimed by staker's StakeState accounts. This is the percentage ceiling of the reward.
+* Account::lamports - The accumulated lamports from the commission. These do not count as stakes.
+* `authorized_vote_signer` - Only this identity is authorized to submit votes, and this field can only modified by this entity
+
+### VoteInstruction::Initialize
+
+* `account[0]` - RW - The VoteState
+
+ `VoteState::authorized_vote_signer` is initialized to `account[0]`
+
+ other VoteState members defaulted
+
+### VoteInstruction::AuthorizeVoteSigner\(Pubkey\)
+
+* `account[0]` - RW - The VoteState
+
+ `VoteState::authorized_vote_signer` is set to to `Pubkey`, instruction must by
+
+ signed by Pubkey
+
+### StakeState
+
+A StakeState takes one of two forms, StakeState::Stake and StakeState::MiningPool.
+
+### StakeState::Stake
+
+Stake is the current delegation preference of the **staker**. Stake contains the following state information:
+
+* `voter_pubkey` - The pubkey of the VoteState instance the lamports are delegated to.
+* `credits_observed` - The total credits claimed over the lifetime of the program.
+* `stake` - The actual activated stake.
+* Account::lamports - Lamports available for staking, including any earned as rewards.
+
+### StakeState::MiningPool
+
+There are two approaches to the mining pool. The bank could allow the StakeState program to bypass the token balance check, or a program representing the mining pool could run on the network. To avoid a single network wide lock, the pool can be split into several mining pools. This design focuses on using a StakeState::MiningPool as the cluster wide mining pools.
+
+* 256 StakeState::MiningPool are initialized, each with 1/256 number of mining pool
+
+ tokens stored as `Account::lamports`.
+
+The stakes and the MiningPool are accounts that are owned by the same `Stake` program.
+
+### StakeInstruction::DelegateStake\(stake\)
+
+* `account[0]` - RW - The StakeState::Stake instance. `StakeState::Stake::credits_observed` is initialized to `VoteState::credits`. `StakeState::Stake::voter_pubkey` is initialized to `account[1]` `StakeState::Stake::stake` is initialized to `stake`, as long as it's less than account\[0\].lamports
+* `account[1]` - R - The VoteState instance.
+
+### StakeInstruction::RedeemVoteCredits
+
+The VoteState program and the StakeState programs maintain a lifetime counter of total rewards generated and claimed. Therefore an explicit `Clear` instruction is not necessary. When claiming rewards, the total lamports deposited into the StakeState and as validator commission is proportional to `VoteState::credits - StakeState::credits_observed`.
+
+* `account[0]` - RW - The StakeState::MiningPool instance that will fulfill the
+
+ reward.
+
+* `account[1]` - RW - The StakeState::Stake instance that is redeeming votes
+
+ credits.
+
+* `account[2]` - R - The VoteState instance, must be the same as
+
+ `StakeState::voter_pubkey`
+
+Reward is payed out for the difference between `VoteState::credits` to `StakeState::Delgate.credits_observed`, and `credits_observed` is updated to `VoteState::credits`. The commission is deposited into the `VoteState` token balance, and the reward is deposited to the `StakeState::Stake` token balance. The reward and the commission is weighted by the `StakeState::lamports` divided by total lamports staked.
+
+The Staker or the owner of the Stake program sends a transaction with this instruction to claim the reward.
+
+Any random MiningPool can be used to redeem the credits.
+
+```text
+let credits_to_claim = vote_state.credits - stake_state.credits_observed;
+stake_state.credits_observed = vote_state.credits;
+```
+
+`credits_to_claim` is used to compute the reward and commission, and `StakeState::Stake::credits_observed` is updated to the latest `VoteState::credits` value.
+
+### Collecting network fees into the MiningPool
+
+At the end of the block, before the bank is frozen, but after it processed all the transactions for the block, a virtual instruction is executed to collect the transaction fees.
+
+* A portion of the fees are deposited into the leader's account.
+* A portion of the fees are deposited into the smallest StakeState::MiningPool
+
+ account.
+
+### Benefits
+
+* Single vote for all the stakers.
+* Clearing of the credit variable is not necessary for claiming rewards.
+* Each delegated stake can claim its rewards independently.
+* Commission for the work is deposited when a reward is claimed by the delegated stake.
+
+This proposal would benefit from the `read-only` accounts proposal to allow for many rewards to be claimed concurrently.
+
+## Passive Delegation
+
+Any number of instances of StakeState::Stake programs can delegate to a single VoteState program without an interactive action from the identity controlling the VoteState program or submitting votes to the program.
+
+The total stake allocated to a VoteState program can be calculated by the sum of all the StakeState programs that have the VoteState pubkey as the `StakeState::Stake::voter_pubkey`.
+
+## Example Callflow
+
+
+
+## Future work
+
+Validators may want to split the stake delegated to them amongst many validator nodes since stake is used as weight in the network control and data planes. One way to implement this would be for the StakeState to delegate to a pool of validators instead of a single one.
+
+Instead of a single `vote_pubkey` and `credits_observed` entry in the StakeState program, the program can be initialized with a vector of tuples.
+
+```text
+Voter {
+ voter_pubkey: Pubkey,
+ credits_observed: u64,
+ weight: u8,
+}
+```
+
+* voters: Vec - Array of VoteState accounts that are voting rewards with
+
+ this stake.
+
+A StakeState program would claim a fraction of the reward from each voter in the `voters` array, and each voter would be delegated a fraction of the stake.
+
diff --git a/book/src/implemented-proposals/persistent-account-storage.md b/book/src/implemented-proposals/persistent-account-storage.md
new file mode 100644
index 0000000000..c09ba7c016
--- /dev/null
+++ b/book/src/implemented-proposals/persistent-account-storage.md
@@ -0,0 +1,94 @@
+# Persistent Account Storage
+
+## Persistent Account Storage
+
+The set of Accounts represent the current computed state of all the transactions that have been processed by a fullnode. Each fullnode needs to maintain this entire set. Each block that is proposed by the network represents a change to this set, and since each block is a potential rollback point the changes need to be reversible.
+
+Persistent storage like NVMEs are 20 to 40 times cheaper than DDR. The problem with persistent storage is that write and read performance is much slower than DDR and care must be taken in how data is read or written to. Both reads and writes can be split between multiple storage drives and accessed in parallel. This design proposes a data structure that allows for concurrent reads and concurrent writes of storage. Writes are optimized by using an AppendVec data structure, which allows a single writer to append while allowing access to many concurrent readers. The accounts index maintains a pointer to a spot where the account was appended to every fork, thus removing the need for explicit checkpointing of state.
+
+## AppendVec
+
+AppendVec is a data structure that allows for random reads concurrent with a single append-only writer. Growing or resizing the capacity of the AppendVec requires exclusive access. This is implemented with an atomic `offset`, which is updated at the end of a completed append.
+
+The underlying memory for an AppendVec is a memory-mapped file. Memory-mapped files allow for fast random access and paging is handled by the OS.
+
+## Account Index
+
+The account index is designed to support a single index for all the currently forked Accounts.
+
+```text
+type AppendVecId = usize;
+
+type Fork = u64;
+
+struct AccountMap(Hashmap);
+
+type AccountIndex = HashMap;
+```
+
+The index is a map of account Pubkeys to a map of Forks and the location of the Account data in an AppendVec. To get the version of an account for a specific Fork:
+
+```text
+/// Load the account for the pubkey.
+/// This function will load the account from the specified fork, falling back to the fork's parents
+/// * fork - a virtual Accounts instance, keyed by Fork. Accounts keep track of their parents with Forks,
+/// the persistent store
+/// * pubkey - The Account's public key.
+pub fn load_slow(&self, id: Fork, pubkey: &Pubkey) -> Option<&Account>
+```
+
+The read is satisfied by pointing to a memory-mapped location in the `AppendVecId` at the stored offset. A reference can be returned without a copy.
+
+### Root Forks
+
+[Tower BFT](tower-bft.md) eventually selects a fork as a root fork and the fork is squashed. A squashed/root fork cannot be rolled back.
+
+When a fork is squashed, all accounts in its parents not already present in the fork are pulled up into the fork by updating the indexes. Accounts with zero balance in the squashed fork are removed from fork by updating the indexes.
+
+An account can be _garbage-collected_ when squashing makes it unreachable.
+
+Three possible options exist:
+
+* Maintain a HashSet of root forks. One is expected to be created every second. The entire tree can be garbage-collected later. Alternatively, if every fork keeps a reference count of accounts, garbage collection could occur any time an index location is updated.
+* Remove any pruned forks from the index. Any remaining forks lower in number than the root are can be considered root.
+* Scan the index, migrate any old roots into the new one. Any remaining forks lower than the new root can be deleted later.
+
+## Append-only Writes
+
+All the updates to Accounts occur as append-only updates. For every account update, a new version is stored in the AppendVec.
+
+It is possible to optimize updates within a single fork by returning a mutable reference to an already stored account in a fork. The Bank already tracks concurrent access of accounts and guarantees that a write to a specific account fork will not be concurrent with a read to an account at that fork. To support this operation, AppendVec should implement this function:
+
+```text
+fn get_mut(&self, index: u64) -> &mut T;
+```
+
+This API allows for concurrent mutable access to a memory region at `index`. It relies on the Bank to guarantee exclusive access to that index.
+
+## Garbage collection
+
+As accounts get updated, they move to the end of the AppendVec. Once capacity has run out, a new AppendVec can be created and updates can be stored there. Eventually references to an older AppendVec will disappear because all the accounts have been updated, and the old AppendVec can be deleted.
+
+To speed up this process, it's possible to move Accounts that have not been recently updated to the front of a new AppendVec. This form of garbage collection can be done without requiring exclusive locks to any of the data structures except for the index update.
+
+The initial implementation for garbage collection is that once all the accounts in an AppendVec become stale versions, it gets reused. The accounts are not updated or moved around once appended.
+
+## Index Recovery
+
+Each bank thread has exclusive access to the accounts during append, since the accounts locks cannot be released until the data is committed. But there is no explicit order of writes between the separate AppendVec files. To create an ordering, the index maintains an atomic write version counter. Each append to the AppendVec records the index write version number for that append in the entry for the Account in the AppendVec.
+
+To recover the index, all the AppendVec files can be read in any order, and the latest write version for every fork should be stored in the index.
+
+## Snapshots
+
+To snapshot, the underlying memory-mapped files in the AppendVec need to be flushed to disk. The index can be written out to disk as well.
+
+## Performance
+
+* Append-only writes are fast. SSDs and NVMEs, as well as all the OS level kernel data structures, allow for appends to run as fast as PCI or NVMe bandwidth will allow \(2,700 MB/s\).
+* Each replay and banking thread writes concurrently to its own AppendVec.
+* Each AppendVec could potentially be hosted on a separate NVMe.
+* Each replay and banking thread has concurrent read access to all the AppendVecs without blocking writes.
+* Index requires an exclusive write lock for writes. Single-thread performance for HashMap updates is on the order of 10m per second.
+* Banking and Replay stages should use 32 threads per NVMe. NVMes have optimal performance with 32 concurrent readers or writers.
+
diff --git a/book/src/implemented-proposals/reliable-vote-transmission.md b/book/src/implemented-proposals/reliable-vote-transmission.md
new file mode 100644
index 0000000000..0da6e97437
--- /dev/null
+++ b/book/src/implemented-proposals/reliable-vote-transmission.md
@@ -0,0 +1,59 @@
+# Reliable Vote Transmission
+
+Validator votes are messages that have a critical function for consensus and continuous operation of the network. Therefore it is critical that they are reliably delivered and encoded into the ledger.
+
+## Challenges
+
+1. Leader rotation is triggered by PoH, which is clock with high drift. So many nodes are likely to have an incorrect view if the next leader is active in realtime or not.
+2. The next leader may be easily be flooded. Thus a DDOS would not only prevent delivery of regular transactions, but also consensus messages.
+3. UDP is unreliable, and our asynchronous protocol requires any message that is transmitted to be retransmitted until it is observed in the ledger. Retransmittion could potentially cause an unintentional _thundering herd_ against the leader with a large number of validators. Worst case flood would be `(num_nodes * num_retransmits)`.
+4. Tracking if the vote has been transmitted or not via the ledger does not guarantee it will appear in a confirmed block. The current observed block may be unrolled. Validators would need to maintain state for each vote and fork.
+
+## Design
+
+1. Send votes as a push message through gossip. This ensures delivery of the vote to all the next leaders, not just the next future one.
+2. Leaders will read the Crds table for new votes and encode any new received votes into the blocks they propose. This allows for validator votes to be included in rollback forks by all the future leaders.
+3. Validators that receive votes in the ledger will add them to their local crds table, not as a push request, but simply add them to the table. This shortcuts the push message protocol, so the validation messages do not need to be retransmitted twice around the network.
+4. CrdsValue for vote should look like this `Votes(Vec)`
+
+Each vote transaction should maintain a `wallclock` in its data. The merge strategy for Votes will keep the last N set of votes as configured by the local client. For push/pull the vector is traversed recursively and each Transaction is treated as an individual CrdsValue with its own local wallclock and signature.
+
+Gossip is designed for efficient propagation of state. Messages that are sent through gossip-push are batched and propagated with a minimum spanning tree to the rest of the network. Any partial failures in the tree are actively repaired with the gossip-pull protocol while minimizing the amount of data transfered between any nodes.
+
+## How this design solves the Challenges
+
+1. Because there is no easy way for validators to be in sync with leaders on the leader's "active" state, gossip allows for eventual delivery regardless of that state.
+2. Gossip will deliver the messages to all the subsequent leaders, so if the current leader is flooded the next leader would have already received these votes and is able to encode them.
+3. Gossip minimizes the number of requests through the network by maintaining an efficient spanning tree, and using bloom filters to repair state. So retransmit back-off is not necessary and messages are batched.
+4. Leaders that read the crds table for votes will encode all the new valid votes that appear in the table. Even if this leader's block is unrolled, the next leader will try to add the same votes without any additional work done by the validator. Thus ensuring not only eventual delivery, but eventual encoding into the ledger.
+
+## Performance
+
+1. Worst case propagation time to the next leader is Log\(N\) hops with a base depending on the fanout. With our current default fanout of 6, it is about 6 hops to 20k nodes.
+2. The leader should receive 20k validation votes aggregated by gossip-push into 64kb blobs. Which would reduce the number of packets for 20k network to 80 blobs.
+3. Each validators votes is replicated across the entire network. To maintain a queue of 5 previous votes the Crds table would grow by 25 megabytes. `(20,000 nodes * 256 bytes * 5)`.
+
+## Two step implementation rollout
+
+Initially the network can perform reliably with just 1 vote transmitted and maintained through the network with the current Vote implementation. For small networks a fanout of 6 is sufficient. With small network the memory and push overhead is minor.
+
+### Sub 1k validator network
+
+1. Crds just maintains the validators latest vote.
+2. Votes are pushed and retransmitted regardless if they are appearing in the ledger.
+3. Fanout of 6.
+4. Worst case 256kb memory overhead per node.
+5. Worst case 4 hops to propagate to every node.
+6. Leader should receive the entire validator vote set in 4 push message blobs.
+
+### Sub 20k network
+
+Everything above plus the following:
+
+1. CRDS table maintains a vector of 5 latest validator votes.
+2. Votes encode a wallclock. CrdsValue::Votes is a type that recurses into the transaction vector for all the gossip protocols.
+3. Increase fanout to 20.
+4. Worst case 25mb memory overhead per node.
+5. Sub 4 hops worst case to deliver to the entire network.
+6. 80 blobs received by the leader for all the validator messages.
+
diff --git a/book/src/implemented-proposals/repair-service.md b/book/src/implemented-proposals/repair-service.md
new file mode 100644
index 0000000000..9f7fd00fef
--- /dev/null
+++ b/book/src/implemented-proposals/repair-service.md
@@ -0,0 +1,49 @@
+# Repair Service
+
+## Repair Service
+
+The RepairService is in charge of retrieving missing blobs that failed to be delivered by primary communication protocols like Avalanche. It is in charge of managing the protocols described below in the `Repair Protocols` section below.
+
+## Challenges:
+
+1\) Validators can fail to receive particular blobs due to network failures
+
+2\) Consider a scenario where blocktree contains the set of slots {1, 3, 5}. Then Blocktree receives blobs for some slot 7, where for each of the blobs b, b.parent == 6, so then the parent-child relation 6 -> 7 is stored in blocktree. However, there is no way to chain these slots to any of the existing banks in Blocktree, and thus the `Blob Repair` protocol will not repair these slots. If these slots happen to be part of the main chain, this will halt replay progress on this node.
+
+3\) Validators that find themselves behind the cluster by an entire epoch struggle/fail to catch up because they do not have a leader schedule for future epochs. If nodes were to blindly accept repair blobs in these future epochs, this exposes nodes to spam.
+
+## Repair Protocols
+
+The repair protocol makes best attempts to progress the forking structure of Blocktree.
+
+The different protocol strategies to address the above challenges:
+
+1. Blob Repair \(Addresses Challenge \#1\): This is the most basic repair protocol, with the purpose of detecting and filling "holes" in the ledger. Blocktree tracks the latest root slot. RepairService will then periodically iterate every fork in blocktree starting from the root slot, sending repair requests to validators for any missing blobs. It will send at most some `N` repair reqeusts per iteration.
+
+ Note: Validators will only accept blobs within the current verifiable epoch \(epoch the validator has a leader schedule for\).
+
+2. Preemptive Slot Repair \(Addresses Challenge \#2\): The goal of this protocol is to discover the chaining relationship of "orphan" slots that do not currently chain to any known fork.
+ * Blocktree will track the set of "orphan" slots in a separate column family.
+ * RepairService will periodically make `RequestOrphan` requests for each of the orphans in blocktree.
+
+ `RequestOrphan(orphan)` request - `orphan` is the orphan slot that the requestor wants to know the parents of `RequestOrphan(orphan)` response - The highest blobs for each of the first `N` parents of the requested `orphan`
+
+ On receiving the responses `p`, where `p` is some blob in a parent slot, validators will:
+
+ * Insert an empty `SlotMeta` in blocktree for `p.slot` if it doesn't already exist.
+ * If `p.slot` does exist, update the parent of `p` based on `parents`
+
+ Note: that once these empty slots are added to blocktree, the `Blob Repair` protocol should attempt to fill those slots.
+
+ Note: Validators will only accept responses containing blobs within the current verifiable epoch \(epoch the validator has a leader schedule for\).
+3. Repairmen \(Addresses Challenge \#3\): This part of the repair protocol is the primary mechanism by which new nodes joining the cluster catch up after loading a snapshot. This protocol works in a "forward" fashion, so validators can verify every blob that they receive against a known leader schedule.
+
+ Each validator advertises in gossip:
+
+ * Current root
+ * The set of all completed slots in the confirmed epochs \(an epoch that was calculated based on a bank <= current root\) past the current root
+
+ Observers of this gossip message with higher epochs \(repairmen\) send blobs to catch the lagging node up with the rest of the cluster. The repairmen are responsible for sending the slots within the epochs that are confrimed by the advertised `root` in gossip. The repairmen divide the responsibility of sending each of the missing slots in these epochs based on a random seed \(simple blob.index iteration by N, seeded with the repairman's node\_pubkey\). Ideally, each repairman in an N node cluster \(N nodes whose epochs are higher than that of the repairee\) sends 1/N of the missing blobs. Both data and coding blobs for missing slots are sent. Repairmen do not send blobs again to the same validator until they see the message in gossip updated, at which point they perform another iteration of this protocol.
+
+ Gossip messages are updated every time a validator receives a complete slot within the epoch. Completed slots are detected by blocktree and sent over a channel to RepairService. It is important to note that we know that by the time a slot X is complete, the epoch schedule must exist for the epoch that contains slot X because WindowService will reject blobs for unconfirmed epochs. When a newly completed slot is detected, we also update the current root if it has changed since the last update. The root is made available to RepairService through Blocktree, which holds the latest root.
+
diff --git a/book/src/implemented-proposals/testing-programs.md b/book/src/implemented-proposals/testing-programs.md
new file mode 100644
index 0000000000..9f10008712
--- /dev/null
+++ b/book/src/implemented-proposals/testing-programs.md
@@ -0,0 +1,52 @@
+# Testing Programs
+
+Applications send transactions to a Solana cluster and query validators to confirm the transactions were processed and to check each transaction's result. When the cluster doesn't behave as anticipated, it could be for a number of reasons:
+
+* The program is buggy
+* The BPF loader rejected an unsafe program instruction
+* The transaction was too big
+* The transaction was invalid
+* The Runtime tried to execute the transaction when another one was accessing
+
+ the same account
+
+* The network dropped the transaction
+* The cluster rolled back the ledger
+* A validator responded to queries maliciously
+
+## The AsyncClient and SyncClient Traits
+
+To troubleshoot, the application should retarget a lower-level component, where fewer errors are possible. Retargeting can be done with different implementations of the AsyncClient and SyncClient traits.
+
+Components implement the following primary methods:
+
+```text
+trait AsyncClient {
+ fn async_send_transaction(&self, transaction: Transaction) -> io::Result;
+}
+
+trait SyncClient {
+ fn get_signature_status(&self, signature: &Signature) -> Result