Compare commits

...

28 Commits

Author SHA1 Message Date
Tyera Eulberg
b0addba2a9 Gate nonce-overwrite change (#11079) 2020-07-15 21:14:28 +00:00
mergify[bot]
bb59525ff8 Refactor file and URL paths in docusaurus (#11080) (#11083) 2020-07-15 14:35:12 -06:00
mergify[bot]
acd25124d4 Make accounts file clean faster (#11071) (#11077)
(cherry picked from commit 7fe870ba48)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-07-15 18:00:41 +00:00
mergify[bot]
d718ab2491 accounts_clean: Convert stack dependency calculation with iterative (#11067) (#11076)
* accounts_clean: Convert stack dependency calculation with iterative

* optimize clean with by creating a reverse-lookup hashset of the affected
keys

* Add dependency bench

reduce bench

* Huge clean

(cherry picked from commit 8bf3a0aa05)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-07-15 15:13:33 +00:00
mergify[bot]
1860aacd1f Temporalily disable inflation to fix it later (#11072) (#11075)
* Revert get_inflation()

* Temporalily disable inflation to fix it later

* Use match and proper type aliases

(cherry picked from commit d81c7250b0)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-07-15 11:20:02 +00:00
mergify[bot]
d4bbb7f516 Expose TransactionStatusService to the other blockstore_processor path (bp #11070) (#11074)
* Expose tss to the other blockstore_processor path (#11070)

(cherry picked from commit 9a80e31bae)

# Conflicts:
#	core/src/validator.rs
#	ledger/src/blockstore_processor.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-07-15 05:50:45 +00:00
mergify[bot]
d1c0f4b4f1 Fix hygiene issues in declare_program! and declare_loader! (bp #10905) (#11073)
* Fix hygiene issues in `declare_program!` and `declare_loader!`

The `declare_program!` and `declare_loader!` macros both expand to
new macro definitions (based on the `$name` argument). These 'inner'
macros make use of the special `$crate` metavariable to access items in
the crate where the 'inner' macros is defined.

However, this only works due to a bug in rustc. When a macro is
expanded, all `$crate` tokens in its output are 'marked' as being
resolved in the defining crate of that macro. An inner macro (including
the body of its arms) is 'just' another set of tokens that appears in
the body of the outer macro, so any `$crate` identifiers used there are
resolved relative to the 'outer' macro.

For example, consider the following code:

```rust
macro_rules! outer {
    () => {
        macro_rules! inner {
            () => {
                $crate::Foo
            }
        }
    }
}
```

The path `$crate::Foo` will be resolved relative to the crate that defines `outer`,
**not** the crate which defines `inner`.

However, rustc currently loses this extra resolution information
(referred to as 'hygiene' information) when a crate is serialized.
In the above example, this means that the macro `inner` (which gets
defined in whatever crate invokes `outer!`) will behave differently
depending on which crate it is invoked from:

When `inner` is invoked from the same crate in which it is defined,
the hygiene information will still be available,
which will cause `$crate::Foo` to be resolved in the crate which defines 'outer'.

When `inner` is invoked from a different crate, it will be loaded from
the metadata of the crate which defines 'inner'. Since the hygiene
information is currently lost, rust will 'forget' that `$crate::Foo` is
supposed to be resolved in the context of 'outer'. Instead, it will be
resolved relative to the crate which defines 'inner', which can cause
incorrect code to compile.

This bug will soon be fixed in rust (see https://github.com/rust-lang/rust/pull/72121),
which will break `declare_program!` and `declare_loader!`. Fortunately,
it's possible to obtain the desired behavior (`$crate` resolving in the
context of the 'inner' macro) by use of a procedural macro.

This commit adds a `respan!` proc-macro to the `sdk/macro` crate.
Using the newly-stabilized (on Nightly) `Span::resolved_at` method,
the `$crate` identifier can be made to be resolved in the context of the
proper crate.

Since `Span::resolved_at` is only stable on the latest nightly,
referencing it on an earlier version of Rust will cause a compilation error.
This requires the `rustversion` crate to be used, which allows conditionally
compiling code epending on the Rust compiler version in use. Since this method is already
stabilized in the latest nightly, there will never be a situation where
the hygiene bug is fixed (e.g. https://github.com/rust-lang/rust/pull/72121)
is merged but we are unable to call `Span::resolved_at`.

(cherry picked from commit 05445c718e)

# Conflicts:
#	Cargo.lock
#	sdk/Cargo.toml

* Replace FIXME with an issue link

(cherry picked from commit b0cb2b0106)

* Update lock files

(cherry picked from commit 42f88484f4)

# Conflicts:
#	programs/bpf/Cargo.lock
#	programs/librapay/Cargo.lock
#	programs/move_loader/Cargo.lock

* Split comment over multiple lines

Due to https://github.com/rust-lang/rustfmt/issues/4325, leaving this as
one line causes rustfmt to add extra indentation to the surrounding
code.

(cherry picked from commit fed69e96a9)

* Fix clippy lints

(cherry picked from commit e7387f60a7)

* Apply #![feature(proc_macro_hygiene)] when needed

This allows the rust-bpf-builder toolchain to build the sdk

(cherry picked from commit 95490ff56e)

# Conflicts:
#	sdk/build.rs
#	sdk/src/lib.rs

* Update Cargo.toml

* Update lib.rs

* Add rustc_version

* lock file updates

Co-authored-by: Aaron Hill <aa1ronham@gmail.com>
Co-authored-by: Jack May <jack@solana.com>
Co-authored-by: Michael Vines <mvines@gmail.com>
2020-07-15 02:40:36 +00:00
carllin
b72b837ba2 Revert dashboard changes (#11069)
Co-authored-by: Carl <carl@solana.com>
2020-07-15 00:42:39 +00:00
mergify[bot]
fde85c96c0 Add dropped vote metrics (#11009) (#11030)
(cherry picked from commit 1880621740)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-07-14 15:21:49 -07:00
mergify[bot]
121418dad2 CLI: Fix vote blind indexing (bp #11045) (#11050)
* CLI: Fix explicitly plumb withdraw_authority through vote-update-commission

(cherry picked from commit 3392ecc310)

* CLI: Fix explicitly plumb withdraw_authority through vote-update-validator

(cherry picked from commit 2284699889)

* CLI: Fix explicitly plumb vote_account through create-vote-account

(cherry picked from commit 14ac233d01)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-07-14 15:35:46 +00:00
Dan Albert
f44f94fe23 Remove docs step from buildkite flow (#11035) (#11044) 2020-07-14 08:20:58 -06:00
mergify[bot]
55a4481022 Clean up docs publishing flow (#11043) (#11051)
* Clean up publishing flow

* Update README

Co-authored-by: publish-docs.sh <maintainers@solana.com>
(cherry picked from commit 303a4df6ef)

Co-authored-by: Dan Albert <dan@solana.com>
2020-07-14 14:09:53 +00:00
mergify[bot]
e859ad37a8 Add TreeDiff trait to reuse tree functions (#11046) (#11048)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit e9cbdf711b)

Co-authored-by: carllin <wumu727@gmail.com>
2020-07-14 09:03:53 +00:00
mergify[bot]
1a28c7fc12 Fix recent blockhashes delay (bp #11036) (#11040)
* Add failing test

(cherry picked from commit 942c019d50)

* Factor locked portion of Bank::update_recent_blockhashes() out to helper

(cherry picked from commit 9cc379af6c)

* Synchronize BlockhashQueue and RecentBlockhashes sysvar update

(cherry picked from commit 5357ff6d60)

* Bump goldens

(cherry picked from commit 837ac77c02)

* Fix test advancing banks from incomplete slots

(cherry picked from commit 51283c931c)

* Mode gate RecentBlockhashes/BlockhashQueue sync

(cherry picked from commit 5741002a32)

Co-authored-by: Tyera Eulberg <tyera@solana.com>
Co-authored-by: Trent Nelson <trent@solana.com>
2020-07-14 04:12:37 +00:00
Dan Albert
c706a07764 Fix travis config (#11033)
* Fix travis config

* Remove linux build job from travis
2020-07-13 17:00:18 -06:00
Dan Albert
59568e5776 Move from gitbook to docusaurus - backport (#10970) (#11029)
* Move v1.2 to docusaurus

* Fixup travis conifg

Co-authored-by: publish-docs.sh <maintainers@solana.com>
2020-07-13 14:45:28 -06:00
Dan Albert
33ca8fa72a Fix Travis PR detection environment (#10974) (#11024) 2020-07-13 14:25:40 -06:00
mergify[bot]
4bb66a81fb Check for deleting key, make sure list is empty again (#11007) (#11011)
Co-authored-by: sakridge <sakridge@gmail.com>
2020-07-13 09:00:48 -07:00
Michael Vines
468c14b14f Revert "Add UiTransactionEncoding::Raw"
This reverts commit bcc890e705.
2020-07-12 09:00:11 -07:00
Tyera Eulberg
03e505897a Backport windows build fixes (#11004)
* Bump spl-memo

* spl memo linking windows (#11000)

* Update spl-memo to fix windows linking error

* Only programs need the stubs

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>

Co-authored-by: Jack May <jack@solana.com>
Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-07-10 21:46:11 -06:00
mergify[bot]
5205eb382e Switch to using weighted repair in RepairService (#10735) (#10985)
Co-authored-by: Carl <carl@solana.com>
2020-07-10 16:15:36 -07:00
Michael Vines
b07b6e56fa getConfirmedBlocks now has an upper limit on slot range
(cherry picked from commit aef6bf272e)
2020-07-10 15:40:03 -07:00
Michael Vines
bcc890e705 Add UiTransactionEncoding::Raw
(cherry picked from commit a4a5438b6d)
2020-07-10 14:55:27 -07:00
mergify[bot]
07d14f6f07 Add RepairWeight to track votes seen in gossip for weighted repair (#10903) (#10938)
* Add RepairWeight

Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit 3f6042d8b3)

Co-authored-by: carllin <wumu727@gmail.com>
2020-07-10 14:13:56 -07:00
mergify[bot]
03b213e296 Add block time placeholder to getConfirmedBlock (#10990)
(cherry picked from commit 491f5ae61a)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-07-10 11:02:27 -07:00
mergify[bot]
1bfce24c9f Fix skipped slot detection for eager rent collect (#10890) (#10978)
(cherry picked from commit f1c1152948)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-07-10 11:59:44 +09:00
mergify[bot]
94b2565969 Fix nonce fee_calculator overwrite (#10973) (#10976)
* Add failing test

* Pass fee_calculator to prepare_if_nonce_account; only overwrite in error case

(cherry picked from commit 25228ca957)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-07-09 16:57:34 -06:00
sakridge
2896fdb603 Update version to v1.2.11 (#10966) 2020-07-09 06:48:30 -07:00
306 changed files with 6037 additions and 4840 deletions

View File

@@ -1,18 +0,0 @@
root: ./docs/src
structure:
readme: introduction.md
summary: SUMMARY.md
redirects:
wallet: ./wallet-guide/README.md
wallet/app-wallets: ./wallet-guide/apps.md
wallet/app-wallets/trust-wallet: ./wallet-guide/trust-wallet.md
wallet/app-wallets/ledger-live: ./wallet-guide/ledger-live.md
wallet/cli-wallets: ./wallet-guide/cli.md
wallet/cli-wallets/paper-wallet: ./paper-wallet/README.md
wallet/cli-wallets/paper-wallet/paper-wallet-usage: ./paper-wallet/paper-wallet-usage.md
wallet/cli-wallets/remote-wallet: ./hardware-wallets/README.md
wallet/cli-wallets/remote-wallet/ledger: ./hardware-wallets/ledger.md
wallet/cli-wallets/file-system-wallet: ./file-system-wallet/README.md
wallet/support: ./wallet-guide/support.md

View File

@@ -1,46 +1,71 @@
os:
- osx
- windows
language: rust
rust:
- stable
install:
- source ci/rust-version.sh
script:
- source ci/env.sh
- ci/publish-tarball.sh
branches:
only:
- master
- /^v\d+\.\d+/
if: type IN (api, cron) OR tag IS present
notifications:
slack:
on_success: change
secure: F4IjOE05MyaMOdPRL+r8qhs7jBvv4yDM3RmFKE1zNXnfUOqV4X38oQM1EI+YVsgpMQLj/pxnEB7wcTE4Bf86N6moLssEULCpvAuMVoXj4QbWdomLX+01WbFa6fLVeNQIg45NHrz2XzVBhoKOrMNnl+QI5mbR2AlS5oqsudHsXDnyLzZtd4Y5SDMdYG1zVWM01+oNNjgNfjcCGmOE/K0CnOMl6GPi3X9C34tJ19P2XT7MTDsz1/IfEF7fro2Q8DHEYL9dchJMoisXSkem5z7IDQkGzXsWdWT4NnndUvmd1MlTCE9qgoXDqRf95Qh8sB1Dz08HtvgfaosP2XjtNTfDI9BBYS15Ibw9y7PchAJE1luteNjF35EOy6OgmCLw/YpnweqfuNViBZz+yOPWXVC0kxnPIXKZ1wyH9ibeH6E4hr7a8o9SV/6SiWIlbYF+IR9jPXyTCLP/cc3sYljPWxDnhWFwFdRVIi3PbVAhVu7uWtVUO17Oc9gtGPgs/GrhOMkJfwQPXaudRJDpVZowxTX4x9kefNotlMAMRgq+Drbmgt4eEBiCNp0ITWgh17BiE1U09WS3myuduhoct85+FoVeaUkp1sxzHVtGsNQH0hcz7WcpZyOM+AwistJA/qzeEDQao5zi1eKWPbO2xAhi2rV1bDH6bPf/4lDBwLRqSiwvlWU=
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY_ID
secret_access_key: $AWS_SECRET_ACCESS_KEY
bucket: release.solana.com
region: us-west-1
skip_cleanup: true
acl: public_read
local_dir: travis-s3-upload
on:
all_branches: true
- provider: releases
api_key: $GITHUB_TOKEN
skip_cleanup: true
file_glob: true
file: travis-release-upload/*
on:
tags: true
os: linux
dist: bionic
language: minimal
jobs:
include:
- &release-artifacts
if: type = push
name: "macOS release artifacts"
os: osx
language: rust
rust:
- stable
install:
- source ci/rust-version.sh
script:
- source ci/env.sh
- ci/publish-tarball.sh
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY_ID
secret_access_key: $AWS_SECRET_ACCESS_KEY
bucket: release.solana.com
region: us-west-1
skip_cleanup: true
acl: public_read
local_dir: travis-s3-upload
on:
all_branches: true
- provider: releases
token: $GITHUB_TOKEN
skip_cleanup: true
file_glob: true
file: travis-release-upload/*
on:
tags: true
- <<: *release-artifacts
name: "Windows release artifacts"
os: windows
# docs pull request or commit
- name: "docs"
if: type IN (push, pull_request) OR tag IS present
language: node_js
node_js:
- "node"
services:
- docker
cache:
directories:
- ~/.npm
before_install:
- .travis/affects.sh docs/ .travis || travis_terminate 0
- cd docs/
- source .travis/before_install.sh
script:
- source .travis/script.sh

20
.travis/affects.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
#
# Check if files in the commit range match one or more prefixes
#
(
set -x
git diff --name-only "$TRAVIS_COMMIT_RANGE"
)
for file in $(git diff --name-only "$TRAVIS_COMMIT_RANGE"); do
for prefix in "$@"; do
if [[ $file =~ ^"$prefix" ]]; then
exit 0
fi
done
done
echo "No modifications to $*"
exit 1

258
Cargo.lock generated
View File

@@ -301,7 +301,7 @@ dependencies = [
[[package]]
name = "btc_spv_bin"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"hex 0.4.2",
@@ -3295,6 +3295,17 @@ dependencies = [
"webpki",
]
[[package]]
name = "rustversion"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
]
[[package]]
name = "rusty-fork"
version = "0.2.2"
@@ -3693,7 +3704,7 @@ dependencies = [
[[package]]
name = "solana-account-decoder"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"Inflector",
"bincode",
@@ -3702,7 +3713,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-vote-program",
"spl-memo",
"thiserror",
@@ -3710,7 +3721,7 @@ dependencies = [
[[package]]
name = "solana-accounts-bench"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"crossbeam-channel",
@@ -3720,12 +3731,12 @@ dependencies = [
"solana-logger",
"solana-measure",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-banking-bench"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"crossbeam-channel",
@@ -3739,14 +3750,14 @@ dependencies = [
"solana-measure",
"solana-perf",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-streamer",
"solana-version",
]
[[package]]
name = "solana-bench-exchange"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"itertools 0.9.0",
@@ -3768,13 +3779,13 @@ dependencies = [
"solana-metrics",
"solana-net-utils",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
]
[[package]]
name = "solana-bench-streamer"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"solana-clap-utils",
@@ -3786,7 +3797,7 @@ dependencies = [
[[package]]
name = "solana-bench-tps"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"clap",
@@ -3809,13 +3820,13 @@ dependencies = [
"solana-move-loader-program",
"solana-net-utils",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
]
[[package]]
name = "solana-bpf-loader-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"byteorder",
@@ -3824,16 +3835,17 @@ dependencies = [
"num-derive 0.3.0",
"num-traits",
"rand 0.7.3",
"rustversion",
"solana-logger",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana_rbpf",
"thiserror",
]
[[package]]
name = "solana-btc-spv-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"hex 0.4.2",
@@ -3842,12 +3854,12 @@ dependencies = [
"num-traits",
"serde",
"serde_derive",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-budget-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"chrono",
@@ -3857,19 +3869,19 @@ dependencies = [
"serde",
"serde_derive",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
]
[[package]]
name = "solana-clap-utils"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"chrono",
"clap",
"rpassword",
"solana-remote-wallet",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
"tiny-bip39",
"url 2.1.1",
@@ -3877,7 +3889,7 @@ dependencies = [
[[package]]
name = "solana-cli"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"Inflector",
"bincode",
@@ -3909,7 +3921,7 @@ dependencies = [
"solana-net-utils",
"solana-remote-wallet",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-transaction-status",
"solana-version",
@@ -3922,7 +3934,7 @@ dependencies = [
[[package]]
name = "solana-cli-config"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"dirs 2.0.2",
"lazy_static",
@@ -3934,7 +3946,7 @@ dependencies = [
[[package]]
name = "solana-client"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"assert_matches",
"bincode",
@@ -3951,7 +3963,7 @@ dependencies = [
"solana-account-decoder",
"solana-logger",
"solana-net-utils",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-transaction-status",
"solana-vote-program",
"thiserror",
@@ -3961,7 +3973,7 @@ dependencies = [
[[package]]
name = "solana-config-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"chrono",
@@ -3969,12 +3981,12 @@ dependencies = [
"serde",
"serde_derive",
"solana-logger",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-core"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"bs58 0.3.1",
@@ -4024,7 +4036,7 @@ dependencies = [
"solana-perf",
"solana-rayon-threadlimit",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-streamer",
"solana-sys-tuner",
@@ -4044,7 +4056,7 @@ dependencies = [
[[package]]
name = "solana-crate-features"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"backtrace",
"bytes 0.4.12",
@@ -4067,7 +4079,7 @@ dependencies = [
[[package]]
name = "solana-dos"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"clap",
@@ -4080,13 +4092,13 @@ dependencies = [
"solana-logger",
"solana-net-utils",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
]
[[package]]
name = "solana-download-utils"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bzip2",
"console 0.10.3",
@@ -4094,13 +4106,13 @@ dependencies = [
"log 0.4.8",
"reqwest",
"solana-ledger",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"tar",
]
[[package]]
name = "solana-exchange-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"log 0.4.8",
@@ -4111,21 +4123,21 @@ dependencies = [
"solana-logger",
"solana-metrics",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
]
[[package]]
name = "solana-failure-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-faucet"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"byteorder",
@@ -4137,7 +4149,7 @@ dependencies = [
"solana-clap-utils",
"solana-logger",
"solana-metrics",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
"tokio 0.1.22",
"tokio-codec",
@@ -4145,7 +4157,7 @@ dependencies = [
[[package]]
name = "solana-genesis"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"base64 0.12.2",
"chrono",
@@ -4157,7 +4169,7 @@ dependencies = [
"solana-genesis-programs",
"solana-ledger",
"solana-logger",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-version",
"solana-vote-program",
@@ -4166,20 +4178,20 @@ dependencies = [
[[package]]
name = "solana-genesis-programs"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"log 0.4.8",
"solana-bpf-loader-program",
"solana-budget-program",
"solana-exchange-program",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-vest-program",
]
[[package]]
name = "solana-gossip"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"solana-clap-utils",
@@ -4187,13 +4199,13 @@ dependencies = [
"solana-core",
"solana-logger",
"solana-net-utils",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
]
[[package]]
name = "solana-install"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"atty",
"bincode",
@@ -4215,7 +4227,7 @@ dependencies = [
"solana-client",
"solana-config-program",
"solana-logger",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
"tar",
"tempdir",
@@ -4226,7 +4238,7 @@ dependencies = [
[[package]]
name = "solana-keygen"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bs58 0.3.1",
"clap",
@@ -4235,14 +4247,14 @@ dependencies = [
"solana-clap-utils",
"solana-cli-config",
"solana-remote-wallet",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
"tiny-bip39",
]
[[package]]
name = "solana-ledger"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"assert_matches",
"bincode",
@@ -4280,7 +4292,7 @@ dependencies = [
"solana-perf",
"solana-rayon-threadlimit",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-transaction-status",
"solana-vote-program",
@@ -4294,7 +4306,7 @@ dependencies = [
[[package]]
name = "solana-ledger-tool"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"assert_cmd",
"bs58 0.3.1",
@@ -4311,7 +4323,7 @@ dependencies = [
"solana-ledger",
"solana-logger",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-transaction-status",
"solana-version",
@@ -4321,20 +4333,20 @@ dependencies = [
[[package]]
name = "solana-librapay"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"log 0.4.8",
"solana-logger",
"solana-move-loader-program",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana_libra_types",
]
[[package]]
name = "solana-local-cluster"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"assert_matches",
"itertools 0.9.0",
@@ -4353,7 +4365,7 @@ dependencies = [
"solana-logger",
"solana-rayon-threadlimit",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-vest-program",
"solana-vote-program",
@@ -4362,7 +4374,7 @@ dependencies = [
[[package]]
name = "solana-log-analyzer"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"byte-unit",
"clap",
@@ -4375,7 +4387,7 @@ dependencies = [
[[package]]
name = "solana-logger"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"env_logger",
"lazy_static",
@@ -4384,27 +4396,27 @@ dependencies = [
[[package]]
name = "solana-measure"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"jemalloc-ctl",
"jemallocator",
"log 0.4.8",
"solana-metrics",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-merkle-tree"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"fast-math",
"hex 0.4.2",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-metrics"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"env_logger",
"gethostname",
@@ -4414,12 +4426,12 @@ dependencies = [
"reqwest",
"serial_test",
"serial_test_derive",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-move-loader-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"indexmap",
@@ -4431,7 +4443,7 @@ dependencies = [
"serde_derive",
"serde_json",
"solana-logger",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana_libra_bytecode_verifier",
"solana_libra_canonical_serialization",
"solana_libra_compiler",
@@ -4448,7 +4460,7 @@ dependencies = [
[[package]]
name = "solana-net-shaper"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"rand 0.7.3",
@@ -4460,7 +4472,7 @@ dependencies = [
[[package]]
name = "solana-net-utils"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"bytes 0.4.12",
@@ -4480,16 +4492,16 @@ dependencies = [
[[package]]
name = "solana-noop-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"log 0.4.8",
"solana-logger",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-notifier"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"log 0.4.8",
"reqwest",
@@ -4498,19 +4510,19 @@ dependencies = [
[[package]]
name = "solana-ownable"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"num-derive 0.3.0",
"num-traits",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
]
[[package]]
name = "solana-perf"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"curve25519-dalek 2.1.0",
@@ -4526,12 +4538,12 @@ dependencies = [
"solana-logger",
"solana-metrics",
"solana-rayon-threadlimit",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-ramp-tps"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bzip2",
"clap",
@@ -4546,14 +4558,14 @@ dependencies = [
"solana-metrics",
"solana-net-utils",
"solana-notifier",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"tar",
]
[[package]]
name = "solana-rayon-threadlimit"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"lazy_static",
"num_cpus",
@@ -4561,7 +4573,7 @@ dependencies = [
[[package]]
name = "solana-remote-wallet"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"base32",
"console 0.10.3",
@@ -4572,14 +4584,14 @@ dependencies = [
"num-traits",
"parking_lot 0.10.2",
"semver",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
"url 2.1.1",
]
[[package]]
name = "solana-runtime"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"assert_matches",
"bincode",
@@ -4606,7 +4618,7 @@ dependencies = [
"solana-metrics",
"solana-noop-program",
"solana-rayon-threadlimit",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-vote-program",
"tempfile",
@@ -4615,7 +4627,7 @@ dependencies = [
[[package]]
name = "solana-scripts"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"csv",
"serde",
@@ -4647,7 +4659,7 @@ dependencies = [
[[package]]
name = "solana-sdk"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"assert_matches",
"bincode",
@@ -4667,6 +4679,8 @@ dependencies = [
"pbkdf2",
"rand 0.7.3",
"rand_chacha 0.2.2",
"rustc_version",
"rustversion",
"serde",
"serde_bytes",
"serde_derive",
@@ -4674,11 +4688,17 @@ dependencies = [
"sha2",
"solana-crate-features",
"solana-logger",
"solana-sdk-macro 1.2.10",
"solana-sdk-macro 1.2.11",
"thiserror",
"tiny-bip39",
]
[[package]]
name = "solana-sdk-bpf-test"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1e668937b3fc2ecb13ad0285f318b0f81ba06c1b923d4cbc4d9868fb09d39d8"
[[package]]
name = "solana-sdk-macro"
version = "1.2.4"
@@ -4693,17 +4713,18 @@ dependencies = [
[[package]]
name = "solana-sdk-macro"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bs58 0.3.1",
"proc-macro2 1.0.18",
"quote 1.0.7",
"rustversion",
"syn 1.0.33",
]
[[package]]
name = "solana-stake-accounts"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"solana-clap-utils",
@@ -4711,13 +4732,13 @@ dependencies = [
"solana-client",
"solana-remote-wallet",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
]
[[package]]
name = "solana-stake-monitor"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"console 0.10.3",
@@ -4733,7 +4754,7 @@ dependencies = [
"solana-local-cluster",
"solana-logger",
"solana-metrics",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-transaction-status",
"solana-version",
@@ -4742,7 +4763,7 @@ dependencies = [
[[package]]
name = "solana-stake-o-matic"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"log 0.4.8",
@@ -4753,14 +4774,14 @@ dependencies = [
"solana-logger",
"solana-metrics",
"solana-notifier",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-transaction-status",
]
[[package]]
name = "solana-stake-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"log 0.4.8",
@@ -4771,14 +4792,14 @@ dependencies = [
"solana-config-program",
"solana-logger",
"solana-metrics",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-vote-program",
"thiserror",
]
[[package]]
name = "solana-streamer"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"libc",
"log 0.4.8",
@@ -4787,13 +4808,13 @@ dependencies = [
"solana-measure",
"solana-metrics",
"solana-perf",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
]
[[package]]
name = "solana-sys-tuner"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"libc",
@@ -4809,7 +4830,7 @@ dependencies = [
[[package]]
name = "solana-tokens"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"chrono",
"clap",
@@ -4826,7 +4847,7 @@ dependencies = [
"solana-core",
"solana-remote-wallet",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-stake-program",
"solana-transaction-status",
"tempfile",
@@ -4835,7 +4856,7 @@ dependencies = [
[[package]]
name = "solana-transaction-status"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"Inflector",
"bincode",
@@ -4844,13 +4865,13 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"spl-memo",
]
[[package]]
name = "solana-upload-perf"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"serde_json",
"solana-metrics",
@@ -4858,7 +4879,7 @@ dependencies = [
[[package]]
name = "solana-validator"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"chrono",
"clap",
@@ -4879,7 +4900,7 @@ dependencies = [
"solana-net-utils",
"solana-perf",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
"solana-vote-program",
"solana-vote-signer",
@@ -4887,16 +4908,16 @@ dependencies = [
[[package]]
name = "solana-version"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"serde",
"serde_derive",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
]
[[package]]
name = "solana-vest-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"chrono",
@@ -4906,13 +4927,13 @@ dependencies = [
"serde_derive",
"solana-config-program",
"solana-runtime",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
]
[[package]]
name = "solana-vote-program"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"bincode",
"log 0.4.8",
@@ -4921,13 +4942,13 @@ dependencies = [
"serde",
"serde_derive",
"solana-metrics",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"thiserror",
]
[[package]]
name = "solana-vote-signer"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"jsonrpc-core",
@@ -4937,13 +4958,13 @@ dependencies = [
"serde_json",
"solana-clap-utils",
"solana-metrics",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-version",
]
[[package]]
name = "solana-watchtower"
version = "1.2.10"
version = "1.2.11"
dependencies = [
"clap",
"humantime 2.0.1",
@@ -4955,7 +4976,7 @@ dependencies = [
"solana-logger",
"solana-metrics",
"solana-notifier",
"solana-sdk 1.2.10",
"solana-sdk 1.2.11",
"solana-transaction-status",
"solana-version",
"solana-vote-program",
@@ -5330,11 +5351,12 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spl-memo"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e6b954ac8b1df3f0bbb6ad1f21607be304f3cc9914bb9107c44b2065c8479e"
checksum = "db4ebc6a6d50b55cbe7c84c7f6cd0259f4f82a169eb49ef65ca62b9c69a76a1f"
dependencies = [
"solana-sdk 1.2.4",
"solana-sdk-bpf-test",
]
[[package]]

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-account-decoder"
version = "1.2.10"
version = "1.2.11"
description = "Solana account decoder"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -13,9 +13,9 @@ bincode = "1.2.1"
bs58 = "0.3.1"
Inflector = "0.11.4"
lazy_static = "1.4.0"
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-vote-program = { path = "../programs/vote", version = "1.2.10" }
spl-memo = "1.0.0"
solana-sdk = { path = "../sdk", version = "1.2.11" }
solana-vote-program = { path = "../programs/vote", version = "1.2.11" }
spl-memo = "1.0.1"
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.54"

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-accounts-bench"
version = "1.2.10"
version = "1.2.11"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -10,10 +10,10 @@ homepage = "https://solana.com/"
[dependencies]
log = "0.4.6"
rayon = "1.3.0"
solana-logger = { path = "../logger", version = "1.2.10" }
solana-runtime = { path = "../runtime", version = "1.2.10" }
solana-measure = { path = "../measure", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-logger = { path = "../logger", version = "1.2.11" }
solana-runtime = { path = "../runtime", version = "1.2.11" }
solana-measure = { path = "../measure", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
rand = "0.7.0"
clap = "2.33.1"
crossbeam-channel = "0.4"

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-banking-bench"
version = "1.2.10"
version = "1.2.11"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -13,16 +13,16 @@ crossbeam-channel = "0.4"
log = "0.4.6"
rand = "0.7.0"
rayon = "1.3.0"
solana-core = { path = "../core", version = "1.2.10" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.10" }
solana-streamer = { path = "../streamer", version = "1.2.10" }
solana-perf = { path = "../perf", version = "1.2.10" }
solana-ledger = { path = "../ledger", version = "1.2.10" }
solana-logger = { path = "../logger", version = "1.2.10" }
solana-runtime = { path = "../runtime", version = "1.2.10" }
solana-measure = { path = "../measure", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-version = { path = "../version", version = "1.2.10" }
solana-core = { path = "../core", version = "1.2.11" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.11" }
solana-streamer = { path = "../streamer", version = "1.2.11" }
solana-perf = { path = "../perf", version = "1.2.11" }
solana-ledger = { path = "../ledger", version = "1.2.11" }
solana-logger = { path = "../logger", version = "1.2.11" }
solana-runtime = { path = "../runtime", version = "1.2.11" }
solana-measure = { path = "../measure", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
solana-version = { path = "../version", version = "1.2.11" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-exchange"
version = "1.2.10"
version = "1.2.11"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -18,21 +18,21 @@ rand = "0.7.0"
rayon = "1.3.0"
serde_json = "1.0.53"
serde_yaml = "0.8.12"
solana-clap-utils = { path = "../clap-utils", version = "1.2.10" }
solana-core = { path = "../core", version = "1.2.10" }
solana-genesis = { path = "../genesis", version = "1.2.10" }
solana-client = { path = "../client", version = "1.2.10" }
solana-faucet = { path = "../faucet", version = "1.2.10" }
solana-exchange-program = { path = "../programs/exchange", version = "1.2.10" }
solana-logger = { path = "../logger", version = "1.2.10" }
solana-metrics = { path = "../metrics", version = "1.2.10" }
solana-net-utils = { path = "../net-utils", version = "1.2.10" }
solana-runtime = { path = "../runtime", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-version = { path = "../version", version = "1.2.10" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.11" }
solana-core = { path = "../core", version = "1.2.11" }
solana-genesis = { path = "../genesis", version = "1.2.11" }
solana-client = { path = "../client", version = "1.2.11" }
solana-faucet = { path = "../faucet", version = "1.2.11" }
solana-exchange-program = { path = "../programs/exchange", version = "1.2.11" }
solana-logger = { path = "../logger", version = "1.2.11" }
solana-metrics = { path = "../metrics", version = "1.2.11" }
solana-net-utils = { path = "../net-utils", version = "1.2.11" }
solana-runtime = { path = "../runtime", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
solana-version = { path = "../version", version = "1.2.11" }
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "1.2.10" }
solana-local-cluster = { path = "../local-cluster", version = "1.2.11" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -2,18 +2,18 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-streamer"
version = "1.2.10"
version = "1.2.11"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.1"
solana-clap-utils = { path = "../clap-utils", version = "1.2.10" }
solana-streamer = { path = "../streamer", version = "1.2.10" }
solana-logger = { path = "../logger", version = "1.2.10" }
solana-net-utils = { path = "../net-utils", version = "1.2.10" }
solana-version = { path = "../version", version = "1.2.10" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.11" }
solana-streamer = { path = "../streamer", version = "1.2.11" }
solana-logger = { path = "../logger", version = "1.2.11" }
solana-net-utils = { path = "../net-utils", version = "1.2.11" }
solana-version = { path = "../version", version = "1.2.11" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-tps"
version = "1.2.10"
version = "1.2.11"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -14,25 +14,25 @@ log = "0.4.8"
rayon = "1.3.0"
serde_json = "1.0.53"
serde_yaml = "0.8.12"
solana-clap-utils = { path = "../clap-utils", version = "1.2.10" }
solana-core = { path = "../core", version = "1.2.10" }
solana-genesis = { path = "../genesis", version = "1.2.10" }
solana-client = { path = "../client", version = "1.2.10" }
solana-faucet = { path = "../faucet", version = "1.2.10" }
solana-librapay = { path = "../programs/librapay", version = "1.2.10", optional = true }
solana-logger = { path = "../logger", version = "1.2.10" }
solana-metrics = { path = "../metrics", version = "1.2.10" }
solana-measure = { path = "../measure", version = "1.2.10" }
solana-net-utils = { path = "../net-utils", version = "1.2.10" }
solana-runtime = { path = "../runtime", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-move-loader-program = { path = "../programs/move_loader", version = "1.2.10", optional = true }
solana-version = { path = "../version", version = "1.2.10" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.11" }
solana-core = { path = "../core", version = "1.2.11" }
solana-genesis = { path = "../genesis", version = "1.2.11" }
solana-client = { path = "../client", version = "1.2.11" }
solana-faucet = { path = "../faucet", version = "1.2.11" }
solana-librapay = { path = "../programs/librapay", version = "1.2.11", optional = true }
solana-logger = { path = "../logger", version = "1.2.11" }
solana-metrics = { path = "../metrics", version = "1.2.11" }
solana-measure = { path = "../measure", version = "1.2.11" }
solana-net-utils = { path = "../net-utils", version = "1.2.11" }
solana-runtime = { path = "../runtime", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
solana-move-loader-program = { path = "../programs/move_loader", version = "1.2.11", optional = true }
solana-version = { path = "../version", version = "1.2.11" }
[dev-dependencies]
serial_test = "0.4.0"
serial_test_derive = "0.4.0"
solana-local-cluster = { path = "../local-cluster", version = "1.2.10" }
solana-local-cluster = { path = "../local-cluster", version = "1.2.11" }
[features]
move = ["solana-librapay", "solana-move-loader-program"]

View File

@@ -211,12 +211,7 @@ pull_or_push_steps() {
all_test_steps
fi
# doc/ changes:
if affects ^docs/; then
command_step docs ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image docs/build.sh" 5
fi
# web3.js and explorer changes run on Travis...
# web3.js, explorer and docs changes run on Travis...
}

View File

@@ -5,9 +5,6 @@ steps:
- command: "ci/publish-tarball.sh"
timeout_in_minutes: 60
name: "publish tarball"
- command: "ci/publish-docs.sh"
timeout_in_minutes: 15
name: "publish docs"
- command: "ci/publish-bpf-sdk.sh"
timeout_in_minutes: 5
name: "publish bpf sdk"

View File

@@ -12,7 +12,7 @@ if [[ -n $CI ]]; then
export CI_BUILD_ID=$TRAVIS_BUILD_ID
export CI_COMMIT=$TRAVIS_COMMIT
export CI_JOB_ID=$TRAVIS_JOB_ID
if $TRAVIS_PULL_REQUEST; then
if [[ $TRAVIS_PULL_REQUEST != false ]]; then
export CI_PULL_REQUEST=true
else
export CI_PULL_REQUEST=

View File

@@ -1,32 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
echo --- build docs
(
set -x
. ci/rust-version.sh stable
ci/docker-run.sh "$rust_stable_docker_image" docs/build.sh
)
echo --- update gitbook-cage
if [[ -n $CI_BRANCH ]]; then
(
# make a local commit for the svgs and generated/updated markdown
set -x
git add -f docs/src
if ! git diff-index --quiet HEAD; then
git config user.email maintainers@solana.com
git config user.name "$(basename "$0")"
git commit -m "gitbook-cage update $(date -Is)"
git push -f git@github.com:solana-labs/solana-gitbook-cage.git HEAD:refs/heads/"$CI_BRANCH"
# pop off the local commit
git reset --hard HEAD~
fi
)
else
echo CI_BRANCH not set
fi
exit 0

View File

@@ -27,5 +27,5 @@ Alternatively, you can source it from within a script:
local PATCH=0
local SPECIAL=""
semverParseInto "1.2.10" MAJOR MINOR PATCH SPECIAL
semverParseInto "1.2.11" MAJOR MINOR PATCH SPECIAL
semverParseInto "3.2.1" MAJOR MINOR PATCH SPECIAL

View File

@@ -34,7 +34,6 @@ _ cargo +"$rust_stable" clippy --workspace -- --deny=warnings
_ cargo +"$rust_stable" audit --version
_ scripts/cargo-for-all-lock-files.sh +"$rust_stable" audit --ignore RUSTSEC-2020-0002 --ignore RUSTSEC-2020-0008
_ ci/order-crates-for-publishing.py
_ docs/build.sh
{
cd programs/bpf

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-clap-utils"
version = "1.2.10"
version = "1.2.11"
description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@@ -11,8 +11,8 @@ edition = "2018"
[dependencies]
clap = "2.33.0"
rpassword = "4.0"
solana-remote-wallet = { path = "../remote-wallet", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
thiserror = "1.0.11"
tiny-bip39 = "0.7.0"
url = "2.1.0"

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-cli-config"
description = "Blockchain, Rebuilt for Scale"
version = "1.2.10"
version = "1.2.11"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "1.2.10"
version = "1.2.11"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -27,29 +27,29 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
serde = "1.0.110"
serde_derive = "1.0.103"
serde_json = "1.0.53"
solana-account-decoder = { path = "../account-decoder", version = "1.2.10" }
solana-budget-program = { path = "../programs/budget", version = "1.2.10" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.10" }
solana-cli-config = { path = "../cli-config", version = "1.2.10" }
solana-client = { path = "../client", version = "1.2.10" }
solana-config-program = { path = "../programs/config", version = "1.2.10" }
solana-faucet = { path = "../faucet", version = "1.2.10" }
solana-logger = { path = "../logger", version = "1.2.10" }
solana-net-utils = { path = "../net-utils", version = "1.2.10" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.2.10" }
solana-runtime = { path = "../runtime", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-stake-program = { path = "../programs/stake", version = "1.2.10" }
solana-transaction-status = { path = "../transaction-status", version = "1.2.10" }
solana-version = { path = "../version", version = "1.2.10" }
solana-vote-program = { path = "../programs/vote", version = "1.2.10" }
solana-vote-signer = { path = "../vote-signer", version = "1.2.10" }
solana-account-decoder = { path = "../account-decoder", version = "1.2.11" }
solana-budget-program = { path = "../programs/budget", version = "1.2.11" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.11" }
solana-cli-config = { path = "../cli-config", version = "1.2.11" }
solana-client = { path = "../client", version = "1.2.11" }
solana-config-program = { path = "../programs/config", version = "1.2.11" }
solana-faucet = { path = "../faucet", version = "1.2.11" }
solana-logger = { path = "../logger", version = "1.2.11" }
solana-net-utils = { path = "../net-utils", version = "1.2.11" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.2.11" }
solana-runtime = { path = "../runtime", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
solana-stake-program = { path = "../programs/stake", version = "1.2.11" }
solana-transaction-status = { path = "../transaction-status", version = "1.2.11" }
solana-version = { path = "../version", version = "1.2.11" }
solana-vote-program = { path = "../programs/vote", version = "1.2.11" }
solana-vote-signer = { path = "../vote-signer", version = "1.2.11" }
thiserror = "1.0.19"
url = "2.1.1"
[dev-dependencies]
solana-core = { path = "../core", version = "1.2.10" }
solana-budget-program = { path = "../programs/budget", version = "1.2.10" }
solana-core = { path = "../core", version = "1.2.11" }
solana-budget-program = { path = "../programs/budget", version = "1.2.11" }
tempfile = "3.1.0"
[[bin]]

View File

@@ -382,6 +382,7 @@ pub enum CliCommand {
},
// Vote Commands
CreateVoteAccount {
vote_account: SignerIndex,
seed: Option<String>,
identity_account: SignerIndex,
authorized_voter: Option<Pubkey>,
@@ -407,10 +408,12 @@ pub enum CliCommand {
VoteUpdateValidator {
vote_account_pubkey: Pubkey,
new_identity_account: SignerIndex,
withdraw_authority: SignerIndex,
},
VoteUpdateCommission {
vote_account_pubkey: Pubkey,
commission: u8,
withdraw_authority: SignerIndex,
},
// Wallet Commands
Address,
@@ -2128,6 +2131,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
// Create vote account
CliCommand::CreateVoteAccount {
vote_account,
seed,
identity_account,
authorized_voter,
@@ -2136,6 +2140,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
} => process_create_vote_account(
&rpc_client,
config,
*vote_account,
seed,
*identity_account,
authorized_voter,
@@ -2180,16 +2185,25 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
CliCommand::VoteUpdateValidator {
vote_account_pubkey,
new_identity_account,
withdraw_authority,
} => process_vote_update_validator(
&rpc_client,
config,
&vote_account_pubkey,
*new_identity_account,
*withdraw_authority,
),
CliCommand::VoteUpdateCommission {
vote_account_pubkey,
commission,
} => process_vote_update_commission(&rpc_client, config, &vote_account_pubkey, *commission),
withdraw_authority,
} => process_vote_update_commission(
&rpc_client,
config,
&vote_account_pubkey,
*commission,
*withdraw_authority,
),
// Wallet Commands
@@ -3417,6 +3431,7 @@ mod tests {
let bob_pubkey = bob_keypair.pubkey();
let identity_keypair = Keypair::new();
config.command = CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 2,
authorized_voter: Some(bob_pubkey),
@@ -3442,6 +3457,7 @@ mod tests {
config.command = CliCommand::VoteUpdateValidator {
vote_account_pubkey: bob_pubkey,
new_identity_account: 2,
withdraw_authority: 1,
};
let result = process_command(&config);
assert!(result.is_ok());
@@ -3659,6 +3675,7 @@ mod tests {
let bob_keypair = Keypair::new();
let identity_keypair = Keypair::new();
config.command = CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 2,
authorized_voter: Some(bob_pubkey),
@@ -3678,6 +3695,7 @@ mod tests {
config.command = CliCommand::VoteUpdateValidator {
vote_account_pubkey: bob_pubkey,
new_identity_account: 1,
withdraw_authority: 1,
};
assert!(process_command(&config).is_err());

View File

@@ -253,7 +253,7 @@ pub fn parse_create_vote_account(
default_signer_path: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let (vote_account, _) = signer_of(matches, "vote_account", wallet_manager)?;
let (vote_account, vote_account_pubkey) = signer_of(matches, "vote_account", wallet_manager)?;
let seed = matches.value_of("seed").map(|s| s.to_string());
let (identity_account, identity_pubkey) =
signer_of(matches, "identity_account", wallet_manager)?;
@@ -271,6 +271,7 @@ pub fn parse_create_vote_account(
Ok(CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: signer_info.index_of(vote_account_pubkey).unwrap(),
seed,
identity_account: signer_info.index_of(identity_pubkey).unwrap(),
authorized_voter,
@@ -320,7 +321,8 @@ pub fn parse_vote_update_validator(
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
let (new_identity_account, new_identity_pubkey) =
signer_of(matches, "new_identity_account", wallet_manager)?;
let (authorized_withdrawer, _) = signer_of(matches, "authorized_withdrawer", wallet_manager)?;
let (authorized_withdrawer, authorized_withdrawer_pubkey) =
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
@@ -334,6 +336,7 @@ pub fn parse_vote_update_validator(
command: CliCommand::VoteUpdateValidator {
vote_account_pubkey,
new_identity_account: signer_info.index_of(new_identity_pubkey).unwrap(),
withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(),
},
signers: signer_info.signers,
})
@@ -346,7 +349,8 @@ pub fn parse_vote_update_commission(
) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey =
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
let (authorized_withdrawer, _) = signer_of(matches, "authorized_withdrawer", wallet_manager)?;
let (authorized_withdrawer, authorized_withdrawer_pubkey) =
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
let commission = value_t_or_exit!(matches, "commission", u8);
let payer_provided = None;
@@ -361,6 +365,7 @@ pub fn parse_vote_update_commission(
command: CliCommand::VoteUpdateCommission {
vote_account_pubkey,
commission,
withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(),
},
signers: signer_info.signers,
})
@@ -420,13 +425,14 @@ pub fn parse_withdraw_from_vote_account(
pub fn process_create_vote_account(
rpc_client: &RpcClient,
config: &CliConfig,
vote_account: SignerIndex,
seed: &Option<String>,
identity_account: SignerIndex,
authorized_voter: &Option<Pubkey>,
authorized_withdrawer: &Option<Pubkey>,
commission: u8,
) -> ProcessResult {
let vote_account = config.signers[1];
let vote_account = config.signers[vote_account];
let vote_account_pubkey = vote_account.pubkey();
let vote_account_address = if let Some(seed) = seed {
Pubkey::create_with_seed(&vote_account_pubkey, &seed, &solana_vote_program::id())?
@@ -551,8 +557,9 @@ pub fn process_vote_update_validator(
config: &CliConfig,
vote_account_pubkey: &Pubkey,
new_identity_account: SignerIndex,
withdraw_authority: SignerIndex,
) -> ProcessResult {
let authorized_withdrawer = config.signers[1];
let authorized_withdrawer = config.signers[withdraw_authority];
let new_identity_account = config.signers[new_identity_account];
let new_identity_pubkey = new_identity_account.pubkey();
check_unique_pubkeys(
@@ -584,8 +591,9 @@ pub fn process_vote_update_commission(
config: &CliConfig,
vote_account_pubkey: &Pubkey,
commission: u8,
withdraw_authority: SignerIndex,
) -> ProcessResult {
let authorized_withdrawer = config.signers[1];
let authorized_withdrawer = config.signers[withdraw_authority];
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ixs = vec![vote_instruction::update_commission(
vote_account_pubkey,
@@ -817,6 +825,7 @@ mod tests {
parse_command(&test_create_vote_account, &default_keypair_file, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 2,
authorized_voter: None,
@@ -845,6 +854,7 @@ mod tests {
parse_command(&test_create_vote_account2, &default_keypair_file, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 2,
authorized_voter: None,
@@ -877,6 +887,7 @@ mod tests {
parse_command(&test_create_vote_account3, &default_keypair_file, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 2,
authorized_voter: Some(authed),
@@ -907,6 +918,7 @@ mod tests {
parse_command(&test_create_vote_account4, &default_keypair_file, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 2,
authorized_voter: None,
@@ -934,6 +946,7 @@ mod tests {
command: CliCommand::VoteUpdateValidator {
vote_account_pubkey: pubkey,
new_identity_account: 2,
withdraw_authority: 1,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -956,6 +969,7 @@ mod tests {
command: CliCommand::VoteUpdateCommission {
vote_account_pubkey: pubkey,
commission: 42,
withdraw_authority: 1,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),

View File

@@ -57,6 +57,7 @@ fn test_stake_delegation_force() {
let vote_keypair = Keypair::new();
config.signers = vec![&default_signer, &vote_keypair];
config.command = CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 0,
authorized_voter: None,

View File

@@ -49,6 +49,7 @@ fn test_vote_authorize_and_withdraw() {
let vote_account_pubkey = vote_account_keypair.pubkey();
config.signers = vec![&default_signer, &vote_account_keypair];
config.command = CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 0,
authorized_voter: None,
@@ -120,6 +121,7 @@ fn test_vote_authorize_and_withdraw() {
config.command = CliCommand::VoteUpdateValidator {
vote_account_pubkey,
new_identity_account: 2,
withdraw_authority: 1,
};
process_command(&config).unwrap();

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "1.2.10"
version = "1.2.11"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@@ -19,11 +19,11 @@ reqwest = { version = "0.10.4", default-features = false, features = ["blocking"
serde = "1.0.110"
serde_derive = "1.0.103"
serde_json = "1.0.53"
solana-account-decoder = { path = "../account-decoder", version = "1.2.10" }
solana-net-utils = { path = "../net-utils", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-transaction-status = { path = "../transaction-status", version = "1.2.10" }
solana-vote-program = { path = "../programs/vote", version = "1.2.10" }
solana-account-decoder = { path = "../account-decoder", version = "1.2.11" }
solana-net-utils = { path = "../net-utils", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
solana-transaction-status = { path = "../transaction-status", version = "1.2.11" }
solana-vote-program = { path = "../programs/vote", version = "1.2.11" }
thiserror = "1.0"
tungstenite = "0.10.1"
url = "2.1.1"
@@ -32,7 +32,7 @@ url = "2.1.1"
assert_matches = "1.3.0"
jsonrpc-core = "14.1.0"
jsonrpc-http-server = "14.1.0"
solana-logger = { path = "../logger", version = "1.2.10" }
solana-logger = { path = "../logger", version = "1.2.11" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -102,6 +102,7 @@ impl fmt::Display for RpcRequest {
pub const NUM_LARGEST_ACCOUNTS: usize = 20;
pub const MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS: usize = 256;
pub const MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE: u64 = 10_000;
pub const MAX_GET_CONFIRMED_BLOCKS_RANGE: u64 = 500_000;
// Validators that are this number of slots behind are considered delinquent
pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;

View File

@@ -1,7 +1,7 @@
[package]
name = "solana-core"
description = "Blockchain, Rebuilt for Scale"
version = "1.2.10"
version = "1.2.11"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "../README.md"
@@ -42,36 +42,36 @@ regex = "1.3.7"
serde = "1.0.110"
serde_derive = "1.0.103"
serde_json = "1.0.53"
solana-account-decoder = { path = "../account-decoder", version = "1.2.10" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.2.10" }
solana-budget-program = { path = "../programs/budget", version = "1.2.10" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.10" }
solana-client = { path = "../client", version = "1.2.10" }
solana-faucet = { path = "../faucet", version = "1.2.10" }
solana-genesis-programs = { path = "../genesis-programs", version = "1.2.10" }
solana-ledger = { path = "../ledger", version = "1.2.10" }
solana-logger = { path = "../logger", version = "1.2.10" }
solana-merkle-tree = { path = "../merkle-tree", version = "1.2.10" }
solana-metrics = { path = "../metrics", version = "1.2.10" }
solana-measure = { path = "../measure", version = "1.2.10" }
solana-net-utils = { path = "../net-utils", version = "1.2.10" }
solana-perf = { path = "../perf", version = "1.2.10" }
solana-runtime = { path = "../runtime", version = "1.2.10" }
solana-sdk = { path = "../sdk", version = "1.2.10" }
solana-stake-program = { path = "../programs/stake", version = "1.2.10" }
solana-streamer = { path = "../streamer", version = "1.2.10" }
solana-sys-tuner = { path = "../sys-tuner", version = "1.2.10" }
solana-transaction-status = { path = "../transaction-status", version = "1.2.10" }
solana-version = { path = "../version", version = "1.2.10" }
solana-vote-program = { path = "../programs/vote", version = "1.2.10" }
solana-vote-signer = { path = "../vote-signer", version = "1.2.10" }
solana-account-decoder = { path = "../account-decoder", version = "1.2.11" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.2.11" }
solana-budget-program = { path = "../programs/budget", version = "1.2.11" }
solana-clap-utils = { path = "../clap-utils", version = "1.2.11" }
solana-client = { path = "../client", version = "1.2.11" }
solana-faucet = { path = "../faucet", version = "1.2.11" }
solana-genesis-programs = { path = "../genesis-programs", version = "1.2.11" }
solana-ledger = { path = "../ledger", version = "1.2.11" }
solana-logger = { path = "../logger", version = "1.2.11" }
solana-merkle-tree = { path = "../merkle-tree", version = "1.2.11" }
solana-metrics = { path = "../metrics", version = "1.2.11" }
solana-measure = { path = "../measure", version = "1.2.11" }
solana-net-utils = { path = "../net-utils", version = "1.2.11" }
solana-perf = { path = "../perf", version = "1.2.11" }
solana-runtime = { path = "../runtime", version = "1.2.11" }
solana-sdk = { path = "../sdk", version = "1.2.11" }
solana-stake-program = { path = "../programs/stake", version = "1.2.11" }
solana-streamer = { path = "../streamer", version = "1.2.11" }
solana-sys-tuner = { path = "../sys-tuner", version = "1.2.11" }
solana-transaction-status = { path = "../transaction-status", version = "1.2.11" }
solana-version = { path = "../version", version = "1.2.11" }
solana-vote-program = { path = "../programs/vote", version = "1.2.11" }
solana-vote-signer = { path = "../vote-signer", version = "1.2.11" }
tempfile = "3.1.0"
thiserror = "1.0"
tokio = "0.1"
tokio-codec = "0.1"
tokio-fs = "0.1"
tokio-io = "0.1"
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.2.10" }
solana-rayon-threadlimit = { path = "../rayon-threadlimit", version = "1.2.11" }
trees = "0.2.1"
[dev-dependencies]

View File

@@ -28,7 +28,7 @@ use solana_sdk::{
pubkey::Pubkey,
transaction::Transaction,
};
use solana_vote_program::vote_instruction::VoteInstruction;
use solana_vote_program::{vote_instruction::VoteInstruction, vote_state::Vote};
use std::{
collections::{HashMap, HashSet},
sync::{
@@ -40,16 +40,18 @@ use std::{
};
// Map from a vote account to the authorized voter for an epoch
pub type VerifiedVotePacketsSender = CrossbeamSender<Vec<(CrdsValueLabel, Packets)>>;
pub type VerifiedVotePacketsReceiver = CrossbeamReceiver<Vec<(CrdsValueLabel, Packets)>>;
pub type VerifiedLabelVotePacketsSender = CrossbeamSender<Vec<(CrdsValueLabel, Packets)>>;
pub type VerifiedLabelVotePacketsReceiver = CrossbeamReceiver<Vec<(CrdsValueLabel, Packets)>>;
pub type VerifiedVoteTransactionsSender = CrossbeamSender<Vec<Transaction>>;
pub type VerifiedVoteTransactionsReceiver = CrossbeamReceiver<Vec<Transaction>>;
pub type VerifiedVoteSender = CrossbeamSender<(Pubkey, Vote)>;
pub type VerifiedVoteReceiver = CrossbeamReceiver<(Pubkey, Vote)>;
#[derive(Default)]
pub struct SlotVoteTracker {
voted: HashSet<Arc<Pubkey>>,
updates: Option<Vec<Arc<Pubkey>>>,
pub total_stake: u64,
total_stake: u64,
}
impl SlotVoteTracker {
@@ -62,7 +64,7 @@ impl SlotVoteTracker {
#[derive(Default)]
pub struct VoteTracker {
// Map from a slot to a set of validators who have voted for that slot
pub slot_vote_trackers: RwLock<HashMap<Slot, Arc<RwLock<SlotVoteTracker>>>>,
slot_vote_trackers: RwLock<HashMap<Slot, Arc<RwLock<SlotVoteTracker>>>>,
// Don't track votes from people who are not staked, acts as a spam filter
epoch_authorized_voters: RwLock<HashMap<Epoch, Arc<EpochAuthorizedVoters>>>,
leader_schedule_epoch: RwLock<Epoch>,
@@ -202,15 +204,17 @@ impl ClusterInfoVoteListener {
pub fn new(
exit: &Arc<AtomicBool>,
cluster_info: Arc<ClusterInfo>,
sender: CrossbeamSender<Vec<Packets>>,
verified_packets_sender: CrossbeamSender<Vec<Packets>>,
poh_recorder: &Arc<Mutex<PohRecorder>>,
vote_tracker: Arc<VoteTracker>,
bank_forks: Arc<RwLock<BankForks>>,
subscriptions: Arc<RpcSubscriptions>,
verified_vote_sender: VerifiedVoteSender,
) -> Self {
let exit_ = exit.clone();
let (verified_vote_packets_sender, verified_vote_packets_receiver) = unbounded();
let (verified_vote_label_packets_sender, verified_vote_label_packets_receiver) =
unbounded();
let (verified_vote_transactions_sender, verified_vote_transactions_receiver) = unbounded();
let listen_thread = Builder::new()
.name("solana-cluster_info_vote_listener".to_string())
@@ -218,7 +222,7 @@ impl ClusterInfoVoteListener {
let _ = Self::recv_loop(
exit_,
&cluster_info,
verified_vote_packets_sender,
verified_vote_label_packets_sender,
verified_vote_transactions_sender,
);
})
@@ -231,9 +235,9 @@ impl ClusterInfoVoteListener {
.spawn(move || {
let _ = Self::bank_send_loop(
exit_,
verified_vote_packets_receiver,
verified_vote_label_packets_receiver,
poh_recorder,
&sender,
&verified_packets_sender,
);
})
.unwrap();
@@ -248,6 +252,7 @@ impl ClusterInfoVoteListener {
vote_tracker,
&bank_forks,
subscriptions,
verified_vote_sender,
);
})
.unwrap();
@@ -267,7 +272,7 @@ impl ClusterInfoVoteListener {
fn recv_loop(
exit: Arc<AtomicBool>,
cluster_info: &ClusterInfo,
verified_vote_packets_sender: VerifiedVotePacketsSender,
verified_vote_label_packets_sender: VerifiedLabelVotePacketsSender,
verified_vote_transactions_sender: VerifiedVoteTransactionsSender,
) -> Result<()> {
let mut last_ts = 0;
@@ -282,7 +287,7 @@ impl ClusterInfoVoteListener {
if !votes.is_empty() {
let (vote_txs, packets) = Self::verify_votes(votes, labels);
verified_vote_transactions_sender.send(vote_txs)?;
verified_vote_packets_sender.send(packets)?;
verified_vote_label_packets_sender.send(packets)?;
}
sleep(Duration::from_millis(GOSSIP_SLEEP_MILLIS));
@@ -322,9 +327,9 @@ impl ClusterInfoVoteListener {
fn bank_send_loop(
exit: Arc<AtomicBool>,
verified_vote_packets_receiver: VerifiedVotePacketsReceiver,
verified_vote_label_packets_receiver: VerifiedLabelVotePacketsReceiver,
poh_recorder: Arc<Mutex<PohRecorder>>,
packets_sender: &CrossbeamSender<Vec<Packets>>,
verified_packets_sender: &CrossbeamSender<Vec<Packets>>,
) -> Result<()> {
let mut verified_vote_packets = VerifiedVotePackets::default();
let mut time_since_lock = Instant::now();
@@ -334,9 +339,10 @@ impl ClusterInfoVoteListener {
return Ok(());
}
if let Err(e) = verified_vote_packets
.get_and_process_vote_packets(&verified_vote_packets_receiver, &mut update_version)
{
if let Err(e) = verified_vote_packets.get_and_process_vote_packets(
&verified_vote_label_packets_receiver,
&mut update_version,
) {
match e {
Error::CrossbeamRecvTimeoutError(RecvTimeoutError::Disconnected) => {
return Ok(());
@@ -353,7 +359,7 @@ impl ClusterInfoVoteListener {
if let Some(bank) = bank {
let last_version = bank.last_vote_sync.load(Ordering::Relaxed);
let (new_version, msgs) = verified_vote_packets.get_latest_votes(last_version);
packets_sender.send(msgs)?;
verified_packets_sender.send(msgs)?;
bank.last_vote_sync.compare_and_swap(
last_version,
new_version,
@@ -371,6 +377,7 @@ impl ClusterInfoVoteListener {
vote_tracker: Arc<VoteTracker>,
bank_forks: &RwLock<BankForks>,
subscriptions: Arc<RpcSubscriptions>,
verified_vote_sender: VerifiedVoteSender,
) -> Result<()> {
loop {
if exit.load(Ordering::Relaxed) {
@@ -387,6 +394,7 @@ impl ClusterInfoVoteListener {
root_bank.slot(),
subscriptions.clone(),
epoch_stakes,
&verified_vote_sender,
) {
match e {
Error::CrossbeamRecvTimeoutError(RecvTimeoutError::Disconnected) => {
@@ -407,6 +415,7 @@ impl ClusterInfoVoteListener {
vote_tracker: &Arc<VoteTracker>,
last_root: Slot,
subscriptions: Arc<RpcSubscriptions>,
verified_vote_sender: &VerifiedVoteSender,
) -> Result<()> {
Self::get_and_process_votes(
vote_txs_receiver,
@@ -414,6 +423,7 @@ impl ClusterInfoVoteListener {
last_root,
subscriptions,
None,
verified_vote_sender,
)
}
@@ -423,6 +433,7 @@ impl ClusterInfoVoteListener {
last_root: Slot,
subscriptions: Arc<RpcSubscriptions>,
epoch_stakes: Option<&EpochStakes>,
verified_vote_sender: &VerifiedVoteSender,
) -> Result<()> {
let timer = Duration::from_millis(200);
let mut vote_txs = vote_txs_receiver.recv_timeout(timer)?;
@@ -435,6 +446,7 @@ impl ClusterInfoVoteListener {
last_root,
subscriptions,
epoch_stakes,
verified_vote_sender,
);
Ok(())
}
@@ -445,6 +457,7 @@ impl ClusterInfoVoteListener {
root: Slot,
subscriptions: Arc<RpcSubscriptions>,
epoch_stakes: Option<&EpochStakes>,
verified_vote_sender: &VerifiedVoteSender,
) {
let mut diff: HashMap<Slot, HashSet<Arc<Pubkey>>> = HashMap::new();
{
@@ -516,6 +529,7 @@ impl ClusterInfoVoteListener {
}
subscriptions.notify_vote(&vote);
let _ = verified_vote_sender.send((*vote_pubkey, vote));
}
}
}
@@ -783,6 +797,7 @@ mod tests {
// Create some voters at genesis
let (vote_tracker, _, validator_voting_keypairs, subscriptions) = setup();
let (votes_sender, votes_receiver) = unbounded();
let (verified_vote_sender, verified_vote_receiver) = unbounded();
let vote_slots = vec![1, 2];
validator_voting_keypairs.iter().for_each(|keypairs| {
@@ -806,8 +821,20 @@ mod tests {
0,
subscriptions,
None,
&verified_vote_sender,
)
.unwrap();
// Check that the received votes were pushed to other commponents
// subscribing via a channel
let received_votes: Vec<_> = verified_vote_receiver.try_iter().collect();
assert_eq!(received_votes.len(), validator_voting_keypairs.len());
for (voting_keypair, (received_pubkey, received_vote)) in
validator_voting_keypairs.iter().zip(received_votes.iter())
{
assert_eq!(voting_keypair.vote_keypair.pubkey(), *received_pubkey);
assert_eq!(received_vote.slots, vote_slots);
}
for vote_slot in vote_slots {
let slot_vote_tracker = vote_tracker.get_slot_vote_tracker(vote_slot).unwrap();
let r_slot_vote_tracker = slot_vote_tracker.read().unwrap();
@@ -828,14 +855,17 @@ mod tests {
// Create some voters at genesis
let (vote_tracker, _, validator_voting_keypairs, subscriptions) = setup();
// Send some votes to process
let (votes_sender, votes_receiver) = unbounded();
let (votes_txs_sender, votes_txs_receiver) = unbounded();
let (verified_vote_sender, verified_vote_receiver) = unbounded();
let mut expected_votes = vec![];
for (i, keyset) in validator_voting_keypairs.chunks(2).enumerate() {
let validator_votes: Vec<_> = keyset
.iter()
.map(|keypairs| {
let node_keypair = &keypairs.node_keypair;
let vote_keypair = &keypairs.vote_keypair;
expected_votes.push((vote_keypair.pubkey(), vec![i as Slot + 1]));
vote_transaction::new_vote_transaction(
vec![i as u64 + 1],
Hash::default(),
@@ -846,18 +876,34 @@ mod tests {
)
})
.collect();
votes_sender.send(validator_votes).unwrap();
votes_txs_sender.send(validator_votes).unwrap();
}
// Check that all the votes were registered for each validator correctly
// Read and process votes from channel `votes_receiver`
ClusterInfoVoteListener::get_and_process_votes(
&votes_receiver,
&votes_txs_receiver,
&vote_tracker,
0,
subscriptions,
None,
&verified_vote_sender,
)
.unwrap();
// Check that the received votes were pushed to other commponents
// subscribing via a channel
let received_votes: Vec<_> = verified_vote_receiver
.try_iter()
.map(|(pubkey, vote)| (pubkey, vote.slots))
.collect();
assert_eq!(received_votes.len(), validator_voting_keypairs.len());
for (expected_pubkey_vote, received_pubkey_vote) in
expected_votes.iter().zip(received_votes.iter())
{
assert_eq!(expected_pubkey_vote, received_pubkey_vote);
}
// Check that all the votes were registered for each validator correctly
for (i, keyset) in validator_voting_keypairs.chunks(2).enumerate() {
let slot_vote_tracker = vote_tracker.get_slot_vote_tracker(i as u64 + 1).unwrap();
let r_slot_vote_tracker = &slot_vote_tracker.read().unwrap();
@@ -974,12 +1020,14 @@ mod tests {
&validator0_keypairs.vote_keypair,
)];
let (verified_vote_sender, _verified_vote_receiver) = unbounded();
ClusterInfoVoteListener::process_votes(
&vote_tracker,
vote_tx,
0,
subscriptions.clone(),
None,
&verified_vote_sender,
);
let ref_count = Arc::strong_count(
&vote_tracker
@@ -1031,7 +1079,14 @@ mod tests {
})
.collect();
ClusterInfoVoteListener::process_votes(&vote_tracker, vote_txs, 0, subscriptions, None);
ClusterInfoVoteListener::process_votes(
&vote_tracker,
vote_txs,
0,
subscriptions,
None,
&verified_vote_sender,
);
let ref_count = Arc::strong_count(
&vote_tracker

View File

@@ -2,6 +2,7 @@ use crate::{
consensus::{ComputedBankState, Tower},
fork_choice::ForkChoice,
progress_map::ProgressMap,
tree_diff::TreeDiff,
};
use solana_ledger::bank_forks::BankForks;
use solana_runtime::{bank::Bank, epoch_stakes::EpochStakes};
@@ -142,10 +143,6 @@ impl HeaviestSubtreeForkChoice {
.map(|fork_info| fork_info.stake_voted_subtree)
}
pub fn contains_slot(&self, slot: Slot) -> bool {
self.fork_infos.contains_key(&slot)
}
pub fn root(&self) -> Slot {
self.root
}
@@ -249,30 +246,6 @@ impl HeaviestSubtreeForkChoice {
self.propagate_new_leaf(slot, parent)
}
// Find all nodes reachable from `root1`, excluding subtree at `root2`
pub fn subtree_diff(&self, root1: Slot, root2: Slot) -> HashSet<Slot> {
if !self.contains_slot(root1) {
return HashSet::new();
}
let mut pending_slots = vec![root1];
let mut reachable_set = HashSet::new();
while !pending_slots.is_empty() {
let current_slot = pending_slots.pop().unwrap();
if current_slot == root2 {
continue;
}
reachable_set.insert(current_slot);
for child in self
.children(current_slot)
.expect("slot was discovered earlier, must exist")
{
pending_slots.push(*child);
}
}
reachable_set
}
// Returns if the given `maybe_best_child` is the heaviest among the children
// it's parent
fn is_best_child(&self, maybe_best_child: Slot) -> bool {
@@ -306,12 +279,6 @@ impl HeaviestSubtreeForkChoice {
AncestorIterator::new(start_slot, &self.fork_infos).collect()
}
pub fn children(&self, slot: Slot) -> Option<&[Slot]> {
self.fork_infos
.get(&slot)
.map(|fork_info| &fork_info.children[..])
}
pub fn merge(
&mut self,
other: HeaviestSubtreeForkChoice,
@@ -349,6 +316,12 @@ impl HeaviestSubtreeForkChoice {
self.add_votes(&new_votes, epoch_stakes, epoch_schedule);
}
pub fn stake_voted_at(&self, slot: Slot) -> Option<u64> {
self.fork_infos
.get(&slot)
.map(|fork_info| fork_info.stake_voted_at)
}
fn propagate_new_leaf(&mut self, slot: Slot, parent: Slot) {
let parent_best_slot = self
.best_slot(parent)
@@ -526,13 +499,6 @@ impl HeaviestSubtreeForkChoice {
);
}
#[cfg(test)]
fn stake_voted_at(&self, slot: Slot) -> Option<u64> {
self.fork_infos
.get(&slot)
.map(|fork_info| fork_info.stake_voted_at)
}
#[cfg(test)]
fn set_stake_voted_at(&mut self, slot: Slot, stake_voted_at: u64) {
self.fork_infos.get_mut(&slot).unwrap().stake_voted_at = stake_voted_at;
@@ -544,6 +510,18 @@ impl HeaviestSubtreeForkChoice {
}
}
impl TreeDiff for HeaviestSubtreeForkChoice {
fn contains_slot(&self, slot: Slot) -> bool {
self.fork_infos.contains_key(&slot)
}
fn children(&self, slot: Slot) -> Option<&[Slot]> {
self.fork_infos
.get(&slot)
.map(|fork_info| &fork_info.children[..])
}
}
impl ForkChoice for HeaviestSubtreeForkChoice {
fn compute_bank_stats(
&mut self,

View File

@@ -41,6 +41,7 @@ pub mod progress_map;
pub mod pubkey_references;
pub mod repair_response;
pub mod repair_service;
pub mod repair_weight;
pub mod repair_weighted_traversal;
pub mod replay_stage;
mod result;
@@ -62,6 +63,7 @@ pub mod sigverify_stage;
pub mod snapshot_packager_service;
pub mod tpu;
pub mod transaction_status_service;
pub mod tree_diff;
pub mod tvu;
pub mod validator;
pub mod verified_vote_packets;

View File

@@ -2,17 +2,15 @@
//! regularly finds missing shreds in the ledger and sends repair requests for those shreds
use crate::{
cluster_info::ClusterInfo,
cluster_info_vote_listener::VoteTracker,
cluster_info_vote_listener::VerifiedVoteReceiver,
cluster_slots::ClusterSlots,
commitment::VOTE_THRESHOLD_SIZE,
repair_weight::RepairWeight,
repair_weighted_traversal::Contains,
result::Result,
serve_repair::{RepairType, ServeRepair, DEFAULT_NONCE},
};
use crossbeam_channel::{Receiver as CrossbeamReceiver, Sender as CrossbeamSender};
use rand::distributions::{Distribution, WeightedIndex};
use rand::{thread_rng, Rng, SeedableRng};
use rand_chacha::ChaChaRng;
use solana_ledger::{
bank_forks::BankForks,
blockstore::{Blockstore, CompletedSlotsReceiver, SlotMeta},
@@ -73,27 +71,37 @@ pub struct RepairStats {
pub shred: RepairStatsGroup,
pub highest_shred: RepairStatsGroup,
pub orphan: RepairStatsGroup,
pub get_best_orphans_us: u64,
pub get_best_shreds_us: u64,
}
#[derive(Default, Debug)]
pub struct RepairTiming {
pub set_root_elapsed: u64,
pub get_votes_elapsed: u64,
pub add_votes_elapsed: u64,
pub lowest_slot_elapsed: u64,
pub update_completed_slots_elapsed: u64,
pub generate_repairs_elapsed: u64,
pub get_best_orphans_elapsed: u64,
pub get_best_shreds_elapsed: u64,
pub send_repairs_elapsed: u64,
}
impl RepairTiming {
fn update(
&mut self,
set_root_elapsed: u64,
get_votes_elapsed: u64,
add_votes_elapsed: u64,
lowest_slot_elapsed: u64,
update_completed_slots_elapsed: u64,
generate_repairs_elapsed: u64,
send_repairs_elapsed: u64,
) {
self.set_root_elapsed += set_root_elapsed;
self.get_votes_elapsed += get_votes_elapsed;
self.add_votes_elapsed += add_votes_elapsed;
self.lowest_slot_elapsed += lowest_slot_elapsed;
self.update_completed_slots_elapsed += update_completed_slots_elapsed;
self.generate_repairs_elapsed += generate_repairs_elapsed;
self.send_repairs_elapsed += send_repairs_elapsed;
}
}
@@ -143,7 +151,7 @@ impl RepairService {
cluster_info: Arc<ClusterInfo>,
repair_info: RepairInfo,
cluster_slots: Arc<ClusterSlots>,
vote_tracker: Arc<VoteTracker>,
verified_vote_receiver: VerifiedVoteReceiver,
) -> Self {
let t_repair = Builder::new()
.name("solana-repair-service".to_string())
@@ -155,7 +163,7 @@ impl RepairService {
cluster_info,
repair_info,
&cluster_slots,
vote_tracker,
verified_vote_receiver,
)
})
.unwrap();
@@ -170,15 +178,18 @@ impl RepairService {
cluster_info: Arc<ClusterInfo>,
repair_info: RepairInfo,
cluster_slots: &ClusterSlots,
vote_tracker: Arc<VoteTracker>,
verified_vote_receiver: VerifiedVoteReceiver,
) {
let mut repair_weight = RepairWeight::new(repair_info.bank_forks.read().unwrap().root());
let serve_repair = ServeRepair::new(cluster_info.clone());
let id = cluster_info.id();
Self::initialize_lowest_slot(id, blockstore, &cluster_info);
let mut repair_stats = RepairStats::default();
let mut repair_timing = RepairTiming::default();
let mut last_stats = Instant::now();
let duplicate_slot_repair_statuses = HashMap::new();
let duplicate_slot_repair_statuses: HashMap<Slot, DuplicateSlotRepairStatus> =
HashMap::new();
Self::initialize_epoch_slots(
blockstore,
&cluster_info,
@@ -189,12 +200,44 @@ impl RepairService {
break;
}
let mut set_root_elapsed;
let mut get_votes_elapsed;
let mut add_votes_elapsed;
let mut lowest_slot_elapsed;
let mut update_completed_slots_elapsed;
let mut generate_repairs_elapsed;
let repairs = {
let root_bank = repair_info.bank_forks.read().unwrap().root_bank().clone();
let new_root = root_bank.slot();
// Purge outdated slots from the weighting heuristic
set_root_elapsed = Measure::start("set_root_elapsed");
repair_weight.set_root(new_root);
set_root_elapsed.stop();
// Add new votes to the weighting heuristic
get_votes_elapsed = Measure::start("get_votes_elapsed");
let mut slot_to_vote_pubkeys: HashMap<Slot, Vec<Pubkey>> = HashMap::new();
verified_vote_receiver
.try_iter()
.for_each(|(vote_pubkey, vote)| {
for slot in vote.slots {
slot_to_vote_pubkeys
.entry(slot)
.or_default()
.push(vote_pubkey);
}
});
get_votes_elapsed.stop();
add_votes_elapsed = Measure::start("add_votes");
repair_weight.add_votes(
&blockstore,
slot_to_vote_pubkeys.into_iter(),
root_bank.epoch_stakes_map(),
root_bank.epoch_schedule(),
);
add_votes_elapsed.stop();
lowest_slot_elapsed = Measure::start("lowest_slot_elapsed");
let lowest_slot = blockstore.lowest_slot();
Self::update_lowest_slot(&id, lowest_slot, &cluster_info);
@@ -227,40 +270,39 @@ impl RepairService {
&repair_socket,
);*/
generate_repairs_elapsed = Measure::start("generate_repairs_elapsed");
let repairs = Self::generate_repairs(
repair_weight.get_best_weighted_repairs(
blockstore,
root_bank.slot(),
root_bank.epoch_stakes_map(),
root_bank.epoch_schedule(),
MAX_ORPHANS,
MAX_REPAIR_LENGTH,
&duplicate_slot_repair_statuses,
&vote_tracker,
);
generate_repairs_elapsed.stop();
repairs
Some(&mut repair_timing),
)
};
let mut cache = HashMap::new();
let mut send_repairs_elapsed = Measure::start("send_repairs_elapsed");
if let Ok(repairs) = repairs {
let mut cache = HashMap::new();
repairs.into_iter().for_each(|repair_request| {
if let Ok((to, req)) = serve_repair.repair_request(
&cluster_slots,
repair_request,
&mut cache,
&mut repair_stats,
) {
repair_socket.send_to(&req, to).unwrap_or_else(|e| {
info!("{} repair req send_to({}) error {:?}", id, to, e);
0
});
}
});
}
repairs.into_iter().for_each(|repair_request| {
if let Ok((to, req)) = serve_repair.repair_request(
&cluster_slots,
repair_request,
&mut cache,
&mut repair_stats,
) {
repair_socket.send_to(&req, to).unwrap_or_else(|e| {
info!("{} repair req send_to({}) error {:?}", id, to, e);
0
});
}
});
send_repairs_elapsed.stop();
repair_timing.update(
set_root_elapsed.as_us(),
get_votes_elapsed.as_us(),
add_votes_elapsed.as_us(),
lowest_slot_elapsed.as_us(),
update_completed_slots_elapsed.as_us(),
generate_repairs_elapsed.as_us(),
send_repairs_elapsed.as_us(),
);
@@ -282,23 +324,31 @@ impl RepairService {
}
datapoint_info!(
"serve_repair-repair-timing",
("set-root-elapsed", repair_timing.set_root_elapsed, i64),
("get-votes-elapsed", repair_timing.get_votes_elapsed, i64),
("add-votes-elapsed", repair_timing.add_votes_elapsed, i64),
(
"lowest_slot_elapsed",
"get-best-orphans-elapsed",
repair_timing.get_best_orphans_elapsed,
i64
),
(
"get-best-shreds-elapsed",
repair_timing.get_best_shreds_elapsed,
i64
),
(
"lowest-slot-elapsed",
repair_timing.lowest_slot_elapsed,
i64
),
(
"update_completed_slots_elapsed",
"update-completed-slots-elapsed",
repair_timing.update_completed_slots_elapsed,
i64
),
(
"generate_repairs_elapsed",
repair_timing.generate_repairs_elapsed,
i64
),
(
"send_repairs_elapsed",
"send-repairs-elapsed",
repair_timing.send_repairs_elapsed,
i64
),
@@ -399,31 +449,6 @@ impl RepairService {
}
}
fn generate_repairs(
blockstore: &Blockstore,
root: Slot,
max_repairs: usize,
duplicate_slot_repair_statuses: &HashMap<Slot, DuplicateSlotRepairStatus>,
vote_tracker: &Arc<VoteTracker>,
) -> Result<Vec<RepairType>> {
// Slot height and shred indexes for shreds we want to repair
let mut repairs: Vec<RepairType> = vec![];
Self::generate_repairs_by_level(
blockstore,
&mut repairs,
max_repairs,
root,
duplicate_slot_repair_statuses,
vote_tracker,
);
// Try to resolve orphans in blockstore
let orphans = blockstore.orphans_iterator(root + 1).unwrap();
Self::generate_repairs_for_orphans(orphans, &mut repairs);
Ok(repairs)
}
#[allow(dead_code)]
fn generate_duplicate_repairs_for_slot(
blockstore: &Blockstore,
@@ -627,81 +652,6 @@ impl RepairService {
.collect()
}
fn generate_repairs_for_orphans(
orphans: impl Iterator<Item = u64>,
repairs: &mut Vec<RepairType>,
) {
repairs.extend(orphans.take(MAX_ORPHANS).map(RepairType::Orphan));
}
/// Repairs any fork starting at the input slot
fn generate_repairs_by_level(
blockstore: &Blockstore,
repairs: &mut Vec<RepairType>,
max_repairs: usize,
slot: Slot,
duplicate_slot_repair_statuses: &HashMap<Slot, DuplicateSlotRepairStatus>,
vote_tracker: &Arc<VoteTracker>,
) {
let mut seed = [0u8; 32];
thread_rng().fill(&mut seed);
let rng = &mut ChaChaRng::from_seed(seed);
let mut pending_slots = vec![slot];
while repairs.len() < max_repairs && !pending_slots.is_empty() {
pending_slots.retain(|slot| !duplicate_slot_repair_statuses.contains_key(slot));
let mut next_pending_slots = vec![];
let mut level_repairs = HashMap::new();
for slot in &pending_slots {
if let Some(slot_meta) = blockstore.meta(*slot).unwrap() {
let new_repairs = Self::generate_repairs_for_slot(
blockstore,
*slot,
&slot_meta,
std::usize::MAX,
);
if !new_repairs.is_empty() {
level_repairs.insert(*slot, new_repairs);
}
next_pending_slots.extend(slot_meta.next_slots);
}
}
if !level_repairs.is_empty() {
let mut slots_to_repair: Vec<_> = level_repairs.keys().cloned().collect();
let mut weights: Vec<_> = {
let r_vote_tracker = vote_tracker.slot_vote_trackers.read().unwrap();
slots_to_repair
.iter()
.map(|slot| {
if let Some(slot_vote_tracker) = r_vote_tracker.get(slot) {
std::cmp::max(slot_vote_tracker.read().unwrap().total_stake, 1)
} else {
// should it be something else?
1
}
})
.collect()
};
let mut weighted_index = WeightedIndex::new(weights.clone()).unwrap();
while repairs.len() < max_repairs && !level_repairs.is_empty() {
let index = weighted_index.sample(rng);
let slot_repairs = level_repairs.get_mut(&slots_to_repair[index]).unwrap();
repairs.push(slot_repairs.remove(0));
if slot_repairs.is_empty() {
level_repairs.remove(&slots_to_repair[index]);
slots_to_repair.remove(index);
weights.remove(index);
if !weights.is_empty() {
weighted_index = WeightedIndex::new(weights.clone()).unwrap();
}
}
}
}
pending_slots = next_pending_slots;
}
}
fn initialize_lowest_slot(id: Pubkey, blockstore: &Blockstore, cluster_info: &ClusterInfo) {
// Safe to set into gossip because by this time, the leader schedule cache should
// also be updated with the latest root (done in blockstore_processor) and thus
@@ -773,6 +723,7 @@ mod test {
use solana_runtime::genesis_utils::{self, GenesisConfigInfo, ValidatorVoteKeypairs};
use solana_sdk::signature::Signer;
use solana_vote_program::vote_transaction;
use std::collections::HashSet;
#[test]
pub fn test_repair_orphan() {
@@ -785,11 +736,18 @@ mod test {
let (shreds2, _) = make_slot_entries(5, 2, 1);
shreds.extend(shreds2);
blockstore.insert_shreds(shreds, None, false).unwrap();
let vote_tracker = Arc::new(VoteTracker::default());
let mut repair_weight = RepairWeight::new(0);
assert_eq!(
RepairService::generate_repairs(&blockstore, 0, 2, &HashMap::new(), &vote_tracker)
.unwrap(),
vec![RepairType::HighestShred(0, 0), RepairType::Orphan(2)]
repair_weight.get_best_weighted_repairs(
&blockstore,
&HashMap::new(),
&EpochSchedule::default(),
MAX_ORPHANS,
MAX_REPAIR_LENGTH,
&HashSet::new(),
None
),
vec![RepairType::Orphan(2), RepairType::HighestShred(0, 0)]
);
}
@@ -807,12 +765,19 @@ mod test {
// Write this shred to slot 2, should chain to slot 0, which we haven't received
// any shreds for
blockstore.insert_shreds(shreds, None, false).unwrap();
let mut repair_weight = RepairWeight::new(0);
let vote_tracker = Arc::new(VoteTracker::default());
// Check that repair tries to patch the empty slot
assert_eq!(
RepairService::generate_repairs(&blockstore, 0, 2, &HashMap::new(), &vote_tracker)
.unwrap(),
repair_weight.get_best_weighted_repairs(
&blockstore,
&HashMap::new(),
&EpochSchedule::default(),
MAX_ORPHANS,
MAX_REPAIR_LENGTH,
&HashSet::new(),
None
),
vec![RepairType::HighestShred(0, 0)]
);
}
@@ -857,83 +822,36 @@ mod test {
})
.collect();
let vote_tracker = Arc::new(VoteTracker::default());
let mut repair_weight = RepairWeight::new(0);
assert_eq!(
RepairService::generate_repairs(
repair_weight.get_best_weighted_repairs(
&blockstore,
0,
std::usize::MAX,
&HashMap::new(),
&vote_tracker
)
.unwrap(),
&EpochSchedule::default(),
MAX_ORPHANS,
MAX_REPAIR_LENGTH,
&HashSet::new(),
None
),
expected
);
assert_eq!(
RepairService::generate_repairs(
repair_weight.get_best_weighted_repairs(
&blockstore,
0,
expected.len() - 2,
&HashMap::new(),
&vote_tracker,
)
.unwrap()[..],
&EpochSchedule::default(),
MAX_ORPHANS,
expected.len() - 2,
&HashSet::new(),
None
)[..],
expected[0..expected.len() - 2]
);
}
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
}
#[test]
pub fn test_repairs_distributed_across_slots() {
solana_logger::setup();
let blockstore_path = get_tmp_ledger_path!();
{
let blockstore = Blockstore::open(&blockstore_path).unwrap();
let num_entries_per_slot = 100;
// Create some shreds
for i in 1..10 {
let (shreds, _) = make_slot_entries(i, 0, num_entries_per_slot as u64);
// Only insert the first shred
blockstore
.insert_shreds(shreds[..1].to_vec(), None, false)
.unwrap();
}
let vote_tracker = Arc::new(VoteTracker::default());
let repairs = RepairService::generate_repairs(
&blockstore,
0,
num_entries_per_slot,
&HashMap::new(),
&vote_tracker,
)
.unwrap();
let mut repairs_slots = HashMap::new();
for repair in repairs {
match repair {
RepairType::Shred(slot, _shred_index) => {
*repairs_slots.entry(slot).or_insert(0) += 1;
}
RepairType::HighestShred(slot, _shred_index) => {
*repairs_slots.entry(slot).or_insert(0) += 1;
}
RepairType::Orphan(slot) => {
*repairs_slots.entry(slot).or_insert(0) += 1;
}
}
}
for i in 1..10 {
assert!(repairs_slots.contains_key(&i));
}
}
Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
}
#[test]
pub fn test_generate_highest_repair() {
let blockstore_path = get_tmp_ledger_path!();
@@ -955,16 +873,17 @@ mod test {
let expected: Vec<RepairType> =
vec![RepairType::HighestShred(0, num_shreds_per_slot - 1)];
let vote_tracker = Arc::new(VoteTracker::default());
let mut repair_weight = RepairWeight::new(0);
assert_eq!(
RepairService::generate_repairs(
repair_weight.get_best_weighted_repairs(
&blockstore,
0,
std::usize::MAX,
&HashMap::new(),
&vote_tracker
)
.unwrap(),
&EpochSchedule::default(),
MAX_ORPHANS,
MAX_REPAIR_LENGTH,
&HashSet::new(),
None
),
expected
);
}

1240
core/src/repair_weight.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
use crate::{
heaviest_subtree_fork_choice::HeaviestSubtreeForkChoice, repair_service::RepairService,
serve_repair::RepairType,
serve_repair::RepairType, tree_diff::TreeDiff,
};
use solana_ledger::blockstore::Blockstore;
use solana_sdk::clock::Slot;

View File

@@ -1,8 +1,8 @@
//! The `retransmit_stage` retransmits shreds between validators
use crate::cluster_info_vote_listener::VoteTracker;
use crate::{
cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT},
cluster_info_vote_listener::VerifiedVoteReceiver,
cluster_slots::ClusterSlots,
contact_info::ContactInfo,
repair_service::DuplicateSlotsResetSender,
@@ -414,7 +414,7 @@ impl RetransmitStage {
shred_version: u16,
cluster_slots: Arc<ClusterSlots>,
duplicate_slots_reset_sender: DuplicateSlotsResetSender,
vote_tracker: Arc<VoteTracker>,
verified_vote_receiver: VerifiedVoteReceiver,
) -> Self {
let (retransmit_sender, retransmit_receiver) = channel();
@@ -459,7 +459,7 @@ impl RetransmitStage {
rv && is_connected
},
cluster_slots,
vote_tracker,
verified_vote_receiver,
);
let thread_hdls = t_retransmit;

View File

@@ -18,7 +18,8 @@ use solana_client::{
rpc_config::*,
rpc_filter::RpcFilterType,
rpc_request::{
DELINQUENT_VALIDATOR_SLOT_DISTANCE, MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE,
DELINQUENT_VALIDATOR_SLOT_DISTANCE, MAX_GET_CONFIRMED_BLOCKS_RANGE,
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE,
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, NUM_LARGEST_ACCOUNTS,
},
rpc_response::Response as RpcResponse,
@@ -535,6 +536,12 @@ impl JsonRpcRequestProcessor {
if end_slot < start_slot {
return Ok(vec![]);
}
if end_slot - start_slot > MAX_GET_CONFIRMED_BLOCKS_RANGE {
return Err(Error::invalid_params(format!(
"Slot range too large; max {}",
MAX_GET_CONFIRMED_BLOCKS_RANGE
)));
}
Ok(self
.blockstore
.rooted_slot_iterator(max(start_slot, self.blockstore.lowest_slot()))
@@ -3544,11 +3551,37 @@ pub mod tests {
assert_eq!(confirmed_blocks, vec![1, 3, 4]);
let req = r#"{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[9,11]}"#;
let res = io.handle_request_sync(&req, meta);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let confirmed_blocks: Vec<Slot> = serde_json::from_value(result["result"].clone()).unwrap();
assert_eq!(confirmed_blocks, Vec::<Slot>::new());
block_commitment_cache
.write()
.unwrap()
.set_largest_confirmed_root(std::u64::MAX);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0,{}]}}"#,
MAX_GET_CONFIRMED_BLOCKS_RANGE
);
let res = io.handle_request_sync(&req, meta.clone());
let result: Value = serde_json::from_str(&res.expect("actual response"))
.expect("actual response deserialization");
let confirmed_blocks: Vec<Slot> = serde_json::from_value(result["result"].clone()).unwrap();
assert_eq!(confirmed_blocks, vec![1, 3, 4, 8]);
let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0,{}]}}"#,
MAX_GET_CONFIRMED_BLOCKS_RANGE + 1
);
let res = io.handle_request_sync(&req, meta);
assert_eq!(
res,
Some(
r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Slot range too large; max 500000"},"id":1}"#.to_string(),
)
);
}
#[test]

View File

@@ -920,11 +920,13 @@ mod tests {
});
// Process votes and check they were notified.
let (s, _r) = unbounded();
ClusterInfoVoteListener::get_and_process_votes_for_tests(
&votes_receiver,
&vote_tracker,
0,
rpc.subscriptions.clone(),
&s,
)
.unwrap();

View File

@@ -33,7 +33,7 @@ use std::{
pub const MAX_ORPHAN_REPAIR_RESPONSES: usize = 10;
pub const DEFAULT_NONCE: u32 = 42;
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum RepairType {
Orphan(Slot),
HighestShred(Slot, u64),

View File

@@ -5,7 +5,7 @@ use crate::{
banking_stage::BankingStage,
broadcast_stage::{BroadcastStage, BroadcastStageType, RetransmitSlotsReceiver},
cluster_info::ClusterInfo,
cluster_info_vote_listener::{ClusterInfoVoteListener, VoteTracker},
cluster_info_vote_listener::{ClusterInfoVoteListener, VerifiedVoteSender, VoteTracker},
fetch_stage::FetchStage,
poh_recorder::{PohRecorder, WorkingBankEntry},
rpc_subscriptions::RpcSubscriptions,
@@ -52,6 +52,7 @@ impl Tpu {
shred_version: u16,
vote_tracker: Arc<VoteTracker>,
bank_forks: Arc<RwLock<BankForks>>,
verified_vote_sender: VerifiedVoteSender,
) -> Self {
let (packet_sender, packet_receiver) = channel();
let fetch_stage = FetchStage::new_with_sender(
@@ -68,22 +69,23 @@ impl Tpu {
SigVerifyStage::new(packet_receiver, verified_sender, verifier)
};
let (verified_vote_sender, verified_vote_receiver) = unbounded();
let (verified_vote_packets_sender, verified_vote_packets_receiver) = unbounded();
let cluster_info_vote_listener = ClusterInfoVoteListener::new(
&exit,
cluster_info.clone(),
verified_vote_sender,
verified_vote_packets_sender,
&poh_recorder,
vote_tracker,
bank_forks,
subscriptions.clone(),
verified_vote_sender,
);
let banking_stage = BankingStage::new(
&cluster_info,
poh_recorder,
verified_receiver,
verified_vote_receiver,
verified_vote_packets_receiver,
transaction_status_sender,
);

32
core/src/tree_diff.rs Normal file
View File

@@ -0,0 +1,32 @@
use solana_sdk::clock::Slot;
use std::collections::HashSet;
pub trait TreeDiff {
fn children(&self, slot: Slot) -> Option<&[Slot]>;
fn contains_slot(&self, slot: Slot) -> bool;
// Find all nodes reachable from `root1`, excluding subtree at `root2`
fn subtree_diff(&self, root1: Slot, root2: Slot) -> HashSet<Slot> {
if !self.contains_slot(root1) {
return HashSet::new();
}
let mut pending_slots = vec![root1];
let mut reachable_set = HashSet::new();
while !pending_slots.is_empty() {
let current_slot = pending_slots.pop().unwrap();
if current_slot == root2 {
continue;
}
reachable_set.insert(current_slot);
for child in self
.children(current_slot)
.expect("slot was discovered earlier, must exist")
{
pending_slots.push(*child);
}
}
reachable_set
}
}

View File

@@ -6,7 +6,7 @@ use crate::{
accounts_hash_verifier::AccountsHashVerifier,
broadcast_stage::RetransmitSlotsSender,
cluster_info::ClusterInfo,
cluster_info_vote_listener::VoteTracker,
cluster_info_vote_listener::{VerifiedVoteReceiver, VoteTracker},
cluster_slots::ClusterSlots,
commitment::BlockCommitmentCache,
ledger_cleanup_service::LedgerCleanupService,
@@ -96,6 +96,7 @@ impl Tvu {
snapshot_package_sender: Option<AccountsPackageSender>,
vote_tracker: Arc<VoteTracker>,
retransmit_slots_sender: RetransmitSlotsSender,
verified_vote_receiver: VerifiedVoteReceiver,
tvu_config: TvuConfig,
) -> Self {
let keypair: Arc<Keypair> = cluster_info.keypair.clone();
@@ -146,7 +147,7 @@ impl Tvu {
tvu_config.shred_version,
cluster_slots.clone(),
duplicate_slots_reset_sender,
vote_tracker.clone(),
verified_vote_receiver,
);
let (ledger_cleanup_slot_sender, ledger_cleanup_slot_receiver) = channel();
@@ -278,6 +279,7 @@ pub mod tests {
BlockCommitmentCache::default_with_blockstore(blockstore.clone()),
));
let (retransmit_slots_sender, _retransmit_slots_receiver) = unbounded();
let (_verified_vote_sender, verified_vote_receiver) = unbounded();
let bank_forks = Arc::new(RwLock::new(bank_forks));
let tvu = Tvu::new(
&vote_keypair.pubkey(),
@@ -310,6 +312,7 @@ pub mod tests {
None,
Arc::new(VoteTracker::new(&bank)),
retransmit_slots_sender,
verified_vote_receiver,
TvuConfig::default(),
);
exit.store(true, Ordering::Relaxed);

View File

@@ -9,7 +9,7 @@ use crate::{
gossip_service::{discover_cluster, GossipService},
poh_recorder::{PohRecorder, GRACE_TICKS_FACTOR, MAX_GRACE_SLOTS},
poh_service::PohService,
rewards_recorder_service::RewardsRecorderService,
rewards_recorder_service::{RewardsRecorderSender, RewardsRecorderService},
rpc::JsonRpcConfig,
rpc_pubsub_service::PubSubService,
rpc_service::JsonRpcService,
@@ -28,11 +28,13 @@ use solana_ledger::{
bank_forks::{BankForks, SnapshotConfig},
bank_forks_utils,
blockstore::{Blockstore, CompletedSlotsReceiver, PurgeType},
blockstore_processor, create_new_tmp_ledger,
blockstore_processor::{self, TransactionStatusSender},
create_new_tmp_ledger,
hardened_unpack::{open_genesis_config, MAX_GENESIS_ARCHIVE_UNPACKED_SIZE},
leader_schedule::FixedSchedule,
leader_schedule_cache::LeaderScheduleCache,
};
use solana_measure::measure::Measure;
use solana_metrics::datapoint_info;
use solana_runtime::bank::Bank;
use solana_sdk::{
@@ -129,6 +131,14 @@ impl ValidatorExit {
}
}
#[derive(Default)]
struct TransactionHistoryServices {
transaction_status_sender: Option<TransactionStatusSender>,
transaction_status_service: Option<TransactionStatusService>,
rewards_recorder_sender: Option<RewardsRecorderSender>,
rewards_recorder_service: Option<RewardsRecorderService>,
}
pub struct Validator {
pub id: Pubkey,
validator_exit: Arc<RwLock<Option<ValidatorExit>>>,
@@ -193,11 +203,21 @@ impl Validator {
}
}
info!("Cleaning accounts paths..");
let mut start = Measure::start("clean_accounts_paths");
for accounts_path in &config.account_paths {
cleanup_accounts_path(accounts_path);
}
start.stop();
info!("done. {}", start);
info!("creating bank...");
let mut validator_exit = ValidatorExit::default();
let exit = Arc::new(AtomicBool::new(false));
let exit_ = exit.clone();
validator_exit.register_exit(Box::new(move || exit_.store(true, Ordering::Relaxed)));
let validator_exit = Arc::new(RwLock::new(Some(validator_exit)));
let (
genesis_config,
bank_forks,
@@ -206,10 +226,15 @@ impl Validator {
completed_slots_receiver,
leader_schedule_cache,
snapshot_hash,
) = new_banks_from_blockstore(config, ledger_path, poh_verify);
TransactionHistoryServices {
transaction_status_sender,
transaction_status_service,
rewards_recorder_sender,
rewards_recorder_service,
},
) = new_banks_from_blockstore(config, ledger_path, poh_verify, &exit);
let leader_schedule_cache = Arc::new(leader_schedule_cache);
let exit = Arc::new(AtomicBool::new(false));
let bank = bank_forks.working_bank();
let bank_forks = Arc::new(RwLock::new(bank_forks));
@@ -221,11 +246,6 @@ impl Validator {
}
}
let mut validator_exit = ValidatorExit::default();
let exit_ = exit.clone();
validator_exit.register_exit(Box::new(move || exit_.store(true, Ordering::Relaxed)));
let validator_exit = Arc::new(RwLock::new(Some(validator_exit)));
node.info.wallclock = timestamp();
node.info.shred_version = compute_shred_version(
&genesis_config.hash(),
@@ -244,7 +264,6 @@ impl Validator {
}
let cluster_info = Arc::new(ClusterInfo::new(node.info.clone(), keypair.clone()));
let blockstore = Arc::new(blockstore);
let block_commitment_cache = Arc::new(RwLock::new(
BlockCommitmentCache::default_with_blockstore(blockstore.clone()),
));
@@ -287,36 +306,6 @@ impl Validator {
)
});
let (transaction_status_sender, transaction_status_service) =
if rpc_service.is_some() && config.rpc_config.enable_rpc_transaction_history {
let (transaction_status_sender, transaction_status_receiver) = unbounded();
(
Some(transaction_status_sender),
Some(TransactionStatusService::new(
transaction_status_receiver,
blockstore.clone(),
&exit,
)),
)
} else {
(None, None)
};
let (rewards_recorder_sender, rewards_recorder_service) =
if rpc_service.is_some() && config.rpc_config.enable_rpc_transaction_history {
let (rewards_recorder_sender, rewards_receiver) = unbounded();
(
Some(rewards_recorder_sender),
Some(RewardsRecorderService::new(
rewards_receiver,
blockstore.clone(),
&exit,
)),
)
} else {
(None, None)
};
info!(
"Starting PoH: epoch={} slot={} tick_height={} blockhash={} leader={:?}",
bank.epoch(),
@@ -411,6 +400,7 @@ impl Validator {
let vote_tracker = Arc::new(VoteTracker::new(bank_forks.read().unwrap().root_bank()));
let (retransmit_slots_sender, retransmit_slots_receiver) = unbounded();
let (verified_vote_sender, verified_vote_receiver) = unbounded();
let tvu = Tvu::new(
vote_account,
authorized_voter_keypairs,
@@ -455,6 +445,7 @@ impl Validator {
snapshot_package_sender,
vote_tracker.clone(),
retransmit_slots_sender,
verified_vote_receiver,
TvuConfig {
max_ledger_shreds: config.max_ledger_shreds,
halt_on_trusted_validators_accounts_hash_mismatch: config
@@ -481,6 +472,7 @@ impl Validator {
node.info.shred_version,
vote_tracker,
bank_forks,
verified_vote_sender,
);
datapoint_info!("validator-new", ("id", id.to_string(), String));
@@ -572,14 +564,16 @@ fn new_banks_from_blockstore(
config: &ValidatorConfig,
blockstore_path: &Path,
poh_verify: bool,
exit: &Arc<AtomicBool>,
) -> (
GenesisConfig,
BankForks,
Blockstore,
Arc<Blockstore>,
Receiver<bool>,
CompletedSlotsReceiver,
LeaderScheduleCache,
Option<(Slot, Hash)>,
TransactionHistoryServices,
) {
let genesis_config =
open_genesis_config(blockstore_path, config.max_genesis_archive_unpacked_size);
@@ -617,12 +611,23 @@ fn new_banks_from_blockstore(
..blockstore_processor::ProcessOptions::default()
};
let blockstore = Arc::new(blockstore);
let transaction_history_services =
if config.rpc_ports.is_some() && config.rpc_config.enable_rpc_transaction_history {
initialize_rpc_transaction_history_services(blockstore.clone(), exit)
} else {
TransactionHistoryServices::default()
};
let (mut bank_forks, mut leader_schedule_cache, snapshot_hash) = bank_forks_utils::load(
&genesis_config,
&blockstore,
config.account_paths.clone(),
config.snapshot_config.as_ref(),
process_options,
transaction_history_services
.transaction_status_sender
.clone(),
)
.unwrap_or_else(|err| {
error!("Failed to load ledger: {:?}", err);
@@ -642,6 +647,7 @@ fn new_banks_from_blockstore(
completed_slots_receiver,
leader_schedule_cache,
snapshot_hash,
transaction_history_services,
)
}
@@ -705,6 +711,33 @@ fn backup_and_clear_blockstore(ledger_path: &Path, start_slot: Slot, shred_versi
drop(blockstore);
}
fn initialize_rpc_transaction_history_services(
blockstore: Arc<Blockstore>,
exit: &Arc<AtomicBool>,
) -> TransactionHistoryServices {
let (transaction_status_sender, transaction_status_receiver) = unbounded();
let transaction_status_sender = Some(transaction_status_sender);
let transaction_status_service = Some(TransactionStatusService::new(
transaction_status_receiver,
blockstore.clone(),
exit,
));
let (rewards_recorder_sender, rewards_receiver) = unbounded();
let rewards_recorder_sender = Some(rewards_recorder_sender);
let rewards_recorder_service = Some(RewardsRecorderService::new(
rewards_receiver,
blockstore,
exit,
));
TransactionHistoryServices {
transaction_status_sender,
transaction_status_service,
rewards_recorder_sender,
rewards_recorder_service,
}
}
// Return true on error, indicating the validator should exit.
fn wait_for_supermajority(
config: &ValidatorConfig,
@@ -962,30 +995,13 @@ fn get_stake_percent_in_gossip(bank: &Bank, cluster_info: &ClusterInfo, log: boo
online_stake * 100 / total_activated_stake
}
fn cleanup_accounts_dir_entry(path: std::fs::DirEntry, accounts_file_regex: &regex::Regex) {
if let Ok(file_type) = path.file_type() {
if file_type.is_file() {
if let Ok(file_name) = path.file_name().into_string() {
if accounts_file_regex.is_match(&file_name) {
if let Err(e) = std::fs::remove_file(path.path()) {
info!("Couldn't delete file: {:?} error: {:?}", path, e);
}
}
}
}
}
}
// Cleanup anything that looks like an accounts append-vec
fn cleanup_accounts_path(account_path: &std::path::Path) {
use regex::Regex;
let accounts_file_regex = Regex::new(r"(\d+).(\d+)").unwrap();
if let Ok(dir_entries) = std::fs::read_dir(&account_path) {
for entry in dir_entries {
if let Ok(path) = entry {
cleanup_accounts_dir_entry(path, &accounts_file_regex);
}
}
if std::fs::remove_dir_all(account_path).is_err() {
warn!(
"encountered error removing accounts path: {:?}",
account_path
);
}
}
@@ -1167,20 +1183,4 @@ mod tests {
rpc_override_health_check
));
}
#[test]
fn accounts_clean() {
use std::fs::File;
let temp_dir = tempfile::tempdir_in("farf").unwrap();
let temp_path = temp_dir.path();
{
let _file1 = File::create(temp_path.join("foo.txt")).unwrap();
let _file2 = File::create(temp_path.join("123.2222")).unwrap();
}
std::fs::create_dir(temp_path.join("12.088")).unwrap();
cleanup_accounts_path(temp_dir.path());
assert!(File::open(temp_path.join("foo.txt")).is_ok());
assert!(File::open(temp_path.join("123.2222")).is_err());
assert!(std::fs::read_dir(temp_path.join("12.088")).is_ok());
}
}

View File

@@ -1,5 +1,5 @@
use crate::{
cluster_info_vote_listener::VerifiedVotePacketsReceiver, crds_value::CrdsValueLabel,
cluster_info_vote_listener::VerifiedLabelVotePacketsReceiver, crds_value::CrdsValueLabel,
result::Result,
};
use solana_perf::packet::Packets;
@@ -18,7 +18,7 @@ impl Deref for VerifiedVotePackets {
impl VerifiedVotePackets {
pub fn get_and_process_vote_packets(
&mut self,
vote_packets_receiver: &VerifiedVotePacketsReceiver,
vote_packets_receiver: &VerifiedLabelVotePacketsReceiver,
last_update_version: &mut u64,
) -> Result<()> {
let timer = Duration::from_millis(200);

View File

@@ -3,7 +3,7 @@
//!
use crate::{
cluster_info::ClusterInfo,
cluster_info_vote_listener::VoteTracker,
cluster_info_vote_listener::VerifiedVoteReceiver,
cluster_slots::ClusterSlots,
repair_response,
repair_service::{RepairInfo, RepairService},
@@ -302,7 +302,7 @@ impl WindowService {
leader_schedule_cache: &Arc<LeaderScheduleCache>,
shred_filter: F,
cluster_slots: Arc<ClusterSlots>,
vote_tracker: Arc<VoteTracker>,
verified_vote_receiver: VerifiedVoteReceiver,
) -> WindowService
where
F: 'static
@@ -319,7 +319,7 @@ impl WindowService {
cluster_info.clone(),
repair_info,
cluster_slots,
vote_tracker,
verified_vote_receiver,
);
let (insert_sender, insert_receiver) = unbounded();

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-crate-features"
version = "1.2.10"
version = "1.2.11"
description = "Solana Crate Features"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"

21
docs/.eslintrc Normal file
View File

@@ -0,0 +1,21 @@
{
"env": {
"browser": true,
"node": true
},
"parser": "babel-eslint",
"rules": {
"strict": 0,
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"no-trailing-spaces": ["error", { "skipBlankLines": true }]
},
"settings": {
"react": {
"version": "detect", // React version. "detect" automatically picks the version you have installed.
}
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
]
}

1
docs/.gitattributes vendored
View File

@@ -1 +0,0 @@
theme/highlight.js binary

23
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
.vercel
/static/img/*.svg
vercel.json
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -0,0 +1,9 @@
# |source| this file
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install -y nodejs
npm install --global docusaurus-init
docusaurus-init
npm install --global vercel

4
docs/.travis/script.sh Normal file
View File

@@ -0,0 +1,4 @@
# |source| this file
set -ex
./build.sh

View File

@@ -1,31 +1,39 @@
Building the Solana Docs
---
# Docs Readme
Install dependencies, build, and test the docs:
Solana's Docs are built using [Docusaurus 2](https://v2.docusaurus.io/) with `npm`.
Static content delivery is handled using `vercel`.
```bash
$ brew install coreutils
$ brew install mscgen
$ cargo install svgbob_cli
$ cargo install mdbook-linkcheck
$ cargo install mdbook
$ ./build.sh
### Installing Docusaurus
```
$ npm install
```
Run any Rust tests in the markdown:
### Local Development
```bash
$ make test
This command starts a local development server and open up a browser window.
Most changes are reflected live without having to restart the server.
```
$ npm run start
```
Render markdown as HTML:
### Build Locally
```bash
$ make build
This command generates static content into the `build` directory and can be
served using any static contents hosting service.
```
$ docs/build.sh
```
Render and view the docs:
### CI Build Flow
The docs are built and published in Travis CI with the `docs/build.sh` script.
On each PR, the docs are built, but not published.
```bash
$ make open
```
In each post-commit build, docs are built and published using `vercel` to their
respective domain depending on the build branch.
- Master branch docs are published to `edge.docs.solana.com`
- Beta branch docs are published to `beta.docs.solana.com`
- Latest release tag docs are published to `docs.solana.com`

3
docs/babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve("@docusaurus/core/lib/babel/preset")],
};

View File

@@ -1,12 +0,0 @@
[book]
title = "Solana: Blockchain Rebuilt for Scale"
authors = ["The Solana Team"]
[build]
build-dir = "html"
create-missing = false
[output.html]
theme = "theme"
[output.linkcheck]

View File

@@ -3,6 +3,9 @@ set -e
cd "$(dirname "$0")"
# shellcheck source=ci/rust-version.sh
source ../ci/rust-version.sh stable
: "${rust_stable:=}" # Pacify shellcheck
usage=$(cargo +"$rust_stable" -q run -p solana-cli -- -C ~/.foo --help | sed -e 's|'"$HOME"'|~|g' -e 's/[[:space:]]\+$//')

View File

@@ -1,17 +1,25 @@
#!/usr/bin/env bash
set -e
set -ex
# shellcheck source=ci/env.sh
source ../ci/env.sh
cd "$(dirname "$0")"
# md check
find src -name '*.md' -a \! -name SUMMARY.md |
while read -r file; do
if ! grep -q '('"${file#src/}"')' src/SUMMARY.md; then
echo "Error: $file missing from SUMMARY.md"
exit 1
fi
done
: "${rust_stable_docker_image:=}" # Pacify shellcheck
mdbook --version
mdbook-linkcheck --version
make -j"$(nproc)"
# shellcheck source=ci/rust-version.sh
source ../ci/rust-version.sh
../ci/docker-run.sh "$rust_stable_docker_image" docs/build-cli-usage.sh
../ci/docker-run.sh "$rust_stable_docker_image" docs/convert-ascii-to-svg.sh
./set-solana-release-tag.sh
# Build from /src into /build
npm run build
# Publish only from merge commits and release tags
if [[ -n $CI ]]; then
if [[ -z $CI_PULL_REQUEST ]]; then
./publish-docs.sh
fi
fi

21
docs/convert-ascii-to-svg.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Convert .bob and .msc files in docs/art to .svg files located where the
# site build will find them.
set -e
cd "$(dirname "$0")"
output_dir=static/img
mkdir -p "$output_dir"
while read -r bob_file; do
svg_file=$(basename "${bob_file%.*}".svg)
svgbob "$bob_file" --output "$output_dir/$svg_file"
done < <(find art/*.bob)
while read -r msc_file; do
svg_file=$(basename "${msc_file%.*}".svg)
mscgen -T svg -o "$output_dir/$svg_file" -i "$msc_file"
done < <(find art/*.msc)

107
docs/docusaurus.config.js Normal file
View File

@@ -0,0 +1,107 @@
module.exports = {
title: "Solana Docs",
tagline:
"Solana is an open source project implementing a new, high-performance, permissionless blockchain.",
url: "https://docs.solana.com",
baseUrl: "/",
favicon: "img/favicon.ico",
organizationName: "solana-labs", // Usually your GitHub org/user name.
projectName: "solana", // Usually your repo name.
themeConfig: {
navbar: {
logo: {
alt: "Solana Logo",
src: "img/logo-horizontal.svg",
srcDark: "img/logo-horizontal-dark.svg",
},
links: [
{
to: "introduction",
label: "Docs",
position: "left",
},
{
to: "apps/README",
label: "Developers",
position: "left",
},
{
to: "running-validator/README",
label: "Validators",
position: "left",
},
{
href: "https://discordapp.com/invite/pquxPsq",
label: "Chat",
position: "right",
},
{
href: "https://github.com/solana-labs/solana",
label: "GitHub",
position: "right",
},
],
},
footer: {
style: "dark",
links: [
{
title: "Docs",
items: [
{
label: "Introduction",
to: "introduction",
},
{
label: "Tour de SOL",
to: "tour-de-sol/README",
},
],
},
{
title: "Community",
items: [
{
label: "Discord",
href: "https://discordapp.com/invite/pquxPsq",
},
{
label: "Twitter",
href: "https://twitter.com/solana",
},
{
label: "Forums",
href: "https://forums.solana.com",
},
],
},
{
title: "More",
items: [
{
label: "GitHub",
href: "https://github.com/solana-labs/solana",
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} Solana Foundation`,
},
},
presets: [
[
"@docusaurus/preset-classic",
{
docs: {
path: "src",
routeBasePath: "/",
sidebarPath: require.resolve("./sidebars.js"),
},
theme: {
customCss: require.resolve("./src/css/custom.css"),
},
},
],
],
};

View File

@@ -1,51 +0,0 @@
BOB_SRCS=$(wildcard art/*.bob)
MSC_SRCS=$(wildcard art/*.msc)
MD_SRCS=$(wildcard src/*.md src/*/*.md) src/cli/usage.md
SVG_IMGS=$(BOB_SRCS:art/%.bob=src/.gitbook/assets/%.svg) $(MSC_SRCS:art/%.msc=src/.gitbook/assets/%.svg)
TARGET=html/index.html
TEST_STAMP=src/tests.ok
all: $(TARGET)
svg: $(SVG_IMGS)
test: $(TEST_STAMP)
open: $(TEST_STAMP)
mdbook build --open
./set-solana-release-tag.sh
watch: $(SVG_IMGS)
mdbook watch
src/.gitbook/assets/%.svg: art/%.bob
@mkdir -p $(@D)
svgbob < $< > $@
src/.gitbook/assets/%.svg: art/%.msc
@mkdir -p $(@D)
mscgen -T svg -i $< -o $@
../target/debug/solana:
cd ../cli && cargo build
src/cli/usage.md: build-cli-usage.sh ../target/debug/solana
./$<
src/%.md: %.md
@mkdir -p $(@D)
@cp $< $@
$(TEST_STAMP): $(TARGET)
mdbook test
touch $@
$(TARGET): $(SVG_IMGS) $(MD_SRCS)
mdbook build
./set-solana-release-tag.sh
clean:
rm -f $(SVG_IMGS) src/tests.ok
rm -rf html

39
docs/package.json Normal file
View File

@@ -0,0 +1,39 @@
{
"name": "solana-docs",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"format": "prettier --check \"**/*.{js,jsx,json,md,scss}\"",
"format:fix": "prettier --write \"**/*.{js,jsx,json,md,scss}\"",
"lint": "set -ex; eslint .",
"lint:fix": "npm run lint -- --fix"
},
"dependencies": {
"@docusaurus/core": "^2.0.0-alpha.58",
"@docusaurus/preset-classic": "^2.0.0-alpha.58",
"@docusaurus/theme-search-algolia": "^2.0.0-alpha.32",
"babel-eslint": "^10.1.0",
"clsx": "^1.1.1",
"eslint": "^7.3.1",
"eslint-plugin-react": "^7.20.0",
"prettier": "^2.0.5",
"react": "^16.8.4",
"react-dom": "^16.8.4"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

39
docs/publish-docs.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -e
if [[ -d .vercel ]]; then
rm -r .vercel
fi
CONFIG_FILE=vercel.json
if [[ -n $CI_TAG ]]; then
PROJECT_NAME=docs-solana-com
else
eval "$(../ci/channel-info.sh)"
case $CHANNEL in
edge)
PROJECT_NAME=edge-docs-solana-com
;;
beta)
PROJECT_NAME=beta-docs-solana-com
;;
*)
PROJECT_NAME=docs
;;
esac
fi
cat > "$CONFIG_FILE" <<EOF
{
"name": "$PROJECT_NAME",
"scope": "solana-labs"
}
EOF
[[ -n $VERCEL_TOKEN ]] || {
echo "VERCEL_TOKEN is undefined. Needed for Vercel authentication."
exit 1
}
vercel deploy . --local-config="$CONFIG_FILE" --confirm --token "$VERCEL_TOKEN" --prod

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
if [[ -n $CI_TAG ]]; then
@@ -23,7 +23,6 @@ if [[ -z "$LATEST_SOLANA_RELEASE_VERSION" ]]; then
fi
set -x
find html/ -name \*.html -exec sed -i "s/LATEST_SOLANA_RELEASE_VERSION/$LATEST_SOLANA_RELEASE_VERSION/g" {} \;
if [[ -n $CI ]]; then
find src/ -name \*.md -exec sed -i "s/LATEST_SOLANA_RELEASE_VERSION/$LATEST_SOLANA_RELEASE_VERSION/g" {} \;
fi

173
docs/sidebars.js Normal file
View File

@@ -0,0 +1,173 @@
module.exports = {
docs: {
"Introduction": ["introduction"],
"Wallet Guide": [
"wallet-guide",
{
type: "category",
label: "App Wallets",
items: [
"wallet-guide/apps",
"wallet-guide/trust-wallet",
"wallet-guide/ledger-live",
],
},
{
type: "category",
label: "Command-line Wallets",
items: [
"wallet-guide/cli",
"wallet-guide/paper-wallet",
{
type: "category",
label: "Hardware Wallets",
items: ["wallet-guide/hardware-wallets", "wallet-guide/hardware-wallets/ledger"],
},
"wallet-guide/file-system-wallet",
],
},
"wallet-guide/support",
],
"Staking Guide": [
"staking",
"staking/stake-accounts",
],
"Command Line Guide": [
"cli",
"cli/install-solana-cli-tools",
"cli/conventions",
"cli/choose-a-cluster",
"cli/transfer-tokens",
"cli/manage-stake-accounts",
"offline-signing",
"offline-signing/durable-nonce",
],
"Solana Clusters": ["clusters"],
"Develop Applications": [
"apps",
"apps/rent",
"apps/webwallet",
"apps/tictactoe",
"apps/drones",
"transaction",
"apps/jsonrpc-api",
"apps/javascript-api",
"apps/builtins",
],
"Integration Guides": ["integrations/exchange"],
"Run a Validator": [
"running-validator",
"running-validator/validator-reqs",
"running-validator/validator-start",
"running-validator/validator-stake",
"running-validator/validator-monitor",
"running-validator/validator-info",
"running-validator/validator-troubleshoot",
],
"Tour de SOL": [
"tour-de-sol",
{
type: "category",
label: "Registration",
items: [
"tour-de-sol/registration/how-to-register",
"tour-de-sol/registration/terms-of-participation",
"tour-de-sol/registration/rewards",
"tour-de-sol/registration/confidentiality",
"tour-de-sol/registration/validator-registration-and-rewards-faq",
],
},
{
type: "category",
label: "Participation",
items: [
"tour-de-sol/participation/validator-technical-requirements",
"tour-de-sol/participation/validator-public-key-registration",
"tour-de-sol/participation/steps-to-create-a-validator",
],
},
"tour-de-sol/useful-links",
"tour-de-sol/submitting-bugs",
],
"Benchmark a Cluster": ["cluster/bench-tps", "cluster/performance-metrics"],
"Solana's Architecture": [
"cluster/overview",
"cluster/synchronization",
"cluster/leader-rotation",
"cluster/fork-generation",
"cluster/managing-forks",
"cluster/turbine-block-propagation",
"cluster/vote-signing",
"cluster/stake-delegation-and-rewards",
],
"Anatomy of a Validator": [
"validator/anatomy",
"validator/tpu",
"validator/tvu",
"validator/blockstore",
"validator/gossip",
"validator/runtime",
],
Terminology: ["terminology"],
History: ["history"],
"Implemented Design Proposals": [
{
type: "category",
label: "Economic Design",
items: [
"implemented-proposals/ed_overview/ed_cluster_economics",
{
type: "category",
label: "Validation Client Economics",
items: [
"implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_overview",
"implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards",
"implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_state_validation_transaction_fees",
"implemented-proposals/ed_overview/ed_validation_client_economics/ed_vce_validation_stake_delegation",
],
},
"implemented-proposals/ed_overview/ed_storage_rent_economics",
"implemented-proposals/ed_overview/ed_economic_sustainability",
"implemented-proposals/ed_overview/ed_mvp",
"implemented-proposals/ed_overview/ed_references",
],
},
"implemented-proposals/transaction-fees",
"implemented-proposals/tower-bft",
"implemented-proposals/leader-leader-transition",
"implemented-proposals/leader-validator-transition",
"implemented-proposals/persistent-account-storage",
"implemented-proposals/reliable-vote-transmission",
"implemented-proposals/repair-service",
"implemented-proposals/testing-programs",
"implemented-proposals/readonly-accounts",
"implemented-proposals/embedding-move",
"implemented-proposals/staking-rewards",
"implemented-proposals/rent",
"implemented-proposals/durable-tx-nonces",
"implemented-proposals/validator-timestamp-oracle",
"implemented-proposals/commitment",
"implemented-proposals/snapshot-verification",
"implemented-proposals/cross-program-invocation",
"implemented-proposals/program-derived-addresses",
],
"Accepted Design Proposals": [
"proposals/accepted_design_proposals",
"proposals/ledger-replication-to-implement",
"proposals/optimistic-confirmation-and-slashing",
"proposals/vote-signing-to-implement",
"proposals/cluster-test-framework",
"proposals/validator-proposal",
"proposals/simple-payment-and-state-verification",
"proposals/interchain-transaction-verification",
"proposals/snapshot-verification",
"proposals/bankless-leader",
"proposals/slashing",
"proposals/tick-verification",
"proposals/block-confirmation",
"proposals/rust-clients",
"proposals/optimistic_confirmation",
"proposals/abi-management",
],
},
};

View File

@@ -1,4 +1,6 @@
# Table of contents
---
title: Table of contents
---
* [Introduction](introduction.md)
* [Wallet Guide](wallet-guide/README.md)

View File

@@ -1,4 +1,6 @@
# Programming Model
---
title: Programming Model
---
An _app_ interacts with a Solana cluster by sending it _transactions_ with one or more _instructions_. The Solana _runtime_ passes those instructions to _programs_ deployed by app developers beforehand. An instruction might, for example, tell a program to transfer _lamports_ from one _account_ to another or create an interactive contract that governs how lamports are transferred. Instructions are executed sequentially and atomically for each transaction. If any instruction is invalid, all account changes in the transaction are discarded.
@@ -18,7 +20,7 @@ Each instruction specifies a single program account \(which must be marked execu
## Deploying Programs to a Cluster
![SDK tools](../.gitbook/assets/sdk-tools.svg)
![SDK tools](/img/sdk-tools.svg)
As shown in the diagram above, a program author creates a program and compiles it to an ELF shared object containing BPF bytecode and uploads it to the Solana cluster with a special _deploy_ transaction. The cluster makes it available to clients via a _program ID_. The program ID is a _address_ specified when deploying and is used to reference the program in subsequent transactions.
@@ -28,7 +30,7 @@ A program may be written in any programming language that can target the Berkley
If the program needs to store state between transactions, it does so using _accounts_. Accounts are similar to files in operating systems such as Linux. Like a file, an account may hold arbitrary data and that data persists beyond the lifetime of a program. Also like a file, an account includes metadata that tells the runtime who is allowed to access the data and how.
Unlike a file, the account includes metadata for the lifetime of the file. That lifetime is expressed in "tokens", which is a number of fractional native tokens, called _lamports_. Accounts are held in validator memory and pay ["rent"](rent.md) to stay there. Each validator periodically scans all accounts and collects rent. Any account that drops to zero lamports is purged.
Unlike a file, the account includes metadata for the lifetime of the file. That lifetime is expressed in "tokens", which is a number of fractional native tokens, called _lamports_. Accounts are held in validator memory and pay ["rent"](apps/rent.md) to stay there. Each validator periodically scans all accounts and collects rent. Any account that drops to zero lamports is purged.
In the same way that a Linux user uses a path to look up a file, a Solana client uses an _address_ to look up an account. The address is usually a 256-bit public key. To create an account with a public-key address, the client generates a _keypair_ and registers its public key using the `CreateAccount` instruction with preallocated fixed storage size in bytes. In fact, the account address can be an arbitrary 32 bytes, and there is a mechanism for advanced users to create derived addresses (`CreateAccountWithSeed`). Addresses are presented in Base58 encoding on user interfaces.

View File

@@ -1,4 +1,6 @@
# Builtin Programs
---
title: Builtin Programs
---
Solana contains a small handful of builtin programs, which are required to run
validator nodes. Unlike third-party programs, the builtin programs are part of
@@ -18,15 +20,15 @@ programs, as well include instructions from third-party programs.
Create accounts and transfer lamports between them
* Program ID: `11111111111111111111111111111111`
* Instructions: [SystemInstruction](https://docs.rs/solana-sdk/LATEST_SOLANA_RELEASE_VERSION/solana_sdk/system_instruction/enum.SystemInstruction.html)
- Program ID: `11111111111111111111111111111111`
- Instructions: [SystemInstruction](https://docs.rs/solana-sdk/LATEST_SOLANA_RELEASE_VERSION/solana_sdk/system_instruction/enum.SystemInstruction.html)
## Config Program
Add configuration data to the chain and the list of public keys that are permitted to modify it
* Program ID: `Config1111111111111111111111111111111111111`
* Instructions: [config_instruction](https://docs.rs/solana-config-program/LATEST_SOLANA_RELEASE_VERSION/solana_config_program/config_instruction/index.html)
- Program ID: `Config1111111111111111111111111111111111111`
- Instructions: [config_instruction](https://docs.rs/solana-config-program/LATEST_SOLANA_RELEASE_VERSION/solana_config_program/config_instruction/index.html)
Unlike the other programs, the Config program does not define any individual
instructions. It has just one implicit instruction, a "store" instruction. Its
@@ -37,25 +39,25 @@ data to store in it.
Create stake accounts and delegate it to validators
* Program ID: `Stake11111111111111111111111111111111111111`
* Instructions: [StakeInstruction](https://docs.rs/solana-stake-program/LATEST_SOLANA_RELEASE_VERSION/solana_stake_program/stake_instruction/enum.StakeInstruction.html)
- Program ID: `Stake11111111111111111111111111111111111111`
- Instructions: [StakeInstruction](https://docs.rs/solana-stake-program/LATEST_SOLANA_RELEASE_VERSION/solana_stake_program/stake_instruction/enum.StakeInstruction.html)
## Vote Program
Create vote accounts and vote on blocks
* Program ID: `Vote111111111111111111111111111111111111111`
* Instructions: [VoteInstruction](https://docs.rs/solana-vote-program/LATEST_SOLANA_RELEASE_VERSION/solana_vote_program/vote_instruction/enum.VoteInstruction.html)
- Program ID: `Vote111111111111111111111111111111111111111`
- Instructions: [VoteInstruction](https://docs.rs/solana-vote-program/LATEST_SOLANA_RELEASE_VERSION/solana_vote_program/vote_instruction/enum.VoteInstruction.html)
## BPF Loader
Add programs to the chain.
* Program ID: `BPFLoader1111111111111111111111111111111111`
* Instructions: [LoaderInstruction](https://docs.rs/solana-sdk/LATEST_SOLANA_RELEASE_VERSION/solana_sdk/loader_instruction/enum.LoaderInstruction.html)
- Program ID: `BPFLoader1111111111111111111111111111111111`
- Instructions: [LoaderInstruction](https://docs.rs/solana-sdk/LATEST_SOLANA_RELEASE_VERSION/solana_sdk/loader_instruction/enum.LoaderInstruction.html)
The BPF Loader marks itself as its "owner" of the executable account it
creates to store your program. When a user invokes an instruction via a
program ID, the Solana runtime will load both your executable account and its
owner, the BPF Loader. The runtime then passes your program to the BPF Loader
to process the instruction.
to process the instruction.

View File

@@ -1,4 +1,6 @@
# Drones
---
title: Drones
---
This section defines an off-chain service called a _drone_, which acts as custodian of a user's private key. In its simplest form, it can be used to create _airdrop_ transactions, a token transfer from the drone's account to a client's account.
@@ -20,7 +22,7 @@ Note: the Solana cluster will not parallelize transactions funded by the same fe
## Attack vectors
### Invalid recent\_blockhash
### Invalid recent_blockhash
The drone may prefer its airdrops only target a particular Solana cluster. To do that, it listens to the cluster for new entry IDs and ensure any requests reference a recent one.
@@ -41,4 +43,3 @@ A client may request multiple airdrops before the first has been submitted to th
If the transaction data size is smaller than the size of the returned signature \(or descriptive error\), a single client can flood the network. Considering that a simple `Transfer` operation requires two public keys \(each 32 bytes\) and a `fee` field, and that the returned signature is 64 bytes \(and a byte to indicate `Ok`\), consideration for this attack may not be required.
In the current design, the drone accepts TCP connections. This allows clients to DoS the service by simply opening lots of idle connections. Switching to UDP may be preferred. The transaction data will be smaller than a UDP packet since the transaction sent to the Solana cluster is already pinned to using UDP.

View File

@@ -1,4 +1,5 @@
# JavaScript API
---
title: JavaScript API
---
See [solana-web3](https://solana-labs.github.io/solana-web3.js/).

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
# Storage Rent for Accounts
---
title: Storage Rent for Accounts
---
Keeping accounts alive on Solana incurs a storage cost called _rent_ because the cluster must actively maintain the data to process any future transactions on it. This is different from Bitcoin and Ethereum, where storing accounts doesn't incur any costs.

View File

@@ -1,4 +1,6 @@
# Example: Tic-Tac-Toe
---
title: "Example: Tic-Tac-Toe"
---
[Click here to play Tic-Tac-Toe](https://solana-example-tictactoe.herokuapp.com/) on the Solana testnet. Open the link and wait for another player to join, or open the link in a second browser tab to play against yourself. You will see that every move a player makes stores a transaction on the ledger.
@@ -19,4 +21,3 @@ Next, follow the steps in the git repository's [README](https://github.com/solan
## Getting lamports to users
You may have noticed you interacted with the Solana cluster without first needing to acquire lamports to pay transaction fees. Under the hood, the web app creates a new ephemeral identity and sends a request to an off-chain service for a signed transaction authorizing a user to start a new game. The service is called a _drone_. When the app sends the signed transaction to the Solana cluster, the drone's lamports are spent to pay the transaction fee and start the game. In a real world app, the drone might request the user watch an ad or pass a CAPTCHA before signing over its lamports.

View File

@@ -1,4 +1,6 @@
# Example Client: Web Wallet
---
title: "Example Client: Web Wallet"
---
## Build and run a web wallet locally
@@ -13,4 +15,3 @@ $ git checkout $TAG
```
Next, follow the steps in the git repository's [README](https://github.com/solana-labs/example-webwallet/blob/master/README.md).

View File

@@ -1,7 +1,9 @@
# Command-line Guide
---
title: Command-line Guide
---
In this section, we will describe how to use the Solana command-line tools to
create a *wallet*, to send and receive SOL tokens, and to participate in
create a _wallet_, to send and receive SOL tokens, and to participate in
the cluster by delegating stake.
To interact with a Solana cluster, we will use its command-line interface, also
@@ -11,8 +13,10 @@ necessarily the easiest to use, but it provides the most direct, flexible, and
secure access to your Solana accounts.
## Getting Started
To get started using the Solana Command Line (CLI) tools:
- [Install the Solana Tools](install-solana-cli-tools.md)
- [Choose a Cluster](choose-a-cluster.md)
- [Create a Wallet](../wallet-guide/cli.md)
- [Check out our CLI conventions](conventions.md)
- [Install the Solana Tools](cli/install-solana-cli-tools.md)
- [Choose a Cluster](cli/choose-a-cluster.md)
- [Create a Wallet](wallet-guide/cli.md)
- [Check out our CLI conventions](cli/conventions.md)

View File

@@ -1,8 +1,12 @@
# Connecting to a Cluster
---
title: Connecting to a Cluster
---
See [Solana Clusters](../clusters.md) for general information about the
available clusters.
## Configure the command-line tool
You can check what cluster the Solana command-line tool (CLI) is currently targeting by
running the following command:
@@ -10,11 +14,12 @@ running the following command:
solana config get
```
Use `solana config set` command to target a particular cluster. After setting
Use `solana config set` command to target a particular cluster. After setting
a cluster target, any future subcommands will send/receive information from that
cluster.
For example to target the Devnet cluster, run:
```bash
solana config set --url https://devnet.solana.com
```

View File

@@ -1,4 +1,6 @@
# Using Solana CLI
---
title: Using Solana CLI
---
Before running any Solana CLI commands, let's go over some conventions that
you will see across all commands. First, the Solana CLI is actually a collection
@@ -19,7 +21,7 @@ where you replace the text `<COMMAND>` with the name of the command you want
to learn more about.
The command's usage message will typically contain words such as `<AMOUNT>`,
`<ACCOUNT_ADDRESS>` or `<KEYPAIR>`. Each word is a placeholder for the *type* of
`<ACCOUNT_ADDRESS>` or `<KEYPAIR>`. Each word is a placeholder for the _type_ of
text you can execute the command with. For example, you can replace `<AMOUNT>`
with a number such as `42` or `100.42`. You can replace `<ACCOUNT_ADDRESS>` with
the base58 encoding of your public key, such as
@@ -27,12 +29,13 @@ the base58 encoding of your public key, such as
## Keypair conventions
Many commands using the CLI tools require a value for a `<KEYPAIR>`. The value
Many commands using the CLI tools require a value for a `<KEYPAIR>`. The value
you should use for the keypair depend on what type of
[command line wallet you created](../wallet-guide/cli.md).
For example, the way to display any wallet's address
(also known as the keypair's pubkey), the CLI help document shows:
```bash
solana-keygen pubkey <KEYPAIR>
```
@@ -49,9 +52,11 @@ enter the word `ASK` and the program will prompt you to enter your seed words
when you run the command.
To display the wallet address of a Paper Wallet:
```bash
solana-keygen pubkey ASK
```
#### File System Wallet
With a file system wallet, the keypair is stored in a file on your computer.
@@ -59,6 +64,7 @@ Replace `<KEYPAIR>` with the complete file path to the keypair file.
For example, if the file system keypair file location is
`/home/solana/my_wallet.json`, to display the address, do:
```bash
solana-keygen pubkey /home/solana/my_wallet.json
```
@@ -66,8 +72,9 @@ solana-keygen pubkey /home/solana/my_wallet.json
#### Hardware Wallet
If you chose a hardware wallet, use your
[keypair URL](../hardware-wallets/README.md#specify-a-hardware-wallet-key),
[keypair URL](../wallet-guide/hardware-wallets.md#specify-a-hardware-wallet-key),
such as `usb://ledger?key=0`.
```bash
solana-keygen pubkey usb://ledger?key=0
```
```

View File

@@ -1,8 +1,14 @@
# Delegate Stake
This page describes the workflow and commands needed to create and manage stake
accounts, and to delegate your stake accounts to a validator using the Solana
command-line tools. The [stake accounts](../staking/stake-accounts.md)
document provides an overview of stake account features and concepts.
---
title: Delegate Stake
---
After you have [received SOL](transfer-tokens.md), you might consider putting
it to use by delegating _stake_ to a validator. Stake is what we call tokens
in a _stake account_. Solana weights validator votes by the amount of stake
delegated to them, which gives those validators more influence in determining
then next valid block of transactions in the blockchain. Solana then generates
new SOL periodically to reward stakers and validators. You earn more rewards
the more stake you delegate.
## Create a Stake Account
To delegate stake, you will need to transfer some tokens into a stake account.
@@ -87,8 +93,7 @@ solana create-stake-account --from <KEYPAIR> <STAKE_ACCOUNT_KEYPAIR> --seed <STR
number corresponding to which derived account this is. The first account might
be "0", then "1", and so on. The public key of `<STAKE_ACCOUNT_KEYPAIR>` acts
as the base address. The command derives a new address from the base address
and seed string. To see what stake address the command will derive, use `solana
create-address-with-seed`:
and seed string. To see what stake address the command will derive, use `solana create-address-with-seed`:
```bash
solana create-address-with-seed --from <PUBKEY> <SEED_STRING> STAKE
@@ -190,6 +195,6 @@ keypair for the new account, and `<AMOUNT>` is the number of tokens to transfer
to the new account.
To split a stake account into a derived account address, use the `--seed`
option. See
option. See
[Derive Stake Account Addresses](#advanced-derive-stake-account-addresses)
for details.

View File

@@ -1,28 +1,31 @@
# Install the Solana Tool Suite
---
title: Install the Solana Tool Suite
---
There are multiple ways to install the Solana tools on your computer
depending on your preferred workflow:
- [Use Solana's Install Tool (Simplest option)](#use-solanas-install-tool)
- [Download Prebuilt Binaries](#download-prebuilt-binaries)
- [Build from Source](#build-from-source)
- [Use Solana's Install Tool (Simplest option)](#use-solanas-install-tool)
- [Download Prebuilt Binaries](#download-prebuilt-binaries)
- [Build from Source](#build-from-source)
## Use Solana's Install Tool
### MacOS & Linux
- Open your favorite Terminal application
- Open your favorite Terminal application
- Install the Solana release
[LATEST_SOLANA_RELEASE_VERSION](https://github.com/solana-labs/solana/releases/tag/LATEST_SOLANA_RELEASE_VERSION) on your
machine by running:
- Install the Solana release
[LATEST_SOLANA_RELEASE_VERSION](https://github.com/solana-labs/solana/releases/tag/LATEST_SOLANA_RELEASE_VERSION) on your
machine by running:
```bash
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/LATEST_SOLANA_RELEASE_VERSION/install/solana-install-init.sh | sh -s - LATEST_SOLANA_RELEASE_VERSION
```
- If you are connecting to a different testnet, you can replace `LATEST_SOLANA_RELEASE_VERSION` with the
release tag matching the software version of your desired testnet, or replace it
with the named channel `stable`, `beta`, or `edge`.
- If you are connecting to a different testnet, you can replace `LATEST_SOLANA_RELEASE_VERSION` with the
release tag matching the software version of your desired testnet, or replace it
with the named channel `stable`, `beta`, or `edge`.
- The following output indicates a successful update:
@@ -36,59 +39,64 @@ Active release directory: /home/solana/.local/share/solana/install/active_releas
Update successful
```
- Depending on your system, the end of the installer messaging may prompt you
to
```bash
- Depending on your system, the end of the installer messaging may prompt you
to
```bash
Please update your PATH environment variable to include the solana programs:
```
- If you get the above message, copy and paste the recommended command below
it to update `PATH`
- Confirm you have the desired version of `solana` installed by running:
```bash
solana --version
- If you get the above message, copy and paste the recommended command below
it to update `PATH`
- Confirm you have the desired version of `solana` installed by running:
```bash
solana --version
```
- After a successful install, `solana-install update` may be used to easily
update the Solana software to a newer version at any time.
- After a successful install, `solana-install update` may be used to easily
update the Solana software to a newer version at any time.
***
---
###Windows
- Open a Command Prompt (`cmd.exe`) as an Administrator
- Search for Command Prompt in the Windows search bar. When the Command
Prompt app appears, right-click and select “Open as Administrator”.
If you are prompted by a pop-up window asking “Do you want to allow this app to
make changes to your device?”, click Yes.
- Open a Command Prompt (`cmd.exe`) as an Administrator
- Copy and paste the following command, then press Enter to download the Solana
installer into a temporary directory:
- Search for Command Prompt in the Windows search bar. When the Command
Prompt app appears, right-click and select “Open as Administrator”.
If you are prompted by a pop-up window asking “Do you want to allow this app to
make changes to your device?”, click Yes.
- Copy and paste the following command, then press Enter to download the Solana
installer into a temporary directory:
```bash
curl http://release.solana.com/LATEST_SOLANA_RELEASE_VERSION/solana-install-init-x86_64-pc-windows-gnu.exe --output C:\solana-install-tmp\solana-install-init.exe --create-dirs
```
- Copy and paste the following command, then press Enter to install the latest
version of Solana. If you see a security pop-up by your system, please select
to allow the program to run.
- Copy and paste the following command, then press Enter to install the latest
version of Solana. If you see a security pop-up by your system, please select
to allow the program to run.
```bash
C:\solana-install-tmp\solana-install-init.exe LATEST_SOLANA_RELEASE_VERSION
```
- When the installer is finished, press Enter.
- When the installer is finished, press Enter.
- Close the command prompt window and re-open a new command prompt window as a
normal user
- Search for "Command Prompt" in the search bar, then left click on the
Command Prompt app icon, no need to run as Administrator)
- Confirm you have the desired version of `solana` installed by entering:
```bash
solana --version
- Close the command prompt window and re-open a new command prompt window as a
normal user
- Search for "Command Prompt" in the search bar, then left click on the
Command Prompt app icon, no need to run as Administrator)
- Confirm you have the desired version of `solana` installed by entering:
```bash
solana --version
```
- After a successful install, `solana-install update` may be used to easily
update the Solana software to a newer version at any time.
- After a successful install, `solana-install update` may be used to easily
update the Solana software to a newer version at any time.
## Download Prebuilt Binaries
@@ -99,7 +107,7 @@ manually download and install the binaries.
Download the binaries by navigating to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
download **solana-release-x86\_64-unknown-linux-gnu.tar.bz2**, then extract the
download **solana-release-x86_64-unknown-linux-gnu.tar.bz2**, then extract the
archive:
```bash
@@ -112,7 +120,7 @@ export PATH=$PWD/bin:$PATH
Download the binaries by navigating to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
download **solana-release-x86\_64-apple-darwin.tar.bz2**, then extract the
download **solana-release-x86_64-apple-darwin.tar.bz2**, then extract the
archive:
```bash
@@ -124,12 +132,12 @@ export PATH=$PWD/bin:$PATH
### Windows
- Download the binaries by navigating to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
download **solana-release-x86\_64-pc-windows-gnu.tar.bz2**, then extract the
archive using WinZip or similar.
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
download **solana-release-x86_64-pc-windows-gnu.tar.bz2**, then extract the
archive using WinZip or similar.
- Open a Command Prompt and navigate to the directory into which you extracted
the binaries and run:
the binaries and run:
```bash
cd solana-release/

View File

@@ -1,4 +1,6 @@
# Manage Stake Accounts
---
title: Manage Stake Accounts
---
If you want to delegate stake to many different validators, you will need
to create a separate stake account for each. If you follow the convention

View File

@@ -1,10 +1,13 @@
# Send and Receive Tokens
---
title: Send and Receive Tokens
---
This page decribes how to receive and send SOL tokens using the command line
tools with a command line wallet such as a [paper wallet](../paper-wallet/README.md),
a [file system wallet](../file-system-wallet/README.md), or a
[hardware wallet](../hardware-wallets/README.md). Before you begin, make sure
tools with a command line wallet such as a [paper wallet](../wallet-guide/paper-wallet.md),
a [file system wallet](../wallet-guide/file-system-wallet.md), or a
[hardware wallet](../wallet-guide/hardware-wallets.md). Before you begin, make sure
you have created a wallet and have access to its address (pubkey) and the
signing keypair. Check out our
signing keypair. Check out our
[conventions for entering keypairs for different wallet types](../cli/conventions.md#keypair-conventions).
## Testing your Wallet
@@ -13,15 +16,15 @@ Before sharing your public key with others, you may want to first ensure the
key is valid and that you indeed hold the corresponding private key.
In this example, we will create a second wallet in addition to your first wallet,
and then transfer some tokens to it. This will confirm that you can send and
and then transfer some tokens to it. This will confirm that you can send and
receive tokens on your wallet type of choice.
This test example uses our Developer Testnet, called devnet. Tokens issued
This test example uses our Developer Testnet, called devnet. Tokens issued
on devnet have **no** value, so don't worry if you lose them.
#### Airdrop some tokens to get started
First, *airdrop* yourself some play tokens on the devnet.
First, _airdrop_ yourself some play tokens on the devnet.
```bash
solana airdrop 10 <RECIPIENT_ACCOUNT_ADDRESS> --url https://devnet.solana.com
@@ -57,8 +60,8 @@ pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
You can also create a second (or more) wallet of any type:
[paper](../paper-wallet/paper-wallet-usage.md#creating-multiple-paper-wallet-addresses),
[file system](../file-system-wallet/README.md#creating-multiple-file-system-wallet-addresses),
or [hardware](../hardware-wallets/README.md#multiple-addresses-on-a-single-hardware-wallet).
[file system](../wallet-guide/file-system-wallet.md#creating-multiple-file-system-wallet-addresses),
or [hardware](../wallet-guide/hardware-wallets.md#multiple-addresses-on-a-single-hardware-wallet).
#### Transfer tokens from your first wallet to the second address
@@ -85,6 +88,7 @@ where `<ACCOUNT_ADDRESS>` is either the public key from your keypair or the
recipient's public key.
#### Full example of test transfer
```bash
$ solana-keygen new --outfile my_solana_wallet.json # Creating my first wallet, a file system wallet
Generating a new keypair
@@ -130,7 +134,7 @@ $ solana balance 7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv --url https://devn
To receive tokens, you will need an address for others to send tokens to. In
Solana, the wallet address is the public key of a keypair. There are a variety
of techniques for generating keypairs. The method you choose will depend on how
you choose to store keypairs. Keypairs are stored in wallets. Before receiving
you choose to store keypairs. Keypairs are stored in wallets. Before receiving
tokens, you will need to [create a wallet](../wallet-guide/cli.md).
Once completed, you should have a public key
for each keypair you generated. The public key is a long string of base58

View File

@@ -1,4 +1,6 @@
# Benchmark a Cluster
---
title: Benchmark a Cluster
---
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.
@@ -92,17 +94,17 @@ What just happened? The client demo spins up several threads to send 500,000 tra
### 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.
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:
- 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:
- To enable BPF program logging:
```bash
$ export RUST_LOG=solana_bpf_loader=trace

View File

@@ -1,4 +1,6 @@
# Fork Generation
---
title: Fork Generation
---
This section describes how forks naturally occur as a consequence of [leader rotation](leader-rotation.md).
@@ -58,7 +60,7 @@ Validators vote based on a greedy choice to maximize their reward described in [
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.
![Fork generation](../.gitbook/assets/fork-generation.svg)
![Fork generation](/img/fork-generation.svg)
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.
@@ -66,10 +68,10 @@ Note that an `E` appearing on 2 forks at the same slot is a slashable condition,
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 |
| 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.

View File

@@ -1,4 +1,6 @@
# Leader Rotation
---
title: Leader Rotation
---
At any given moment, a cluster expects only one validator 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.
@@ -31,8 +33,8 @@ Two partitions that are generating half of the blocks each. Neither is coming to
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.
- 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.
@@ -73,8 +75,8 @@ The seed that is selected is predictable but unbiasable. There is no grinding at
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
- 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.

View File

@@ -1,4 +1,6 @@
# Managing Forks
---
title: Managing Forks
---
The ledger is permitted to fork at slot boundaries. The resulting data structure forms a tree called a _blockstore_. When the validator interprets the blockstore, it must maintain state for each fork in the chain. We call each instance an _active fork_. It is the responsibility of a validator to weigh those forks, such that it may eventually select a fork.
@@ -8,14 +10,14 @@ A validator selects a fork by submiting a vote to a slot leader on that fork. Th
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:
![Forks](../.gitbook/assets/forks.svg)
![Forks](/img/forks.svg)
The following sequences are _active forks_:
* {4, 2, 1}
* {5, 2, 1}
* {6, 3, 1}
* {7, 3, 1}
- {4, 2, 1}
- {5, 2, 1}
- {6, 3, 1}
- {7, 3, 1}
## Pruning and Squashing
@@ -23,12 +25,12 @@ A validator may vote on any checkpoint in the tree. In the diagram above, that's
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:
![Forks after pruning](../.gitbook/assets/forks-pruned.svg)
![Forks after pruning](/img/forks-pruned.svg)
The new root is 2, and any active forks that are not descendants from 2 are pruned.
Alternatively, a vote on 6:
![Forks](../.gitbook/assets/forks-pruned2.svg)
![Forks](/img/forks-pruned2.svg)
The tree remains with a root of 1, since the active fork starting at 6 is only 2 checkpoints from the root.

View File

@@ -1,4 +1,6 @@
# A Solana Cluster
---
title: A Solana Cluster
---
A Solana cluster is a set of validators 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 section, 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.

View File

@@ -1,4 +1,6 @@
# Performance Metrics
---
title: 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\).
@@ -21,4 +23,3 @@ The validator software is deployed to GCP n1-standard-16 instances with 1TB pd-s
solana-bench-tps is started after the network converges from a client machine with n1-standard-16 CPU-only instance with the following arguments: `--tx\_count=50000 --thread-batch-sleep 1000`
TPS and confirmation metrics are captured from the dashboard numbers over a 5 minute average of when the bench-tps transfer stage begins.

View File

@@ -1,4 +1,6 @@
# Stake Delegation and Rewards
---
title: 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](../implemented-proposals/staking-rewards.md). This section, on the other hand, describes the underlying mechanics of its implementation.
@@ -22,18 +24,18 @@ The rewards process is split into two on-chain programs. The Vote program solves
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_voter` - Only this identity is authorized to submit votes. This field can only modified by this identity.
* `node_pubkey` - The Solana node that votes in this account.
* `authorized_withdrawer` - the identity of the entity in charge of the lamports of this account, separate from the account's address and the authorized vote signer
- `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_voter` - Only this identity is authorized to submit votes. This field can only modified by this identity.
- `node_pubkey` - The Solana node that votes in this account.
- `authorized_withdrawer` - the identity of the entity in charge of the lamports of this account, separate from the account's address and the authorized vote signer
### VoteInstruction::Initialize\(VoteInit\)
* `account[0]` - RW - The VoteState
- `account[0]` - RW - The VoteState
`VoteInit` carries the new vote account's `node_pubkey`, `authorized_voter`, `authorized_withdrawer`, and `commission`
@@ -43,16 +45,16 @@ VoteState is the current state of all the votes the validator has submitted to t
Updates the account with a new authorized voter or withdrawer, according to the VoteAuthorize parameter \(`Voter` or `Withdrawer`\). The transaction must be by signed by the Vote account's current `authorized_voter` or `authorized_withdrawer`.
* `account[0]` - RW - The VoteState
- `account[0]` - RW - The VoteState
`VoteState::authorized_voter` or `authorized_withdrawer` is set to to `Pubkey`.
### VoteInstruction::Vote\(Vote\)
* `account[0]` - RW - The VoteState
- `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 - `sysvar::slot_hashes` A list of some N most recent slots and their hashes for the vote to be verified against.
* `account[2]` - RO - `sysvar::clock` The current network time, expressed in slots, epochs.
- `account[1]` - RO - `sysvar::slot_hashes` A list of some N most recent slots and their hashes for the vote to be verified against.
- `account[2]` - RO - `sysvar::clock` The current network time, expressed in slots, epochs.
### StakeState
@@ -62,15 +64,15 @@ A StakeState takes one of four forms, StakeState::Uninitialized, StakeState::Ini
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 was de-activated, some cool down epochs are required before the account is fully deactivated, and the stake available for withdrawal
- 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 was de-activated, some cool down epochs are required before the account is fully deactivated, and the stake available for withdrawal
* `authorized_staker` - the pubkey of the entity that must sign delegation, activation, and deactivation transactions
* `authorized_withdrawer` - the identity of the entity in charge of the lamports of this account, separate from the account's address, and the authorized staker
- `authorized_staker` - the pubkey of the entity that must sign delegation, activation, and deactivation transactions
- `authorized_withdrawer` - the identity of the entity in charge of the lamports of this account, separate from the account's address, and the authorized staker
### StakeState::RewardsPool
@@ -82,17 +84,17 @@ The Stakes and the RewardsPool are accounts that are owned by the same `Stake` p
The Stake account is moved from Initialized to StakeState::Stake form, or from a deactivated (i.e. fully cooled-down) StakeState::Stake to activated StakeState::Stake. This is how stakers choose the vote account and validator node to which their stake account lamports are delegated. The transaction must be signed by the stake's `authorized_staker`.
* `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]`. If this is the initial delegation of stake, `StakeState::Stake::stake` is initialized to the account's balance in lamports, `StakeState::Stake::activated` is initialized to the current Bank epoch, and `StakeState::Stake::deactivated` is initialized to std::u64::MAX
* `account[1]` - R - The VoteState instance.
* `account[2]` - R - sysvar::clock account, carries information about current Bank epoch
* `account[3]` - R - sysvar::stakehistory account, carries information about stake history
* `account[4]` - R - stake::Config accoount, carries warmup, cooldown, and slashing configuration
- `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]`. If this is the initial delegation of stake, `StakeState::Stake::stake` is initialized to the account's balance in lamports, `StakeState::Stake::activated` is initialized to the current Bank epoch, and `StakeState::Stake::deactivated` is initialized to std::u64::MAX
- `account[1]` - R - The VoteState instance.
- `account[2]` - R - sysvar::clock account, carries information about current Bank epoch
- `account[3]` - R - sysvar::stakehistory account, carries information about stake history
- `account[4]` - R - stake::Config accoount, carries warmup, cooldown, and slashing configuration
### StakeInstruction::Authorize\(Pubkey, StakeAuthorize\)
Updates the account with a new authorized staker or withdrawer, according to the StakeAuthorize parameter \(`Staker` or `Withdrawer`\). The transaction must be by signed by the Stakee account's current `authorized_staker` or `authorized_withdrawer`. Any stake lock-up must have expired, or the lock-up custodian must also sign the transaction.
Updates the account with a new authorized staker or withdrawer, according to the StakeAuthorize parameter \(`Staker` or `Withdrawer`\). The transaction must be by signed by the Stakee account's current `authorized_staker` or `authorized_withdrawer`. Any stake lock-up must have expired, or the lock-up custodian must also sign the transaction.
* `account[0]` - RW - The StakeState
- `account[0]` - RW - The StakeState
`StakeState::authorized_staker` or `authorized_withdrawer` is set to to `Pubkey`.
@@ -101,8 +103,8 @@ Updates the account with a new authorized staker or withdrawer, according to the
A staker may wish to withdraw from the network. To do so he must first deactivate his stake, and wait for cool down.
The transaction must be signed by the stake's `authorized_staker`.
* `account[0]` - RW - The StakeState::Stake instance that is deactivating.
* `account[1]` - R - sysvar::clock account from the Bank that carries current epoch
- `account[0]` - RW - The StakeState::Stake instance that is deactivating.
- `account[1]` - R - sysvar::clock 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.
@@ -110,21 +112,21 @@ StakeState::Stake::deactivated is set to the current epoch + cool down. The acco
Lamports build up over time in a Stake account and any excess over activated stake can be withdrawn. The transaction must be signed by the stake's `authorized_withdrawer`.
* `account[0]` - RW - The StakeState::Stake from which to withdraw.
* `account[1]` - RW - Account that should be credited with the withdrawn lamports.
* `account[2]` - R - sysvar::clock 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
- `account[0]` - RW - The StakeState::Stake from which to withdraw.
- `account[1]` - RW - Account that should be credited with the withdrawn lamports.
- `account[2]` - R - sysvar::clock 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.
- 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
![Passive Staking Callflow](../.gitbook/assets/passive-staking-callflow.svg)
![Passive Staking Callflow](/img/passive-staking-callflow.svg)
## Staking Rewards
@@ -171,22 +173,22 @@ Consider the situation of a single stake of 1,000 activated at epoch N, with net
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 |
| :---- | --------: | ---------: | --------------: | ---------------: |
| 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 | 333 | 667 | 67 | 133 | 2,400 | 800 |
| N+2 | 733 | 267 | 146 | 54 | 2,880 | 321 |
| N+3 | 1000 | 0 | 200 | 0 | 3,200 | 0 |
| :---- | ----: | ----: | ----: | ----: | --------------: | ---------------: |
| N-1 | | | | | 2,000 | 0 |
| N | 0 | 1,000 | 0 | 200 | 2,000 | 1,200 |
| N+1 | 333 | 667 | 67 | 133 | 2,400 | 800 |
| N+2 | 733 | 267 | 146 | 54 | 2,880 | 321 |
| N+3 | 1000 | 0 | 200 | 0 | 3,200 | 0 |
### Withdrawal
@@ -194,4 +196,4 @@ Only lamports in excess of effective+activating stake may be withdrawn at any ti
### Lock-up
Stake accounts support the notion of lock-up, wherein the stake account balance is unavailable for withdrawal until a specified time. Lock-up is specified as an epoch height, i.e. the minimum epoch height that must be reached by the network before the stake account balance is available for withdrawal, unless the transaction is also signed by a specified custodian. This information is gathered when the stake account is created, and stored in the Lockup field of the stake account's state. Changing the authorized staker or withdrawer is also subject to lock-up, as such an operation is effectively a transfer.
Stake accounts support the notion of lock-up, wherein the stake account balance is unavailable for withdrawal until a specified time. Lock-up is specified as an epoch height, i.e. the minimum epoch height that must be reached by the network before the stake account balance is available for withdrawal, unless the transaction is also signed by a specified custodian. This information is gathered when the stake account is created, and stored in the Lockup field of the stake account's state. Changing the authorized staker or withdrawer is also subject to lock-up, as such an operation is effectively a transfer.

View File

@@ -1,4 +1,6 @@
# Synchronization
---
title: 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 validators producing a new valid block at the same time. There's no such constraint in Proof of Stake consensus, but without reliable timestamps, a validator 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.
@@ -22,6 +24,5 @@ Proof of History is not a consensus mechanism, but it is used to improve the per
## 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)
- [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)

View File

@@ -1,4 +1,6 @@
# Turbine Block Propagation
---
title: Turbine Block Propagation
---
A Solana cluster uses a multi-layer block propagation mechanism called _Turbine_ to broadcast transaction shreds 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.
@@ -20,15 +22,15 @@ This way each node only has to communicate with a maximum of `2 * DATA_PLANE_FAN
The following diagram shows how the Leader sends shreds with a Fanout of 2 to Neighborhood 0 in Layer 0 and how the nodes in Neighborhood 0 share their data with each other.
![Leader sends shreds to Neighborhood 0 in Layer 0](../.gitbook/assets/data-plane-seeding.svg)
![Leader sends shreds to Neighborhood 0 in Layer 0](/img/data-plane-seeding.svg)
The following diagram shows how Neighborhood 0 fans out to Neighborhoods 1 and 2.
![Neighborhood 0 Fanout to Neighborhood 1 and 2](../.gitbook/assets/data-plane-fanout.svg)
![Neighborhood 0 Fanout to Neighborhood 1 and 2](/img/data-plane-fanout.svg)
Finally, the following diagram shows a two layer cluster with a Fanout of 2.
![Two layer cluster with a Fanout of 2](../.gitbook/assets/data-plane.svg)
![Two layer cluster with a Fanout of 2](/img/data-plane.svg)
### Configuration Values
@@ -38,59 +40,62 @@ Currently, configuration is set when the cluster is launched. In the future, the
## Calcuating the required FEC rate
Turbine relies on retransmission of packets between validators. Due to
Turbine relies on retransmission of packets between validators. Due to
retransmission, any network wide packet loss is compounded, and the
probability of the packet failing to reach is destination increases
on each hop. The FEC rate needs to take into account the network wide
on each hop. The FEC rate needs to take into account the network wide
packet loss, and the propagation depth.
A shred group is the set of data and coding packets that can be used
to reconstruct each other. Each shred group has a chance of failure,
to reconstruct each other. Each shred group has a chance of failure,
based on the likelyhood of the number of packets failing that exceeds
the FEC rate. If a validator fails to reconstruct the shred group,
then the block cannot be reconstructed, and the validator has to rely
on repair to fixup the blocks.
The probability of the shred group failing can be computed using the
binomial distribution. If the FEC rate is `16:4`, then the group size
binomial distribution. If the FEC rate is `16:4`, then the group size
is 20, and at least 4 of the shreds must fail for the group to fail.
Which is equal to the sum of the probability of 4 or more trails failing
out of 20.
Probability of a block succeeding in turbine:
* Probability of packet failure: `P = 1 - (1 - network_packet_loss_rate)^2`
* FEC rate: `K:M`
* Number of trials: `N = K + M`
* Shred group failure rate: `S = SUM of i=0 -> M for binomial(prob_failure = P, trials = N, failures = i)`
* Shreds per block: `G`
* Block success rate: `B = (1 - S) ^ (G / N) `
* Binomial distribution for exactly `i` results with probability of P in N trials is defined as `(N choose i) * P^i * (1 - P)^(N-i)`
- Probability of packet failure: `P = 1 - (1 - network_packet_loss_rate)^2`
- FEC rate: `K:M`
- Number of trials: `N = K + M`
- Shred group failure rate: `S = SUM of i=0 -> M for binomial(prob_failure = P, trials = N, failures = i)`
- Shreds per block: `G`
- Block success rate: `B = (1 - S) ^ (G / N)`
- Binomial distribution for exactly `i` results with probability of P in N trials is defined as `(N choose i) * P^i * (1 - P)^(N-i)`
For example:
* Network packet loss rate is 15%.
* 50kpts network generates 6400 shreds per second.
* FEC rate increases the total shres per block by the FEC ratio.
- Network packet loss rate is 15%.
- 50kpts network generates 6400 shreds per second.
- FEC rate increases the total shres per block by the FEC ratio.
With a FEC rate: `16:4`
* `G = 8000`
* `P = 1 - 0.85 * 0.85 = 1 - 0.7225 = 0.2775`
* `S = SUM of i=0 -> 4 for binomial(prob_failure = 0.2775, trials = 20, failures = i) = 0.689414`
* `B = (1 - 0.689) ^ (8000 / 20) = 10^-203`
- `G = 8000`
- `P = 1 - 0.85 * 0.85 = 1 - 0.7225 = 0.2775`
- `S = SUM of i=0 -> 4 for binomial(prob_failure = 0.2775, trials = 20, failures = i) = 0.689414`
- `B = (1 - 0.689) ^ (8000 / 20) = 10^-203`
With FEC rate of `16:16`
* `G = 12800`
* `S = SUM of i=0 -> 32 for binomial(prob_failure = 0.2775, trials = 64, failures = i) = 0.002132`
* `B = (1 - 0.002132) ^ (12800 / 32) = 0.42583`
- `G = 12800`
- `S = SUM of i=0 -> 32 for binomial(prob_failure = 0.2775, trials = 64, failures = i) = 0.002132`
- `B = (1 - 0.002132) ^ (12800 / 32) = 0.42583`
With FEC rate of `32:32`
* `G = 12800`
* `S = SUM of i=0 -> 32 for binomial(prob_failure = 0.2775, trials = 64, failures = i) = 0.000048`
* `B = (1 - 0.000048) ^ (12800 / 64) = 0.99045`
- `G = 12800`
- `S = SUM of i=0 -> 32 for binomial(prob_failure = 0.2775, trials = 64, failures = i) = 0.000048`
- `B = (1 - 0.000048) ^ (12800 / 64) = 0.99045`
## 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 shreds 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.
![Inner workings of a neighborhood](../.gitbook/assets/data-plane-neighborhood.svg)
![Inner workings of a neighborhood](/img/data-plane-neighborhood.svg)

View File

@@ -1,4 +1,6 @@
# Secure Vote Signing
---
title: Secure Vote Signing
---
A validator 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.
@@ -20,30 +22,30 @@ Currently, there is a 1:1 relationship between validators and vote signers, and
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
- 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
- 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
- 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
- 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
- The service verifies the voting data
- The service returns a signature for the transaction
## Validator voting
@@ -64,4 +66,3 @@ The validator looks up the votes submitted by all the nodes in the cluster for t
### 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.

View File

@@ -1,34 +1,40 @@
# Solana Clusters
---
title: Solana Clusters
---
Solana maintains several different clusters with different purposes.
Before you begin make sure you have first
[installed the Solana command line tools](cli/install-solana-cli-tools.md)
Explorers:
* [http://explorer.solana.com/](https://explorer.solana.com/).
* [http://solanabeach.io/](http://solanabeach.io/).
- [http://explorer.solana.com/](https://explorer.solana.com/).
- [http://solanabeach.io/](http://solanabeach.io/).
## Devnet
* Devnet serves as a playground for anyone who wants to take Solana for a
test drive, as a user, token holder, app developer, or validator.
* Application developers should target Devnet.
* Potential validators should first target Devnet.
* Key differences between Devnet and Mainnet Beta:
* Devnet tokens are **not real**
* Devnet includes a token faucet for airdrops for application testing
* Devnet may be subject to ledger resets
* Devnet typically runs a newer software version than Mainnet Beta
* Devnet may be maintained by different validators than Mainnet Beta
* Gossip entrypoint for Devnet: `devnet.solana.com:8001`
* RPC URL for Devnet: `https://devnet.solana.com`
- Devnet serves as a playground for anyone who wants to take Solana for a
test drive, as a user, token holder, app developer, or validator.
- Application developers should target Devnet.
- Potential validators should first target Devnet.
- Key differences between Devnet and Mainnet Beta:
- Devnet tokens are **not real**
- Devnet includes a token faucet for airdrops for application testing
- Devnet may be subject to ledger resets
- Devnet typically runs a newer software version than Mainnet Beta
- Devnet may be maintained by different validators than Mainnet Beta
- Gossip entrypoint for Devnet: `devnet.solana.com:8001`
- RPC URL for Devnet: `https://devnet.solana.com`
##### Example `solana` command-line configuration
```bash
solana config set --url https://devnet.solana.com
```
##### Example `solana-validator` command-line
```bash
$ solana-validator \
--identity ~/validator-keypair.json \
@@ -46,29 +52,30 @@ $ solana-validator \
The `--trusted-validator`s is operated by Solana
## Testnet
* Testnet is where we stress test recent release features on a live
cluster, particularly focused on network performance, stability and validator
behavior.
* [Tour de SOL](tour-de-sol/README.md) initiative runs on Testnet, where we
encourage malicious behavior and attacks on the network to help us find and
squash bugs or network vulnerabilities.
* Testnet tokens are **not real**
* Testnet may be subject to ledger resets.
* Testnet typically runs a newer software release than both Devnet and
Mainnet Beta
* Testnet may be maintained by different validators than Mainnet Beta
* Gossip entrypoint for Testnet: `35.203.170.30:8001`
* RPC URL for Testnet: `https://testnet.solana.com`
- Testnet is where we stress test recent release features on a live
cluster, particularly focused on network performance, stability and validator
behavior.
- [Tour de SOL](tour-de-sol.md) initiative runs on Testnet, where we
encourage malicious behavior and attacks on the network to help us find and
squash bugs or network vulnerabilities.
- Testnet tokens are **not real**
- Testnet may be subject to ledger resets.
- Testnet typically runs a newer software release than both Devnet and
Mainnet Beta
- Testnet may be maintained by different validators than Mainnet Beta
- Gossip entrypoint for Testnet: `35.203.170.30:8001`
- RPC URL for Testnet: `https://testnet.solana.com`
##### Example `solana` command-line configuration
```bash
solana config set --url https://testnet.solana.com
```
##### Example `solana-validator` command-line
```bash
$ solana-validator \
--identity ~/validator-keypair.json \
@@ -87,28 +94,33 @@ $ solana-validator \
```
The identity of the `--trusted-validator`s are:
* `5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on` - testnet.solana.com (Solana)
* `Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN` - Certus One
* `9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv` - Algo|Stake
- `5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on` - testnet.solana.com (Solana)
- `Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN` - Certus One
- `9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv` - Algo|Stake
## Mainnet Beta
A permissionless, persistent cluster for early token holders and launch partners.
Currently smart contracts, rewards, and inflation are disabled.
* Tokens that are issued on Mainnet Beta are **real** SOL
* If you have paid money to purchase/be issued tokens, such as through our
CoinList auction, these tokens will be transferred on Mainnet Beta.
* Note: If you are using a non-command-line wallet such as
[Trust Wallet](wallet-guide/trust-wallet.md),
the wallet will always be connecting to Mainnet Beta.
* Gossip entrypoint for Mainnet Beta: `mainnet-beta.solana.com:8001`
* RPC URL for Mainnet Beta: `https://api.mainnet-beta.solana.com`
- Tokens that are issued on Mainnet Beta are **real** SOL
- If you have paid money to purchase/be issued tokens, such as through our
CoinList auction, these tokens will be transferred on Mainnet Beta.
- Note: If you are using a non-command-line wallet such as
[Trust Wallet](wallet-guide/trust-wallet.md),
the wallet will always be connecting to Mainnet Beta.
- Gossip entrypoint for Mainnet Beta: `mainnet-beta.solana.com:8001`
- RPC URL for Mainnet Beta: `https://api.mainnet-beta.solana.com`
##### Example `solana` command-line configuration
```bash
solana config set --url https://api.mainnet-beta.solana.com
```
##### Example `solana-validator` command-line
```bash
$ solana-validator \
--identity ~/validator-keypair.json \

69
docs/src/css/custom.css Normal file
View File

@@ -0,0 +1,69 @@
/* stylelint-disable docusaurus/copyright-header */
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
* work well for content-centric websites.
*/
/* You can override the default Infima variables here. */
@import url('https://fonts.googleapis.com/css2?family=Roboto');
:root {
--ifm-color-primary: #25c2a0;
--ifm-color-primary-dark: #409088;
--ifm-color-primary-darker: #387462;
--ifm-color-primary-darkest: #1b4e3f;
--ifm-color-primary-light: #42ba96;
--ifm-color-primary-lighter: #86b8b6;
--ifm-color-primary-lightest: #abd5c6;
--ifm-code-font-size: 95%;
--ifm-spacing-horizontal: 1em;
--ifm-font-family-base: "Roboto", system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
--ifm-footer-background-color: #232323;
}
@keyframes fadeInUp {
0% { opacity: 0; transform: translateY(1.5rem); }
}
main {
margin: 1rem 0 5rem 0;
}
.docusaurus-highlight-code-line {
background-color: rgb(72, 77, 91);
display: block;
margin: 0 calc(-1 * var(--ifm-pre-padding));
padding: 0 var(--ifm-pre-padding);
}
.card {
padding: 1rem;
margin-top: 2rem;
animation: fadeInUp 400ms backwards;
animation-delay: 150ms;
transition-property: all;
transition-duration: 200ms;
box-shadow: 0 8px 28px 4px rgba(86,91,115,0.15);
}
.card a {
text-decoration: none;
}
.card:hover {
transform: translate(0px, -5px);
}
.footer--dark {
background-color: #232323 !important;
}
footer .text--center {
padding: 2rem 0 0 0;
}

View File

@@ -1,4 +1,6 @@
# History of the Solana Codebase
---
title: History of the Solana Codebase
---
In November of 2017, Anatoly Yakovenko published a whitepaper describing Proof
of History, a technique for keeping time between computers that do not trust

View File

@@ -1,4 +0,0 @@
# Implemented Design Proposals
The following design proposals are fully implemented.

View File

@@ -1,4 +1,6 @@
# Commitment
---
title: Commitment
---
The commitment metric aims to give clients a measure of the network confirmation
and stake levels on a particular block. Clients can then use this information to
@@ -48,9 +50,10 @@ banks are not included in the commitment calculations here.
Now we can naturally augment the above computation to also build a
`BlockCommitment` array for every bank `b` by:
1) Adding a `ForkCommitmentCache` to collect the `BlockCommitment` structs
2) Replacing `f` with `f'` such that the above computation also builds this
`BlockCommitment` for every bank `b`.
1. Adding a `ForkCommitmentCache` to collect the `BlockCommitment` structs
2. Replacing `f` with `f'` such that the above computation also builds this
`BlockCommitment` for every bank `b`.
We will proceed with the details of 2) as 1) is trivial.
@@ -76,6 +79,7 @@ Now more specifically, we augment the above computation to:
```
where `f'` is defined as:
```text
fn f`(
stake_lockout: &mut StakeLockout,

View File

@@ -1,4 +1,6 @@
# Cross-Program Invocation
---
title: Cross-Program Invocation
---
## Problem
@@ -67,13 +69,13 @@ mod acme {
`invoke()` is built into Solana's runtime and is responsible for routing the given instruction to the `token` program via the instruction's `program_id` field.
Before invoking `pay()`, the runtime must ensure that `acme` didn't modify any accounts owned by `token`. It does this by applying the runtime's policy to the current state of the accounts at the time `acme` calls `invoke` vs. the initial state of the accounts at the beginning of the `acme`'s instruction. After `pay()` completes, the runtime must again ensure that `token` didn't modify any accounts owned by `acme` by again applying the runtime's policy, but this time with the `token` program ID. Lastly, after `pay_and_launch_missiles()` completes, the runtime must apply the runtime policy one more time, where it normally would, but using all updated `pre_*` variables. If executing `pay_and_launch_missiles()` up to `pay()` made no invalid account changes, `pay()` made no invalid changes, and executing from `pay()` until `pay_and_launch_missiles()` returns made no invalid changes, then the runtime can transitively assume `pay_and_launch_missiles()` as whole made no invalid account changes, and therefore commit all these account modifications.
Before invoking `pay()`, the runtime must ensure that `acme` didn't modify any accounts owned by `token`. It does this by applying the runtime's policy to the current state of the accounts at the time `acme` calls `invoke` vs. the initial state of the accounts at the beginning of the `acme`'s instruction. After `pay()` completes, the runtime must again ensure that `token` didn't modify any accounts owned by `acme` by again applying the runtime's policy, but this time with the `token` program ID. Lastly, after `pay_and_launch_missiles()` completes, the runtime must apply the runtime policy one more time, where it normally would, but using all updated `pre_*` variables. If executing `pay_and_launch_missiles()` up to `pay()` made no invalid account changes, `pay()` made no invalid changes, and executing from `pay()` until `pay_and_launch_missiles()` returns made no invalid changes, then the runtime can transitively assume `pay_and_launch_missiles()` as whole made no invalid account changes, and therefore commit all these account modifications.
### Instructions that require privileges
The runtime uses the privileges granted to the caller program to determine what privileges can be extended to the callee. Privileges in this context refer to signers and writable accounts. For example, if the instruction the caller is processing contains a signer or writable account, then the caller can invoke an instruction that also contains that signer and/or writable account.
The runtime uses the privileges granted to the caller program to determine what privileges can be extended to the callee. Privileges in this context refer to signers and writable accounts. For example, if the instruction the caller is processing contains a signer or writable account, then the caller can invoke an instruction that also contains that signer and/or writable account.
This privilege extension relies on the fact that programs are immutable. In the case of the `acme` program, the runtime can safely treat the transaction's signature as a signature of a `token` instruction. When the runtime sees the `token` instruction references `alice_pubkey`, it looks up the key in the `acme` instruction to see if that key corresponds to a signed account. In this case, it does and thereby authorizes the `token` program to modify Alice's account.
This privilege extension relies on the fact that programs are immutable. In the case of the `acme` program, the runtime can safely treat the transaction's signature as a signature of a `token` instruction. When the runtime sees the `token` instruction references `alice_pubkey`, it looks up the key in the `acme` instruction to see if that key corresponds to a signed account. In this case, it does and thereby authorizes the `token` program to modify Alice's account.
### Program signed accounts
@@ -92,4 +94,4 @@ To sign an account with program derived addresses, a program may `invoke_signed(
### Reentrancy
Reentrancy is currently limited to direct self recursion capped at a fixed depth. This restriction prevents situations where a program might invoke another from an intermediary state without the knowledge that it might later be called back into. Direct recursion gives the program full control of its state at the point that it gets called back.
Reentrancy is currently limited to direct self recursion capped at a fixed depth. This restriction prevents situations where a program might invoke another from an intermediary state without the knowledge that it might later be called back into. Direct recursion gives the program full control of its state at the point that it gets called back.

View File

@@ -1,4 +1,6 @@
# Durable Transaction Nonces
---
title: Durable Transaction Nonces
---
## Problem
@@ -11,8 +13,8 @@ offline network participants.
## Requirements
1) The transaction's signature needs to cover the nonce value
2) The nonce must not be reusable, even in the case of signing key disclosure
1. The transaction's signature needs to cover the nonce value
2. The nonce must not be reusable, even in the case of signing key disclosure
## A Contract-based Solution
@@ -25,8 +27,8 @@ When making use of a durable nonce, the client must first query its value from
account data. A transaction is now constructed in the normal way, but with the
following additional requirements:
1) The durable nonce value is used in the `recent_blockhash` field
2) An `AdvanceNonceAccount` instruction is the first issued in the transaction
1. The durable nonce value is used in the `recent_blockhash` field
2. An `AdvanceNonceAccount` instruction is the first issued in the transaction
### Contract Mechanics
@@ -63,7 +65,7 @@ WithdrawInstruction(to, lamports)
success
```
A client wishing to use this feature starts by creating a nonce account under
A client wishing to use this feature starts by creating a nonce account under
the system program. This account will be in the `Uninitialized` state with no
stored hash, and thus unusable.
@@ -95,11 +97,7 @@ can be changed using the `AuthorizeNonceAccount` instruction. It takes one param
the `Pubkey` of the new authority. Executing this instruction grants full
control over the account and its balance to the new authority.
{% hint style="info" %}
`AdvanceNonceAccount`, `WithdrawNonceAccount` and `AuthorizeNonceAccount` all require the current
[nonce authority](../offline-signing/durable-nonce.md#nonce-authority) for the
account to sign the transaction.
{% endhint %}
> `AdvanceNonceAccount`, `WithdrawNonceAccount` and `AuthorizeNonceAccount` all require the current [nonce authority](../offline-signing/durable-nonce.md#nonce-authority) for the account to sign the transaction.
### Runtime Support
@@ -114,11 +112,11 @@ instruction as the first instruction in the transaction.
If the runtime determines that a Durable Transaction Nonce is in use, it will
take the following additional actions to validate the transaction:
1) The `NonceAccount` specified in the `Nonce` instruction is loaded.
2) The `NonceState` is deserialized from the `NonceAccount`'s data field and
confirmed to be in the `Initialized` state.
3) The nonce value stored in the `NonceAccount` is tested to match against the
one specified in the transaction's `recent_blockhash` field.
1. The `NonceAccount` specified in the `Nonce` instruction is loaded.
2. The `NonceState` is deserialized from the `NonceAccount`'s data field and
confirmed to be in the `Initialized` state.
3. The nonce value stored in the `NonceAccount` is tested to match against the
one specified in the transaction's `recent_blockhash` field.
If all three of the above checks succeed, the transaction is allowed to continue
validation.

View File

@@ -1,4 +1,6 @@
# Cluster Economics
---
title: Cluster Economics
---
**Subject to change.**
@@ -10,8 +12,8 @@ These protocol-based rewards, to be distributed to participating validation clie
Transaction fees are market-based participant-to-participant transfers, attached to network interactions as a necessary motivation and compensation for the inclusion and execution of a proposed transaction. A mechanism for long-term economic stability and forking protection through partial burning of each transaction fee is also discussed below.
A high-level schematic of Solanas crypto-economic design is shown below in **Figure 1**. The specifics of validation-client economics are described in sections: [Validation-client Economics](ed_validation_client_economics/README.md), [State-validation Protocol-based Rewards](ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md), [State-validation Transaction Fees](ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md). Also, the section titled [Validation Stake Delegation](ed_validation_client_economics/ed_vce_validation_stake_delegation.md) closes with a discussion of validator delegation opportunities and marketplace. Additionally, in [Storage Rent Economics](ed_storage_rent_economics.md), we describe an implementation of storage rent to account for the externality costs of maintaining the active state of the ledger. An outline of features for an MVP economic design is discussed in the [Economic Design MVP](ed_mvp.md) section.
A high-level schematic of Solanas crypto-economic design is shown below in **Figure 1**. The specifics of validation-client economics are described in sections: [Validation-client Economics](ed_validation_client_economics/ed_vce_overview.md), [State-validation Protocol-based Rewards](ed_validation_client_economics/ed_vce_state_validation_protocol_based_rewards.md), [State-validation Transaction Fees](ed_validation_client_economics/ed_vce_state_validation_transaction_fees.md). Also, the section titled [Validation Stake Delegation](ed_validation_client_economics/ed_vce_validation_stake_delegation.md) closes with a discussion of validator delegation opportunities and marketplace. Additionally, in [Storage Rent Economics](ed_storage_rent_economics.md), we describe an implementation of storage rent to account for the externality costs of maintaining the active state of the ledger. An outline of features for an MVP economic design is discussed in the [Economic Design MVP](ed_mvp.md) section.
![](../../.gitbook/assets/economic_design_infl_230719.png)
![](/img/economic_design_infl_230719.png)
**Figure 1**: Schematic overview of Solana economic incentive design.

View File

@@ -1,4 +1,6 @@
# Economic Sustainability
---
title: Economic Sustainability
---
**Subject to change.**

View File

@@ -1,4 +1,6 @@
# Economic Design MVP
---
title: Economic Design MVP
---
**Subject to change.**
@@ -6,7 +8,7 @@ The preceding sections, outlined in the [Economic Design Overview](../README.md)
## MVP Economic Features
* Faucet to deliver testnet SOLs to validators for staking and application development.
* Mechanism by which validators are rewarded via network inflation.
* Ability to delegate tokens to validator nodes
* Validator set commission fees on interest from delegated tokens.
- Faucet to deliver testnet SOLs to validators for staking and application development.
- Mechanism by which validators are rewarded via network inflation.
- Ability to delegate tokens to validator nodes
- Validator set commission fees on interest from delegated tokens.

View File

@@ -1,6 +1,7 @@
# References
---
title: References
---
1. [https://blog.ethereum.org/2016/07/27/inflation-transaction-fees-cryptocurrency-monetary-policy/](https://blog.ethereum.org/2016/07/27/inflation-transaction-fees-cryptocurrency-monetary-policy/)
2. [https://medium.com/solana-labs/how-to-create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281](https://medium.com/solana-labs/how-to-create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281)
3. [https://medium.com/solana-labs/how-to-create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281](https://medium.com/solana-labs/how-to-create-decentralized-storage-for-a-multi-petabyte-digital-ledger-2499a3a8c281)

View File

@@ -1,4 +1,6 @@
## Storage Rent Economics
---
title: Storage Rent Economics
---
Each transaction that is submitted to the Solana ledger imposes costs. Transaction fees paid by the submitter, and collected by a validator, in theory, account for the acute, transactional, costs of validating and adding that data to the ledger. Unaccounted in this process is the mid-term storage of active ledger state, necessarily maintained by the rotating validator set. This type of storage imposes costs not only to validators but also to the broader network as active state grows so does data transmission and validation overhead. To account for these costs, we describe here our preliminary design and implementation of storage rent.
@@ -13,6 +15,3 @@ Method 2: Pay per byte
If an account has less than two-years worth of deposited rent the network charges rent on a per-epoch basis, in credit for the next epoch. This rent is deducted at a rate specified in genesis, in lamports per kilobyte-year.
For information on the technical implementation details of this design, see the [Rent](../rent.md) section.

View File

@@ -1,8 +1,9 @@
# Validation-client Economics
---
title: Validation-client Economics
---
**Subject to change.**
Validator-clients are eligible to receive protocol-based \(i.e. inflation-based\) rewards issued via stake-based annual interest rates \(calculated per epoch\) by providing compute \(CPU+GPU\) resources to validate and vote on a given PoH state. These protocol-based rewards are determined through an algorithmic disinflationary schedule as a function of total amount of circulating tokens. The network is expected to launch with an annual inflation rate around 15%, set to decrease by 15% per year until a long-term stable rate of 1-2% is reached. These issuances are to be split and distributed to participating validators, with around 90% of the issued tokens allocated for validator rewards. Because the network will be distributing a fixed amount of inflation rewards across the stake-weighted validator set, any individual validator's interest rate will be a function of the amount of staked SOL in relation to the circulating SOL.
Additionally, validator clients may earn revenue through fees via state-validation transactions. For clarity, we separately describe the design and motivation of these revenue distributions for validation-clients below: state-validation protocol-based rewards and state-validation transaction fees and rent.

Some files were not shown because too many files have changed in this diff Show More