Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b0addba2a9 | ||
|
bb59525ff8 | ||
|
acd25124d4 | ||
|
d718ab2491 | ||
|
1860aacd1f | ||
|
d4bbb7f516 | ||
|
d1c0f4b4f1 | ||
|
b72b837ba2 | ||
|
fde85c96c0 | ||
|
121418dad2 | ||
|
f44f94fe23 | ||
|
55a4481022 | ||
|
e859ad37a8 | ||
|
1a28c7fc12 | ||
|
c706a07764 | ||
|
59568e5776 | ||
|
33ca8fa72a | ||
|
4bb66a81fb | ||
|
468c14b14f | ||
|
03e505897a | ||
|
5205eb382e | ||
|
b07b6e56fa | ||
|
bcc890e705 | ||
|
07d14f6f07 | ||
|
03b213e296 | ||
|
1bfce24c9f | ||
|
94b2565969 | ||
|
2896fdb603 |
@@ -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
|
97
.travis.yml
97
.travis.yml
@@ -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
20
.travis/affects.sh
Executable 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
258
Cargo.lock
generated
@@ -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]]
|
||||
|
@@ -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"
|
||||
|
@@ -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"
|
||||
|
@@ -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"]
|
||||
|
@@ -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"]
|
||||
|
@@ -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"]
|
||||
|
@@ -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"]
|
||||
|
@@ -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...
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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"
|
||||
|
@@ -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=
|
||||
|
@@ -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
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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/"
|
||||
|
@@ -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]]
|
||||
|
@@ -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());
|
||||
|
||||
|
@@ -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(),
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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"]
|
||||
|
@@ -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;
|
||||
|
@@ -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]
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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
1240
core/src/repair_weight.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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]
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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),
|
||||
|
@@ -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
32
core/src/tree_diff.rs
Normal 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
|
||||
}
|
||||
}
|
@@ -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);
|
||||
|
@@ -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: ®ex::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());
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
|
@@ -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
21
docs/.eslintrc
Normal 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
1
docs/.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
theme/highlight.js binary
|
23
docs/.gitignore
vendored
Normal file
23
docs/.gitignore
vendored
Normal 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*
|
9
docs/.travis/before_install.sh
Normal file
9
docs/.travis/before_install.sh
Normal 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
4
docs/.travis/script.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
# |source| this file
|
||||
|
||||
set -ex
|
||||
./build.sh
|
@@ -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
3
docs/babel.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: [require.resolve("@docusaurus/core/lib/babel/preset")],
|
||||
};
|
@@ -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]
|
@@ -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:]]\+$//')
|
||||
|
@@ -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
21
docs/convert-ascii-to-svg.sh
Executable 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
107
docs/docusaurus.config.js
Normal 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"),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
@@ -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
39
docs/package.json
Normal 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
39
docs/publish-docs.sh
Executable 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
|
@@ -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
173
docs/sidebars.js
Normal 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",
|
||||
],
|
||||
},
|
||||
};
|
Binary file not shown.
@@ -1,4 +1,6 @@
|
||||
# Table of contents
|
||||
---
|
||||
title: Table of contents
|
||||
---
|
||||
|
||||
* [Introduction](introduction.md)
|
||||
* [Wallet Guide](wallet-guide/README.md)
|
||||
|
@@ -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
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
@@ -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.
|
@@ -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.
|
||||
|
||||
|
@@ -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
@@ -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.
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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).
|
||||
|
||||
|
@@ -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)
|
@@ -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
|
||||
```
|
||||
|
@@ -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
|
||||
```
|
||||
```
|
||||
|
@@ -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.
|
||||
|
@@ -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/
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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:
|
||||
|
||||

|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||

|
||||
|
||||
The new root is 2, and any active forks that are not descendants from 2 are pruned.
|
||||
|
||||
Alternatively, a vote on 6:
|
||||
|
||||

|
||||

|
||||
|
||||
The tree remains with a root of 1, since the active fork starting at 6 is only 2 checkpoints from the root.
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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
|
||||
|
||||

|
||||

|
||||
|
||||
## 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.
|
||||
|
@@ -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)
|
||||
|
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
The following diagram shows how Neighborhood 0 fans out to Neighborhoods 1 and 2.
|
||||
|
||||

|
||||

|
||||
|
||||
Finally, the following diagram shows a two layer cluster with a Fanout of 2.
|
||||
|
||||

|
||||

|
||||
|
||||
### Configuration Values
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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
69
docs/src/css/custom.css
Normal 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;
|
||||
}
|
@@ -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
|
||||
|
@@ -1,4 +0,0 @@
|
||||
# Implemented Design Proposals
|
||||
|
||||
The following design proposals are fully implemented.
|
||||
|
@@ -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,
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
@@ -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 Solana’s 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 Solana’s 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.
|
||||
|
||||

|
||||

|
||||
|
||||
**Figure 1**: Schematic overview of Solana economic incentive design.
|
@@ -1,4 +1,6 @@
|
||||
# Economic Sustainability
|
||||
---
|
||||
title: Economic Sustainability
|
||||
---
|
||||
|
||||
**Subject to change.**
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
||||
|
||||
|
@@ -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
Reference in New Issue
Block a user