Compare commits

...

1050 Commits

Author SHA1 Message Date
b4adb1c266 Cherry pick fix for freeze (#4459)
* check freeze before updating slot_hashes (#4448)

* check freeze before updating slot_hashes

* fixup

* add more information to dropped vote warning (#4449)

* add more information to dropped vote warning

* fixup
2019-05-28 20:35:54 -06:00
b9b541441b update book with passive staking (#4451) (#4455)
* update book with passive staking (#4451)

* undelete votestate etc
2019-05-28 16:01:53 -07:00
e510d4e272 Drop influxcloud (#4461) 2019-05-28 15:34:36 -07:00
9341e64ec7 Lock down blockexplorer version (#4462) 2019-05-28 15:26:53 -07:00
d934f94e05 Add commented correct future test lines 2019-05-28 09:59:07 -06:00
59dc123fa8 Add test indicating need for credit-only account handling 2019-05-28 09:58:57 -06:00
0faea87c84 Revert --retry-on-http-error usage, Travis CI's wget doesn't recognize it 2019-05-27 19:34:46 -07:00
19137ce3f4 Bump logging level of validator procsesing errors (#4444)
automerge
2019-05-27 15:36:35 -07:00
8bdeb2d1ed Use nohup and sleep a little to improve stability when launching a node 2019-05-27 14:00:24 -07:00
d29a45266b data_dir -> data-dir 2019-05-27 07:32:29 -07:00
2adb98a4a0 Ignore flaky test_repairman_catchup (#4439)
automerge
2019-05-26 12:24:20 -07:00
471465a5f4 net/: Add solana-install test to sanity (#4438)
* Add instance creation date to motd

* Setup localtime

* Add solana-install test
2019-05-26 11:17:07 -07:00
942785b626 sdk/bpf/scripts/install.sh: Retry downloads on transient 403 S3 failures seen in CI (#4436)
* Avoid caching perf-libs in CI

* Retry downloads on transient 403 S3 failures seen in CI
2019-05-25 14:41:09 -07:00
aa3c00231a Fix should_update check to update EpochSlots in gossip (#4435)
automerge
2019-05-25 06:44:40 -07:00
d772a27936 Plumb ClusterInfoRepairListener (#4428)
automerge
2019-05-24 19:20:09 -07:00
0302f13b97 add datapoint for corrupt vote_account (#4424) 2019-05-24 18:34:56 -07:00
16b25d0874 Clone with https for Travis/repo with submodules (#4431) 2019-05-24 21:18:31 -04:00
c2dcbee6af cd within the subshell 2019-05-24 18:10:25 -07:00
1f71d05299 remove copying of forwarded packets (#4425)
automerge
2019-05-24 17:35:09 -07:00
bfa1c025fd Add rust bpf allocator (#4426) 2019-05-24 16:21:42 -07:00
8611b40074 Add argument to net/net to specify number of nodes (#4429)
Allows for testing different node counts without recreating the network.
2019-05-24 16:20:14 -07:00
916844d399 Fix replicator account setup in fullnode.sh (#4430) 2019-05-24 15:40:49 -07:00
4c9b7c9d2b Submit all incoming proofs as valid (#4377) 2019-05-24 14:49:10 -07:00
9843c3a5cb Restrict transaction fee payers to system accounts (#4198)
automerge
2019-05-24 13:06:55 -07:00
f56955a17c Use absolute path to env.sh 2019-05-24 12:27:12 -07:00
9784bbf154 Pay for storage transactions with a system account (#4423)
automerge
2019-05-24 11:04:05 -07:00
45642c4da1 Add path to env.sh 2019-05-24 09:56:07 -07:00
8eac199e8b Include perf-libs in release tarball (#4422) 2019-05-24 09:28:52 -07:00
2e251ccc5c De-fullnode variable names (#4420) 2019-05-24 04:31:39 -07:00
cf4bb70d80 Rename id to pubkey in cluster_info_repair_listener (#4421) 2019-05-24 04:31:32 -07:00
57f8a15b96 Fix issues in ClusterInfoRepairListener (#4418)
* Sort repairmen before shuffling so order is the same across all validators

* Reduce repair redundancy to 1 for now

* Fix local cache of roots so that 1) Timestamps are only updated to acknowledge a repair was sent 2) Roots are updated even when timestamps aren't updated to keep in sync with network

* Refactor code, add test
2019-05-24 00:47:51 -07:00
cfe5afd34c _id => _pubkey variable renaming (#4419)
* wallet: rename *_account_id to *_account_pubkey

* s/from_id/from_pubkey/g

* s/node_id/node_pubkey/g

* s/stake_id/stake_pubkey/g

* s/voter_id/voter_pubkey/g

* s/vote_id/vote_pubkey/g

* s/delegate_id/delegate_pubkey/g

* s/account_id/account_pubkey/g

* s/to_id/to_pubkey/g

* s/my_id/my_pubkey/g

* cargo fmt

* s/staker_id/staker_pubkey/g

* s/mining_pool_id/mining_pool_pubkey/g

* s/leader_id/leader_pubkey/g

* cargo fmt

* s/funding_id/funding_pubkey/g
2019-05-23 23:20:04 -07:00
94beb4b8c2 More fullnode -> validator renaming (#4414)
* s/fullnode_config/validator_config/g

* s/FullnodeConfig/ValidatorConfig/g

* mv core/lib/fullnode.rs core/lib/validator.rs

* s/Fullnode/Validator/g

* Add replicator-x.sh

* Rename fullnode.md to validator.md

* cargo fmt
2019-05-23 22:05:16 -07:00
50207a30ef Rename solana-fullnode to solana-validator redux (#4417) 2019-05-23 21:28:18 -07:00
35e8f966e3 add freeze_lock() and fix par_process_entries() failure to detect self conflict (#4415)
* add freeze_lock and fix par_process_entries failure to detect self conflict

* fixup

* fixup
2019-05-23 17:35:15 -07:00
943cd0a24a Add credit-only info to AccountMetadata (#4405)
* Add credit-only flag to AccountMeta, default to false

* Sort keys by is_credit_only within signed/unsigned groupings

* Process and de-dupe program keys along with other account keys

* Add message helper functions

* Fix test

* Improve comment

* s/is_credit_only/is_debitable

* Add InstructionKeys helper struct, and simplify program_position method
2019-05-23 18:19:53 -04:00
0b892b2579 Reduce 100ms to 1ms. (#4412)
automerge
2019-05-23 15:15:26 -07:00
fb2eac20bb Rename solana-fullnode to solana-validator (#4411) 2019-05-23 15:06:01 -07:00
b37d2fde3d Add storage mining pool (#4364)
* Add storage mining pool

* Set gossip port

* Add create-storage-mining-pool-account wallet command

* Add claim-storage-reward wallet command

* Create storage account upfront

* Add storage program to genesis

* Use STORAGE_ACCOUNT_SPACE

* Fix tests

* Add wallet commands to create validator/replicator storage accounts

* Add create_validator_storage_account()

* Storage stage no longer implicitly creates a storage account
2019-05-23 14:50:23 -07:00
6b35e16676 Turn on real PoH in perf testnets (#4407)
* Turn on real PoH in perf testnets

* enable real PoH for all testnets except "testnet"
2019-05-23 13:22:52 -07:00
6a9e0bc593 Change EpochSlots to use BtreeSet so that serialization/deserialization returns the same order (#4404)
automerge
2019-05-23 03:50:41 -07:00
591fd72e0b Implement listener for serving repairs through Repairman protocol (#4306)
* Make listener for serving repairs through Repairman protocol
2019-05-23 03:10:16 -07:00
2ed77b040a create_genesis_block() now returns a struct (#4403) 2019-05-22 20:39:00 -07:00
7ada8510c4 add slot_hashes to bank, remove phony slot_hashes_from_vote_instruction (#4401) 2019-05-22 19:07:56 -07:00
b8f6c17dee Don't filter transactions if we are buffering it locally (#4395)
automerge
2019-05-22 17:54:28 -07:00
2f976ae460 Dashboard update for real PoH performance (#4397) 2019-05-22 16:18:57 -07:00
36019cb1e3 Tweaks to real PoH based on perf testing (#4396)
* Some counters for real poh perf analysis

* more metrics

* Comment on CPU affinity change, and reduce hash batch size based on TPS perf

* review comments
2019-05-22 15:54:24 -07:00
99d2428041 Transaction format changes toward Credit-Only accounts (#4386)
* Add num_readonly_accounts slice

* Impl programs in account_keys

* Emulate current account-loading functionality using program-account_keys (breaks exchange_program_api tests)

* Fix test

* Add temporary exchange faucet id

* Update chacha golden

* Split num_credit_only_accounts into separate fields

* Improve readability

* Move message field constants into Message

* Add MessageHeader struct and fixup comments
2019-05-22 18:23:16 -04:00
c121498b5b Check that Rust project exists (#4393) 2019-05-22 15:09:59 -07:00
eef2bdf690 Add CPU affinity for PoH service thread (#4394)
automerge
2019-05-22 14:21:43 -07:00
190656967d Bump nix from 0.13.0 to 0.14.0 (#4382)
Bumps [nix](https://github.com/nix-rust/nix) from 0.13.0 to 0.14.0.
- [Release notes](https://github.com/nix-rust/nix/releases)
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.13.0...v0.14.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-22 14:07:35 -07:00
90e73515ed Remove ls which is innacurate since we never clean up the logs (#4392)
automerge
2019-05-22 13:11:20 -07:00
1d7a758c97 Bump perf libs version to fix out buffer sizing (#4385) 2019-05-22 13:00:03 -07:00
e5b7aead12 Cargo watch ignores local metrics (#4384) 2019-05-22 00:08:18 -07:00
578c2ad3ea add bank hash to votes (#4381) 2019-05-21 21:45:38 -07:00
de6838da78 change unwrap to expect where WSL sometimes aborts (#4375)
* change unwrap to expect where WSL sometimes aborts

* clippy
2019-05-21 21:34:51 -07:00
604071c5d8 Bump num-traits from 0.2.7 to 0.2.8 (#4379)
Bumps [num-traits](https://github.com/rust-num/num-traits) from 0.2.7 to 0.2.8.
- [Release notes](https://github.com/rust-num/num-traits/releases)
- [Changelog](https://github.com/rust-num/num-traits/blob/master/RELEASES.md)
- [Commits](https://github.com/rust-num/num-traits/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-21 21:27:00 -07:00
41a377013f fix spelling (#4378)
automerge
2019-05-21 17:13:21 -07:00
52d453d06f Reduce broadcast prints (#4368) 2019-05-21 17:02:19 -07:00
58295b825d introduce syscalls (#4373) 2019-05-21 15:19:41 -07:00
f6c7812fcc Rename Broker to Swapper (#4371) 2019-05-21 14:21:41 -07:00
2f7561e4ee Split SDK's BPF Rust-utils (#4369) 2019-05-21 13:39:27 -07:00
1cbd2372fc Revert 4271 workaround (#4367)
* Revert "#4271 not reproducable, remove workaround (#4363)"

This reverts commit ef0580bd3d.

* Remove old comment
2019-05-21 11:53:53 -07:00
28f948aa7f Multi rust projects (#4362) 2019-05-21 11:22:33 -07:00
c9ba9e4eb7 Add storage space constant (#4366)
automerge
2019-05-21 11:07:13 -07:00
f877fb8c8f Don't print leader update message unless leader actually updates (#4365) 2019-05-21 11:06:56 -07:00
772ba41ede Cargo.lock 2019-05-21 08:08:07 -07:00
6374e69a69 Add mining pool wallet commands (#4360)
automerge
2019-05-21 07:32:38 -07:00
ef0580bd3d #4271 not reproducable, remove workaround (#4363) 2019-05-20 23:45:09 -07:00
1a77486f8e Make RootedSlotsIterator for traversing slots on the root fork (#4361) 2019-05-20 23:09:00 -07:00
ead15d294e add get_epoch_vote_accounts rpc (#4317)
* add get_epoch_vote_accounts rpc

* fixups

* documentation and type updates
2019-05-20 22:21:13 -07:00
1acfcf3acf Fix storage-keypair 2019-05-20 19:54:37 -07:00
d15e248cdb Add bootstrap storage account to genesis (#4359)
* Add bootstrap storage account to genesis

* Add storage account genesis command to run.sh

* Update airdrop for all validators

* Remove unhelpful Short for arg

* Set the correct program owner
2019-05-20 19:46:15 -07:00
f1e5edee14 Modify Roots Column To Support Multiple Roots (#4321)
* Fix 1) Roots column family to handle storing multiple slots, 2) Store all slots on the rooted path in the roots column family
2019-05-20 19:04:18 -07:00
7153abd483 Revert "Performance tweaks (#4340)" (#4350)
* Revert "Performance tweaks (#4340)"

This reverts commit 55cee5742f.

* Revert Rc change
2019-05-20 17:48:42 -07:00
90fb5d074d Bump num-traits from 0.2.6 to 0.2.7 (#4355)
Bumps [num-traits](https://github.com/rust-num/num-traits) from 0.2.6 to 0.2.7.
- [Release notes](https://github.com/rust-num/num-traits/releases)
- [Changelog](https://github.com/rust-num/num-traits/blob/master/RELEASES.md)
- [Commits](https://github.com/rust-num/num-traits/compare/num-traits-0.2.6...num-traits-0.2.7)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-20 16:35:14 -06:00
af82b0dce9 Fix sending root slots instead of current slot (#4354)
automerge
2019-05-20 15:01:55 -07:00
d4da2fbacd fix bench warnings (#4356) 2019-05-20 14:32:23 -07:00
77efe95730 Order "install" correctly 2019-05-20 13:54:15 -07:00
86e03a6d1b support issuing vote instructions from system account (#4338)
* issue vote instructions from system account

* fixup

* bring back KeypairUtil
2019-05-20 13:32:32 -07:00
114e2989fa Improve PoH unit test asserts (#4351)
automerge
2019-05-20 13:02:44 -07:00
7024c73e9b Revert banking threads increase which seems to be slower in testing. (#4349) 2019-05-20 11:42:37 -07:00
6d418aa3f1 Use rust_stable 2019-05-20 10:48:48 -07:00
f079a78c5e Remove fee arg from system_transaction::* (#4346)
automerge
2019-05-20 10:03:19 -07:00
6365c4c061 Use cleanup (#4347) 2019-05-20 09:58:27 -07:00
55cee5742f Performance tweaks (#4340)
* Use Rc to prevent clone of Packets

* Fix min => max in banking_stage threads.

Coalesce packet buffers better since a larger batch will
be faster through banking and sigverify.

Deconstruct batches into banking_stage from sigverify since
sigverify likes to accumulate batches but then a single banking_stage
thread will be stuck with a large batch. Maximize parallelism by
creating more chunks of work for banking_stage.
2019-05-20 09:15:00 -07:00
034eda4546 Fix a couple replicator nits (#4345)
automerge
2019-05-20 08:55:45 -07:00
44ff25d044 Update readme
* rustfmt no longer in preview
* since virtual manifest, cargo commands no longer require `--all`
2019-05-19 19:41:15 -06:00
a7e160e5c4 Add datapoint metrics to dashboard (#4343)
automerge
2019-05-19 15:07:03 -07:00
6283cc916d Add SOLANA_METRICS_MAX_POINTS_PER_SECOND env var (#4342) 2019-05-19 13:56:52 -07:00
4b6aca6120 Bump tempfile from 3.0.7 to 3.0.8 (#4341)
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.0.7 to 3.0.8.
- [Release notes](https://github.com/Stebalien/tempfile/releases)
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/NEWS)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.0.7...v3.0.8)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-18 19:56:51 -07:00
20b2be6e0b Enable real PoH on beta testnet as well 2019-05-18 19:45:00 -07:00
cbebc7a80c Expand shortArgs correctly 2019-05-18 19:00:48 -07:00
06eb2364f2 Handle missed slots in storage stage (#4337)
* Handle missed slots in storage stage

* Fix test compile

* Make test use the new missed slot support
2019-05-18 15:24:50 -07:00
167890ca63 Set rust_version 2019-05-18 14:48:53 -07:00
392a39dd54 Poh subsystem cleanup, genesis plumbing, enable real PoH on edge testnet (#4292)
* Remove unused PohServiceConfig::Step

* Clarify variable name

* Poh::hash() now takes an iteration counter

* man -> max

* Inline functions with single call site

* Move PohServiceConfig into GenesisBlock

* Add plumbing to enable real PoH on testnets

* Batch hashes to improve PoH hash rate

* Ensure a constant hashes_per_tick

* Remove PohEntry mixin field

* Poh/PohEntry no longer maintains tick_height

* Ensure a constant hashes_per_tick

* ci/localnet-sanity.sh: Use real PoH

* Rework Poh/PohService to keep PohRecorder unlocked as much as possible while hashing
2019-05-18 14:01:36 -07:00
7e1a7862db test_process_store_ok() now pays with a system account (#4339)
automerge
2019-05-17 20:17:50 -07:00
458ae3fdac Switch to instances with AVX-512 if possible for better interop with dev machines (#4328)
automerge
2019-05-17 20:06:07 -07:00
431cc82032 add Transaction::partial_sign() (#4333)
* add partial sign

* nits
2019-05-17 18:55:57 -07:00
18c6729d6c Bump tar from 0.4.25 to 0.4.26 (#4330)
Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.25 to 0.4.26.
- [Release notes](https://github.com/alexcrichton/tar-rs/releases)
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.25...0.4.26)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-17 17:46:12 -07:00
9476fe5ce3 Use log levels for datapoint metrics (#4335)
* Use log levels for datapoint metrics

* address review comments

* fix cyclomatic complexity
2019-05-17 17:34:05 -07:00
788290ad82 Rework Storage Program to accept multiple proofs per segment (#4319)
automerge
2019-05-17 14:52:54 -07:00
6b5bcfaa58 Bump libc from 0.2.54 to 0.2.55 (#4324)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.54 to 0.2.55.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.54...0.2.55)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-17 13:24:12 -07:00
4ed0cded9c Rm metrics docker even if not running (#4329) 2019-05-17 13:13:38 -07:00
035a364122 Add expect to get better errors on crash (#4327) 2019-05-17 12:49:41 -07:00
b114bc3674 Add benchmark for sigverify stage (#4320) 2019-05-17 11:09:42 -07:00
bc74ee7117 Common Rust-BPF utilities and types (#4325) 2019-05-17 11:04:29 -07:00
b2ce5dc9f5 Adjust log level for counter metrics (#4323) 2019-05-17 07:00:06 -07:00
e920191de0 Rate limit metrics per log level (#4313)
* Rate limit metrics per log level

* fix tests
2019-05-16 22:27:05 -07:00
39e85a3e53 kill some bs58 (#4316)
* kill some bs58

* fixup
2019-05-16 21:43:18 -07:00
41156da4ca Sync run.sh with fd3f2cb (#4322)
automerge
2019-05-16 21:32:23 -07:00
9271ba0039 Cleanup Rust BPF program building (#4318) 2019-05-16 17:35:42 -07:00
b3e45fd6b7 Add erroring tx to unexpected validator error logging (#4314)
* Add tx logging to error

* Add tx logging to unexpected validator errors
2019-05-16 14:59:22 -07:00
7bfb60f82e add impl FromStr for Signature (#4315)
automerge
2019-05-16 14:54:31 -07:00
359c50f1b3 cp -a includes -r (#4312) 2019-05-16 12:24:04 -07:00
fff1631a8b Return a better error when a program account isn't found (#4310) 2019-05-16 11:32:27 -06:00
7d42ae30d9 Update Rust-BPF to 2018 Edition (#4307) 2019-05-16 09:12:33 -07:00
87414de3e2 switch over to passive stakes (#4295)
* add failing test

* switch over to passive stakes

* test multiple stakers
2019-05-16 08:23:31 -07:00
a0ffbf50a5 Correctly remove replicator from data plane after its done repairing (#4301)
* Correctly remove replicator from data plane after its done repairing

* Update discover to report nodes and replicators separately

* Fix print and condition to be spy
2019-05-16 07:14:58 -07:00
d40b66ff7b Bump solana_rbpf from 0.1.10 to 0.1.11 (#4304)
Bumps [solana_rbpf](https://github.com/solana-labs/rbpf) from 0.1.10 to 0.1.11.
- [Release notes](https://github.com/solana-labs/rbpf/releases)
- [Commits](https://github.com/solana-labs/rbpf/commits/v0.1.11)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-16 01:07:10 -07:00
abd7f6b090 Change slot_meta_iterator() to return an iterator not a cursor (#4303)
automerge
2019-05-15 18:28:23 -07:00
d8735df1de Update replicator to use cluster_info instead of cached client (#4302) 2019-05-15 18:14:04 -07:00
481853e1b1 Bump reqwest from 0.9.16 to 0.9.17 (#4296)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.9.16 to 0.9.17.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.9.16...v0.9.17)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-15 16:02:17 -07:00
778bcbce50 Reduce log level for frequent log message and frequency for metrics datapoint (#4300)
automerge
2019-05-15 16:01:17 -07:00
fd3f2cb910 Add Storage accounts for all nodes (#4298)
* Setup storage keypairs for all nodes

* Clean up naming

* clippy

* Update arg value_names
2019-05-15 15:19:29 -07:00
915956b94b Remove disable leader rotation option (#4299)
automerge
2019-05-15 15:16:45 -07:00
4576250342 Fix bug in storage processor and remove duplicate Constant (#4294)
* Fix bug in storage processor and remove duplicate Constant

* Add test

* Bump replicator timeout
2019-05-15 13:28:56 -07:00
2bef1b0433 Use rust-bpf-sysroot release branches (#4293) 2019-05-15 12:45:48 -07:00
628128b376 add passive staking to local_cluster (#4285)
* add passive staking to local_cluster

* add stake_program to genesis

* use equal stakes in local_cluster tests
2019-05-15 12:15:31 -07:00
916017ca2c Fix repair for a range of slots (#4286)
* Fix repair for a range of slots

* Delete RepairInfo
2019-05-15 11:37:20 -07:00
3204a00e73 Update rust-bpf-sysroot to latest (#4291) 2019-05-15 09:53:44 -07:00
1d327a5167 Bump bincode from 1.1.3 to 1.1.4 (#4290)
Bumps [bincode](https://github.com/TyOverby/bincode) from 1.1.3 to 1.1.4.
- [Release notes](https://github.com/TyOverby/bincode/releases)
- [Commits](https://github.com/TyOverby/bincode/compare/v1.1.3...v1.1.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-15 09:47:55 -06:00
6e4f9cedf2 Fix Plum Tree link 2019-05-15 08:15:22 -07:00
a79fbbafc9 SlotMeta is incorrectly updated on insertion of erasure blobs (#4289)
* Fix put_coding_blob_bytes to properly update slotmetas and chaining
2019-05-15 00:28:31 -07:00
1d54d29076 Fix reading ledger for chacha encrypt (#4288) 2019-05-14 16:59:17 -07:00
10b9a4806b Fix incorrect genesis blockhashes on restart (#4287) 2019-05-14 16:32:44 -07:00
0c1191c3ee rework staking_utils (#4283) 2019-05-14 16:15:51 -07:00
18b386cd10 remove unused make_active_set_entries (#4284) 2019-05-14 15:08:49 -07:00
714b8c7fc8 Bump tokio from 0.1.18 to 0.1.20 (#4280)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 0.1.18 to 0.1.20.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-0.1.18...tokio-0.1.20)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-14 15:30:56 -06:00
216e9a61a0 expose stake directly from bank (#4281) 2019-05-14 13:35:14 -07:00
0f498e6265 remove unused filter_zero_balance (#4279) 2019-05-14 10:44:29 -07:00
e8ad822111 get program names from programs (#4273)
* get program names from programs

* fixup
2019-05-14 10:44:16 -07:00
65a82ebf50 Fix broken tip (#4278)
automerge
2019-05-14 02:35:32 -07:00
727802684c Use 20 bytes signature slice for cache purposes (#4260) 2019-05-13 22:53:10 -07:00
e20a8329d3 Add API to iterate over slot's blobs (#4276) 2019-05-13 22:04:54 -07:00
88c2d0fad4 Add genesis blockhash to replicators and blob filter for window (#4275)
* Add genesis blockhash to replicators and blob filter for window

* Fixes to mining submission and ledger download

* Add todo over sleep

* Update log
2019-05-13 21:19:51 -07:00
3bd921264a Move EpochSchedule into own module (#4272) 2019-05-13 16:24:32 -07:00
7501ed65e5 Initialize and Update EpochSlots in RepairService (#4255)
* Initialize EpochSlots in RepairService

* Fix flaky test
2019-05-13 15:37:50 -07:00
2eaa64c4e8 valhashators -> validators 2019-05-13 15:29:23 -07:00
c9b86018c6 Filter out all unprocessed transactions before forwarding them (#4266)
* Filter out all unprocessed transactions before forwarding them

* fix clippy
2019-05-13 14:40:05 -07:00
a4fb01b42b Add +x 2019-05-13 14:30:44 -07:00
0d2574f8f0 get DLL names from programs that made the DLL (#4269)
* get program names from programs

* fixup
2019-05-13 14:17:44 -07:00
796000e96f Improve erasure metrics (#4268)
* Improve erasure metrics

* Simplify metrics submission
2019-05-13 16:04:43 -05:00
e2f00dc205 Cargo.toml implied (#4270)
automerge
2019-05-13 13:51:42 -07:00
5e91f8f59d Update reported tx count to exclude errors (#4201) 2019-05-13 13:23:52 -07:00
e2830f5b0e Add rate limit to metrics datapoint submission (#4237)
Cleanup

Raise limit on submission threshold

Pick nits and add metrics point

fmt

Fixup compiler warning

Cleanup if-else

Append new point to vec rather than submit
2019-05-13 14:17:25 -06:00
a2e3a92b01 Extend GetBlockHash RPC API to include the fee scehdule for using the returned blockhash (#4222) 2019-05-13 12:49:37 -07:00
23c696706b add stake_accounts to banks' caches (#4267) 2019-05-13 12:33:23 -07:00
1393d26f63 Remove obsolete internal multinode-demo/ logging (#4265) 2019-05-13 10:51:18 -07:00
1b68da7572 Use solana-ed25519-dalek v0.2.0 (#4264)
automerge
2019-05-13 09:51:59 -07:00
8542006259 Config instructions now only require one key (#4258) 2019-05-12 22:47:12 -07:00
426d06b89b Improve target/ cache logging 2019-05-12 22:16:23 -07:00
06378d6db6 Refine killNode logging 2019-05-12 21:21:31 -07:00
dccfe31e8c Increase target cache size for coverage build 2019-05-12 21:21:31 -07:00
1dce5976cf Disable node restart in localnet-sanity.sh 2019-05-12 21:21:31 -07:00
340d01665c Avoid generating default keypair 2019-05-12 21:21:31 -07:00
50f79e495e net/ improvements (#4257)
automerge
2019-05-11 22:54:50 -07:00
dd12db2f06 Correctly handle more zones than additional nodes 2019-05-11 14:47:27 -07:00
1afccb7351 Add more regions to the testnet 2019-05-11 14:12:13 -07:00
bfc65e829e Use zone[0] for any left over nodes 2019-05-11 14:07:36 -07:00
eb4515525d Bump ws from 0.8.0 to 0.8.1 (#4251)
Bumps [ws](https://github.com/housleyjk/ws-rs) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/housleyjk/ws-rs/releases)
- [Changelog](https://github.com/housleyjk/ws-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/housleyjk/ws-rs/compare/v0.8.0...v0.8.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-10 21:06:33 -07:00
55f5f6a033 Make links clickable 2019-05-10 19:49:45 -07:00
7ae421eaf6 Update release version in book (#4254) 2019-05-10 18:43:08 -06:00
e7da2c0931 Add validator registration link (#4229) 2019-05-10 15:14:03 -07:00
133be2df51 Check for transaction forwarding delay to detect an expired transaction before forwarding it (#4249)
Also refactored code for forwarding packets, and added test for it
2019-05-10 14:28:38 -07:00
06a93dcb43 Move to solana-ed25519-dalek (#4248) 2019-05-10 15:26:46 -06:00
ad7f04a245 Add genesis_blockhash to erasure blobs so they don't get filtered out by window_service (#4247) 2019-05-10 14:06:31 -07:00
0da6e1af14 Repair Design Proposal (#3402)
* Update information about existing repair protocol + new repairman proposal
2019-05-10 13:50:23 -07:00
576524f13b Updates to storage proposal with more storage contract details (#3373) 2019-05-10 09:19:06 -07:00
f567877d1d Cleanup metrics (#4230) 2019-05-10 08:33:58 -07:00
9881820444 RepairService saves db_iterator instead of reconstructing on every search (#4242) 2019-05-09 19:57:51 -07:00
ba8f49366d passive staking 4 (#4240)
* support passive staking with wallet, use it

* fixups

* clippy

* cleanup app generation in wallet, finish fullnode.sh staking

* _id and _keypair => pubkey
use keygen, not wallet to get pubkey

* found 'em
2019-05-09 19:31:42 -07:00
81fa69d347 Revert "Create bank snapshots (#3671)" (#4243)
This reverts commit abf2b300da.
2019-05-09 19:27:27 -07:00
abf2b300da Create bank snapshots (#3671)
* Be able to create bank snapshots

* fix clippy

* load snapshot on start

* regenerate account index from the storage

* Remove rc feature dependency

* cleanup

* save snapshot for slot 0
2019-05-09 19:27:06 -07:00
a8254fd258 Clear stale ledger on fullnode startup if necessary (#4238) 2019-05-09 17:09:36 -07:00
b15848de3b Bump tar from 0.4.24 to 0.4.25 (#4239)
Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.24 to 0.4.25.
- [Release notes](https://github.com/alexcrichton/tar-rs/releases)
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.24...0.4.25)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-09 17:07:31 -07:00
ab3c988146 API for getting first and last slots in epoch (#4241)
automerge
2019-05-09 16:06:57 -07:00
575a0e318b Add newly completed slots signal to Blocktree (#4225)
* Add channel to blocktree for communicating when slots are completed

* Refactor RepairService options into a RepairStrategy
2019-05-09 14:10:04 -07:00
a031b09190 Add replicator support to multinode demo (#4221)
automerge
2019-05-09 13:43:39 -07:00
df43e721e3 Exit 1 on ledger verification failure 2019-05-09 12:05:51 -07:00
5f72650c7f add derive Debug to Keypair (#4236) 2019-05-09 11:41:11 -07:00
5d0d467287 fix banking_stage benches (#4231) 2019-05-09 11:20:26 -07:00
994515d0f2 add impl PartialEq for Keypair (#4233)
* add-impl-PartialEq-for-Keypair

* clippy

* do the TODO, improve wrapper comments
2019-05-09 11:03:14 -07:00
1e949caa7f Move airdrop retries fully out of bash (#4234)
automerge
2019-05-09 09:48:27 -07:00
f2b727b534 Update mint keypair filename 2019-05-09 07:27:13 -07:00
f7680752e7 make gen_keypair_file take &str (#4232)
automerge
2019-05-08 23:00:48 -07:00
da4c37beec multinode-demo/ grooming (#4226)
* Rename leader to entrypoint

* The fullnode identity keypair can now be provided

* Rename _id to _keypair
2019-05-08 19:59:22 -07:00
d486d2b8ce Consolidate default arg parsing (#4224)
automerge
2019-05-08 19:12:43 -07:00
bba94c43b9 Add BankForks to RepairService (#4223)
automerge
2019-05-08 18:51:43 -07:00
9cdffc7d64 Don't push empty vecs into the unprocessed buffers (#4214) 2019-05-08 17:58:07 -07:00
5a86f2506d Remove unnecessary retrying (#4219) 2019-05-08 16:20:37 -07:00
518227eac0 add-rpc_client.get_account (#4218) 2019-05-08 15:50:23 -07:00
b8fd51e97d Add new gossip structure for supporting repairs (#4205)
* Add Epoch Slots to gossip

* Add new gossip structure to support Repair

* remove unnecessary clones

* Setup dummy fast repair in repair_service

* PR comments
2019-05-08 13:50:32 -07:00
965c1e0000 staking plumbing part 3, 3.5 (#4216) 2019-05-08 12:56:11 -07:00
a80176496d add /target/ to .gitignore files for all crates (#4217)
* add /target/ to .gitignore files for all crates

* shellcheck
2019-05-08 12:15:05 -07:00
5719b8f251 Change remote node's ssh config to allow more login retries (#4215)
automerge
2019-05-08 11:20:06 -07:00
1a2b131ceb Don't forward transactions that are expired or failed signature check (#4199) 2019-05-08 10:32:25 -07:00
349306ddf7 Bump proc-macro2 from 0.4.27 to 0.4.29 (#4180)
Bumps [proc-macro2](https://github.com/alexcrichton/proc-macro2) from 0.4.27 to 0.4.29.
- [Release notes](https://github.com/alexcrichton/proc-macro2/releases)
- [Commits](https://github.com/alexcrichton/proc-macro2/compare/0.4.27...0.4.29)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-08 09:03:30 -07:00
791ee411a5 Add root to bank forks (#4206) 2019-05-07 23:34:10 -07:00
f690c64375 Disable solana-upload-perf until performance can be debugged (#4210) 2019-05-07 23:02:09 -07:00
427963f554 Core depends on vote and budget program directly (#4204) 2019-05-07 22:41:47 -07:00
b0f2220ef6 Fix solana-upload-perf log folding. Upload bench output too (#4208) 2019-05-07 22:30:42 -07:00
908b48bf0e Increase test-stable build timeout 2019-05-07 22:23:43 -07:00
b49f8c0984 reduce replicode, introduce passive staking support (#4207) 2019-05-07 22:22:43 -07:00
7609a007c6 Add FeeCalculator to the genesis block (#4196) 2019-05-07 20:28:41 -07:00
674a49f8d7 Bump serde_derive from 1.0.90 to 1.0.91 (#4172)
Bumps [serde_derive](https://github.com/serde-rs/serde) from 1.0.90 to 1.0.91.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.90...v1.0.91)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 20:05:41 -07:00
d10bde656a Pass payer key into get_keys() (#4203) 2019-05-07 18:48:31 -07:00
401764ddb1 add create_delegate_stake_account (#4197) 2019-05-07 17:08:49 -07:00
69eeb7cf08 Fix parent record locks usage in child banks (#4159)
* Introduce record locks on txs that will be recorded

* Add tests for LockedAccountsResults

* Fix broken bench

* Exit process_entries on detecting conflicting locks within same entry
2019-05-07 15:51:35 -07:00
55e3b7d380 Storage transactions are now paid for by a system account (#4193)
* Pay program loading fees from a system account

* Pay transaction fees from a system account
2019-05-07 15:01:10 -07:00
d9e18a71ec Pay program loading fees from a system account (#4190) 2019-05-07 15:00:54 -07:00
2107e15bd3 Reduce Avalanche redundancy and implement traditional fanout (#4174)
* Reduce Avalanche redundancy and implement traditional fanout

* Revert tiny fanout

* Update diagrams and docs based on review comments
2019-05-07 13:24:58 -07:00
4f3b22d04e Minor code restyling, no functional changes 2019-05-07 12:35:29 -07:00
2c78a93001 GenesisBlock::new(X) => create_genesis_block(X) 2019-05-07 12:34:17 -07:00
2621aeee82 Set default wallet rpc port correctly 2019-05-07 11:37:51 -07:00
8e400fc4bd rework genesis (passive staking groundwork) (#4187)
* rework genesis

* fixup
2019-05-07 11:16:22 -07:00
29c2a63c8b Retry transactions that failed due to account lock (#4184)
* added test
2019-05-07 10:23:02 -07:00
736ada4e21 Bump dtoa from 0.4.3 to 0.4.4 (#4178)
Bumps [dtoa](https://github.com/dtolnay/dtoa) from 0.4.3 to 0.4.4.
- [Release notes](https://github.com/dtolnay/dtoa/releases)
- [Commits](https://github.com/dtolnay/dtoa/compare/0.4.3...0.4.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 07:31:57 -07:00
3df9b44d4c Bump nom from 4.2.2 to 4.2.3 (#4182)
Bumps [nom](https://github.com/Geal/nom) from 4.2.2 to 4.2.3.
- [Release notes](https://github.com/Geal/nom/releases)
- [Changelog](https://github.com/Geal/nom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Geal/nom/compare/4.2.2...4.2.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 07:31:48 -07:00
7225b89142 Bump globset from 0.4.2 to 0.4.3 (#4176)
Bumps [globset](https://github.com/BurntSushi/ripgrep) from 0.4.2 to 0.4.3.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/globset-0.4.2...globset-0.4.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 07:15:34 -07:00
0cc0d3ab7a Bump socket2 from 0.3.8 to 0.3.9 (#4186)
Bumps [socket2](https://github.com/alexcrichton/socket2-rs) from 0.3.8 to 0.3.9.
- [Release notes](https://github.com/alexcrichton/socket2-rs/releases)
- [Commits](https://github.com/alexcrichton/socket2-rs/compare/0.3.8...0.3.9)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 07:15:04 -07:00
88d9618788 Bump futures from 0.1.25 to 0.1.26 (#4179)
Bumps [futures](https://github.com/rust-lang-nursery/futures-rs) from 0.1.25 to 0.1.26.
- [Release notes](https://github.com/rust-lang-nursery/futures-rs/releases)
- [Changelog](https://github.com/rust-lang-nursery/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang-nursery/futures-rs/compare/0.1.25...0.1.26)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 07:14:48 -07:00
57038529e0 Bump hex-literal from 0.1.4 to 0.2.0 (#4185)
Bumps [hex-literal](https://github.com/RustCrypto/utils) from 0.1.4 to 0.2.0.
- [Release notes](https://github.com/RustCrypto/utils/releases)
- [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v0.1.4...hex-literal-v0.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-07 07:14:16 -07:00
5c25eae631 Bump tokio-sync from 0.1.4 to 0.1.5 (#4177)
Bumps [tokio-sync](https://github.com/tokio-rs/tokio) from 0.1.4 to 0.1.5.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-sync-0.1.4...tokio-sync-0.1.5)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-06 22:06:09 -07:00
b8b4d33f72 Bump h2 from 0.1.17 to 0.1.18 (#4175)
Bumps [h2](https://github.com/carllerche/h2) from 0.1.17 to 0.1.18.
- [Release notes](https://github.com/carllerche/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/carllerche/h2/compare/v0.1.17...v0.1.18)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-06 21:42:22 -07:00
673a9417ef Bump serde from 1.0.90 to 1.0.91 (#4171)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.90 to 1.0.91.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.90...v1.0.91)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-06 21:41:30 -07:00
3fd9aada8b Add missing modules to workspace (#4183) 2019-05-06 22:40:54 -06:00
453fdb9e28 Add support for local metric collection/viewing (#4170) 2019-05-06 16:44:06 -07:00
3f6a79b078 Add a validator node proposal (#3035)
automerge
2019-05-06 13:41:28 -07:00
e9f80e5542 Don't use default ticks per slot in calculating next slot leader (#4169) 2019-05-06 11:23:06 -07:00
694d28acf8 remove some boilerplate (#4143) 2019-05-06 10:11:18 -07:00
88fdba5aca Temp: bump test-bench timeout 2019-05-06 10:00:00 -07:00
a19df7a36c Add type annotations for external crates (#4125) 2019-05-06 10:11:50 -06:00
9b50583641 wallet: add --url, remove --host/--rpc-host/--rpc-port/-rpc-tls (#4153)
Also by default the wallet now talks to testnet.solana.com instead of
localhost
2019-05-06 07:38:26 -07:00
71f9b44687 Add Confirmations parameter to RPC Subscriptions (#4154)
* Add optional depth parameter to pubsub, and store in subscriptions

* Pass bank_forks into rpc_subscription; add method to check depth before notify and impl for account subscriptions

* Impl check-depth for signature subscriptions

* Impl check-depth for program subscriptions

* Plumb fork id through accounts

* Use fork id and root to prevent repeated account notifications; also s/Depth/Confirmations

* Write tests in terms of bank_forks

* Fixup accounts tests

* Add pubsub-confirmations tests

* Update pubsub documentation
2019-05-06 08:31:50 -06:00
0139e5db21 Correct blockstreamer node args 2019-05-04 08:22:36 -07:00
586fb15c2c fullnode positional arguments may now be mixed with optional arguments (#4151) 2019-05-03 20:49:24 -07:00
297328ff9a Fix improper tick sleeping time in test (#4155)
automerge
2019-05-03 20:15:10 -07:00
6b3384c205 Bump serde_yaml from 0.8.8 to 0.8.9 (#4127)
Bumps [serde_yaml](https://github.com/dtolnay/serde-yaml) from 0.8.8 to 0.8.9.
- [Release notes](https://github.com/dtolnay/serde-yaml/releases)
- [Commits](https://github.com/dtolnay/serde-yaml/compare/0.8.8...0.8.9)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-03 19:45:09 -07:00
3ef961fe37 Record poh ticks even when the node is not in leader schedule (#4148)
* remove obsolete test
2019-05-03 16:41:19 -07:00
a7b695c27a Change replicators to slot-based (#4118) 2019-05-03 16:27:53 -07:00
5bb75a5894 Fix roots never being purged (#4134) 2019-05-03 15:17:37 -07:00
f3f416b7ba Rename --network argument to --entrypoint (#4149) 2019-05-03 15:00:19 -07:00
31b74bdf0b Display release date in the local timezone (#4144) 2019-05-03 14:54:25 -07:00
ed48d8323c Reduce locking in Blocktree (#4075)
* Reduce lock contention in blocktree

* Store root slot in separate column
2019-05-03 16:46:02 -05:00
f91627a230 Remove extra-fullnode-args.sh (#4142) 2019-05-03 13:32:59 -07:00
f9c093022c multinode-demo/: Merge bootstrap-leader.sh into fullnode.sh (#4139) 2019-05-03 12:33:48 -07:00
7fe3c75c6b Add a node-specific ip echo service to remove dependency on ifconfig.co (#4137) 2019-05-03 11:01:35 -07:00
c8ed41167a Factor tune_system() out of multinode-demo/ (#4138)
* Remove x bit from ulimit-n.sh

* Factor tune_system() out of multinode-demo/
2019-05-03 10:40:02 -07:00
5b2a82a951 Fix validator confirmation graph y axis scale (#4136) 2019-05-02 19:51:56 -07:00
441e76ebeb Index buffered transactions at the correct offset (#4126)
* tests
2019-05-02 19:05:53 -07:00
c2dfb9900e Revert "Change forwarded metrics to be in line with fetch stage metrics (#4068)" (#4135)
automerge
2019-05-02 17:36:19 -07:00
916458e132 Change erasure set size to 8:8 (#4129)
* Change erasure set size to 8:8

* Change tests to be agnostic to exact set size and ratio

* Add convenience methods for setting presence
2019-05-02 19:04:40 -05:00
ffb15578ce remove cargo install cargo-audit from CI (#4123) 2019-05-02 15:35:47 -07:00
abcbbb925f push latest, too (#4131) 2019-05-02 15:33:08 -07:00
059755fe59 install mdbook and svgbob_cli (#4128) 2019-05-02 15:32:31 -07:00
ae12dc2c75 Add specs to testnet participation guide (#4078) 2019-05-02 15:21:05 -07:00
37b5c6afaa install cargo audit (#4122) 2019-05-02 13:16:21 -07:00
92ed7b36a2 Bump libc from 0.2.53 to 0.2.54 (#4124)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.53 to 0.2.54.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.53...0.2.54)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-02 13:11:29 -06:00
379d2e6d95 add support for single-crate coverage to help iterate, update to latest grcov (#4085)
* add support for single-crate coverage to help iterate, update to latest grcov

* shellcheck

* fixup

* remove unused

* install grcov before setting RUSTFLAGS ;)

* rely on nightly having grcov installed
2019-05-01 23:33:28 -07:00
7f75cc8906 update nightly to 2019-05-01 (#4111)
* update nightly to 2019-05-01

* cargo fmt

* cargo fmt

* increase bench timeout
2019-05-01 20:08:42 -07:00
1ab5098576 Move get_clients into gossip_service (#4109) 2019-05-01 17:14:01 -07:00
598f765960 Fix net.sh for running on macos (#4107)
automerge
2019-05-01 16:03:35 -07:00
aac626c2c2 Add sample_txs function to perf_utils shared crate (#4104)
Shared code between bench-tps and bench-exchange
2019-05-01 15:58:35 -07:00
3eec3cfac2 Cleanup banking stage in lieu of recent transaction forwarding changes (#4101) 2019-05-01 15:13:10 -07:00
5eee9e62e5 Add swapper back-off (#4088)
* Add swapper back-off

* Reset back-off if bench-exchange suspects back-log

* nudge

* nudge
2019-05-01 14:29:57 -07:00
a7d18125d3 install grcov (#4097) 2019-05-01 14:27:17 -07:00
8202310073 Minor update to gossip spy command (#4103) 2019-05-01 14:25:26 -07:00
1e2ba110eb Bump reqwest from 0.9.15 to 0.9.16 (#4089)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.9.15 to 0.9.16.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.9.15...v0.9.16)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-01 14:24:59 -06:00
62c9b7d850 Fix and un-ignore bench-tps local_cluster test (#4019)
* un-ignore bench-tps local_cluster test

And add bench_tps_fund_keys test.

* Unify generate_and_airdrop logic for tests
2019-05-01 13:21:45 -07:00
4f18fc836f Forward transactions to the next slot leader (#4092)
- this ensures that transactions will reach in time for the next node to process them
2019-05-01 11:37:29 -07:00
950d8494ba earlyoom: Stop using unsupported -k option (#4096)
automerge
2019-05-01 11:29:02 -07:00
cb528af4e2 fix accounts_db storage.reset() (#4094)
* fix accounts_db storage.reset()

* fix compilation errors, remove unused, fix test_accounts_grow() failure
2019-05-01 09:27:13 -07:00
ad27c30623 Cleanup bench-exchange messages (#4093) 2019-04-30 23:09:33 -07:00
9add8d0afc Add alternative to Spy Nodes that can fully participate in Gossip (#4087)
automerge
2019-04-30 16:42:56 -07:00
af2e7ea285 Add 1 decimal to validator confirmation (#4084) 2019-04-30 16:37:03 -07:00
675a78aaa1 get vote_instruction off bank for tests (#4086)
* get vote_instruction off bank for tests

* clippy
2019-04-30 15:11:08 -07:00
408bdbce7a Add non_default_stream parameter to cuda_verify (#4079) 2019-04-30 13:34:46 -07:00
1a259d4a3f Prevent Requests/Caching of leader schedules for epochs beyond confirmed roots (#4033)
automerge
2019-04-30 13:23:21 -07:00
c5f8b4960c Stop nodes in parallel 2019-04-30 10:42:59 -07:00
21f845ed39 Use more -w 2019-04-30 09:57:14 -07:00
7a369df9a7 Add flag to skip slow extras when deploying a large testnet 2019-04-30 09:26:50 -07:00
f02ec31c68 Flip if/else 2019-04-30 08:56:53 -07:00
d21fa4a177 v0.14: various net/ fixes for large clusters (#4080)
* net.sh: Add -F to discard validator nodes that didn't bootup successfully

* Relax sanity node count when validator bootup failure is permitted

* Less sanity for testnet-demo

* net.sh: Add -F to discard validator nodes that didn't bootup successfully
2019-04-29 21:38:32 -07:00
bd0871cbe7 Update release doc to include testnet update instuctions (#4066)
* Update release doc to include testnet update instuctions

* Fixup headers and pick nits

* Remove outdated testnet behavior
2019-04-29 19:40:18 -06:00
2604f8ac0a Move implemented functionality into the Implemented Proposals section (#4057) 2019-04-29 17:29:41 -06:00
a7574f8657 Cleanup metrics dashboard (#4072) 2019-04-29 15:52:04 -07:00
73f250f03a Make minimum warmup period 32 slots long (#4031)
* Make minimum warmup period 32 slots long

* PR fixes
2019-04-29 15:26:52 -07:00
bae0aadafa Remove Bench Exchange Contract Execution graph 2019-04-29 14:29:54 -07:00
5524146ddf push down noop's messages (#4069)
automerge
2019-04-29 14:10:36 -07:00
3b2adbc9df Change forwarded metrics to be in line with fetch stage metrics (#4068)
automerge
2019-04-29 13:50:14 -07:00
4e41c81bc7 Fix the output from Gossip Discovery (#4067)
automerge
2019-04-29 13:19:24 -07:00
c545e812d0 Expand bank benches to include async/sync and native_loader (#4026) 2019-04-29 13:09:11 -07:00
c2193a37ce cleanup unused function (#4064) 2019-04-29 12:45:14 -07:00
fabba82173 ignore non-descendants of roots in blocktree (#4032) 2019-04-29 12:29:14 -07:00
c3ec5ad846 testnet-demo: use more low quota nodes 2019-04-29 12:18:39 -07:00
c4945cc04a Bump tar from 0.4.23 to 0.4.24 (#4060)
Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.23 to 0.4.24.
- [Release notes](https://github.com/alexcrichton/tar-rs/releases)
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.23...0.4.24)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-29 10:34:30 -06:00
e2e55f81d0 Increase testnet-demo node count a little 2019-04-29 09:09:55 -07:00
d862565b16 Move Transact proposal to implemented (#4055)
And update names to reflect what was implemented.
2019-04-29 09:13:39 -06:00
0cc3956693 testnet-demo now runs across more GCE zones (#4053)
* testnet-demo now runs across more GCE zones

* Save zone info to config file

* Add geoip whitelist for common data centers

* Skip more of start

* Include -x for config

* Fetch private key from first validator node if necessary

* Correct -r propagation
2019-04-28 19:50:52 -07:00
4e5677f116 Sample random trade_infos for success (#4043)
Just looking at a single trade_info which may or may not succeed
can fail often.
2019-04-28 11:00:16 -07:00
acba1d6f9e Roots are added out of order to the accounts index (#4051)
* fix root race

* assert root order

* fixup! assert root order

* last root test

* update

* fix tests
2019-04-28 10:27:37 -07:00
3e14af5033 bast bank ancestor check (#4050) 2019-04-28 10:27:09 -07:00
6f56501034 Correctly terminate instances across multiple zones 2019-04-28 09:09:02 -07:00
0b7269b64e Switch testnet-demo to influxcloud 2019-04-27 22:12:50 -07:00
457a2d948b Correct us-central1-b zone name 2019-04-27 21:43:18 -07:00
528bdf34fd testnet-demo: skip over validator nodes that fail to boot 2019-04-27 21:34:23 -07:00
697cd17b59 Use GPU nodes for blockstreamer as well if rest of testnet has GPUs (#4046)
- The blockstreamer crashes otherwise, as sigverify() looks for CUDA libs
2019-04-27 20:45:38 -07:00
13fcfcb964 Blockstreamer annotation fix for non buildkite deployments (#4045) 2019-04-27 20:37:36 -07:00
9c1fd55768 testnet-demo: add more GCE zones, remove client 2019-04-27 16:52:09 -07:00
7f9a476660 Performance metrics computation methodology (#4041) 2019-04-27 16:37:51 -07:00
b07290df81 Add usage to net.sh when it encounters an invalid argument (#4042)
automerge
2019-04-27 16:12:13 -07:00
4b599a95b3 Bump libc from 0.2.51 to 0.2.53 (#4009)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.51 to 0.2.53.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.51...0.2.53)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-27 14:04:23 -06:00
64222cfff7 update lock file for 0.15 (#4039)
automerge
2019-04-27 11:43:12 -07:00
e81d434903 Add DNS resolution for network/drone arguments (#4038)
automerge
2019-04-27 10:06:58 -07:00
bf0dd158de Avoid inaccurate PATH nagging (#4034)
automerge
2019-04-27 09:11:02 -07:00
18e398131d Fix issues with bench-tps (#4005) 2019-04-27 08:39:29 -07:00
4a5837a286 Add " 2019-04-27 07:41:21 -07:00
656e2649a7 v0.15.0 2019-04-27 07:38:46 -07:00
d36af917ea Swap testnet-beta and testnet configuration 2019-04-26 23:24:35 -07:00
c81733b41a Add testnet-demo configuration 2019-04-26 22:59:26 -07:00
b6558a2ef3 Remove created lockfile 2019-04-26 21:36:20 -07:00
634d8e25ee testnet-deploy.sh updates 2019-04-26 21:29:42 -07:00
fea212e64e Initialize stopNetwork var 2019-04-26 21:10:36 -07:00
e3ab76f1a7 Pin recommended release version (#4021) 2019-04-26 21:10:31 -07:00
87f1bd58b9 Reduce submit frequency of counters that are very frequent and killing metrics DB (#4027) 2019-04-26 20:37:40 -07:00
a056c1f18f Don't send packets when msgs len is 0 (#4030)
And don't send metrics every iteration.
2019-04-26 17:27:31 -07:00
8b34fd2c75 Fix warnings on nightly (#4028) 2019-04-26 16:25:13 -07:00
b912ee7fdf Nit: Spelling (#4025) 2019-04-26 16:02:37 -07:00
3cf708f019 nit: remove copyposta (#4024) 2019-04-26 16:02:13 -07:00
070e0e9613 Skip *de*serializing too 2019-04-26 14:43:07 -07:00
3e678511d2 Add enable/disable key value pairs into the steps block (#4018) 2019-04-26 14:26:05 -06:00
4ce2105548 Switch from a S3 URL to release.solana.com for release assets (#4017)
automerge
2019-04-26 13:06:55 -07:00
721c6a7e2d Update metrics dashboard (#4012)
automerge
2019-04-26 10:32:49 -07:00
08f0fb1e14 Implement working lockfile for testnet lockout (#4013) 2019-04-26 11:22:23 -06:00
f5f5281f85 Add on-demand functionality to all testnets (#4003)
* Add on-demand functionality to all testnets
2019-04-26 10:02:23 -06:00
1684a7bd18 Move validators from testnet-beta to testnet (#4011)
* Move validators from testnet-beta to testnet

* Move testnet influxdb datasource to influxcloud
2019-04-26 09:02:12 -07:00
8b1724bb70 Serialize blocktree writes by locking the database (#4008)
Move several private methods to free functions
2019-04-26 10:52:10 -05:00
eebdfe8d73 wait for network recovery after restart (#4000) 2019-04-26 07:30:52 -07:00
82776b333d Merge the "cloud" grafana dashboard into the normal dashboard (#4007)
automerge
2019-04-25 21:14:36 -07:00
e71ab55288 Rename in-tree program_ids to be base-58 human readable (#4001) 2019-04-25 17:58:49 -07:00
fd60ef8a8d Allow metrics rate to differ from log rate (#3993)
And reduce metrics rate for exchange contract counters.
Since we can go 10s-100s thousands of contracts per second,
some metrics would be dropped if submitting every time.
2019-04-25 16:58:49 -07:00
aa0b67c93c Use newer blockhash for recent_confirmed_blockhash api (#3995)
Oldest blockhash is sometimes too old and does not allow
for transactions to go through.
2019-04-25 16:57:25 -07:00
15aa07f2a0 Fix node count metrics (#3997)
- the count was truncated to avalanche neighborhood size
2019-04-25 13:47:38 -07:00
e4536621df Log all uncommittable errors on validator (#3999) 2019-04-25 13:37:30 -07:00
a3c302c36a Add signature polling to SyncClient (#3996)
automerge
2019-04-25 12:46:40 -07:00
d12705f9b0 Remove wait loops in non-GPU instance creation and add SSD option as default disk type (#3992) 2019-04-25 13:43:42 -06:00
0add5c1dc8 Move testnet buildkite env variables back into the tree (#3989) 2019-04-25 11:44:58 -07:00
a9e63455a1 Get blockhash every batch and don't wait for tx threads (#3994)
* Get blockhash every batch and don't wait for tx threads

* nudge
2019-04-25 11:20:08 -07:00
4dc0495a1b Fix tar version check 2019-04-25 11:16:49 -07:00
5a79676b8a Custom error decoder (#3783)
automerge
2019-04-25 10:29:44 -07:00
b67b0bff05 Do not enable rpc exit on the blockstreamer node (#3977) 2019-04-25 09:30:59 -07:00
4c200635b7 Shuffle initial mention of solana-gossip (#3991)
automerge
2019-04-25 09:30:30 -07:00
b98200aca4 Use rm -rf (#3990) 2019-04-25 08:58:34 -07:00
d59c1cd412 Expose Rpc methods to rpc_request (#3988)
* Add new rpc methods to rpc-request

* A-Z
2019-04-25 08:52:53 -06:00
c4d9dff590 Cherry-pick #3934 (#3982)
* Fix inserting bogus is_last blobs into blocktree

* Check for pre-existing blob before insert

* Ignore test that performs concurrent writes on blocktree as that is not supported
2019-04-25 00:04:49 -07:00
cf91ff8694 Remove Thin Client from storage stage (#3976)
automerge
2019-04-24 22:34:10 -07:00
e867ce0944 Find unique zones and delete nodes in each zone (#3978) 2019-04-24 17:50:42 -07:00
29a25990d3 Add provision in testnet scripts to ignore validator nodes that failed to bootup (#3972)
* Skip writing to config file if the node didn't bootup
* Detect dead nodes quicker
2019-04-24 16:23:26 -07:00
9a40ad76bd Fix race in erasure metadata tracking (#3962)
* Fix erasure metadata race condition

* make erasure return the underlying error without wrapping it in the `solana::Error` type

* Add metric for erasure failures

* add tests to `ErasureMeta` indexing logic

* Add test to ensure erasure recovery failures don't cause panics
2019-04-24 17:53:01 -05:00
54b44977e0 Lower test time (#3967) 2019-04-24 12:19:31 -07:00
9c7ccc0e2b More metrics to track memory usage (#3966)
automerge
2019-04-24 11:11:30 -07:00
7710ef8b2b Bump num-derive from 0.2.4 to 0.2.5 (#3960)
Bumps [num-derive](https://github.com/rust-num/num-derive) from 0.2.4 to 0.2.5.
- [Release notes](https://github.com/rust-num/num-derive/releases)
- [Changelog](https://github.com/rust-num/num-derive/blob/master/RELEASES.md)
- [Commits](https://github.com/rust-num/num-derive/compare/num-derive-0.2.4...num-derive-0.2.5)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-24 11:50:26 -06:00
c969975fde lockfree storage (#3963) 2019-04-24 11:51:57 -05:00
3eed6a6090 Annotate testnet buildkite logs with blockexplorer URL (#3964)
automerge
2019-04-24 08:09:37 -07:00
1661a7a55f Correct variable name 2019-04-24 07:39:29 -07:00
6293d324db Spellnig 2019-04-24 07:39:29 -07:00
c1ecfec3b0 Bump stable build timeout 2019-04-23 20:29:14 -07:00
05b4dbf148 Document an alternative mechanism to locate the validator's vote id 2019-04-23 19:35:20 -07:00
4efada6d84 Update keygen.rs 2019-04-23 19:24:42 -07:00
23c01473a0 Use cache for dll symbols (#3950)
Speeds up loaded programs.
2019-04-23 17:25:03 -07:00
f2e2106f62 Bench exchange tweaks (#3957) 2019-04-23 16:48:17 -07:00
0cbac26591 Add genesis blockhash to blobs (#3953) 2019-04-23 16:24:44 -07:00
4e7e5ace9d Add support for Azure instances in testnet creation (#3905)
* Add support for Azure instances in testnet creation

* Fixup

* Fix shellcheck errors

* More shellcheck and cleanup node creation and deletion

* More shellcheck and cleanup node creation and deletion

* Fixup instance wait API

* Fix revieew comments and add GPU installation extension
2019-04-23 16:41:45 -06:00
ab11327e34 Fix mismatch between leader/validator bank votability (#3942)
* Fix mismatch between leader/validator bank votability
2019-04-23 15:32:19 -07:00
3ba93aa8fe Facility to pass extra arguments to bench clients from net.sh command (#3952)
automerge
2019-04-23 15:13:29 -07:00
c309cd80aa Add getClusterNodes/getSlotLeader JSON RPC API (#3940)
* Minor cleanup

* Include _this_ node in the contact info trace

* Add getClusterNodes/getSlotLeader RPC API
2019-04-23 14:46:41 -07:00
d22a1c9b1f Use smaller batch size in sigverify stage if CUDA is not available (#3951) 2019-04-23 12:41:50 -07:00
29698fcd38 Cleanup stragglers from move-to-transfer rename (#3947) 2019-04-23 13:30:42 -06:00
7372ec9e1a Use poh would_be_leader check in banking stage to hold or forward txs (#3948) 2019-04-23 11:56:30 -07:00
840a64ee8b Optimize exchange contract (#3926) 2019-04-23 11:39:53 -07:00
524bc2b9a6 Bump hashbrown from 0.2.2 to 0.3.0 (#3931)
Bumps [hashbrown](https://github.com/Amanieu/hashbrown) from 0.2.2 to 0.3.0.
- [Release notes](https://github.com/Amanieu/hashbrown/releases)
- [Changelog](https://github.com/Amanieu/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/hashbrown/compare/v0.2.2...v0.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-23 10:15:33 -07:00
62a29a41d1 Bump tar from 0.4.22 to 0.4.23 (#3944)
Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.22 to 0.4.23.
- [Release notes](https://github.com/alexcrichton/tar-rs/releases)
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.22...0.4.23)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-23 10:15:12 -07:00
5406d82d89 fix race in get_exclusive_storage() and load() (#3941)
* Revert "Revert "account storage is not in sync with the index after gc (#3914)" (#3936)"

This reverts commit 4f47fc00bc.

* fix get_exclusive_storage

* clippy
2019-04-23 09:56:36 -07:00
de6af95061 Process forwarded packets only when the node is about to be the leader (#3935)
* Tests and metrics
2019-04-22 19:49:32 -07:00
43f7cd8149 Fix Retransmit slamming the leader with its own blobs (#3938) 2019-04-22 18:41:01 -07:00
69e67d06a7 Default to Docker based testnet deployment on unsupported Ubuntu versions (#3937)
* Run docker if Ubuntu version is unsupported

* ShellCheck fixes
2019-04-22 18:22:43 -07:00
4f47fc00bc Revert "account storage is not in sync with the index after gc (#3914)" (#3936)
This reverts commit 101d6b92ee.
2019-04-22 17:14:41 -07:00
4b04c37c36 verify that blobs match a known leader for the slot (#3927)
* validate that blobs match a known leader for the slot

* clippy
2019-04-22 15:21:10 -07:00
b27b515186 Add more dashboard text to metrics readme (#3925) 2019-04-22 14:55:19 -07:00
05bcb7f292 Add stop node command to solana-gossip (#3928) 2019-04-22 14:51:20 -07:00
95a16426f3 Cleanup bench-exchange (#3919)
* bench-exchange changes

Generate new keypair for each bench-exchange
Add metrics
Tweak network sleep parameters for better reliability.

* Bench-exchange contract metrics
2019-04-22 13:16:28 -07:00
bec094bb3e Start bench tps clients as default (#3917) 2019-04-21 20:18:52 -07:00
af9ebf1d1a Add status logging while processing a ledger (#3916) 2019-04-20 20:17:57 -07:00
6f2f7018e8 Update testnet-participation.md 2019-04-20 19:14:07 -07:00
101d6b92ee account storage is not in sync with the index after gc (#3914)
* account storage is not in sync with the index after gc

* builds

* clippy fmt

* test

* purge dead forks on store

* rm println

* also fixed count_stores

* comments
2019-04-20 20:50:50 -05:00
349e8a9462 Ensure forwarded Blobs don't break Erasure (#3907) 2019-04-20 16:44:06 -07:00
c0bffb56df Update Avalanche to use Epoch Stakes (#3900) 2019-04-19 22:31:40 -07:00
970cc32e65 Fix Data Plane computation when stakes are equal (#3913) 2019-04-19 21:07:21 -07:00
3ab492ccf8 save erasure set size, initialize coding blob erasures with that size (#3910)
* save erasure set size, initialize coding blob erasures with that size

* fixup

* fixup
2019-04-19 20:22:51 -07:00
d83a71d89f More AWS regions for testnet deployment (#3911)
- also some minor fixes to gce.sh
2019-04-19 17:46:14 -07:00
efbb573316 add an env::var driven localcluster test (#3906) 2019-04-19 15:47:03 -07:00
85554087d1 treat negatives like zero instead of crashing out (#3899) 2019-04-19 15:46:39 -07:00
c3155a6e39 silence sigverify disabled, make disabling sigverify easier (#3901)
* silence sigverify disabled, make disabling sigverify easier

* fixup
2019-04-19 14:18:19 -07:00
4abe95abec Helper function for filtering/creating clients in bench-exchange (#3903) 2019-04-19 14:05:07 -07:00
e0acd48944 Write bench-tps in terms of client (#3904)
* Write bench-tps in terms of client

* Add transactions_addr method for logging

* Move cluster config outside do_bench_tps

* Add BankClient test
2019-04-19 15:04:36 -06:00
afb00432d4 Add BankClient support to bench-exchange (#3902) 2019-04-19 13:18:20 -07:00
320bd66c84 handle zero num_will_fit (#3892)
* handle zero num_will_fit

* clippy
2019-04-19 12:02:33 -07:00
1a9ac62f60 Add bench-exchange support to the net framework (#3893) 2019-04-19 09:56:01 -07:00
809b051f10 Allow thin clients to be passed across thread boundaries (#3887)
* Remove ThinClient wrapper

* Allow RpcClient (and ThinClient) to be passed across thread boundaries

* Pass clients, not constructors

* Fix bad rebase
2019-04-19 08:54:21 -06:00
baac21209e Recreate SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_unknown_linux_gnu (#3895) 2019-04-19 07:39:41 -07:00
5fb8baed04 Process async BankClient transactions in batches (#3738)
* Process async transactions in batches

This aims to process transactions at least as fast as LocalCluster

* Add benchmark
2019-04-19 07:29:07 -06:00
512bfc93cb Add a cache for leader schedules (#3841)
* Add a cache for leader schedules
2019-04-19 02:39:44 -07:00
0f88872650 Compatible network is now default (#3896) 2019-04-18 23:19:03 -07:00
f4e40d2c41 Add bench-exchange tx send metrics (#3890) 2019-04-18 22:31:25 -07:00
6eac5951ed Revert "Revert "revert-revert-erasure and erasure fixes (#3833)" (#3855)" (#3889)
This reverts commit 596f611ede.
2019-04-18 21:56:43 -07:00
475a74d37f Reduce packet recv batches (#3894)
* Reduce packet recv batches

* Fix type
2019-04-18 19:24:37 -07:00
b8ee952135 Dedup drone code (#3885) 2019-04-18 19:06:56 -06:00
15bed29afa Add rpc request debug to make_rpc_request (#3888) 2019-04-18 17:04:40 -07:00
6dbe7e8bee Better drone error when cap is hit. (#3884)
* Better drone error when cap is hit.

* Update drone/src/drone.rs

Co-Authored-By: sakridge <sakridge@gmail.com>
2019-04-18 16:05:45 -07:00
2cd556e43c Add drone cap parameter (#3876) 2019-04-18 15:42:20 -07:00
060793f451 Fix testnet automation scripts (#3886)
- missing machine type since change in gce.sh
2019-04-18 15:12:35 -07:00
7e409a13cd Ack on empty Gossip Pull Responses and keep Entrypoint around (#3881)
* Ack on empty Gossip Pull Responses and keep Entrypoint around

* Address comments and fix test

* Update core/src/cluster_info.rs

Co-Authored-By: sagar-solana <sagar@solana.com>

* Update core/src/cluster_info.rs

Co-Authored-By: sagar-solana <sagar@solana.com>
2019-04-18 15:12:17 -07:00
aab410380e Fix net for macos and local (#3872) 2019-04-18 14:49:35 -07:00
67b8ad6a0f fix entries.to_blobs() (#3882)
* * rename Entry::serialized_size() to Entry::to_blob_size() to better
    reduce confusion with bincode, et al. and to better reflect its
    real meaning

* fix implementation of to_blob_size() to actually return what happens
    when we do entries.to_blobs() (i.e. we serialize Vec<Entry>, not Entry)

* update tests to be more rigorous

* clippy
2019-04-18 14:45:41 -07:00
c1e39a3b98 git ignore more (#3870) 2019-04-18 14:23:34 -07:00
7e1a7b1f64 Add bench-exchange to installed bins (#3883)
Need to run exchange clients on remote machines.
2019-04-18 13:55:41 -07:00
a9cfae486c Revert-revert migrate to ed25519-dalek crate (#3877)
* Revert "Revert "Migrate from ring to ed25519-dalek, take 2 (#3844)" (#3868)"

This reverts commit 6a878602f2.

* Fix Signature::verify method
2019-04-18 14:37:20 -06:00
8514d27c2f Update testnet-participation.md 2019-04-18 13:16:15 -07:00
8999bfef65 Try to delete nodes in all cloud zones (#3874) 2019-04-18 13:16:14 -07:00
96425fb520 Don't panic the drone on a request that ends in error. (#3869) 2019-04-18 12:18:31 -07:00
ce505d24b1 Bump ws from 0.7.9 to 0.8.0 (#3866)
Bumps [ws](https://github.com/housleyjk/ws-rs) from 0.7.9 to 0.8.0.
- [Release notes](https://github.com/housleyjk/ws-rs/releases)
- [Changelog](https://github.com/housleyjk/ws-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/housleyjk/ws-rs/compare/v0.7.9...v0.8.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-18 13:16:30 -06:00
f2187780d2 Do not forward vote transactions (#3871) 2019-04-18 11:18:49 -07:00
6a878602f2 Revert "Migrate from ring to ed25519-dalek, take 2 (#3844)" (#3868)
This reverts commit e9b82bacda.
2019-04-18 11:47:34 -06:00
f8543a268f solana-gossip now displays other spy nodes and contact info age (#3867) 2019-04-18 09:48:21 -07:00
e9b82bacda Migrate from ring to ed25519-dalek, take 2 (#3844)
* Migrate from ring to ed25519-dalek

* Move gen_keypair_file test to a more appropriate location

* Fixup bench-exchange and add helper fn for single deterministic keypair

* Update golden
2019-04-18 10:38:32 -06:00
684e1c73dd Allow for custom cpu config on gce and use 20gb ram for clients (#3856) 2019-04-18 09:36:11 -07:00
901c74b653 Add packages and fix publish script (#3839)
* Add packages and fix publish script

* Fixup
2019-04-18 09:24:18 -06:00
2c0afe71b2 minor grooming 2019-04-18 07:31:42 -07:00
2f4a3ed190 Use a separate channel to process votes in banking stage (#3861)
- This will help expedite the vote processing on peer nodes
2019-04-17 21:07:45 -07:00
26a7eb6fa5 Don't use barrier transaction in testnet for perf testing (#3862) 2019-04-17 20:29:36 -07:00
aa21f5343a Remove broken read().unwrap() call to a non-shared packet 2019-04-17 21:24:40 -05:00
9c2809db21 Delete SharedPackets (#3843)
* Delete SharedPackets

* Fix bench and sigverify
2019-04-17 18:15:50 -07:00
9ccd362461 Correct ./net.sh sanity argument order 2019-04-17 18:10:38 -07:00
596f611ede Revert "revert-revert-erasure and erasure fixes (#3833)" (#3855)
This reverts commit 6bef16a6a1.
2019-04-17 18:04:30 -07:00
78d5ace754 Refactor multinode-demo/ scripts to avoid shipping fullnode-x.sh (#3835) 2019-04-17 18:03:58 -07:00
2b3218b5f2 Fix flaky tests by waiting for test node to boot (#3845) 2019-04-17 17:50:34 -07:00
d0fb55d9b1 Allow testnet creation with no validator nodes (#3846) 2019-04-17 17:38:18 -07:00
a2c8e3952f Fixes to TPS calculation and reporting (#3836)
Fixes to TPS calculations and reporting
2019-04-17 15:37:01 -07:00
beb8c7914e Disable testnet-sanity ledger verification, too slow 2019-04-17 15:19:37 -07:00
6bef16a6a1 revert-revert-erasure and erasure fixes (#3833)
* fix erasure, more tests for full blobs, more metrics

* Revert "Revert "Use Rust erasure library and turn on erasure (#3768)" (#3827)"

This reverts commit 4b8cb72977.
2019-04-17 15:13:54 -07:00
e03215c4c0 Remove iterations with leader rotation disabled 2019-04-17 15:07:51 -07:00
8d1fd29fa6 Add readme (#3838) 2019-04-17 14:42:04 -07:00
46f655eddd Add .gitignore to bench-exchange (#3837) 2019-04-17 14:34:04 -07:00
ca36a6f4e0 Run sanity only in the zone that contains the bootstrap leader and blockstreamer nodes (#3828) 2019-04-17 14:25:40 -07:00
fdb12b54fa Run multinode-demo from anywhere (#3831) 2019-04-17 14:23:32 -07:00
09dd4bb702 Fix build (#3834) 2019-04-17 15:17:04 -06:00
01657ddfe7 packet.rs optimizations (#3818)
* packet.rs optimizations

* remove redundant and aggressive metric submission

* remove metrics submit(), get compiling again, honor log level in inc()
2019-04-17 14:14:57 -07:00
51a2988bb2 Revert "Rename programs to instruction_processors (#3789)" (#3824)
This reverts commit 34344982a9.
2019-04-17 15:05:49 -06:00
083090817a Fix DuplicateSignatures caused by races on frozen banks (#3819)
* Duplicate parent account locks into children in new_from_parent, check parent locks in lock_account()
2019-04-17 13:45:33 -07:00
f3676e2d03 Enable bench exchange test (#3830) 2019-04-17 13:37:02 -07:00
4b8cb72977 Revert "Use Rust erasure library and turn on erasure (#3768)" (#3827)
This reverts commit b9bb5af4a5.
2019-04-17 12:52:12 -07:00
2518e95fb0 Add bench-exchange (#3826) 2019-04-17 11:28:26 -07:00
bc17edcda3 Add --keypair to avoid writing a new one to ~ in CI 2019-04-17 10:12:18 -07:00
eb185b9ea5 testnet-beta sanity no longer tries to check inactive zones 2019-04-17 09:30:41 -07:00
aa6c82cfdc Add show-vote-account command (#3814) 2019-04-17 07:45:07 -07:00
b9bb5af4a5 Use Rust erasure library and turn on erasure (#3768)
* split out erasure into new crate; add implementation using rust reed-solomon-library

* Track erasures with a &[bool] instead of indexes

* fix bug that reported the number of erasures incorrectly

* Introduce erasure `Session` for consistent config

* Increase test coverage; fix bugs

* Add ability to remove blobs from erasure meta tracking. test added

* Track deletion of coding blobs in blocktree via ErasureMeta. Added to
test

* Remove unused functions in blocktree

* add randomness to recovery thread to exercise recovery due to either new
data or coding blobs

* Add unit test for ErasureMeta index handling

* Re-enable test in broadcast stage
2019-04-16 23:00:24 -05:00
1e20d449ce bank_height / slot is the block drop rate (#3816)
* bank_height/slot would give is the block drop rate

* use metrics
2019-04-16 19:35:38 -07:00
e94f268346 reduce sigverify verbosity (#3813) 2019-04-16 18:25:53 -07:00
7ec198b9cc Minor doc fixes++ 2019-04-16 17:45:48 -07:00
b2e762ccc6 Minor doc fixes 2019-04-16 17:43:52 -07:00
bee411e826 Preserve extra dependency annotations (optional=,features=) during version bump (#3810) 2019-04-16 15:12:10 -07:00
34344982a9 Rename programs to instruction_processors (#3789)
* Rename programs to instruction_processors

* Updates around the code base to support instruction_processors rename

* Kabab instruction_processors

* Update Cargo.toml files and scripts to use instruction-processors

* Update Cargo.toml to use instruction-processors

* Update CI scripts to use instruction-processors
2019-04-16 22:39:00 +02:00
f73d38739a Split AccountsDB from Accounts (#3808)
Split AccountsDB from Accounts
2019-04-16 13:32:22 -07:00
63d66ece57 net/ testnet nodes now stake more lamports (#3812)
* Add --bootstrap-leader-lamports

* Generalize --no-stake into --stake NUM

* Use a large stake for net/ fullnodes

* Setup vote account before starting fullnode to avoid mixed log output
2019-04-16 13:03:01 -07:00
a4b5493ba1 Document unsafe usage in AppendVec (#3804)
* document unsafe usage

* clippy
2019-04-16 10:53:37 -07:00
8d613f3977 Selectively deploy beta testnet to GCE/AWS or both clouds (#3805) 2019-04-16 10:40:30 -07:00
0ff2bfdd0c Fewer unsafe hacks for AppendVec (#3801)
* storage account changes

* cleanup

* checks

* comments

* clippy

* tests

* woot!

* comments

* benches
2019-04-16 08:50:05 -07:00
141e25d567 Bump hashbrown from 0.2.1 to 0.2.2 (#3800)
Bumps [hashbrown](https://github.com/Amanieu/hashbrown) from 0.2.1 to 0.2.2.
- [Release notes](https://github.com/Amanieu/hashbrown/releases)
- [Changelog](https://github.com/Amanieu/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/hashbrown/compare/v0.2.1...v0.2.2)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-16 06:49:02 -07:00
c67cc694ae Remove stake from ./net sanity ephemeral validator (#3797) 2019-04-15 21:42:25 -07:00
d77359914f Log the spy node id by default for better debug (#3796) 2019-04-15 20:58:37 -07:00
9293a54234 Remove stray + 2019-04-15 20:28:11 -07:00
d9983905b3 Cargo.lock 2019-04-15 20:28:07 -07:00
3dc47a46d5 Revert "Revert "disable staking of blockstreamer node""
This reverts commit 03da63b41b.
2019-04-15 20:11:00 -07:00
8638b3bb19 Update Cargo.toml files for version = 0.14.0 2019-04-16 02:50:20 +00:00
819a0c5c7e Update testnet automation script to reflect changes in metrics (#3779) 2019-04-15 18:56:04 -07:00
7afd8644b3 Clarify release instructions (#3792) 2019-04-15 19:05:15 -06:00
68fc303b9b Rework Accounts for fast squash, hashing state and checkpoint recovery. (#3613)
* accounts rewrite

* ignore grow tests

* skip duplicate roots

* allow for a root race

* logger

* accounts_index tests

* tests

* tests
2019-04-15 17:15:50 -07:00
2bbed7727f Wait a bit for the funding transactions to go through (#3788) 2019-04-15 16:30:00 -07:00
63b1fd3675 Correctly fill out IP address for rpc ports (#3791) 2019-04-15 16:21:06 -07:00
3fcf03ff3e Refactor LocalCluster and add support for listener nodes (#3790) 2019-04-15 15:27:45 -07:00
80f3568062 Upgrade to Rust 1.34.0 (#3781)
* Upgrade to Rust 1.34.0

* Remove redundant closures

Thanks Clippy!
2019-04-15 15:56:08 -06:00
3e1214a871 Don't add reviewers to draft PRs (#3780) 2019-04-15 15:03:44 -06:00
149d809e86 Minor cli help cleanup (#3786) 2019-04-15 13:36:14 -07:00
784dbb00ab Bump reqwest from 0.9.14 to 0.9.15 (#3785)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.9.14 to 0.9.15.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.9.14...v0.9.15)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-15 13:31:33 -07:00
87aef92e71 Fix up bash array handling (#3771) 2019-04-15 13:25:44 -07:00
d026ebb83a Use tvu_peers() since validators no longer run an RPC port by default (#3784) 2019-04-15 13:25:09 -07:00
64c6f05da2 persist set_root() and use it in blocktree_processor to limit squashes (#3782)
* rename locktower's slot to epoch

* persist set_root() and use it in blocktree_processor to limit squashes
2019-04-15 13:12:28 -07:00
8963500aa8 Bump generic-array from 0.12.0 to 0.13.0
Bumps [generic-array](https://github.com/fizyk20/generic-array) from 0.12.0 to 0.13.0.
- [Release notes](https://github.com/fizyk20/generic-array/releases)
- [Changelog](https://github.com/fizyk20/generic-array/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fizyk20/generic-array/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-15 12:35:06 -06:00
175c0090de Bump hashbrown from 0.2.0 to 0.2.1
Bumps [hashbrown](https://github.com/Amanieu/hashbrown) from 0.2.0 to 0.2.1.
- [Release notes](https://github.com/Amanieu/hashbrown/releases)
- [Changelog](https://github.com/Amanieu/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/hashbrown/compare/v0.2.0...v0.2.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-15 12:18:44 -06:00
5c4689a326 rename locktower's slot to epoch (#3776) 2019-04-15 10:46:14 -07:00
5e2831f09e Disable cluster restart attempt 2019-04-15 09:59:53 -07:00
666882fbbd -r does not require an argument 2019-04-15 09:40:34 -07:00
6c9fba058b Reenable validator sanity check for testnet-{beta,edge} 2019-04-15 08:58:29 -07:00
0767c0c07f Add DNS resolution to cli tools 2019-04-14 21:25:46 -07:00
6859907df9 more rigorous erasure constants, comments (#3766)
* more rigorous erasure constants, comments

* new header size means new golden
2019-04-14 21:10:09 -07:00
de52747950 remove max_tick_height replicode (#3765) 2019-04-14 19:15:31 -07:00
bd1db51e07 delete db_window.rs, move contents to window_service, clean up process_blobs (#3746) 2019-04-14 18:52:05 -07:00
dd005fb50e fix broadcast to *always* call erasure generation, simplify generator, test slot reset better (#3764) 2019-04-14 18:12:37 -07:00
542bafeb71 groom packet.rs, add blob.data alignment (#3763) 2019-04-14 17:30:08 -07:00
e57a0ab05d test some bits (#3762) 2019-04-14 17:10:30 -07:00
2c745ce108 Shorten recv wait when there are buffered packets in banking stage (#3757)
- packets are buffered on leader rotation, when the next leader is
  unknown
- shortening the wait allows the banking stage to poll for next
  leader more frequently
2019-04-14 12:34:07 -07:00
f6aa90e193 Add fullnode --dynamic-port-range option 2019-04-14 07:08:29 -07:00
c7a7d6db84 Use |solana-keygen pubkey| instead of |solana-wallet address|
Same end result but solana-keygen is a smaller program that builds
faster
2019-04-14 07:08:29 -07:00
2277a39dd2 Default solana-gossip log-level to 'info' 2019-04-14 07:07:15 -07:00
ee35ed5250 Refactored buffered packet forwarding code (#3750)
- Added unit tests
- Don't consume packets if bank is not known
2019-04-13 23:19:54 -07:00
92b5e131fe Name sigverify threads 2019-04-13 11:24:36 -07:00
1f35779821 Add solana-install usage info 2019-04-12 17:08:18 -07:00
5b438d917d Create fullnode-x.sh wrapper script for use with |solana-install run ...| 2019-04-12 17:08:18 -07:00
bf4d5745c9 Symlink the entire release to preserve relative paths from bin/ 2019-04-12 17:08:18 -07:00
1e8f83a74a Use a better name for new api 2019-04-12 14:58:22 -07:00
1db80d79fc Update get recent blockhashes to return confirmed blockhashes only 2019-04-12 14:58:22 -07:00
1dac4c33b8 Change sigverify counter from entries to packets
batch or entries kind of useless since it can have some
variable number of packets
2019-04-12 13:19:46 -07:00
656b3139e3 see perf-libs all the time (#3748) 2019-04-12 08:38:14 -07:00
8b08fe265a AppendVec PR with using "/tmp" as the default directory and a random file (#3743)
* AppendVec with raw pointers
* fixed test target directory
2019-04-12 04:30:17 -07:00
29dc139a22 shellcheck 2019-04-11 17:39:04 -07:00
44ebfa736a Don't forward buffered packet to the same node (#3712)
- instead, process the packets
2019-04-11 17:23:45 -07:00
b001685e7b Added missing feature flag for erasure (#3741) 2019-04-11 15:25:32 -07:00
ca6290b117 remove wallet stuff, bootstrap node is already staked (#3744) 2019-04-11 15:16:38 -07:00
767e0a201e stak*->vote (#3740) 2019-04-11 14:52:56 -07:00
877ec08280 Send recent votes in Vote Transactions (#3734) 2019-04-11 14:48:36 -07:00
485013b7ce Revert "AppendVecs that can return references and read/append without locks (#3713)"
This reverts commit f669ae5868.
2019-04-11 14:47:30 -07:00
efd19b07e7 implement erasure-based recovery inside blocktree (#3739)
* implement recover in blocktree

* erasures metric

* erasure metrics only

* fixup
2019-04-11 14:14:57 -07:00
d31989f878 CustomError from Vec->u32 2019-04-11 13:59:48 -07:00
f669ae5868 AppendVecs that can return references and read/append without locks (#3713)
* AppendVec with raw pointers

* appendvecs

* imports

* review

* review comments

* clippy
2019-04-11 13:16:56 -07:00
a28c3b0e9a Consume Bank in BankClient
This will allow BankClient to spin up a thread to use the Bank.
It'll also ease the transaction from BankClient to ThinClient since
it won't let you depend on Bank.

Drawback, you the transition from Bank to BankClient will be harder
because the Bank methods are inaccessible.
2019-04-11 12:16:33 -07:00
0aa05158c9 Adjust noop/failure program names to be consistent with all other programs 2019-04-11 11:59:56 -07:00
787dc5748a Fixed DuplicateSigs (#3727)
* Fixed DuplicateSigs by not recording errors in signature cache of bank
2019-04-11 11:51:34 -07:00
8ada4bfd1f Remove test now covered by Vote crate 2019-04-11 10:53:11 -07:00
5d4624e75f Use Bank::add_instruction_processor to bypass manual build step 2019-04-11 10:53:11 -07:00
2f1b0bf4f5 Add solana-install deployments to the testnets 2019-04-11 10:03:35 -07:00
e1d5bb1a26 add redundant broadcast (#3724)
* add redundant broadcast

* crank up to full redundancy

* Update broadcast_stage.rs

* Update broadcast_stage.rs

* Update broadcast_stage.rs

* Update broadcast_stage.rs
2019-04-11 09:15:17 -07:00
d0f46d6a8a Cleanup client traits and create super trait (#3728) 2019-04-11 00:25:14 -07:00
4b6c0198ad reset coding generator on slot boundaries (#3726) 2019-04-10 18:18:55 -07:00
f1e7237c09 vote_api cleanup (#3710)
* vote_api cleanup

* fixups

* fixup

* remove unused code

* revert removal of serialize and deserialize

* ...

* increase coverage, bootstrap staking

* Sagar's STAKE to my VOTE
2019-04-10 17:52:47 -07:00
1b5845ac3e Fix getting votes from gossip (#3723) 2019-04-10 17:16:08 -07:00
58a049ebe5 pick up logs as artifacts (#3721) 2019-04-10 17:05:39 -07:00
c0808d01f8 Add tests 2019-04-10 15:51:00 -07:00
7fd5e51168 Make sure bank 0 is votable and correctly designate signer 2019-04-10 15:51:00 -07:00
d2ea782372 Always use bootstrap vote account for leader 2019-04-10 15:51:00 -07:00
e6f02d1a10 Use latest release for testnet doc (#3711)
* Use latest release for testnet doc

* Clean up markdown
2019-04-10 15:01:37 -07:00
894135a084 Less pub in PohRecorder 2019-04-10 12:50:45 -07:00
df9cf92782 testnet-participation.md is now /implemented/ 2019-04-10 12:26:47 -07:00
f243a96e01 Remove testnet/metrics server debug info from book 2019-04-10 12:26:47 -07:00
842d146b0d Limit USE_INSTALL scope 2019-04-10 11:50:23 -07:00
81d43c57a2 Add missing feature flags to gossip (#3708) 2019-04-10 06:52:46 -07:00
7da4142d33 Process votes from gossip only in leader node (#3707) 2019-04-09 22:06:32 -07:00
88e5b14afc Exit faster on sanity failures 2019-04-09 17:16:15 -07:00
0b95a5c121 Include blockstreamer node in sanity 2019-04-09 16:52:57 -07:00
62c28a8592 Bump reqwest from 0.9.13 to 0.9.14
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.9.13 to 0.9.14.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.9.13...v0.9.14)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-09 16:22:17 -07:00
b80c6840da Metrics dashboard publish script updates for influx cloud 2019-04-09 15:44:01 -07:00
003fd6545c Logging for unexpected validator errors (#3697) 2019-04-09 15:05:43 -07:00
393ed978d1 Update testnet monitor to use influx cloud end point (#3700) 2019-04-09 14:56:21 -07:00
2c93062f54 Improve banking_stage performance messages
Use transaction count instead of batch count,
and set the recv_start from when we finished processing
the previous batch to get a more accurate number.
2019-04-09 14:54:12 -07:00
7b2abf2087 Update count for the right store (#3683) 2019-04-09 13:48:13 -07:00
a5254a3f7a Add TESTNET_TAG Env var to buildkite (#3692)
* Add TESTNET_TAG Env var to buildkite
2019-04-09 13:00:45 -07:00
dc6c34da5d Fast-track vote signature verification and processing (#3695) 2019-04-09 12:57:12 -07:00
d4eebcc2aa Check for frozen in confirm_forks (#3678) 2019-04-09 11:45:38 -07:00
4f232cbc27 Make MAX_RECENT_BLOCKHASHES <= MAX_HASH_AGE_IN_SECONDS (#3679)
* Make MAX_RECENT_BLOCKHASHES == MAX_HASH_AGE_IN_SECONDS
2019-04-09 11:45:25 -07:00
76e524ae48 Remove check for 0 additional nodes
Network with 1 leader is valid.
2019-04-09 11:16:55 -07:00
6ac919c71a Set warn log level only for perf testnets 2019-04-09 11:09:16 -07:00
1ba4806f8c Document recent -z and -x command-line arg changes 2019-04-09 10:39:55 -07:00
20a2c59b70 Reduce udp read/write buffer sizes
With 18.04, these large values cause packet errors and mess up the system.
2019-04-08 15:21:45 -07:00
6540fa9121 Add sleep for check_signature 2019-04-08 15:09:02 -07:00
21287ba554 Bump clap from 2.32.0 to 2.33.0
Bumps [clap](https://github.com/clap-rs/clap) from 2.32.0 to 2.33.0.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-08 12:56:44 -07:00
7295a84d69 Bump bincode from 1.1.2 to 1.1.3 (#3672)
Bumps [bincode](https://github.com/TyOverby/bincode) from 1.1.2 to 1.1.3.
- [Release notes](https://github.com/TyOverby/bincode/releases)
- [Commits](https://github.com/TyOverby/bincode/compare/v1.1.2...v1.1.3)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-08 12:55:18 -07:00
483cc2fa4e Support old repair strategy for reparing slots in a range for supporting replicators (#3665) 2019-04-08 12:46:23 -07:00
e551f6b552 Support settable drone lamport cap (#3675) 2019-04-08 12:37:01 -07:00
44b391096d Configurable local cluster native processors (#3676) 2019-04-08 11:15:58 -07:00
d45d8e9670 s/credit/read/ 2019-04-08 08:39:59 -07:00
88bda58836 remove unused (#3674) 2019-04-08 04:50:42 -07:00
79bf3cf70d add rewards math (#3673)
* add rewards math

* fixup
2019-04-07 21:45:28 -07:00
72b7419e1c Define list of valid cloud regions for GCE and AWS (#3670) 2019-04-07 14:29:09 -07:00
7baff0920c Propagate cloud env variables to buildkite job 2019-04-07 11:48:25 -07:00
d9ecc278b4 Configure cloud zones and nodes from buildkite for beta testnet (#3666) 2019-04-07 08:25:34 -07:00
0904df327d Parallelize cloud node deployment commands in case of multiple zones (#3657) 2019-04-07 08:13:48 -07:00
444e87f888 Fix metric (#3664) 2019-04-06 21:57:01 -07:00
20aa4434e2 Fix repair (#3581)
Add DetachedHeads repair protocol

Add DetachedHeads repair test

Repair starting from root
2019-04-06 19:41:22 -07:00
03da63b41b Revert "disable staking of blockstreamer node"
This reverts commit 42d8a7d9e7.
2019-04-06 08:57:06 -07:00
878a842611 Move append_vec bench to the crate with append_vec (#3650)
* Move append_vec bench to the crate with append_vec

* Use black_box to tell the compiler not to optimize away test data

```
pub fn black_box<T>(dummy: T) -> T {
    unsafe {
        let ret = std::ptr::read_volatile(&dummy);
        std::mem::forget(dummy);
        ret
    }
}
```

* Revert "Use black_box to tell the compiler not to optimize away test data"

This reverts commit 5610b8ee95.

* Use black_box to tell the compiler not to optimize away test data

* Create bench directories
2019-04-06 07:18:56 -06:00
f3eda38b65 Fix broken lockout doubling 2019-04-05 23:15:46 -07:00
68e21911eb Remove redundant transfer_signed 2019-04-05 22:04:32 -07:00
95cc36af96 Impl SyncClient and AsyncClient for ThinClient 2019-04-05 22:04:32 -07:00
d3c4e4f7b3 Update docs 2019-04-05 22:09:29 -06:00
4068612300 Remove RpcSignatureStatus 2019-04-05 22:09:29 -06:00
f349c1f0dc Get everything off RpcSignatureStatus 2019-04-05 22:09:29 -06:00
90c1300bb6 Plumb TransactionError through Rpc 2019-04-05 22:09:29 -06:00
569a289a6f Cargo.lock, serde_derive 2019-04-05 22:09:29 -06:00
89efe67e73 Fix the ordering of beta testnet zones 2019-04-05 17:53:31 -07:00
c3654b0f65 Add sdk benches to ci
And add `-a` to `tee` for more reliable copypasta.
2019-04-05 17:58:11 -06:00
f5f4434e0a Remove unnecessary lock in sigverify 2019-04-05 16:57:45 -07:00
d30049b8eb test for debit of TX fees on full process_transaction() (#3643)
* fix double debit of TX fees

* add test that fails when removing that line

* put that line back in

* comments
2019-04-05 16:55:58 -07:00
42d8a7d9e7 disable staking of blockstreamer node
- this will stop it from entering leader rotation schedule
2019-04-05 16:48:52 -07:00
adcda3c715 Remove airdrop dependency from replicators 2019-04-05 16:11:39 -07:00
a5b5248a09 move vote_accounts up (#3647) 2019-04-05 14:23:00 -07:00
3fcca5bc0a Suppress shellcheck array expansion warnings 2019-04-05 13:25:14 -07:00
9d4c6f6aaa Appease shellcheck 2019-04-05 13:25:14 -07:00
d570b08134 Clean up array expansion 2019-04-05 13:25:14 -07:00
8b6d7129f3 Fix option flag lettering 2019-04-05 13:25:14 -07:00
50444181c5 Fix arg array ordering and rename network-name option 2019-04-05 13:25:14 -07:00
0c51f156ae Reverse order of zone arg array building 2019-04-05 13:25:14 -07:00
fe2fb40d88 Add multi-region deploy functionality 2019-04-05 13:25:14 -07:00
9ba0439593 Add multi-region deploy functionality 2019-04-05 13:25:14 -07:00
b33a1fa019 Fix clippy errors 2019-04-05 12:22:10 -07:00
63fd4222aa Fix testnet sanity check for beta testnet 2019-04-05 12:22:10 -07:00
ef5df6f3fe Add server specification 2019-04-05 11:44:57 -07:00
2f90f9fbd4 Version all jsonrpc crates, in core too 2019-04-05 11:44:57 -07:00
12b099ea78 Bump jsonrpc-core from 10.1.0 to 11.0.0
Bumps [jsonrpc-core](https://github.com/paritytech/jsonrpc) from 10.1.0 to 11.0.0.
- [Release notes](https://github.com/paritytech/jsonrpc/releases)
- [Commits](https://github.com/paritytech/jsonrpc/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-05 11:44:57 -07:00
9f046a023e move transaction_count up (#3618)
* move transaction_count up

* fixup
2019-04-05 10:42:25 -07:00
46e6911ec1 Add get_signature_status() to SyncClient
And move bank::Result to transaction module.
2019-04-05 10:22:05 -07:00
d3844ef32a Add AsyncClient 2019-04-05 10:22:05 -07:00
4507dca342 Boot exchange_transaction. No tests depend on it. 2019-04-05 11:10:57 -06:00
c2fdd1362a bump release version in testnet participation document 2019-04-05 08:30:42 -07:00
4ea19b90a4 Fix update_ancestor_stakes in locktower (#3631)
* Fix update_ancestor_stakes in locktower

* Add test for vote threshold
2019-04-05 03:05:31 -07:00
9cd555cad5 AWS script change for additional zones and regions 2019-04-04 15:59:59 -07:00
ed78c8d3bb Fix beta testnet launch script 2019-04-04 15:16:01 -07:00
0b23af324b Refactor Storage Program (#3622)
* Refactor Storage Program

* Replace KeyedAccount trait with StorageAccount struct

* Implement State for Account, not StorageAccount

* Make State trait more generic

* Move validation check into function
2019-04-04 12:01:09 -07:00
1598a02a7a Wrap all client errors with TransportError 2019-04-04 12:00:19 -06:00
167f5bdc58 Add get_balance() and get_account_data() to SyncClient
Migrate tests to use them.
2019-04-04 12:00:19 -06:00
5cd7bccdf3 Add SyncClient and use from BankClient 2019-04-04 12:00:19 -06:00
acbc261891 Add gossip to build script, and fix bash strings 2019-04-04 00:18:48 -07:00
f97f0c4758 Bump serde_derive from 1.0.89 to 1.0.90
Bumps [serde_derive](https://github.com/serde-rs/serde) from 1.0.89 to 1.0.90.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.89...v1.0.90)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-03 19:54:50 -07:00
e6ac5bc546 Bump serde from 1.0.89 to 1.0.90
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.89 to 1.0.90.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.89...v1.0.90)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-03 20:26:48 -06:00
ef1e5db0ee Force delete all beta testnet nodes before restarting them 2019-04-03 17:58:54 -07:00
5cdfd79e96 Replace print with debug 2019-04-03 16:23:02 -07:00
b441bac7b2 Add separate Struct for Replicator submissions 2019-04-03 16:23:02 -07:00
00cb52c444 Update Storage Program to support multiple accounts 2019-04-03 16:23:02 -07:00
9323a3e257 Use keyed_account index names (#3555) 2019-04-03 15:57:26 -07:00
35298e01a8 Remove Instruction wrapper structs and name functions after enum fields 2019-04-03 13:34:27 -07:00
867f6f107b Rename SystemInstruction::Move to SystemInstruction::Transfer 2019-04-03 08:35:57 -06:00
43bb813cbe Rename 'new_account' to 'new_user_account'
And 'new_program_account' to 'new_account'
2019-04-02 21:24:42 -06:00
7b82e96467 Bump libc from 0.2.50 to 0.2.51 (#3554)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.50 to 0.2.51.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.50...0.2.51)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-02 20:32:35 -05:00
978ff87b76 Fix potential storage bug
The previous code was assuming the instruction index and the
program_id index were the same. That's always true for
single-instruction transactions, but not for multiples.
2019-04-02 19:00:35 -06:00
4c0bc1fd88 Add program_ids() methods
Added CompiledInstruction::program_id() so that we don't need to pass
around instruction indexes just for Message::program_id().

Also added Message.program_ids() that returns a slice so that we
can move those pubkeys into Message::account_keys.
2019-04-02 19:00:35 -06:00
025b4f90de Pre-populate tokens (#3605) 2019-04-02 16:50:53 -07:00
20189c5d45 Bump hashbrown to 0.2.0 2019-04-02 16:37:21 -06:00
2e4acba579 Remove second block streamer from testnet beta 2019-04-02 15:15:11 -07:00
d90b8c331d Refactor blocktree storage abstraction (#3588) 2019-04-02 16:58:07 -05:00
efbb49d579 Don't use external node ssh key if one is not configured 2019-04-02 14:20:00 -07:00
f0079cd7b3 Bump hashbrown from 0.1.8 to 0.2.0
Bumps [hashbrown](https://github.com/Amanieu/hashbrown) from 0.1.8 to 0.2.0.
- [Release notes](https://github.com/Amanieu/hashbrown/releases)
- [Changelog](https://github.com/Amanieu/hashbrown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Amanieu/hashbrown/compare/v0.1.8...v0.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-02 13:45:49 -06:00
a0041cec97 Rename Runtime to MessageProcessor 2019-04-02 12:49:26 -06:00
77bb9e7ffc Fix the release number in testnet participation document 2019-04-02 11:26:54 -07:00
f441177840 Deploy beta testnet with 100 nodes across AWS and GCP 2019-04-02 11:21:57 -07:00
cd634801a2 Re-enable test but remove replicators from config 2019-04-02 10:38:30 -07:00
5f10a87dec Ignore Flaky Local Cluster test 2019-04-02 10:56:29 -06:00
fa1c1e3734 Rename native programs to native instruction processors 2019-04-02 10:36:19 -06:00
947cdd8748 Rename system_program to system_instrution_processor 2019-04-02 10:36:19 -06:00
0a9f063d3e Rename native_program.rs to instruction_processor_utils.rs
Prefer the term "instruction processor" over "program". Reserve
the term "native" for the loader and shared object it loads.
Compiling an instruction processor to BPF shouldn't imply changing
to a non-native entrypoint.
2019-04-02 10:36:19 -06:00
dd4c512954 Rename Wallet's id to keypair 2019-04-02 07:38:28 -06:00
d228b6467c Implement finalizer so that all locked accounts are dropped (#3585)
* Implement finalizer so that all locked accounts are dropped when finalizer goes out of scope

* Add test for tx error with lock conflict

* Fix double unlock from destructor running after a call to unlock
2019-04-02 03:55:42 -07:00
92c66a411b Remove bench-tps converge-only 2019-04-01 23:05:25 -06:00
af97ad3d68 Add solana-gossip module 2019-04-01 23:05:25 -06:00
6ff2a0a75e Rework discover to handle additional parameters, and be unit-testable 2019-04-01 23:05:25 -06:00
5b7d5e2e02 Bump reqwest from 0.9.12 to 0.9.13
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.9.12 to 0.9.13.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.9.12...v0.9.13)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-01 20:34:08 -06:00
97bd7a00f1 Support for configuring testnet nodes across multiple cloud services 2019-04-01 17:11:41 -07:00
25a2f08f8d add passive staking and rewards (#3579)
* add stake stuff

* more generic

* test decode bail cases

* favor early returns
2019-04-01 16:45:53 -07:00
3152090a66 update with review comments 2019-04-01 15:54:53 -06:00
9a0f9b910e add bench tests for squash operations 2019-04-01 15:54:53 -06:00
f853c39169 remove unused member 2019-04-01 15:54:53 -06:00
75ad1305c0 Cache vote accounts and optimize squash 2019-04-01 15:54:53 -06:00
cb3adea94f Increase node count in beta testnet 2019-04-01 11:06:24 -07:00
fcef54d062 Add a constructor to generate random pubkeys 2019-03-31 16:23:18 -06:00
32683cac7c Move markdown into book 2019-03-31 16:23:06 -06:00
15947b8642 Congestion stats, take 3 2019-03-31 16:23:06 -06:00
4e0316f792 Apply review feedback 2019-03-31 16:23:06 -06:00
9594b7fdce Use stake-weighted congestion statistics 2019-03-31 16:23:06 -06:00
1adf8355f2 Add design proposal for deterministic transaction fees 2019-03-31 16:23:06 -06:00
8660c3581e Add squashing metrics (#3573) 2019-03-29 21:21:59 -07:00
f886b3b12b Fix resetting PohRecorder to wrong bank (#3553)
* Check whether future slot already has transmission
2019-03-29 20:00:36 -07:00
5646daa820 Delete lots of fee parameters
So many zeros!
2019-03-29 19:21:51 -06:00
7896e8288d Replace Transaction::fee with a FeeCalculator 2019-03-29 19:21:51 -06:00
9369ea86ea Track detached slots in blocktree (#3536)
* Add contains_all_parents flag to SlotMeta to prep for tracking detached heads

* Add new DetachedHeads column family

* Remove has_complete_parents

* Fix test
2019-03-29 16:07:24 -07:00
dee5ede16d Get rid of unnecessary frozen banks (#3572) 2019-03-29 16:06:48 -07:00
3b516c0710 Fix build 2019-03-29 14:56:29 -06:00
0887832b00 Early exit if buffered packets is empty 2019-03-29 13:40:07 -07:00
8e04fadb05 Cleanup magic numbers
Rename `num_signatures` to `num_required_signatures` to
disambiguate it from `tx.signatures.len()`.
2019-03-29 13:03:29 -07:00
31f8b6d352 Integrate Message into Transaction 2019-03-29 13:03:29 -07:00
98d60e6124 Expose a method for getting the Message from a Transaction
This currently constructs the message, but when message
is integrated, it can return a `&Message`.
2019-03-29 13:03:29 -07:00
fc678f53ba Send metrics data to the correct/configured database host 2019-03-29 12:14:15 -07:00
8e25c39564 fix formatting of numbered list 2019-03-29 11:46:21 -07:00
78ab79c322 fix build failure 2019-03-29 11:46:21 -07:00
052fc9b74f Information on how to debug testnet issues 2019-03-29 11:46:21 -07:00
f482c9ab61 Functionalize tx serialization; make testing more explicit 2019-03-29 11:31:46 -06:00
75dcd97f5f Update test to deserialize txs 2019-03-29 11:31:46 -06:00
4776dc36ab Map entry txs to serialized txs in blockstream 2019-03-29 11:31:46 -06:00
10239c3b3c Replace recursive status cache with a single global fast status cache (#3541)
Fast Status Cache
2019-03-29 10:03:55 -07:00
753d0dcabe Fix the cuda build
And add a test to check the condition that the cuda tests are
exercising.
2019-03-29 08:25:56 -06:00
b708998d9d Fix chacha build 2019-03-29 08:25:56 -06:00
3759b0d2a5 Fix Blockstreamer test 2019-03-29 08:25:56 -06:00
c4bc710d3a Use Serde's with attribute to shorten length encodings in Transaction 2019-03-29 08:25:56 -06:00
857dc2ba47 Remove custom serialization 2019-03-29 08:25:56 -06:00
981e057363 Just test features in core 2019-03-28 21:40:52 -07:00
37494c67d0 Add pubkey read/write tools
Co-authored-by: Tyera Eulberg <tyera@solana.com>
Co-authored-by: Tristan Debrunner <tristan@solana.com>
2019-03-28 20:04:32 -06:00
7a81f327ce Add sigverify tests 2019-03-28 19:42:11 -06:00
845ddc3496 Fixup wallet-sanity to match new balance string 2019-03-28 16:56:27 -07:00
c61bb16fdf Fix manifest path for cargo commands (#3549) 2019-03-28 15:56:08 -07:00
15b945a652 Fix EC2 scripts for blockstream startup 2019-03-28 15:37:23 -07:00
1d48c4dd45 enable leader rotation in beta testnet 2019-03-28 13:44:44 -07:00
2ab50cbae8 Move untested code out of SDK
verify_signature() was only used in a test that was testing
binary layout. It only worked because the test transaction only
had one signature.

from() was only used by verify_signature() and that's something
we'd typically called `pubkey()`.

hash() didn't return the hash of the Transaction, as you might
guess. It's only used for PoH, so move it into Entry.
2019-03-28 14:24:59 -06:00
0482f153d0 Lower a bunch of debug
Can't afford to be printing on every transaction error, it will slow
the system down.
2019-03-28 12:24:47 -07:00
92e1c4c531 Report which account is in use (#3539) 2019-03-28 08:17:49 -07:00
4bca60861e Specialize GenericInstruction 2019-03-28 05:45:46 -06:00
50b0a5ae83 Blocktree+Erasure tests of basic erasure functionality (#3535)
* Remove WindowSlot; add Blocktree based tests to erasure
2019-03-28 01:55:51 -05:00
c30eb6185c Enable logging in exchange program (#3538) 2019-03-27 23:02:05 -07:00
a94bc80383 fix clippy errors 2019-03-27 18:05:17 -07:00
586b6fc3d7 review comments 2019-03-27 18:05:17 -07:00
a14c202d60 fix the ip address that's stored in the config file 2019-03-27 18:05:17 -07:00
ed48c495a3 fix shell-check errors 2019-03-27 18:05:17 -07:00
f0abd06a46 Added support for multi-region cloud testnet 2019-03-27 18:05:17 -07:00
7d0ff8e713 Re-enable Replicator test (#3534) 2019-03-27 17:21:49 -07:00
e8cc566b2b Storage Account setup for replicators and validators (#3516)
* Setup Storage Accounts for replicators

* Setup Storage Accounts for validators

* Add Replicator Info to Local Cluster and Add test
2019-03-27 15:54:09 -07:00
e45f7afd85 use the right id for delegate id 2019-03-27 15:04:09 -07:00
054ae3a3e3 Document current transaction size awkwardness 2019-03-27 14:27:20 -06:00
36ea088387 Fix Storage Stage not receiving entries when node is leader (#3528) 2019-03-27 13:10:33 -07:00
47b6707c07 Don't use a loader to test Storage instruction processor 2019-03-27 11:02:41 -06:00
0346b9cb5c hang out on progress until fork is confirmed 2019-03-27 08:41:41 -07:00
6bfe497ab5 remove leader confirmaiton 2019-03-27 08:41:41 -07:00
6956bf635e validator confirmaiton 2019-03-27 08:41:41 -07:00
e27d6d0988 validator confirmation 2019-03-27 08:41:41 -07:00
3fc09fb23f Remove keypairs from BankClient
Bring its interface closer to the other clients.
2019-03-27 09:37:19 -06:00
cecdb7061e Remove blockhash parameter from Bank::transfer
That parameter is an artifact from the Loom days, when I thought
Bank should implement the same interace as ThinClient.
2019-03-27 08:51:10 -06:00
0ac865f08c Remove BankClient::process_instructions 2019-03-27 08:51:10 -06:00
55115d0eeb Add process_message() to BankClient 2019-03-27 08:51:10 -06:00
16ff4ac1a8 Simplify storage interface in blocktree (#3522) 2019-03-27 01:36:39 -05:00
5ce31168ef Remove Transaction::new_signed 2019-03-26 19:51:16 -07:00
b9ff70c8ab pub Transaction::new_unsigned
Offer an incremental path off Transaction::new_unsigned_instructions().
2019-03-26 20:06:05 -06:00
77498c6efe Expose Message via the new default Transaction constructor 2019-03-26 20:06:05 -06:00
8c69c40834 Make space for a new Transaction::new 2019-03-26 20:06:05 -06:00
d497b99abb use solana_entrypoint directly (#3518) 2019-03-26 16:40:34 -07:00
ca2ac1e5ea Remove a mostly unused Transaction constructor 2019-03-26 15:46:58 -07:00
c09e0eb536 propagate TESTNET_DB_HOST env variable to next step in buildkite 2019-03-26 14:40:18 -07:00
0d90dfae1a Add provisions to specify a database server in testnet manager buildkite 2019-03-26 14:40:18 -07:00
bf61321cab fix metrics 2019-03-26 14:30:25 -07:00
591653981b fix metrics 2019-03-26 14:30:25 -07:00
e651510805 Instructions on how to boot metrics server 2019-03-26 14:02:41 -07:00
9d73fbb84a also check the delegate_id 2019-03-26 12:03:22 -07:00
215b07c1a9 remove status_cache.freeze (#3506) 2019-03-26 11:56:25 -07:00
420cbc45cd Record the current nodes locktower votes from the bank (#3502)
* observed_locktower_stats

* fixup! observed_locktower_stats
2019-03-26 11:06:31 -07:00
df333e8b6e Move new_move_many to SystemInstruction 2019-03-26 09:22:29 -07:00
9759ac2961 Mark book's javascript library as binary
highlight.js has a big dictionary of words. When git-grep includes
one of those words, it floods the screen with the whole dictionary.

Mark it as binary so that it'll now just report one line:

     Binary file book/theme/highlight.js matches
2019-03-26 07:39:34 -07:00
af9b173dfd fix link 2019-03-26 05:43:02 -07:00
b61aed7250 Minor cleanup 2019-03-25 20:31:13 -07:00
e1c0425c2b Remove rewards crate from publishing script 2019-03-25 20:19:58 -07:00
615472b52c Initailize locktower with heaviest bank (#3489) 2019-03-25 20:00:11 -07:00
4d34102d9c Move stragglers into the book
The stuff added between the time we switched to proposals/ and the git-revert
2019-03-25 19:39:22 -07:00
3e22ce4154 Added stats for locktower in testnet dashboard 2019-03-25 18:49:15 -07:00
215f33680b Fix the filename in testnet pariticpation instructions 2019-03-25 17:33:41 -07:00
a5420f19da Update testnet-participation.md
add instructions for finding metrics
2019-03-25 17:12:00 -07:00
4bc3f70150 Boot VoteTransaction 2019-03-25 17:11:57 -07:00
e8814b1297 Add support for influx cloud 2019-03-25 17:10:38 -07:00
46ab0e6449 Update testnet-participation.md
multinode-demo/validator-x.sh uses cargo run unless USE_INSTALL==1
2019-03-25 16:30:56 -07:00
59b4f40f4e fixup! fixup! keep track of locktower slots and stakes 2019-03-25 16:05:28 -07:00
93c57934cb fixup! keep track of locktower slots and stakes 2019-03-25 16:05:28 -07:00
e8e1d6b8ce keep track of locktower slots and stakes 2019-03-25 16:05:28 -07:00
4916cd8da5 bench-tps in a cargo test 2019-03-25 15:05:56 -07:00
573dec63da Fix runtime benches 2019-03-25 14:32:01 -06:00
34c051f183 add hash_fromstr (#3476) 2019-03-25 12:23:19 -07:00
51004881f8 filter out banks that have an older epoch (#3472) 2019-03-25 11:09:39 -07:00
5c536e423c Inline InstructionCompiler
The object-oriented paradigm isn't helpful here; go functional.
2019-03-25 12:08:27 -06:00
4efa144916 Generate a Message instead of a Transaction 2019-03-25 12:08:27 -06:00
f3936c21a3 Add message 2019-03-25 12:08:27 -06:00
caff603497 Less code 2019-03-24 21:44:04 -07:00
aefa9891c0 Delete unused code 2019-03-24 21:44:04 -07:00
6286947697 Inline payment_plan
This module predates Accounts. That was a separate module because
it used to be part of Bank and those types could be sent to any
smart contract. Now each instruction processor defines for itself
what instructions it accepts.
2019-03-24 14:52:06 -06:00
33972ef89e Boot BudgetTransaction 2019-03-24 14:52:06 -06:00
b53cbdd9e6 Punt on the Script abstraction
Low ROI
2019-03-24 14:52:06 -06:00
c49e84c75b Boot StorageTransaction 2019-03-24 13:51:02 -07:00
dcf2337e58 Add StorageInstruction constructors 2019-03-24 13:51:02 -07:00
5a65c3f72e Test-drive StorageContract 2019-03-24 13:51:02 -07:00
8ff1987d2d Reorg Storage program to look more like the others 2019-03-24 13:51:02 -07:00
acedf4ca5a Move Instruction into its own module 2019-03-23 20:31:55 -07:00
68c35bfde6 Restart node test (#3459) (#3465)
* Restart node test (#3459)

* Add test to local_cluster for restarting a node

* fix so that we don't hit end of epoch - leader not found before trying to transfer

* Do not look for confirmations, b/c nobody is voting on empty transmissions in this single node test
2019-03-23 19:19:55 -07:00
e1a3708844 Ensure accounts are unlocked (#3458) 2019-03-23 13:30:56 -07:00
46ecac3310 Update leader slot in poh recorder if we skipped it (#3452)
* reset poh recorder with the original start slot
2019-03-23 13:07:09 -07:00
028b9da0da Revert "Move the design proposals to a separate book"
This reverts commit 4ca18d6b9a.
2019-03-23 14:04:34 -06:00
74cea2748c Revert "Publish design proposals"
This reverts commit fb44e2bf48.
2019-03-23 14:04:34 -06:00
a478b2a05a Bump assert_cmd from 0.11.0 to 0.11.1
Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 0.11.0 to 0.11.1.
- [Release notes](https://github.com/assert-rs/assert_cmd/releases)
- [Changelog](https://github.com/assert-rs/assert_cmd/blob/master/CHANGELOG.md)
- [Commits](https://github.com/assert-rs/assert_cmd/compare/v0.11.0...v0.11.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-23 13:18:51 -06:00
41a52dbfea Document solana-install-init.sh 2019-03-23 09:01:08 -07:00
4923f889c4 Add trick to ensure the entire script is downloaded 2019-03-23 09:01:08 -07:00
31b8743052 delay freeze of status_cache until squash (#3453) 2019-03-22 22:14:56 -07:00
6505221629 Add exchange program (#3444) 2019-03-22 21:07:36 -07:00
de2b6bc9fc Bump tokio from 0.1.17 to 0.1.18
Bumps [tokio](https://github.com/tokio-rs/tokio) from 0.1.17 to 0.1.18.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-0.1.17...tokio-0.1.18)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-22 19:54:18 -06:00
f565292852 Update testnet-participation.md 2019-03-22 17:58:58 -07:00
90f17e8fd4 Update testnet-participation.md 2019-03-22 17:18:27 -07:00
d6da7dc1b6 Initial testnet participation doc 2019-03-22 17:11:47 -07:00
7e2aad2590 Refrain from trying to configure a staking account that was previously configured 2019-03-22 17:00:09 -07:00
f09b8d3921 Demote log level 2019-03-22 17:00:09 -07:00
52f6c33ff9 Make sure banking stage is recording with the same bank that it read (#3447)
* make sure banking stage is recording with the same bank that it read with
2019-03-22 14:17:39 -07:00
60dfb35924 Why do I need to see raw bytes from the drone? 2019-03-22 14:07:44 -07:00
5f41909098 Stop using VoteTransaction in Vote processor 2019-03-22 14:07:00 -06:00
a28f7db950 Retry more for a new blockhash 2019-03-22 11:14:03 -07:00
38fdbbba3f Reduce remaining program crates to boilerplate crates 2019-03-22 06:46:44 -07:00
0a5b6154e8 Use same gossip port for all testnet nodes 2019-03-22 00:16:58 -07:00
4542a7042a Add --poll-for-new-genesis-block flag 2019-03-22 00:15:19 -07:00
6113b64fee Include multinode-demo scripts in release tarball 2019-03-21 22:09:44 -07:00
f777ed76a3 Use installed binaries if not within the cargo workspace 2019-03-21 22:09:44 -07:00
e6b9babf53 Run a drone on blockstreamer nodes 2019-03-21 22:09:44 -07:00
ed8bada439 Kill all node processes (blockexplorer) 2019-03-21 22:09:44 -07:00
06b0c98c75 Remove accounts when the fork is removed (#3384)
* Fix test

* Cleanup accounts when the fork is removed

* Update test to check for deleted accounts
2019-03-21 17:36:10 -07:00
dbb145c266 Fixup ledger path 2019-03-21 17:06:57 -07:00
437481853b Ensure genesis ledger directory is populated on all validator nodes
This allows all nodes to serve the genesis ledger over rsync instead of
just the bootstrap leader
2019-03-21 16:35:40 -07:00
3b5a9f512c Get client-id.json out of the genesis ledger directory 2019-03-21 16:35:40 -07:00
045af04784 Reduce budget_program and config_program into boilerplate crates 2019-03-21 16:53:08 -06:00
d0761f57e8 Add _program suffix to directories of crates with _program suffix 2019-03-21 16:24:06 -06:00
4bb88619fd Move entrypoint boilerplate into a macro 2019-03-21 15:27:49 -06:00
412ebfcaf2 ReplayStage::new is too long
break into more functions
2019-03-21 14:08:11 -07:00
3a7647f611 Add curl-able install script 2019-03-21 13:45:54 -07:00
d4cc48f99d Check from account balance and exit cleanly if 0 2019-03-21 13:00:46 -07:00
852fcbd700 Automatically update PATH for the user 2019-03-21 13:00:46 -07:00
8ab4b8e6ac Support local networks for easy testing 2019-03-21 13:00:46 -07:00
a8095e204f Cleanup SystemTransaction 2019-03-21 12:41:39 -07:00
98979c7d53 Cargo.lock 2019-03-21 11:24:10 -07:00
c18fcde385 Move installer to the implemented section 2019-03-21 11:24:10 -07:00
f286bbac99 Initial commands implementation 2019-03-21 11:24:10 -07:00
4e029d81a2 Setup staking 2019-03-21 11:12:35 -07:00
2b00a42b06 Boot Rewards program 2019-03-21 12:07:20 -06:00
07d55d0092 Downgrade 'No next leader found' to warning 2019-03-21 11:18:49 -06:00
fb44e2bf48 Publish design proposals 2019-03-21 10:54:59 -06:00
9b0bf5ad66 Add tests for table mappers; Bugfix on-disk mapper (#3408)
add tests to `kvstore::mapper::{disk, memory}` modules

fix bug in disk mapper uncovered by tests

use `tempdir` crate for unit test-directories
2019-03-21 11:38:29 -05:00
4247fa946e Add solana-wallet balance <PUBKEY> 2019-03-21 09:51:27 -06:00
071b1d8b77 Cargo.lock 2019-03-21 08:47:58 -07:00
63aadc4905 Turn top-level Cargo.toml into a virtual manifest 2019-03-21 08:47:58 -07:00
d2415613de Migrate loader tests to BankClient 2019-03-21 09:19:24 -06:00
58f071b7a0 Migrate loader to high-level instructions 2019-03-21 09:19:24 -06:00
148e08a8a5 Enable cluster tests (#3372)
* Cluster tests

* stable!

* fixup! stable!

* fixup! fixup! stable!

* fixup! fixup! fixup! stable!

* fixup! fixup! fixup! fixup! stable!

* fixed space

* add getNumBlocksSinceSignatureConfirmation entry for the json rpc docs

* Check in upcoming epochs for potential leadership slots in next_leader_slot()
2019-03-21 07:43:21 -07:00
402a733cd7 Upload tarball as a github release asset 2019-03-20 21:39:35 -07:00
78be3652de Add script to upload github release assets 2019-03-20 21:39:35 -07:00
b03d9884a3 Ensure current crate versions match the tag before publishing to crates.io 2019-03-20 20:51:58 -07:00
799085a105 Remove dead code 2019-03-20 20:51:58 -07:00
7812b67471 deduplicate some test code (#3401) 2019-03-20 19:35:25 -05:00
4033fa031b Add convenience script for testnet deployments 2019-03-20 16:57:55 -07:00
b41737259a Add GITHUB_TOKEN 2019-03-20 16:57:55 -07:00
7c8a4bf6a4 use ticks per slot to check if the current tick is in the leader slot 2019-03-20 16:55:01 -07:00
71314d79a7 address review comments 2019-03-20 16:55:01 -07:00
d7ff6645a9 change pubkey to ref 2019-03-20 16:55:01 -07:00
1824e09d0a find next leader slot before resetting working bank in Poh recorder 2019-03-20 16:55:01 -07:00
205907d3d7 Check if poh recorder has over stepped the leader slot 2019-03-20 16:55:01 -07:00
d4bcc4d474 🐳 2019-03-20 16:21:47 -07:00
bcb190a12a Remove erroneous comment 2019-03-20 16:15:25 -07:00
63e8496473 Cleanup pubkey parsing copypasta 2019-03-20 16:08:03 -07:00
4107d70e93 Bump reqwest from 0.9.11 to 0.9.12
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.9.11 to 0.9.12.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/commits)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-20 16:26:31 -06:00
4fb0782892 Rename blocktree SlotMeta::is_rooted to is_connected
is_rooted is now is_connected and (still) indicates the set of connected
completed slots. 'rooted' slot terminology is used for a different
meaning in bank_forks and replay_stage.
2019-03-20 14:43:39 -07:00
9b7c1d5650 Relocate *-help.sh to their respective packages 2019-03-20 14:34:57 -07:00
985592cf40 Fix cp args 2019-03-20 14:29:30 -07:00
2694654a98 Change fixed 8050 port to one from bind_in_range. 2019-03-20 14:17:21 -07:00
4126461f87 Fix dupe port on cluster_info
and remove unintended grow file
2019-03-20 14:17:21 -07:00
791ead6053 Include TARGET in release URL to make room for future targets 2019-03-20 13:54:32 -07:00
3048de18bb add doc that should have been copy-pasta'd from bench (#3389) 2019-03-20 11:10:42 -07:00
df9fd2bc0b stop copying Blooms (#3379)
* stop copying Blooms

* fixup

* clippy
2019-03-20 11:06:39 -07:00
13c9d3d4e1 Kvstore: use bincode serialization (#3385)
* use bincode for SSTable serialization; add tests

* Fix bug uncovered in merge algorithm by unit tests

* use bincode in write-ahead-log serialization

* Add helper `Fill` trait for zeroing buffers
2019-03-20 09:55:44 -05:00
0dc364c17a Relocate transaction reference verification to join the other validity checks 2019-03-20 07:46:01 -07:00
b3cdf58e4b Add WriteBatch to KvStore (#3364)
* implement write-batch in kvstore

* Add tests to writebatch, and in-memory table
2019-03-20 06:55:39 -05:00
61f950a60c Sign Gossip Vote Messages 2019-03-19 19:56:17 -07:00
da77789881 Revert "Drop 'unchecked' from get_subset_mut()"
This reverts commit 70b21b3795.
2019-03-19 17:52:02 -07:00
61af87972e allow empty ancestors 2019-03-19 17:51:01 -07:00
fe9e771b9b Clear progress map on squash (#3377) 2019-03-19 17:30:36 -07:00
94b5835738 Make AccountMeta a traditional struct instead of a tuple struct 2019-03-19 17:22:39 -06:00
a4652a9aaf Label tuple with AccountMeta 2019-03-19 17:22:39 -06:00
7246d72f03 fix is_locked_out logic 2019-03-19 16:21:46 -07:00
70b21b3795 Drop 'unchecked' from get_subset_mut() 2019-03-19 16:12:53 -07:00
682b1b89b3 Adjust for vector of entries in blobs. 2019-03-19 13:49:48 -07:00
f1802e592a Review comments: node creation functions for replicators
And rework download loop.
2019-03-19 13:49:48 -07:00
ee58c1f960 Add test for replicator ledger download
Add an interface to query the storage slot a
  replicator is holding on storage_addr port.
Fix logic to poll blocktree for all slots
  replicated being filled.
Add test logic to ask replicator what slot it
  is replicating and then download an entry in
  the slot.
2019-03-19 13:49:48 -07:00
07f4dd385d Cleanup replicator sockets
Add optional UdpSocket for storage interface.
Add new_localhost_replicator to create a new replicator local node.
2019-03-19 13:49:48 -07:00
1be7ee51be Fix potential crash in banking stage 2019-03-19 12:06:42 -07:00
56fcc93ef5 Schedule node for consecutive slots as leader (#3353)
* Also tweak epoch and slot duration

* new test for leader schedule
2019-03-19 06:36:45 -07:00
c70412d7bb move core tests to core (#3355)
* move core tests to core

* remove window

* fix up flaky tests

* test_entryfication needs a singly-threaded banking_stage

* move core benches to core

* remove unnecessary dependencies

* remove core as a member for now, test it like runtime

* stop running tests twice

* remove duplicate runs of tests in perf
2019-03-18 22:08:21 -07:00
5e21268ca0 PR comments 2019-03-18 20:46:11 -07:00
b38e3bef01 Modify bank_forks to support squashing/filtering new root and also don't remove parents from bank_forks when inserting, otherwise we lose potential fork points when querying blocktree for child slots 2019-03-18 20:46:11 -07:00
89cc82c71b Update cli interface 2019-03-18 18:34:08 -07:00
1d0f6a5d85 Add scripts/install-help.sh 2019-03-18 18:34:08 -07:00
d0292b1cf1 store transaction no longer takes the transaction fee from the config account 2019-03-18 18:34:08 -07:00
15aed9f320 Self 2019-03-18 18:34:08 -07:00
5a67362b8e update passive staking proposal (#3335)
* update passive staking proposal

* fixup
2019-03-18 18:25:29 -07:00
5d73ab299b Clean up locks in KvStore (#3358)
* Lift all shared mutable state into Kvstore

commit is now an AtomicUsize

In-memory table and write-log are now struct members behind individual RwLocks
2019-03-18 19:04:31 -05:00
ef111dcbe1 Decendent is not a word 2019-03-18 15:58:27 -07:00
da7e49c880 Fix broken build
- build breaks if Cuda feature is used
2019-03-18 15:29:51 -07:00
f16f88873d Add multiple signer support to BankClient 2019-03-18 16:07:45 -06:00
211c81f2a2 bank fork rpc (#3351) 2019-03-18 14:18:43 -07:00
efc39ffdde Report how many grace ticks were afforded to previous leader (#3350) 2019-03-18 13:24:07 -07:00
61a4b998fa Implement locktower voting (#3251)
* locktower components and tests

* integrate locktower into replay stage

* track locktower duration

* make sure threshold is checked after simulating the vote

* check vote lockouts using the VoteState program

* duplicate vote test

* epoch stakes

* disable impossible to verify tests
2019-03-18 12:12:33 -07:00
cedff2fca1 Cleanup sockets test 2019-03-18 11:56:18 -07:00
8d032aba9d Merge InstructionError and ProgramError
From the user's perspective, it's just an instruction error.
For program-specific errors, we still have
InstructionError::CustomError.
2019-03-18 10:39:20 -06:00
607b368fe3 Add back in test to check the account program id 2019-03-18 08:22:54 -07:00
a54854abc7 Do Budget verification in BudgetScript 2019-03-18 08:22:54 -07:00
ce6257a069 Delete misplaced unit-tests
These tests were from back in the day when Bank(then-called Accountant)
would call `verify_plan()` on all transactions. Nowadays `verify_plan`
is only useful to the client. At can be used to ensure a transaction
won't trigger runtime errors.
2019-03-18 08:22:54 -07:00
7b28d3a231 Move Budget's verify_plan() into tests
This functionality is supposed to be the the interpreter
2019-03-18 08:22:54 -07:00
ea01ff2aab Add pubkey to BudgetExpr::new_cancelable_future_payment for wallet 2019-03-18 08:22:54 -07:00
3369019943 Add BudgetExpr::new_cancelable_authorized_payment 2019-03-18 08:22:54 -07:00
dbd4176b97 Move script constructors into a separate module 2019-03-18 08:22:54 -07:00
122c7bc2ef Rename TransactionCompiler to Script and use it to replace the type alias 2019-03-18 08:22:54 -07:00
99671472d1 Migrate config tests to Bank 2019-03-18 08:22:54 -07:00
0c0716abfb Move Bank-based tests into unit-tests 2019-03-18 08:22:54 -07:00
c09accb685 Rename StaticEntrypoint to ProcessInstruction 2019-03-18 08:22:54 -07:00
ae4d14a2ad Introducing Scripts
A sequence of instructions. A client compiles the script and then uses
the compiled script to construction a transaction. Then it adds a
adds a blockhash, signs the transaction, and sends it off for
processing.
2019-03-18 08:22:54 -07:00
55cdbedb52 Allow tests to add instruction processors
Make runtime a private module again.
2019-03-18 08:22:54 -07:00
ee39f31d81 Add Runtime object. Allow any number of static loaders. 2019-03-18 08:22:54 -07:00
70b45de012 Get access to runtime errors in Budget unit-tests 2019-03-18 08:22:54 -07:00
60437a8dcb Multiple entries per blob (#3337)
* Pack multiple entries into blob

* fix tests

* Add test for deserializing multi-entry blobs in blocktree

* more test fixes
2019-03-17 18:48:23 -07:00
a35ebe1186 Avoid RpcRequest 2019-03-17 01:34:58 -07:00
c498775a3d Move generic rpc_client functions from wallet/ to client/ 2019-03-17 01:34:58 -07:00
3ad019a176 Increment stable timeout 2019-03-16 23:56:35 -07:00
9632136cda Clean up stray retry_get_balance() function 2019-03-16 23:56:35 -07:00
42cea7a785 Remove metrics dependency 2019-03-16 23:56:35 -07:00
4c9d852b08 Remove ThinClient::transfer() 2019-03-16 23:56:35 -07:00
9566a5cc68 Organize accounts on a per fork basis (#3336)
* Organize accounts by fork

* Keep track of vote accounts in account info

* update comments
2019-03-16 23:42:32 -07:00
ac03c59b41 client/: get_transaction_count() now returns a Result 2019-03-16 23:27:23 -07:00
73ceaf07b1 client/: move RpcClient from rpc_request.rs to rpc_client.rs 2019-03-16 23:27:23 -07:00
7b314f47f7 Factor RPC request mechanism out of RpcClient into *RpcClientRequest 2019-03-16 23:27:23 -07:00
23337e08eb client/: Merge client.rs into thin_client.rs 2019-03-16 22:48:26 -07:00
97e73311c5 Move mock request_airdrop_transaction into drone/, closer to the real impl 2019-03-16 22:14:09 -07:00
e2c24481e4 wallet/ now only dev-depends on core/ 2019-03-16 21:40:39 -07:00
ad252fe4c5 Remove unnecessary Option from get_account_data 2019-03-16 11:32:01 -07:00
4b04bc8612 Move thin_client RPC requests into rpc_request; de-mut thin_client 2019-03-16 11:32:01 -07:00
bcc34b906c Relieve the caller of having to care about the rpc request id 2019-03-16 11:32:01 -07:00
c2b1010f18 Clarify url vs addr 2019-03-16 11:32:01 -07:00
e3ef4f25d3 Update Dockerfile
install mscgen (for book art)
2019-03-15 20:44:35 -07:00
ad12b0efce Bump kvstore version to 0.13.0 to match all other solana crates (#3334) 2019-03-15 19:05:24 -05:00
00f005af25 Fix leader rotation counter 2019-03-15 17:01:18 -07:00
656fb173f9 Extract kvstore into separate crate (#3327)
* extract kvstore into new crate

* add kvstore crate to CI publishing list
2019-03-15 18:42:47 -05:00
5f58e9cd6e Config program - useful for storing/updating simple config items on chain 2019-03-15 16:39:45 -07:00
1d876df8b3 Add command plumbing 2019-03-15 16:30:31 -07:00
c8bbca08f8 Install the install program 2019-03-15 16:30:31 -07:00
971da7325d Reduce log level for periodic debug messages 2019-03-15 15:41:26 -07:00
ca4f874f52 Remove ci/run-local.sh 2019-03-15 15:09:25 -07:00
a88b36d718 Rename TransactionBuilder to TransactionCompiler 2019-03-15 14:46:44 -06:00
24d9138067 Abandon Builder pattern 2019-03-15 14:46:44 -06:00
aca739b800 Boot fees from TransactionBuilder 2019-03-15 14:46:44 -06:00
e091aa87ea More precise constructor names 2019-03-15 14:46:44 -06:00
968022a1b0 Instruction name swap
* Instruction -> GenericInstruction
* Instruction<u8, u8> -> CompiledInstruction
* Instruction<Pubkey, (Pubkey, bool)> -> Instruction
2019-03-15 14:46:44 -06:00
66fb1bbb2e Give last leader some grace ticks to catch up (#3299)
* Wait for last leader for some ticks

* New tests and fixed existing tests
2019-03-15 13:22:16 -07:00
fa3e1fa7c9 Add error correction to write-log (#3323) 2019-03-15 15:04:34 -05:00
36763d0802 Cleanup entry.rs packing code (#3303) 2019-03-15 12:48:32 -07:00
be5f800390 Use the Mining Proof's Signature as storage keys (#3321) 2019-03-15 11:44:10 -07:00
ca69b7b75b Add CRC Reader and Writer I/O wrappers (#3322)
* add CRC Reader and Writer I/O wrappers

* typo fix and variable rename
2019-03-15 13:17:49 -05:00
a15927f8d0 make KvStore Send+Sync (#3317) 2019-03-15 13:01:34 -05:00
4ba4ad9878 Update README.md 2019-03-15 11:53:37 -06:00
be1511a7ff delete accidental file (#3316) 2019-03-15 11:28:08 -05:00
41b98c603b Upgrade rust stable to 1.33.0 2019-03-15 09:25:28 -07:00
5430dd28b6 Update docker-rust to 1.33 2019-03-15 09:25:28 -07:00
e9d687329b Only push newly built container 2019-03-15 09:25:28 -07:00
d72cac6e97 Fix chacha test 2019-03-15 09:06:54 -06:00
4e51a444f4 Simplify TransactionBuilder::new_with_instructions 2019-03-15 09:06:54 -06:00
48d86683e2 Abuse KeypairUtil 2019-03-15 09:06:54 -06:00
42d5dde5b1 new_singleton -> new_with_instruction 2019-03-15 09:06:54 -06:00
142eeffe5d Add BankClient to minimize copypasta 2019-03-15 09:06:54 -06:00
6a68df3ebd Don't resign airdrop requests with the keypair asking for an airdrop
The correct thing to do here is retry until you get a
BlockhashNotFound error, and then send another request
to the drone for a new signed transaction.

Also, this test is an integration test masquerading as a unit-test..
2019-03-15 09:06:54 -06:00
8306c1841c Fix build 2019-03-15 09:06:54 -06:00
73bd396dfb Rewrite system integration test
Create Client helpers instead of Bank helpers.
2019-03-15 09:06:54 -06:00
36fb0a0aef Add new preferred transaction constructors 2019-03-15 09:06:54 -06:00
4d53be8350 Make it unappealing to build and sign transactions at the same time
Use a client to sign transactions. It'll need that keypair anyway
to resign new blockhashes on retries.
2019-03-15 09:06:54 -06:00
f8bf9ca218 Make safe transaction signing the default 2019-03-15 09:06:54 -06:00
7b4568b9bf Migrate to sign_checked() 2019-03-15 09:06:54 -06:00
bd8502e87e Implement Transaction::new_unsigned with TransactionBuilder 2019-03-15 09:06:54 -06:00
21815f26d5 Implement signed transaction using unsigned transaction 2019-03-15 09:06:54 -06:00
8ef5195037 Don't test a transaction with a duplicate key 2019-03-15 09:06:54 -06:00
57606c6bf8 Bump log level for better CI logs 2019-03-15 07:48:23 -07:00
0465abf75b move (#2738) 2019-03-15 06:58:45 -07:00
8a142966be Avoid stray '' when rust version is not specified 2019-03-14 21:30:24 -07:00
7498488f5f cloud_DeleteInstances() now waits for the instances to be terminated 2019-03-14 21:15:00 -07:00
ede99d5913 Revert "Block until instances are confirmed to be deleted"
This reverts commit 47ddbbe53b.
2019-03-14 20:53:10 -07:00
3ced91319f Upgrade nightly rust version 2019-03-14 20:22:46 -07:00
3d1413e619 Preserve original nightly name 2019-03-14 20:22:46 -07:00
8f25548781 Overhaul cargo/rustc version management 2019-03-14 20:22:46 -07:00
47ddbbe53b Block until instances are confirmed to be deleted 2019-03-14 16:20:18 -07:00
5741400713 add support for finding the next slot a node will be leader (#3298) 2019-03-14 16:06:56 -07:00
9f02a8d3d0 remove ticks_per_slot from blocktree (#3297) 2019-03-14 15:18:37 -07:00
c208f4dbb5 Add option of replicators to local cluster test 2019-03-14 13:55:11 -07:00
a17843c8f6 solana-install design proposal 2019-03-14 13:21:00 -07:00
3f2fc21bb3 Rename hash_queue and fix boundary condition (#3289) 2019-03-14 11:56:36 -07:00
9fac3b26ee Move the design proposals to a separate book
Fixes #3262
2019-03-14 10:08:43 -07:00
c1eec0290e Rename userdata to data (#3282)
* Rename userdata to data

Instead of saying "userdata", which is ambiguous and imprecise,
say "instruction data" or "account data".

Also, add `ProgramError::InvalidInstructionData`

Fixes #2761
2019-03-14 10:48:27 -06:00
de13082347 add economic design mvp to summary and overview 2019-03-14 09:42:19 -06:00
48b5d666d0 some economic mvp features 2019-03-14 09:42:19 -06:00
70bb49a46d some economic mvp features 2019-03-14 09:42:19 -06:00
105fc7029e create mvp section 2019-03-14 09:42:19 -06:00
77a7ffe543 Bump hex-literal from 0.1.3 to 0.1.4
Bumps [hex-literal](https://github.com/RustCrypto/utils) from 0.1.3 to 0.1.4.
- [Release notes](https://github.com/RustCrypto/utils/releases)
- [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v0.1.3...hex-literal-v0.1.4)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-14 07:21:32 -06:00
7d593e6c61 Exit gracefully when no subcommand is specified 2019-03-14 00:35:34 -05:00
bb420cb995 Use crate_description and crate_name Clap macros 2019-03-14 00:35:34 -05:00
e58220282a Move TransactionError into the SDK 2019-03-13 21:26:57 -06:00
4ca4038d54 Rename BankError to TransactionError 2019-03-13 21:26:57 -06:00
150cd31ec0 Blur the line between Bank and Runtime 2019-03-13 21:26:57 -06:00
6fd0d4dcf5 Boot error piggybacking on BankError 2019-03-13 21:26:57 -06:00
296415945a Generalize error codes 2019-03-13 21:26:57 -06:00
1de5ae1ef0 Remove SystemError from ProgramError 2019-03-13 21:26:57 -06:00
6a89c68a1d Add utility function to help get System error out of ProgramError 2019-03-13 21:26:57 -06:00
c14cce4c85 Add InstructionError for runtime instruction errors 2019-03-13 21:26:57 -06:00
959961b596 Modified test 2019-03-13 18:18:27 -07:00
6f76c2da6c Fix confirmation test 2019-03-13 17:50:53 -07:00
8d2bd2b30f Reduce ticks per second
- It's improving TPS. Temp fix for beacons timeframe
2019-03-13 17:50:53 -07:00
34a8d591fa Switch version file from .txt to .yaml; add target tuple to version.yml 2019-03-13 16:30:07 -07:00
d94ff4bf4a Bump tokio from 0.1.15 to 0.1.17
Bumps [tokio](https://github.com/tokio-rs/tokio) from 0.1.15 to 0.1.17.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Changelog](https://github.com/tokio-rs/tokio/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-0.1.15...tokio-0.1.17)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-03-13 15:45:33 -06:00
af03df38b9 Don't vote for empty leader transmissions (#3248)
* Don't vote for empty leader transmissions

* Add is_delta flag to bank to detect empty leader transmissions

* Plumb new is_votable flag through replay stage

* Fix PohRecorder tests

* Change is_delta to AtomicBool to avoid making Bank references mutable

* Reset start slot in poh_recorder when working bank is cleared, so that connsecutive TPU's will start from the correct place

* Use proper max tick height calculation

* Test for not voting on empty transmission

* tests for is_votable
2019-03-13 14:06:12 -07:00
242bcf44db Replace stale --no-signer usage with --no-voting 2019-03-13 13:50:30 -07:00
ebd540972d Remove duplicate --rpc-drone-address 2019-03-13 13:24:02 -07:00
a17be9f8bd Revert "Add case for --rpc-drone-address"
This reverts commit 42ad297778.
2019-03-13 13:23:54 -07:00
42ad297778 Add case for --rpc-drone-address 2019-03-13 13:04:44 -07:00
0568d7238e Add implemented design proposals section 2019-03-13 13:20:37 -06:00
9bc05313a2 Update TPU ASCII art 2019-03-13 13:14:15 -06:00
fedbae6f8c Enable rpc for all testnet nodes 2019-03-13 10:49:40 -07:00
64de639817 Fixes to replicator
Move functionality into more functions.
Break down the current test and just test creation/joining the network.
2019-03-13 10:15:03 -07:00
ec9e13d1f4 Add repair slot range
Use default impl RepairSlotRange
2019-03-13 10:15:03 -07:00
5d27f221f7 Drop socat for iptables 2019-03-13 12:03:56 -05:00
61db74d98e Run socat in the background 2019-03-13 08:15:58 -07:00
1d689e84f1 Move and rename cluster_client 2019-03-12 22:05:38 -06:00
b7f420412b Update publish script 2019-03-12 22:05:38 -06:00
e3ac9e9679 Move thin client tests to integration test suite 2019-03-12 22:05:38 -06:00
12fde77ecd Update crate references 2019-03-12 22:05:38 -06:00
3fc96c4a18 Add solana-client crate 2019-03-12 22:05:38 -06:00
cb3eeace56 Replay Stage start_leader() can use wrong parent fork() (#3238)
*  Make sure start_leader starts on the last voted block, not necessarily the biggest indexed bank in frozen_slots()

* Fix tvu test
2019-03-12 17:42:53 -07:00
76feb2098e Use same VM type for validators as leader, if CUDA is enabled (#3253)
- Since all nodes are created equal
2019-03-12 17:42:47 -07:00
06cb266cfe remove unused code (#3252) 2019-03-12 16:46:41 -07:00
866d3f467f Fix flag to disable leader-rotation (#3243) 2019-03-12 16:35:13 -07:00
c1e726da87 Remove comment 2019-03-12 15:32:41 -07:00
7d7528eb18 Fix test_bank_storage 2019-03-12 15:32:41 -07:00
9f916f9d47 remove Option<> wrapper for accounts 2019-03-12 15:03:26 -07:00
a7d8bfdf8b Adjust crate list 2019-03-12 14:02:51 -07:00
abdd4f371b Adjust readme path 2019-03-12 14:02:51 -07:00
13adee332e Add retry transfer logic to kill_entry_and_spend_and_verify_rest to account for dead forks (#3239) 2019-03-12 13:48:02 -07:00
a799f8f4b1 tell blockexplorer to run on port 8080 (#3237)
* tell blockexplorer to run on port 8080

* forward port 80 to 5000 for a blockexplorer node
2019-03-12 13:39:09 -07:00
1ee43a7633 Remove non-essential programs from runtime/ 2019-03-12 15:11:59 -05:00
3d2b7dd1ef Move programs/system into runtime/ 2019-03-12 11:30:58 -05:00
7b35114c0f Filter vote accounts with no delegate from being selected in Rotation (#3224) 2019-03-11 17:58:21 -07:00
b418525464 Update current leader information in metrics and dashboard 2019-03-11 17:43:59 -07:00
8bba11367e Provide drone's host address while setting up staking account 2019-03-11 17:11:34 -07:00
9eb7e63819 Add staking rewards design proposal for delegation (#3148)
* proposal for single vote many delegators
2019-03-11 16:35:42 -07:00
092501039c Cargo.lock 2019-03-11 16:27:22 -07:00
6899bd7099 0.13.0 2019-03-11 16:21:19 -07:00
5a0416b925 Keep stable dashboard on stable channel at all times 2019-03-11 16:19:16 -07:00
ba2cdd0bf6 Move testnet/testnet-perf to the stable channel 2019-03-11 16:14:16 -07:00
540 changed files with 61296 additions and 26389 deletions

View File

@ -1,10 +1,12 @@
{
"_public_key": "ae29f4f7ad2fc92de70d470e411c8426d5d48db8817c9e3dae574b122192335f",
"environment": {
"CODECOV_TOKEN": "EJ[1:Kqnm+k1Z4p8nr7GqMczXnzh6azTk39tj3bAbCKPitUc=:EzVa4Gpj2Qn5OhZQlVfGFchuROgupvnW:CbWc6sNh1GCrAbrncxDjW00zUAD/Sa+ccg7CFSz8Ua6LnCYnSddTBxJWcJEbEs0MrjuZRQ==]",
"CRATES_IO_TOKEN": "EJ[1:Kqnm+k1Z4p8nr7GqMczXnzh6azTk39tj3bAbCKPitUc=:qF7QrUM8j+19mptcE1YS71CqmrCM13Ah:TZCatJeT1egCHiufE6cGFC1VsdJkKaaqV6QKWkEsMPBKvOAdaZbbVz9Kl+lGnIsF]",
"INFLUX_DATABASE": "EJ[1:Kqnm+k1Z4p8nr7GqMczXnzh6azTk39tj3bAbCKPitUc=:PetD/4c/EbkQmFEcK21g3cBBAPwFqHEw:wvYmDZRajy2WngVFs9AlwyHk]",
"INFLUX_USERNAME": "EJ[1:Kqnm+k1Z4p8nr7GqMczXnzh6azTk39tj3bAbCKPitUc=:WcnqZdmDFtJJ01Zu5LbeGgbYGfRzBdFc:a7c5zDDtCOu5L1Qd2NKkxT6kljyBcbck]",
"INFLUX_PASSWORD": "EJ[1:Kqnm+k1Z4p8nr7GqMczXnzh6azTk39tj3bAbCKPitUc=:LIZgP9Tp9yE9OlpV8iogmLOI7iW7SiU3:x0nYdT1A6sxu+O+MMLIN19d2t6rrK1qJ3+HnoWG3PDodsXjz06YJWQKU/mx6saqH+QbGtGV5mk0=]"
"CODECOV_TOKEN": "EJ[1:eSGdiZR0Qi0g7qnsI+qJ5H+/ik+H2qL3ned/cBdv/SY=:jA0WqO70coUtF0iokRdgtCR/lF/lETAI:d/Wl8Tdl6xVh/B39cTf1DaQkomR7I/2vMhvxd1msJ++BjI2l3p2dFoGsXqWT+/os8VgiPg==]",
"CRATES_IO_TOKEN": "EJ[1:eSGdiZR0Qi0g7qnsI+qJ5H+/ik+H2qL3ned/cBdv/SY=:2FaZ6k4RGH8luyNRaN6yeZUQDNAu2KwC:XeYe0tCAivYE0F9HEWM79mAI6kNbfYaqP7k7yY+SBDvs0341U9BdGZp7SErbHleS]",
"GITHUB_TOKEN": "EJ[1:eSGdiZR0Qi0g7qnsI+qJ5H+/ik+H2qL3ned/cBdv/SY=:9kh4DGPiGDcUU7ejSFWg3gTW8nrOM09Q:b+GE07Wu6/bEnkDZcUtf48vTKAFphrCSt3tNNER9h6A+wZ80k499edw4pbDdl9kEvxB30fFwrLQ=]",
"INFLUX_DATABASE": "EJ[1:eSGdiZR0Qi0g7qnsI+qJ5H+/ik+H2qL3ned/cBdv/SY=:rCHsYi0rc7dmvr1V3wEgNoaNIyr+9ClM:omjVcOqM7vwt44kJ+As4BjJL]",
"INFLUX_PASSWORD": "EJ[1:eSGdiZR0Qi0g7qnsI+qJ5H+/ik+H2qL3ned/cBdv/SY=:bP5Gw1Vy66viKFKO41o2Gho998XajH/5:khkCYz2LFvkJkk7R4xY1Hfz1yU3/NENjauiUkPhXA+dmg1qOIToxEagCgIkRwyeCiYaoCR6CZyw=]",
"INFLUX_USERNAME": "EJ[1:eSGdiZR0Qi0g7qnsI+qJ5H+/ik+H2qL3ned/cBdv/SY=:ZamCvza2W9/bZRGSkqDu55xNN04XKKhp:5jlmCOdFbpL7EFez41zCbLfk3ZZlfmhI]",
"SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_unknown_linux_gnu": "EJ[1:eSGdiZR0Qi0g7qnsI+qJ5H+/ik+H2qL3ned/cBdv/SY=:Oi2nsRxnvWnnBYsB6KwEDzLPcYgpYojU:ELbvjXkXKlgFCMES45R+fxG7Ex43WHWErjMbxZoqasxyr7GSH66hQzUWqiQSJyT4ukYrRhRC9YrsKKGkjACLU57X4EGIy9TuLgTnyBYhPnxLYStC3y/7o/MB5FCTt5wHJw3/A9p+me5+T4UmyZ7OeP21NhDUCGQcb0040VwYWS78klW2aQESJJ6wTI1xboE8/zC0vtnB/u50+LydbKEyb21r6y3OH9FYNEpSwIspWKcgpruJdQSCnDoKxP9YR1yzvk2rabss13LJNdV1Y6mQNIdP4OIFQhCs6dXT253RTl5qdZ0MruHwlp8wX4btOuYDcCoM5exr]"
}
}

View File

@ -10,6 +10,8 @@
set -x
rsync -a --delete --link-dest="$PWD" target "$d"
du -hs "$d"
read -r cacheSizeInGB _ < <(du -s --block-size=1800000000 "$d")
echo "--- ${cacheSizeInGB}GB: $d"
)
#

View File

@ -14,14 +14,18 @@ export PS4="++"
(
set -x
d=$HOME/cargo-target-cache/"$BUILDKITE_LABEL"
MAX_CACHE_SIZE=18 # gigabytes
if [[ -d $d ]]; then
du -hs "$d"
read -r cacheSizeInGB _ < <(du -s --block-size=1000000000 "$d")
if [[ $cacheSizeInGB -gt 10 ]]; then
echo "$d has gotten too large, removing it"
read -r cacheSizeInGB _ < <(du -s --block-size=1800000000 "$d")
echo "--- ${cacheSizeInGB}GB: $d"
if [[ $cacheSizeInGB -gt $MAX_CACHE_SIZE ]]; then
echo "--- $d is too large, removing it"
rm -rf "$d"
fi
else
echo "--- $d not present"
fi
mkdir -p "$d"/target

9
.gitignore vendored
View File

@ -1,10 +1,11 @@
/target/
/ledger-tool/target/
/wallet/target/
/core/target/
/book/html/
/book/src/img/
/book/src/tests.ok
/farf/
/metrics/scripts/lib/
/solana-release/
solana-release.tar.bz2
/target/
**/*.rs.bk
.cargo

View File

@ -46,10 +46,17 @@ and longer descriptions detailing what problem it solves and how it solves it.
Draft Pull Requests
---
If you want early feedback on your PR, use GitHub's "Draft Pull Request" mechanism. Draft
PRs are a convenient way to collaborate with the Solana maintainers without triggering
notifications as you make changes. When you feel your PR is ready for a broader audience,
you can transition your draft PR to a standard PR with the click of a button.
If you want early feedback on your PR, use GitHub's "Draft Pull Request"
mechanism. Draft PRs are a convenient way to collaborate with the Solana
maintainers without triggering notifications as you make changes. When you feel
your PR is ready for a broader audience, you can transition your draft PR to a
standard PR with the click of a button.
Do not add reviewers to draft PRs. GitHub doesn't automatically clear approvals
when you click "Ready for Review", so a review that meant "I approve of the
direction" suddenly has the appearance of "I approve of these changes." Instead,
add a comment that mentions the usernames that you would like a review from. Ask
explicitly what you would like feedback on.
Rust coding conventions
---
@ -89,24 +96,23 @@ understood. Avoid introducing new 3-letter terms, which can be confused with 3-l
[Terms currently in use](book/src/terminology.md)
Proposing architectural changes
Design Proposals
---
Solana's architecture is described by a book generated from markdown files in
the `book/src/` directory, maintained by an *editor* (currently @garious). To
change the architecture, you'll need to at least propose a change the content
under the [Proposed
Changes](https://solana-labs.github.io/book-edge/proposals.html) chapter. Here's
the full process:
add a design proposal, you'll need to at least propose a change the content
under the [Accepted Design
Proposals](https://solana-labs.github.io/book-edge/proposals.html) chapter.
Here's the full process:
1. Propose to a change to the architecture by creating a PR that adds a
markdown document to the directory `book/src/` and references it from the
[table of contents](book/src/SUMMARY.md). Add the editor and any relevant
*maintainers* to the PR review.
1. Propose a design by creating a PR that adds a markdown document to the
directory `book/src/` and references it from the [table of
contents](book/src/SUMMARY.md). Add any relevant *maintainers* to the PR review.
2. The PR being merged indicates your proposed change was accepted and that the
editor and maintainers support your plan of attack.
maintainers support your plan of attack.
3. Submit PRs that implement the proposal. When the implementation reveals the
need for tweaks to the architecture, be sure to update the proposal and have
need for tweaks to the proposal, be sure to update the proposal and have
that change reviewed by the same people as in step 1.
4. Once the implementation is complete, the editor will then work to integrate
the document into the book.
4. Once the implementation is complete, submit a PR that moves the link from
the Accepted Proposals to the Implemented Proposals section.

2182
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,87 +1,41 @@
[package]
name = "solana-workspace"
description = "Blockchain, Rebuilt for Scale"
version = "0.12.0"
documentation = "https://docs.rs/solana"
homepage = "https://solana.com/"
readme = "README.md"
repository = "https://github.com/solana-labs/solana"
authors = ["Solana Maintainers <maintainers@solana.com>"]
license = "Apache-2.0"
edition = "2018"
[badges]
codecov = { repository = "solana-labs/solana", branch = "master", service = "github" }
[features]
chacha = ["solana/chacha"]
cuda = ["solana/cuda"]
erasure = ["solana/erasure"]
[dev-dependencies]
bincode = "1.1.2"
bs58 = "0.2.0"
hashbrown = "0.1.8"
log = "0.4.2"
rand = "0.6.5"
rayon = "1.0.0"
reqwest = "0.9.11"
serde_json = "1.0.39"
solana = { path = "core", version = "0.12.0" }
solana-logger = { path = "logger", version = "0.12.0" }
solana-netutil = { path = "netutil", version = "0.12.0" }
solana-runtime = { path = "runtime", version = "0.12.0" }
solana-sdk = { path = "sdk", version = "0.12.0" }
sys-info = "0.5.6"
[[bench]]
name = "banking_stage"
[[bench]]
name = "blocktree"
[[bench]]
name = "ledger"
[[bench]]
name = "gen_keys"
[[bench]]
name = "sigverify"
[[bench]]
required-features = ["chacha"]
name = "chacha"
[workspace]
members = [
".",
"bench-exchange",
"bench-streamer",
"bench-tps",
"client",
"core",
"drone",
"fullnode",
"validator",
"genesis",
"gossip",
"install",
"keygen",
"kvstore",
"ledger-tool",
"logger",
"metrics",
"netutil",
"programs/bpf",
"programs/bpf_loader",
"programs/budget",
"programs/budget_api",
"programs/token",
"programs/token_api",
"programs/failure",
"programs/noop",
"programs/rewards",
"programs/rewards_api",
"programs/storage",
"programs/budget_program",
"programs/config_api",
"programs/config_program",
"programs/exchange_api",
"programs/exchange_program",
"programs/failure_program",
"programs/noop_program",
"programs/stake_api",
"programs/stake_program",
"programs/storage_api",
"programs/system",
"programs/vote",
"programs/storage_program",
"programs/token_api",
"programs/token_program",
"programs/vote_api",
"programs/vote_program",
"replicator",
"runtime",
"sdk",
"upload-perf",
"vote-signer",

View File

@ -41,10 +41,10 @@ Install rustc, cargo and rustfmt:
```bash
$ curl https://sh.rustup.rs -sSf | sh
$ source $HOME/.cargo/env
$ rustup component add rustfmt-preview
$ rustup component add rustfmt
```
If your rustc version is lower than 1.31.0, please update it:
If your rustc version is lower than 1.34.0, please update it:
```bash
$ rustup update
@ -66,7 +66,7 @@ $ cd solana
Build
```bash
$ cargo build --all
$ cargo build
```
Then to run a minimal local cluster
@ -80,13 +80,7 @@ Testing
Run the test suite:
```bash
$ cargo test --all
```
To emulate all the tests that will run on a Pull Request, run:
```bash
$ ./ci/run-local.sh
$ cargo test
```
Local Testnet
@ -131,6 +125,47 @@ can run your own testnet using the scripts in the `net/` directory.
Edit `ci/testnet-manager.sh`
## Metrics Server Maintenance
Sometimes the dashboard becomes unresponsive. This happens due to glitch in the metrics server.
The current solution is to reset the metrics server. Use the following steps.
1. The server is hosted in a GCP VM instance. Check if the VM instance is down by trying to SSH
into it from the GCP console. The name of the VM is ```metrics-solana-com```.
2. If the VM is inaccessible, reset it from the GCP console.
3. Once VM is up (or, was already up), the metrics services can be restarted from build automation.
1. Navigate to https://buildkite.com/solana-labs/metrics-dot-solana-dot-com in your web browser
2. Click on ```New Build```
3. This will show a pop up dialog. Click on ```options``` drop down.
4. Type in ```FORCE_START=true``` in ```Environment Variables``` text box.
5. Click ```Create Build```
6. This will restart the metrics services, and the dashboards should be accessible afterwards.
## Debugging Testnet
Testnet may exhibit different symptoms of failures. Primary statistics to check are
1. Rise in Confirmation Time
2. Nodes are not voting
3. Panics, and OOM notifications
Check the following if there are any signs of failure.
1. Did testnet deployment fail?
1. View buildkite logs for the last deployment: https://buildkite.com/solana-labs/testnet-management
2. Use the relevant branch
3. If the deployment failed, look at the build logs. The build artifacts for each remote node is uploaded.
It's a good first step to triage from these logs.
2. You may have to log into remote node if the deployment succeeded, but something failed during runtime.
1. Get the private key for the testnet deployment from ```metrics-solana-com``` GCP instance.
2. SSH into ```metrics-solana-com``` using GCP console and do the following.
```bash
sudo bash
cd ~buildkite-agent/.ssh
ls
```
3. Copy the relevant private key to your local machine
4. Find the public IP address of the AWS instance for the remote node using AWS console
5. ```ssh -i <private key file> ubuntu@<ip address of remote node>```
6. The logs are in ```~solana\solana``` folder
Benchmarking
---

View File

@ -61,45 +61,97 @@ There are three release channels that map to branches as follows:
## Release Steps
### Changing channels
When cutting a new channel branch these pre-steps are required:
### Advance the Channels
#### Create the new branch
1. Pick your branch point for release on master.
1. Create the branch. The name should be "v" + the first 2 "version" fields
from Cargo.toml. For example, a Cargo.toml with version = "0.9.0" implies
the next branch name is "v0.9".
1. Push the new branch to the solana repository
1. Update Cargo.toml on master to the next semantic version (e.g. 0.9.0 -> 0.10.0)
by running `./scripts/increment-cargo-version.sh`, then rebuild with a
`cargo build --all` to cause a refresh of `Cargo.lock`.
1. Note the Cargo.toml in the repo root directory does not contain a version. Look at any other Cargo.toml file.
1. Create a new branch and push this branch to the solana repository.
1. `git checkout -b <branchname>`
1. `git push -u origin <branchname>`
#### Update master with the next version
1. After the new branch has been created and pushed, update Cargo.toml on **master** to the next semantic version (e.g. 0.9.0 -> 0.10.0)
by running `./scripts/increment-cargo-version.sh`, then rebuild with
`cargo build` to cause a refresh of `Cargo.lock`.
1. Push your Cargo.toml change and the autogenerated Cargo.lock changes to the
master branch
At this point, ci/channel-info.sh should show your freshly cut release branch as
At this point, `ci/channel-info.sh` should show your freshly cut release branch as
"BETA_CHANNEL" and the previous release branch as "STABLE_CHANNEL".
### Updating channels (i.e. "making a release")
### Make the Release
We use [github's Releases UI](https://github.com/solana-labs/solana/releases) for tagging a release.
1. Go [there ;)](https://github.com/solana-labs/solana/releases).
1. Click "Draft new release". The release tag must exactly match the `version`
field in `/Cargo.toml` prefixed by `v` (ie, `<branchname>.X`).
1. If the first major release on the branch (e.g. v0.8.0), paste in [this
1. If the Cargo.toml verion field is **0.12.3**, then the release tag must be **v0.12.3**
1. If this is the first release on the branch (e.g. v0.13.**0**), paste in [this
template](https://raw.githubusercontent.com/solana-labs/solana/master/.github/RELEASE_TEMPLATE.md)
and fill it in.
1. Test the release by generating a tag using semver's rules. First try at a
release should be `<branchname>.X-rc.0`.
1. Verify release automation:
1. [Crates.io](https://crates.io/crates/solana) should have an updated Solana version.
1. ...
1. After testnet deployment, verify that testnets are running correct software.
http://metrics.solana.com should show testnet running on a hash from your
newly created branch.
1. Once the release has been made, update Cargo.toml on release to the next
1. Once the release has been made, update Cargo.toml on the release branch to the next
semantic version (e.g. 0.9.0 -> 0.9.1) by running
`./scripts/increment-cargo-version.sh patch`, then rebuild with a `cargo
build --all` to cause a refresh of `Cargo.lock`.
`./scripts/increment-cargo-version.sh patch`, then rebuild with `cargo
build` to cause a refresh of `Cargo.lock`.
1. Push your Cargo.toml change and the autogenerated Cargo.lock changes to the
release branch
release branch.
### Update software on testnet.solana.com
The testnet running on testnet.solana.com is set to use a fixed release tag
which is set in the Buildkite testnet-management pipeline.
This tag needs to be updated and the testnet restarted after a new release
tag is created.
#### Update testnet schedules
Go to https://buildkite.com/solana-labs and click through: Pipelines ->
testnet-management -> Pipeline Settings -> Schedules
Or just click here:
https://buildkite.com/solana-labs/testnet-management/settings/schedules
There are two scheduled jobs for testnet: a daily restart and an hourly sanity-or-restart. \
https://buildkite.com/solana-labs/testnet-management/settings/schedules/0efd7856-7143-4713-8817-47e6bdb05387
https://buildkite.com/solana-labs/testnet-management/settings/schedules/2a926646-d972-42b5-aeb9-bb6759592a53
On each schedule:
1. Set TESTNET_TAG environment variable to the desired release tag.
1. Example, TESTNET_TAG=v0.13.2
1. Set the Build Branch to the branch that TESTNET_TAG is from.
1. Example: v0.13
#### Restart the testnet
Trigger a TESTNET_OP=create-and-start to refresh the cluster with the new version
1. Go to https://buildkite.com/solana-labs/testnet-management
2. Click "New Build" and use the following settings, then click "Create Build"
1. Commit: HEAD
1. Branch: [channel branch as set in the schedules]
1. Environment Variables:
```
TESTNET=testnet
TESTNET_TAG=[same value as used in TESTNET_TAG in the schedules]
TESTNET_OP=create-and-start
```
#### Update documentation
Document the new recommended version by updating
```export SOLANA_RELEASE=[new scheduled TESTNET_TAG value]```
in book/src/testnet-participation.md for both edge and beta channel branches.
### Alert the community
Notify Discord users on #validator-support that a new release for
testnet.solana.com is available

3
bench-exchange/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target/
/config/
/config-local/

40
bench-exchange/Cargo.toml Normal file
View File

@ -0,0 +1,40 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-exchange"
version = "0.15.0"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
bs58 = "0.2.0"
clap = "2.32.0"
bincode = "1.1.4"
env_logger = "0.6.0"
itertools = "0.8.0"
log = "0.4.6"
num-traits = "0.2"
num-derive = "0.2"
rand = "0.6.5"
rayon = "1.0.3"
serde = "1.0.91"
serde_derive = "1.0.91"
serde_json = "1.0.38"
# solana-runtime = { path = "../solana/runtime"}
solana = { path = "../core", version = "0.15.0" }
solana-client = { path = "../client", version = "0.15.0" }
solana-drone = { path = "../drone", version = "0.15.0" }
solana-exchange-api = { path = "../programs/exchange_api", version = "0.15.0" }
solana-exchange-program = { path = "../programs/exchange_program", version = "0.15.0" }
solana-logger = { path = "../logger", version = "0.15.0" }
solana-metrics = { path = "../metrics", version = "0.15.0" }
solana-netutil = { path = "../netutil", version = "0.15.0" }
solana-runtime = { path = "../runtime", version = "0.15.0" }
solana-sdk = { path = "../sdk", version = "0.15.0" }
ws = "0.8.1"
untrusted = "0.6.2"
[features]
cuda = ["solana/cuda"]
erasure = []

483
bench-exchange/README.md Normal file
View File

@ -0,0 +1,483 @@
# token-exchange
Solana Token Exchange Bench
If you can't wait; jump to [Running the exchange](#Running-the-exchange) to
learn how to start and interact with the exchange.
### Table of Contents
[Overview](#Overview)<br>
[Premiss](#Premiss)<br>
[Exchange startup](#Exchange-startup)<br>
[Trade requests](#Trade-requests)<br>
[Trade cancellations](#Trade-cancellations)<br>
[Trade swap](#Trade-swap)<br>
[Exchange program operations](#Exchange-program-operations)<br>
[Quotes and OHLCV](#Quotes-and-OHLCV)<br>
[Investor strategies](#Investor-strategies)<br>
[Running the exchange](#Running-the-exchange)<br>
## Overview
An exchange is a marketplace where one asset can be traded for another. This
demo demonstrates one way to host an exchange on the Solana blockchain by
emulating a currency exchange.
The assets are virtual tokens held by investors who may post trade requests to
the exchange. A Swapper monitors the exchange and posts swap requests for
matching trade orders. All the transactions can execute concurrently.
## Premise
- Exchange
- An exchange is a marketplace where one asset can be traded for another.
The exchange in this demo is the on-chain program that implements the
tokens and the policies for trading those tokens.
- Token
- A virtual asset that can be owned, traded, and holds virtual intrinsic value
compared to other assets. There are four types of tokens in this demo, A,
B, C, D. Each one may be traded for another.
- Token account
- An account owned by the exchange that holds a quantity of one type of token.
- Account request
- A request to create a token account
- Token request
- A request to deposit tokens of a particular type into a token account.
- Token pair
- A unique ordered list of two tokens. For the four types of tokens used in
this demo, the valid pairs are AB, AC, AD, BC, BD, CD.
- Direction of trade
- Describes which token in the pair the investor wants to sell and buy and can
be either "To" or "From". For example, if an investor issues a "To" trade
for "AB" then they which to exchange A tokens to B tokens. A "From" order
would read the other way, A tokens from B tokens.
- Price ratio
- An expression of the relative prices of two tokens. They consist of the
price of the primary token and the price of the secondary token. For
simplicity sake, the primary token's price is always 1, which forces the
secondary to be the common denominator. For example, if token A was worth
2 and token B was worth 6, the price ratio would be 1:3 or just 3. Price
ratios are represented as fixed point numbers. The fixed point scaler is
defined in
[exchange_state.rs](https://github.com/solana-labs/solana/blob/c2fdd1362a029dcf89c8907c562d2079d977df11/programs/exchange_api/src/exchange_state.rs#L7)
- Trade request
- A Solana transaction executed by the exchange requesting the trade of one
type of token for another. Trade requests are made up of the token pair,
the direction of the trade, quantity of the primary token, the price ratio,
and the two token accounts to be credited/deducted. An example trade
request looks like "T AB 5 2" which reads "Exchange 5 A tokens to B tokens
at a price ratio of 1:2" A fulfilled trade would result in 5 A tokens
deducted and 10 B tokens credited to the trade initiator's token accounts.
Successful trade requests result in a trade order.
- Trade order
- The result of a successful trade request. Trade orders are stored in
accounts owned by the submitter of the trade request. They can only be
canceled by their owner but can be used by anyone in a trade swap. They
contain the same information as the trade request.
- Price spread
- The difference between the two matching trade orders. The spread is the
profit of the Swapper initiating the swap request.
- Swap requirements
- Policies that result in a successful trade swap.
- Swap request
- A request to exchange tokens between to trade orders
- Trade swap
- A successful trade. A swap consists of two matching trade orders that meet
swap requirements. A trade swap may not wholly satisfy one or both of the
trade orders in which case the trade orders are adjusted appropriately. As
long as the swap requirements are met there will be an exchange of tokens
between accounts. Any price spread is deposited into the Swapper's profit
account. All trade swaps are recorded in a new account for posterity.
- Investor
- Individual investors who hold a number of tokens and wish to trade them on
the exchange. Investors operate as Solana thin clients who own a set of
accounts containing tokens and/or trade requests. Investors post
transactions to the exchange in order to request tokens and post or cancel
trade requests.
- Swapper
- An agent who facilitates trading between investors. Swappers operate as
Solana thin clients who monitor all the trade orders looking for a trade
match. Once found, the Swapper issues a swap request to the exchange.
Swappers are the engine of the exchange and are rewarded for their efforts by
accumulating the price spreads of the swaps they initiate. Swappers also
provide current bid/ask price and OHLCV (Open, High, Low, Close, Volume)
information on demand via a public network port.
- Transaction fees
- Solana transaction fees are paid for by the transaction submitters who are
the Investors and Swappers.
## Exchange startup
The exchange is up and running when it reaches a state where it can take
investor's trades and Swapper's swap requests. To achieve this state the
following must occur in order:
- Start the Solana blockchain
- Start the Swapper thin-client
- The Swapper subscribes to change notifications for all the accounts owned by
the exchange program id. The subscription is managed via Solana's JSON RPC
interface.
- The Swapper starts responding to queries for bid/ask price and OHLCV
The Swapper responding successfully to price and OHLCV requests is the signal to
the investors that trades submitted after that point will be analyzed. <!--This
is not ideal, and instead investors should be able to submit trades at any time,
and the Swapper could come and go without missing a trade. One way to achieve
this is for the Swapper to read the current state of all accounts looking for all
open trade orders.-->
Investors will initially query the exchange to discover their current balance
for each type of token. If the investor does not already have an account for
each type of token, they will submit account requests. Swappers as well will
request accounts to hold the tokens they earn by initiating trade swaps.
```rust
/// Supported token types
pub enum Token {
A,
B,
C,
D,
}
/// Supported token pairs
pub enum TokenPair {
AB,
AC,
AD,
BC,
BD,
CD,
}
pub enum ExchangeInstruction {
/// New token account
/// key 0 - Signer
/// key 1 - New token account
AccountRequest,
}
/// Token accounts are populated with this structure
pub struct TokenAccountInfo {
/// Investor who owns this account
pub owner: Pubkey,
/// Current number of tokens this account holds
pub tokens: Tokens,
}
```
For this demo investors or Swappers can request more tokens from the exchange at
any time by submitting token requests. In non-demos, an exchange of this type
would provide another way to exchange a 3rd party asset into tokens.
To request tokens, investors submit transfer requests:
```rust
pub enum ExchangeInstruction {
/// Transfer tokens between two accounts
/// key 0 - Account to transfer tokens to
/// key 1 - Account to transfer tokens from. This can be the exchange program itself,
/// the exchange has a limitless number of tokens it can transfer.
TransferRequest(Token, u64),
}
```
## Trade requests
When an investor decides to exchange a token of one type for another, they
submit a transaction to the Solana Blockchain containing a trade request, which,
if successful, is turned into a trade order. Trade orders do not expire but are
cancellable. <!-- Trade orders should have a timestamp to enable trade
expiration --> When a trade order is created, tokens are deducted from a token
account and the trade order acts as an escrow. The tokens are held until the
trade order is fulfilled or canceled. If the direction is `To`, then the number
of `tokens` are deducted from the primary account, if `From` then `tokens`
multiplied by `price` are deducted from the secondary account. Trade orders are
no longer valid when the number of `tokens` goes to zero, at which point they
can no longer be used. <!-- Could support refilling trade orders, so trade order
accounts are refilled rather than accumulating -->
```rust
/// Direction of the exchange between two tokens in a pair
pub enum Direction {
/// Trade first token type (primary) in the pair 'To' the second
To,
/// Trade first token type in the pair 'From' the second (secondary)
From,
}
pub struct TradeRequestInfo {
/// Direction of trade
pub direction: Direction,
/// Token pair to trade
pub pair: TokenPair,
/// Number of tokens to exchange; refers to the primary or the secondary depending on the direction
pub tokens: u64,
/// The price ratio the primary price over the secondary price. The primary price is fixed
/// and equal to the variable `SCALER`.
pub price: u64,
/// Token account to deposit tokens on successful swap
pub dst_account: Pubkey,
}
pub enum ExchangeInstruction {
/// Trade request
/// key 0 - Signer
/// key 1 - Account in which to record the swap
/// key 2 - Token account associated with this trade
TradeRequest(TradeRequestInfo),
}
/// Trade accounts are populated with this structure
pub struct TradeOrderInfo {
/// Owner of the trade order
pub owner: Pubkey,
/// Direction of the exchange
pub direction: Direction,
/// Token pair indicating two tokens to exchange, first is primary
pub pair: TokenPair,
/// Number of tokens to exchange; primary or secondary depending on direction
pub tokens: u64,
/// Scaled price of the secondary token given the primary is equal to the scale value
/// If scale is 1 and price is 2 then ratio is 1:2 or 1 primary token for 2 secondary tokens
pub price: u64,
/// account which the tokens were source from. The trade account holds the tokens in escrow
/// until either one or more part of a swap or the trade is canceled.
pub src_account: Pubkey,
/// account which the tokens the tokens will be deposited into on a successful trade
pub dst_account: Pubkey,
}
```
## Trade cancellations
An investor may cancel a trade at anytime, but only trades they own. If the
cancellation is successful, any tokens held in escrow are returned to the
account from which they came.
```rust
pub enum ExchangeInstruction {
/// Trade cancellation
/// key 0 - Signer
/// key 1 -Trade order to cancel
TradeCancellation,
}
```
## Trade swaps
The Swapper is monitoring the accounts assigned to the exchange program and
building a trade-order table. The trade order table is used to identify
matching trade orders which could be fulfilled. When a match is found the
Swapper should issue a swap request. Swap requests may not satisfy the entirety
of either order, but the exchange will greedily fulfill it. Any leftover tokens
in either account will keep the trade order valid for further swap requests in
the future.
Matching trade orders are defined by the following swap requirements:
- Opposite polarity (one `To` and one `From`)
- Operate on the same token pair
- The price ratio of the `From` order is greater than or equal to the `To` order
- There are sufficient tokens to perform the trade
Orders can be written in the following format:
`investor direction pair quantity price-ratio`
For example:
- `1 T AB 2 1`
- Investor 1 wishes to exchange 2 A tokens to B tokens at a ratio of 1 A to 1
B
- `2 F AC 6 1.2`
- Investor 2 wishes to exchange A tokens from 6 B tokens at a ratio of 1 A
from 1.2 B
An order table could look something like the following. Notice how the columns
are sorted low to high and high to low, respectively. Prices are dramatic and
whole for clarity.
|Row| To | From |
|---|-------------|------------|
| 1 | 1 T AB 2 4 | 2 F AB 2 8 |
| 2 | 1 T AB 1 4 | 2 F AB 2 8 |
| 3 | 1 T AB 6 6 | 2 F AB 2 7 |
| 4 | 1 T AB 2 8 | 2 F AB 3 6 |
| 5 | 1 T AB 2 10 | 2 F AB 1 5 |
As part of a successful swap request, the exchange will credit tokens to the
Swapper's account equal to the difference in the price ratios or the two orders.
These tokens are considered the Swapper's profit for initiating the trade.
The Swapper would initiate the following swap on the order table above:
- Row 1, To: Investor 1 trades 2 A tokens to 8 B tokens
- Row 1, From: Investor 2 trades 2 A tokens from 8 B tokens
- Swapper takes 8 B tokens as profit
Both row 1 trades are fully realized, table becomes:
|Row| To | From |
|---|-------------|------------|
| 1 | 1 T AB 1 4 | 2 F AB 2 8 |
| 2 | 1 T AB 6 6 | 2 F AB 2 7 |
| 3 | 1 T AB 2 8 | 2 F AB 3 6 |
| 4 | 1 T AB 2 10 | 2 F AB 1 5 |
The Swapper would initiate the following swap:
- Row 1, To: Investor 1 trades 1 A token to 4 B tokens
- Row 1, From: Investor 2 trades 1 A token from 4 B tokens
- Swapper takes 4 B tokens as profit
Row 1 From is not fully realized, table becomes:
|Row| To | From |
|---|-------------|------------|
| 1 | 1 T AB 6 6 | 2 F AB 1 8 |
| 2 | 1 T AB 2 8 | 2 F AB 2 7 |
| 3 | 1 T AB 2 10 | 2 F AB 3 6 |
| 4 | | 2 F AB 1 5 |
The Swapper would initiate the following swap:
- Row 1, To: Investor 1 trades 1 A token to 6 B tokens
- Row 1, From: Investor 2 trades 1 A token from 6 B tokens
- Swapper takes 2 B tokens as profit
Row 1 To is now fully realized, table becomes:
|Row| To | From |
|---|-------------|------------|
| 1 | 1 T AB 5 6 | 2 F AB 2 7 |
| 2 | 1 T AB 2 8 | 2 F AB 3 5 |
| 3 | 1 T AB 2 10 | 2 F AB 1 5 |
The Swapper would initiate the following last swap:
- Row 1, To: Investor 1 trades 2 A token to 12 B tokens
- Row 1, From: Investor 2 trades 2 A token from 12 B tokens
- Swapper takes 4 B tokens as profit
Table becomes:
|Row| To | From |
|---|-------------|------------|
| 1 | 1 T AB 3 6 | 2 F AB 3 5 |
| 2 | 1 T AB 2 8 | 2 F AB 1 5 |
| 3 | 1 T AB 2 10 | |
At this point the lowest To's price is larger than the largest From's price so
no more swaps would be initiated until new orders came in.
```rust
pub enum ExchangeInstruction {
/// Trade swap request
/// key 0 - Signer
/// key 1 - Account in which to record the swap
/// key 2 - 'To' trade order
/// key 3 - `From` trade order
/// key 4 - Token account associated with the To Trade
/// key 5 - Token account associated with From trade
/// key 6 - Token account in which to deposit the Swappers profit from the swap.
SwapRequest,
}
/// Swap accounts are populated with this structure
pub struct TradeSwapInfo {
/// Pair swapped
pub pair: TokenPair,
/// `To` trade order
pub to_trade_order: Pubkey,
/// `From` trade order
pub from_trade_order: Pubkey,
/// Number of primary tokens exchanged
pub primary_tokens: u64,
/// Price the primary tokens were exchanged for
pub primary_price: u64,
/// Number of secondary tokens exchanged
pub secondary_tokens: u64,
/// Price the secondary tokens were exchanged for
pub secondary_price: u64,
}
```
## Exchange program operations
Putting all the commands together from above, the following operations will be
supported by the on-chain exchange program:
```rust
pub enum ExchangeInstruction {
/// New token account
/// key 0 - Signer
/// key 1 - New token account
AccountRequest,
/// Transfer tokens between two accounts
/// key 0 - Account to transfer tokens to
/// key 1 - Account to transfer tokens from. This can be the exchange program itself,
/// the exchange has a limitless number of tokens it can transfer.
TransferRequest(Token, u64),
/// Trade request
/// key 0 - Signer
/// key 1 - Account in which to record the swap
/// key 2 - Token account associated with this trade
TradeRequest(TradeRequestInfo),
/// Trade cancellation
/// key 0 - Signer
/// key 1 -Trade order to cancel
TradeCancellation,
/// Trade swap request
/// key 0 - Signer
/// key 1 - Account in which to record the swap
/// key 2 - 'To' trade order
/// key 3 - `From` trade order
/// key 4 - Token account associated with the To Trade
/// key 5 - Token account associated with From trade
/// key 6 - Token account in which to deposit the Swappers profit from the swap.
SwapRequest,
}
```
## Quotes and OHLCV
The Swapper will provide current bid/ask price quotes based on trade actively and
also provide OHLCV based on some time window. The details of how the bid/ask
price quotes are calculated are yet to be decided.
## Investor strategies
To make a compelling demo, the investors needs to provide interesting trade
behavior. Something as simple as a randomly twiddled baseline would be a
minimum starting point.
## Running the exchange
The exchange bench posts trades and swaps matches as fast as it can.
You might want to bump the duration up
to 60 seconds and the batch size to 1000 for better numbers. You can modify those
in client_demo/src/demo.rs::test_exchange_local_cluster.
The following command runs the bench:
```bash
$ RUST_LOG=solana_bench_exchange=info cargo test --release -- --nocapture test_exchange_local_cluster
```
To also see the cluster messages:
```bash
$ RUST_LOG=solana_bench_exchange=info,solana=info cargo test --release -- --nocapture test_exchange_local_cluster
```

996
bench-exchange/src/bench.rs Normal file
View File

@ -0,0 +1,996 @@
#![allow(clippy::useless_attribute)]
use crate::order_book::*;
use itertools::izip;
use log::*;
use rand::{thread_rng, Rng};
use rayon::prelude::*;
use solana::gen_keys::GenKeys;
use solana_client::perf_utils::{sample_txs, SampleStats};
use solana_drone::drone::request_airdrop_transaction;
use solana_exchange_api::exchange_instruction;
use solana_exchange_api::exchange_state::*;
use solana_exchange_api::id;
use solana_metrics::datapoint_info;
use solana_sdk::client::Client;
use solana_sdk::client::SyncClient;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction;
use solana_sdk::timing::{duration_as_ms, duration_as_s};
use solana_sdk::transaction::Transaction;
use std::cmp;
use std::collections::VecDeque;
use std::mem;
use std::net::SocketAddr;
use std::process::exit;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, RwLock};
use std::thread::{sleep, Builder};
use std::time::{Duration, Instant};
// TODO Chunk length as specified results in a bunch of failures, divide by 10 helps...
// Assume 4MB network buffers, and 512 byte packets
const FUND_CHUNK_LEN: usize = 4 * 1024 * 1024 / 512;
// Maximum system transfers per transaction
const MAX_TRANSFERS_PER_TX: u64 = 4;
pub type SharedTransactions = Arc<RwLock<VecDeque<Vec<Transaction>>>>;
pub struct Config {
pub identity: Keypair,
pub threads: usize,
pub duration: Duration,
pub transfer_delay: u64,
pub fund_amount: u64,
pub batch_size: usize,
pub chunk_size: usize,
pub account_groups: usize,
}
impl Default for Config {
fn default() -> Self {
Self {
identity: Keypair::new(),
threads: 4,
duration: Duration::new(u64::max_value(), 0),
transfer_delay: 0,
fund_amount: 100_000,
batch_size: 10,
chunk_size: 10,
account_groups: 100,
}
}
}
pub fn do_bench_exchange<T>(clients: Vec<T>, config: Config)
where
T: 'static + Client + Send + Sync,
{
let Config {
identity,
threads,
duration,
transfer_delay,
fund_amount,
batch_size,
chunk_size,
account_groups,
} = config;
info!(
"Exchange client: threads {} duration {} fund_amount {}",
threads,
duration_as_s(&duration),
fund_amount
);
info!(
"Exchange client: transfer delay {} batch size {} chunk size {}",
transfer_delay, batch_size, chunk_size
);
let accounts_in_groups = batch_size * account_groups;
let exit_signal = Arc::new(AtomicBool::new(false));
let clients: Vec<_> = clients.into_iter().map(Arc::new).collect();
let client = clients[0].as_ref();
const NUM_KEYPAIR_GROUPS: u64 = 4;
let total_keys = accounts_in_groups as u64 * NUM_KEYPAIR_GROUPS;
info!("Generating {:?} keys", total_keys);
let mut keypairs = generate_keypairs(total_keys);
let trader_signers: Vec<_> = keypairs
.drain(0..accounts_in_groups)
.map(Arc::new)
.collect();
let swapper_signers: Vec<_> = keypairs
.drain(0..accounts_in_groups)
.map(Arc::new)
.collect();
let src_pubkeys: Vec<_> = keypairs
.drain(0..accounts_in_groups)
.map(|keypair| keypair.pubkey())
.collect();
let profit_pubkeys: Vec<_> = keypairs
.drain(0..accounts_in_groups)
.map(|keypair| keypair.pubkey())
.collect();
info!("Fund trader accounts");
fund_keys(client, &identity, &trader_signers, fund_amount);
info!("Fund swapper accounts");
fund_keys(client, &identity, &swapper_signers, fund_amount);
info!("Create {:?} source token accounts", src_pubkeys.len());
create_token_accounts(client, &trader_signers, &src_pubkeys);
info!("Create {:?} profit token accounts", profit_pubkeys.len());
create_token_accounts(client, &swapper_signers, &profit_pubkeys);
// Collect the max transaction rate and total tx count seen (single node only)
let sample_stats = Arc::new(RwLock::new(Vec::new()));
let sample_period = 1; // in seconds
info!("Sampling clients for tps every {} s", sample_period);
info!(
"Requesting and swapping trades with {} ms delay per thread...",
transfer_delay
);
let shared_txs: SharedTransactions = Arc::new(RwLock::new(VecDeque::new()));
let total_txs_sent_count = Arc::new(AtomicUsize::new(0));
let s_threads: Vec<_> = (0..threads)
.map(|_| {
let exit_signal = exit_signal.clone();
let shared_txs = shared_txs.clone();
let total_txs_sent_count = total_txs_sent_count.clone();
let client = clients[0].clone();
Builder::new()
.name("solana-exchange-transfer".to_string())
.spawn(move || {
do_tx_transfers(&exit_signal, &shared_txs, &total_txs_sent_count, &client)
})
.unwrap()
})
.collect();
trace!("Start swapper thread");
let (swapper_sender, swapper_receiver) = channel();
let swapper_thread = {
let exit_signal = exit_signal.clone();
let shared_txs = shared_txs.clone();
let client = clients[0].clone();
Builder::new()
.name("solana-exchange-swapper".to_string())
.spawn(move || {
swapper(
&exit_signal,
&swapper_receiver,
&shared_txs,
&swapper_signers,
&profit_pubkeys,
transfer_delay,
batch_size,
chunk_size,
account_groups,
&client,
)
})
.unwrap()
};
trace!("Start trader thread");
let trader_thread = {
let exit_signal = exit_signal.clone();
let shared_txs = shared_txs.clone();
let client = clients[0].clone();
Builder::new()
.name("solana-exchange-trader".to_string())
.spawn(move || {
trader(
&exit_signal,
&swapper_sender,
&shared_txs,
&trader_signers,
&src_pubkeys,
transfer_delay,
batch_size,
chunk_size,
account_groups,
&client,
)
})
.unwrap()
};
let sample_threads: Vec<_> = clients
.iter()
.map(|client| {
let exit_signal = exit_signal.clone();
let sample_stats = sample_stats.clone();
let client = client.clone();
Builder::new()
.name("solana-exchange-sample".to_string())
.spawn(move || sample_txs(&exit_signal, &sample_stats, sample_period, &client))
.unwrap()
})
.collect();
sleep(duration);
info!("Stopping threads");
exit_signal.store(true, Ordering::Relaxed);
info!("Wait for trader thread");
let _ = trader_thread.join();
info!("Waiting for swapper thread");
let _ = swapper_thread.join();
info!("Wait for tx threads");
for t in s_threads {
let _ = t.join();
}
info!("Wait for sample threads");
for t in sample_threads {
let _ = t.join();
}
compute_and_report_stats(
&sample_stats,
total_txs_sent_count.load(Ordering::Relaxed) as u64,
);
}
fn do_tx_transfers<T>(
exit_signal: &Arc<AtomicBool>,
shared_txs: &SharedTransactions,
total_txs_sent_count: &Arc<AtomicUsize>,
client: &Arc<T>,
) where
T: Client,
{
loop {
let txs;
{
let mut shared_txs_wl = shared_txs.write().unwrap();
txs = shared_txs_wl.pop_front();
}
if let Some(txs0) = txs {
let n = txs0.len();
let now = Instant::now();
for tx in txs0 {
client.async_send_transaction(tx).expect("Transfer");
}
let duration = now.elapsed();
total_txs_sent_count.fetch_add(n, Ordering::Relaxed);
datapoint_info!(
"bench-exchange-do_tx_transfers",
("duration", duration_as_ms(&duration), i64),
("count", n, i64)
);
}
if exit_signal.load(Ordering::Relaxed) {
return;
}
}
}
struct TradeInfo {
trade_account: Pubkey,
order_info: TradeOrderInfo,
}
#[allow(clippy::too_many_arguments)]
fn swapper<T>(
exit_signal: &Arc<AtomicBool>,
receiver: &Receiver<Vec<TradeInfo>>,
shared_txs: &SharedTransactions,
signers: &[Arc<Keypair>],
profit_pubkeys: &[Pubkey],
transfer_delay: u64,
batch_size: usize,
chunk_size: usize,
account_groups: usize,
client: &Arc<T>,
) where
T: Client,
{
let mut order_book = OrderBook::default();
let mut account_group: usize = 0;
let mut txs = 0;
let mut total_txs = 0;
let mut now = Instant::now();
let start_time = now;
let mut total_elapsed = start_time.elapsed();
// Chunks may have been dropped and we don't want to wait a long time
// for each time, Back-off each time we fail to confirm a chunk
const CHECK_TX_TIMEOUT_MAX_MS: u64 = 15000;
const CHECK_TX_DELAY_MS: u64 = 100;
let mut max_tries = CHECK_TX_TIMEOUT_MAX_MS / CHECK_TX_DELAY_MS;
// If we dump too many chunks maybe we are just waiting on a back-log
// rather than a series of dropped packets, reset to max waits
const MAX_DUMPS: u64 = 50;
let mut dumps = 0;
'outer: loop {
if let Ok(trade_infos) = receiver.try_recv() {
let mut tries = 0;
let mut trade_index = 0;
while client
.get_balance(&trade_infos[trade_index].trade_account)
.unwrap_or(0)
== 0
{
tries += 1;
if tries >= max_tries {
if exit_signal.load(Ordering::Relaxed) {
break 'outer;
}
error!("Give up and dump batch");
if dumps >= MAX_DUMPS {
error!("Max batches dumped, reset wait back-off");
max_tries = CHECK_TX_TIMEOUT_MAX_MS / CHECK_TX_DELAY_MS;
dumps = 0;
} else {
dumps += 1;
max_tries /= 2;
}
continue 'outer;
}
debug!("{} waiting for trades batch to clear", tries);
sleep(Duration::from_millis(CHECK_TX_DELAY_MS));
trade_index = thread_rng().gen_range(0, trade_infos.len());
}
max_tries = CHECK_TX_TIMEOUT_MAX_MS / CHECK_TX_DELAY_MS;
dumps = 0;
trade_infos.iter().for_each(|info| {
order_book
.push(info.trade_account, info.order_info)
.expect("Failed to push to order_book");
});
let mut swaps = Vec::new();
while let Some((to, from)) = order_book.pop() {
swaps.push((to, from));
if swaps.len() >= batch_size {
break;
}
}
let swaps_size = swaps.len();
let mut to_swap = vec![];
let start = account_group * swaps_size as usize;
let end = account_group * swaps_size as usize + batch_size as usize;
for (signer, swap, profit) in izip!(
signers[start..end].iter(),
swaps,
profit_pubkeys[start..end].iter(),
) {
to_swap.push((signer, swap, profit));
}
account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.expect("Failed to get blockhash");
let to_swap_txs: Vec<_> = to_swap
.par_iter()
.map(|(signer, swap, profit)| {
let s: &Keypair = &signer;
let owner = &signer.pubkey();
Transaction::new_signed_instructions(
&[s],
vec![exchange_instruction::swap_request(
owner,
&swap.0.pubkey,
&swap.1.pubkey,
&profit,
)],
blockhash,
)
})
.collect();
txs += to_swap_txs.len() as u64;
total_txs += to_swap_txs.len() as u64;
total_elapsed = start_time.elapsed();
let duration = now.elapsed();
if duration_as_s(&duration) >= 1_f32 {
now = Instant::now();
let tps = txs as f32 / duration_as_s(&duration);
info!(
"Swapper {:9.2} TPS, Transactions: {:6}, Total transactions: {} over {} s",
tps,
txs,
total_txs,
total_elapsed.as_secs(),
);
txs = 0;
}
datapoint_info!("bench-exchange-swaps", ("count", to_swap_txs.len(), i64));
let chunks: Vec<_> = to_swap_txs.chunks(chunk_size).collect();
{
let mut shared_txs_wl = shared_txs.write().unwrap();
for chunk in chunks {
shared_txs_wl.push_back(chunk.to_vec());
}
}
// Throttle the swapper so it doesn't try to catchup unbridled
sleep(Duration::from_millis(transfer_delay / 2));
}
if exit_signal.load(Ordering::Relaxed) {
break 'outer;
}
}
info!(
"Swapper sent {} at {:9.2} TPS",
total_txs,
total_txs as f32 / duration_as_s(&total_elapsed)
);
assert_eq!(
order_book.get_num_outstanding().0 + order_book.get_num_outstanding().1,
0
);
}
#[allow(clippy::too_many_arguments)]
fn trader<T>(
exit_signal: &Arc<AtomicBool>,
sender: &Sender<Vec<TradeInfo>>,
shared_txs: &SharedTransactions,
signers: &[Arc<Keypair>],
srcs: &[Pubkey],
transfer_delay: u64,
batch_size: usize,
chunk_size: usize,
account_groups: usize,
client: &Arc<T>,
) where
T: Client,
{
// TODO Hard coded for now
let pair = TokenPair::AB;
let tokens = 1;
let price = 1000;
let mut account_group: usize = 0;
let mut txs = 0;
let mut total_txs = 0;
let mut now = Instant::now();
let start_time = now;
let mut total_elapsed = start_time.elapsed();
loop {
let trade_keys = generate_keypairs(batch_size as u64);
let mut trades = vec![];
let mut trade_infos = vec![];
let start = account_group * batch_size as usize;
let end = account_group * batch_size as usize + batch_size as usize;
let mut direction = Direction::To;
for (signer, trade, src) in izip!(
signers[start..end].iter(),
trade_keys,
srcs[start..end].iter(),
) {
direction = if direction == Direction::To {
Direction::From
} else {
Direction::To
};
let order_info = TradeOrderInfo {
/// Owner of the trade order
owner: Pubkey::default(), // don't care
direction,
pair,
tokens,
price,
tokens_settled: 0,
};
trade_infos.push(TradeInfo {
trade_account: trade.pubkey(),
order_info,
});
trades.push((signer, trade.pubkey(), direction, src));
}
account_group = (account_group + 1) % account_groups as usize;
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.expect("Failed to get blockhash");
trades.chunks(chunk_size).for_each(|chunk| {
let trades_txs: Vec<_> = chunk
.par_iter()
.map(|(signer, trade, direction, src)| {
let s: &Keypair = &signer;
let owner = &signer.pubkey();
let space = mem::size_of::<ExchangeState>() as u64;
Transaction::new_signed_instructions(
&[s],
vec![
system_instruction::create_account(owner, trade, 1, space, &id()),
exchange_instruction::trade_request(
owner, trade, *direction, pair, tokens, price, src,
),
],
blockhash,
)
})
.collect();
{
txs += chunk_size as u64;
total_txs += chunk_size as u64;
total_elapsed = start_time.elapsed();
let duration = now.elapsed();
if duration_as_s(&duration) >= 1_f32 {
now = Instant::now();
let tps = txs as f32 / duration_as_s(&duration);
info!(
"Trader {:9.2} TPS, Transactions: {:6}, Total transactions: {} over {} s",
tps,
txs,
total_txs,
total_elapsed.as_secs(),
);
txs = 0;
}
datapoint_info!("bench-exchange-trades", ("count", trades_txs.len(), i64));
{
let mut shared_txs_wl = shared_txs
.write()
.expect("Failed to send tx to transfer threads");
shared_txs_wl.push_back(trades_txs);
}
}
if transfer_delay > 0 {
sleep(Duration::from_millis(transfer_delay));
}
});
if exit_signal.load(Ordering::Relaxed) {
info!(
"Trader sent {} at {:9.2} TPS",
total_txs,
total_txs as f32 / duration_as_s(&total_elapsed)
);
return;
}
// TODO chunk the trade infos and send them when the batch is sent
sender
.send(trade_infos)
.expect("Failed to send trades to swapper");
}
}
fn verify_transfer<T>(sync_client: &T, tx: &Transaction) -> bool
where
T: SyncClient + ?Sized,
{
for s in &tx.signatures {
if let Ok(Some(r)) = sync_client.get_signature_status(s) {
match r {
Ok(_) => {
return true;
}
Err(e) => {
info!("error: {:?}", e);
}
}
}
}
false
}
pub fn fund_keys(client: &Client, source: &Keypair, dests: &[Arc<Keypair>], lamports: u64) {
let total = lamports * (dests.len() as u64 + 1);
let mut funded: Vec<(&Keypair, u64)> = vec![(source, total)];
let mut notfunded: Vec<&Arc<Keypair>> = dests.iter().collect();
info!(
" Funding {} keys with {} lamports each",
dests.len(),
lamports
);
while !notfunded.is_empty() {
if funded.is_empty() {
panic!("No funded accounts left to fund remaining");
}
let mut new_funded: Vec<(&Keypair, u64)> = vec![];
let mut to_fund = vec![];
debug!(" Creating from... {}", funded.len());
for f in &mut funded {
let max_units = cmp::min(
cmp::min(notfunded.len() as u64, MAX_TRANSFERS_PER_TX),
(f.1 - lamports) / lamports,
);
if max_units == 0 {
continue;
}
let per_unit = ((f.1 - lamports) / lamports / max_units) * lamports;
f.1 -= per_unit * max_units;
let start = notfunded.len() - max_units as usize;
let moves: Vec<_> = notfunded[start..]
.iter()
.map(|k| (k.pubkey(), per_unit))
.collect();
notfunded[start..]
.iter()
.for_each(|k| new_funded.push((k, per_unit)));
notfunded.truncate(start);
if !moves.is_empty() {
to_fund.push((f.0, moves));
}
}
to_fund.chunks(FUND_CHUNK_LEN).for_each(|chunk| {
#[allow(clippy::clone_double_ref)] // sigh
let mut to_fund_txs: Vec<_> = chunk
.par_iter()
.map(|(k, m)| {
(
k.clone(),
Transaction::new_unsigned_instructions(system_instruction::transfer_many(
&k.pubkey(),
&m,
)),
)
})
.collect();
let mut retries = 0;
while !to_fund_txs.is_empty() {
let receivers = to_fund_txs
.iter()
.fold(0, |len, (_, tx)| len + tx.message().instructions.len());
debug!(
" {} to {} in {} txs",
if retries == 0 {
" Transferring"
} else {
" Retrying"
},
receivers,
to_fund_txs.len(),
);
let (blockhash, _fee_calculator) =
client.get_recent_blockhash().expect("blockhash");
to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
tx.sign(&[*k], blockhash);
});
to_fund_txs.iter().for_each(|(_, tx)| {
client.async_send_transaction(tx.clone()).expect("transfer");
});
let mut waits = 0;
loop {
sleep(Duration::from_millis(200));
to_fund_txs.retain(|(_, tx)| !verify_transfer(client, &tx));
if to_fund_txs.is_empty() {
break;
}
debug!(
" {} transactions outstanding, {:?} waits",
to_fund_txs.len(),
waits
);
waits += 1;
if waits >= 5 {
break;
}
}
if !to_fund_txs.is_empty() {
retries += 1;
debug!(" Retry {:?}", retries);
if retries >= 10 {
error!(" Too many retries, give up");
exit(1);
}
}
}
});
funded.append(&mut new_funded);
funded.retain(|(k, b)| {
client.get_balance(&k.pubkey()).unwrap_or(0) > lamports && *b > lamports
});
debug!(" Funded: {} left: {}", funded.len(), notfunded.len());
}
}
pub fn create_token_accounts(client: &Client, signers: &[Arc<Keypair>], accounts: &[Pubkey]) {
let mut notfunded: Vec<(&Arc<Keypair>, &Pubkey)> = signers.iter().zip(accounts).collect();
while !notfunded.is_empty() {
notfunded.chunks(FUND_CHUNK_LEN).for_each(|chunk| {
let mut to_create_txs: Vec<_> = chunk
.par_iter()
.map(|(signer, new)| {
let owner_pubkey = &signer.pubkey();
let space = mem::size_of::<ExchangeState>() as u64;
let create_ix =
system_instruction::create_account(owner_pubkey, new, 1, space, &id());
let request_ix = exchange_instruction::account_request(owner_pubkey, new);
(
signer,
Transaction::new_unsigned_instructions(vec![create_ix, request_ix]),
)
})
.collect();
let accounts = to_create_txs
.iter()
.fold(0, |len, (_, tx)| len + tx.message().instructions.len() / 2);
debug!(
" Creating {} accounts in {} txs",
accounts,
to_create_txs.len(),
);
let mut retries = 0;
while !to_create_txs.is_empty() {
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.expect("Failed to get blockhash");
to_create_txs.par_iter_mut().for_each(|(k, tx)| {
let kp: &Keypair = k;
tx.sign(&[kp], blockhash);
});
to_create_txs.iter().for_each(|(_, tx)| {
client.async_send_transaction(tx.clone()).expect("transfer");
});
let mut waits = 0;
while !to_create_txs.is_empty() {
sleep(Duration::from_millis(200));
to_create_txs.retain(|(_, tx)| !verify_transfer(client, &tx));
if to_create_txs.is_empty() {
break;
}
debug!(
" {} transactions outstanding, waits {:?}",
to_create_txs.len(),
waits
);
waits += 1;
if waits >= 5 {
break;
}
}
if !to_create_txs.is_empty() {
retries += 1;
debug!(" Retry {:?}", retries);
if retries >= 20 {
error!(" Too many retries, give up");
exit(1);
}
}
}
});
let mut new_notfunded: Vec<(&Arc<Keypair>, &Pubkey)> = vec![];
for f in &notfunded {
if client.get_balance(&f.1).unwrap_or(0) == 0 {
new_notfunded.push(*f)
}
}
notfunded = new_notfunded;
debug!(" Left: {}", notfunded.len());
}
}
fn compute_and_report_stats(maxes: &Arc<RwLock<Vec<(String, SampleStats)>>>, total_txs_sent: u64) {
let mut max_txs = 0;
let mut max_elapsed = Duration::new(0, 0);
info!("| Max TPS | Total Transactions");
info!("+---------------+--------------------");
for (_sock, stats) in maxes.read().unwrap().iter() {
let maybe_flag = match stats.txs {
0 => "!!!!!",
_ => "",
};
info!("| {:13.2} | {} {}", stats.tps, stats.txs, maybe_flag);
if stats.elapsed > max_elapsed {
max_elapsed = stats.elapsed;
}
if stats.txs > max_txs {
max_txs = stats.txs;
}
}
info!("+---------------+--------------------");
if max_txs >= total_txs_sent {
info!(
"Warning: Average TPS might be under reported, there were no txs sent for a portion of the duration"
);
max_txs = total_txs_sent;
}
info!(
"{} txs outstanding when test ended (lag) ({:.2}%)",
total_txs_sent - max_txs,
(total_txs_sent - max_txs) as f64 / total_txs_sent as f64 * 100_f64
);
info!(
"\tAverage TPS: {:.2}",
max_txs as f32 / max_elapsed.as_secs() as f32
);
}
fn generate_keypairs(num: u64) -> Vec<Keypair> {
let mut seed = [0_u8; 32];
seed.copy_from_slice(&Keypair::new().pubkey().as_ref());
let mut rnd = GenKeys::new(seed);
rnd.gen_n_keypairs(num)
}
pub fn airdrop_lamports(client: &Client, drone_addr: &SocketAddr, id: &Keypair, amount: u64) {
let balance = client.get_balance(&id.pubkey());
let balance = balance.unwrap_or(0);
if balance >= amount {
return;
}
let amount_to_drop = amount - balance;
info!(
"Airdropping {:?} lamports from {} for {}",
amount_to_drop,
drone_addr,
id.pubkey(),
);
let mut tries = 0;
loop {
let (blockhash, _fee_calculator) = client
.get_recent_blockhash()
.expect("Failed to get blockhash");
match request_airdrop_transaction(&drone_addr, &id.pubkey(), amount_to_drop, blockhash) {
Ok(transaction) => {
let signature = client.async_send_transaction(transaction).unwrap();
for _ in 0..30 {
if let Ok(Some(_)) = client.get_signature_status(&signature) {
break;
}
sleep(Duration::from_millis(100));
}
if client.get_balance(&id.pubkey()).unwrap_or(0) >= amount {
break;
}
}
Err(err) => {
panic!(
"Error requesting airdrop: {:?} to addr: {:?} amount: {}",
err, drone_addr, amount
);
}
};
debug!(" Retry...");
tries += 1;
if tries > 50 {
error!("Too many retries, give up");
exit(1);
}
sleep(Duration::from_secs(2));
}
}
#[cfg(test)]
mod tests {
use super::*;
use solana::gossip_service::{discover_cluster, get_clients};
use solana::local_cluster::{ClusterConfig, LocalCluster};
use solana::validator::ValidatorConfig;
use solana_drone::drone::run_local_drone;
use solana_exchange_api::exchange_processor::process_instruction;
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_sdk::genesis_block::create_genesis_block;
use std::sync::mpsc::channel;
#[test]
fn test_exchange_local_cluster() {
solana_logger::setup();
const NUM_NODES: usize = 1;
let validator_config = ValidatorConfig::default();
let mut config = Config::default();
config.identity = Keypair::new();
config.duration = Duration::from_secs(1);
config.fund_amount = 100_000;
config.threads = 1;
config.transfer_delay = 20; // 15
config.batch_size = 100; // 1000;
config.chunk_size = 10; // 200;
config.account_groups = 1; // 10;
let Config {
fund_amount,
batch_size,
account_groups,
..
} = config;
let accounts_in_groups = batch_size * account_groups;
let cluster = LocalCluster::new(&ClusterConfig {
node_stakes: vec![100_000; NUM_NODES],
cluster_lamports: 100_000_000_000_000,
validator_config,
native_instruction_processors: [solana_exchange_program!()].to_vec(),
..ClusterConfig::default()
});
let drone_keypair = Keypair::new();
cluster.transfer(
&cluster.funding_keypair,
&drone_keypair.pubkey(),
2_000_000_000_000,
);
let (addr_sender, addr_receiver) = channel();
run_local_drone(drone_keypair, addr_sender, Some(1_000_000_000_000));
let drone_addr = addr_receiver.recv_timeout(Duration::from_secs(2)).unwrap();
info!("Connecting to the cluster");
let (nodes, _) = discover_cluster(&cluster.entry_point_info.gossip, NUM_NODES)
.unwrap_or_else(|err| {
error!("Failed to discover {} nodes: {:?}", NUM_NODES, err);
exit(1);
});
let clients = get_clients(&nodes);
if clients.len() < NUM_NODES {
error!(
"Error: Insufficient nodes discovered. Expecting {} or more",
NUM_NODES
);
exit(1);
}
const NUM_SIGNERS: u64 = 2;
airdrop_lamports(
&clients[0],
&drone_addr,
&config.identity,
fund_amount * (accounts_in_groups + 1) as u64 * NUM_SIGNERS,
);
do_bench_exchange(clients, config);
}
#[test]
fn test_exchange_bank_client() {
solana_logger::setup();
let (genesis_block, identity) = create_genesis_block(100_000_000_000_000);
let mut bank = Bank::new(&genesis_block);
bank.add_instruction_processor(id(), process_instruction);
let clients = vec![BankClient::new(bank)];
let mut config = Config::default();
config.identity = identity;
config.duration = Duration::from_secs(1);
config.fund_amount = 100_000;
config.threads = 1;
config.transfer_delay = 20; // 0;
config.batch_size = 100; // 1500;
config.chunk_size = 10; // 1500;
config.account_groups = 1; // 50;
do_bench_exchange(clients, config);
}
}

188
bench-exchange/src/cli.rs Normal file
View File

@ -0,0 +1,188 @@
use clap::{crate_description, crate_name, crate_version, value_t, App, Arg, ArgMatches};
use solana::gen_keys::GenKeys;
use solana_drone::drone::DRONE_PORT;
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
use std::net::SocketAddr;
use std::process::exit;
use std::time::Duration;
pub struct Config {
pub entrypoint_addr: SocketAddr,
pub drone_addr: SocketAddr,
pub identity: Keypair,
pub threads: usize,
pub num_nodes: usize,
pub duration: Duration,
pub transfer_delay: u64,
pub fund_amount: u64,
pub batch_size: usize,
pub chunk_size: usize,
pub account_groups: usize,
}
impl Default for Config {
fn default() -> Self {
Self {
entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
drone_addr: SocketAddr::from(([127, 0, 0, 1], DRONE_PORT)),
identity: Keypair::new(),
num_nodes: 1,
threads: 4,
duration: Duration::new(u64::max_value(), 0),
transfer_delay: 0,
fund_amount: 100_000,
batch_size: 100,
chunk_size: 100,
account_groups: 100,
}
}
}
pub fn build_args<'a, 'b>() -> App<'a, 'b> {
App::new(crate_name!())
.about(crate_description!())
.version(crate_version!())
.arg(
Arg::with_name("entrypoint")
.short("n")
.long("entrypoint")
.value_name("HOST:PORT")
.takes_value(true)
.required(false)
.default_value("127.0.0.1:8001")
.help("Cluster entry point; defaults to 127.0.0.1:8001"),
)
.arg(
Arg::with_name("drone")
.short("d")
.long("drone")
.value_name("HOST:PORT")
.takes_value(true)
.required(false)
.default_value("127.0.0.1:9900")
.help("Location of the drone; defaults to 127.0.0.1:9900"),
)
.arg(
Arg::with_name("identity")
.short("i")
.long("identity")
.value_name("PATH")
.takes_value(true)
.help("File containing a client identity (keypair)"),
)
.arg(
Arg::with_name("threads")
.long("threads")
.value_name("<threads>")
.takes_value(true)
.required(false)
.default_value("1")
.help("Number of threads submitting transactions"),
)
.arg(
Arg::with_name("num-nodes")
.long("num-nodes")
.value_name("NUM")
.takes_value(true)
.required(false)
.default_value("1")
.help("Wait for NUM nodes to converge"),
)
.arg(
Arg::with_name("duration")
.long("duration")
.value_name("SECS")
.takes_value(true)
.default_value("60")
.help("Seconds to run benchmark, then exit; default is forever"),
)
.arg(
Arg::with_name("transfer-delay")
.long("transfer-delay")
.value_name("<delay>")
.takes_value(true)
.required(false)
.default_value("0")
.help("Delay between each chunk"),
)
.arg(
Arg::with_name("fund-amount")
.long("fund-amount")
.value_name("<fund>")
.takes_value(true)
.required(false)
.default_value("100000")
.help("Number of lamports to fund to each signer"),
)
.arg(
Arg::with_name("batch-size")
.long("batch-size")
.value_name("<batch>")
.takes_value(true)
.required(false)
.default_value("1000")
.help("Number of transactions before the signer rolls over"),
)
.arg(
Arg::with_name("chunk-size")
.long("chunk-size")
.value_name("<cunk>")
.takes_value(true)
.required(false)
.default_value("500")
.help("Number of transactions to generate and send at a time"),
)
.arg(
Arg::with_name("account-groups")
.long("account-groups")
.value_name("<groups>")
.takes_value(true)
.required(false)
.default_value("10")
.help("Number of account groups to cycle for each batch"),
)
}
pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
let mut args = Config::default();
args.entrypoint_addr = solana_netutil::parse_host_port(matches.value_of("entrypoint").unwrap())
.unwrap_or_else(|e| {
eprintln!("failed to parse entrypoint address: {}", e);
exit(1)
});
args.drone_addr = solana_netutil::parse_host_port(matches.value_of("drone").unwrap())
.unwrap_or_else(|e| {
eprintln!("failed to parse drone address: {}", e);
exit(1)
});
if matches.is_present("identity") {
args.identity = read_keypair(matches.value_of("identity").unwrap())
.expect("can't read client identity");
} else {
args.identity = {
let seed = [42_u8; 32];
let mut rnd = GenKeys::new(seed);
rnd.gen_keypair()
};
}
args.threads = value_t!(matches.value_of("threads"), usize).expect("Failed to parse threads");
args.num_nodes =
value_t!(matches.value_of("num-nodes"), usize).expect("Failed to parse num-nodes");
let duration = value_t!(matches.value_of("duration"), u64).expect("Failed to parse duration");
args.duration = Duration::from_secs(duration);
args.transfer_delay =
value_t!(matches.value_of("transfer-delay"), u64).expect("Failed to parse transfer-delay");
args.fund_amount =
value_t!(matches.value_of("fund-amount"), u64).expect("Failed to parse fund-amount");
args.batch_size =
value_t!(matches.value_of("batch-size"), usize).expect("Failed to parse batch-size");
args.chunk_size =
value_t!(matches.value_of("chunk-size"), usize).expect("Failed to parse chunk-size");
args.account_groups = value_t!(matches.value_of("account-groups"), usize)
.expect("Failed to parse account-groups");
args
}

View File

@ -0,0 +1,72 @@
pub mod bench;
mod cli;
pub mod order_book;
#[cfg(test)]
#[macro_use]
extern crate solana_exchange_program;
use crate::bench::{airdrop_lamports, do_bench_exchange, Config};
use log::*;
use solana::gossip_service::{discover_cluster, get_clients};
use solana_sdk::signature::KeypairUtil;
fn main() {
solana_logger::setup();
solana_metrics::set_panic_hook("bench-exchange");
let matches = cli::build_args().get_matches();
let cli_config = cli::extract_args(&matches);
let cli::Config {
entrypoint_addr,
drone_addr,
identity,
threads,
num_nodes,
duration,
transfer_delay,
fund_amount,
batch_size,
chunk_size,
account_groups,
..
} = cli_config;
info!("Connecting to the cluster");
let (nodes, _replicators) =
discover_cluster(&entrypoint_addr, num_nodes).unwrap_or_else(|_| {
panic!("Failed to discover nodes");
});
let clients = get_clients(&nodes);
info!("{} nodes found", clients.len());
if clients.len() < num_nodes {
panic!("Error: Insufficient nodes discovered");
}
info!("Funding keypair: {}", identity.pubkey());
let accounts_in_groups = batch_size * account_groups;
const NUM_SIGNERS: u64 = 2;
airdrop_lamports(
&clients[0],
&drone_addr,
&identity,
fund_amount * (accounts_in_groups + 1) as u64 * NUM_SIGNERS,
);
let config = Config {
identity,
threads,
duration,
transfer_delay,
fund_amount,
batch_size,
chunk_size,
account_groups,
};
do_bench_exchange(clients, config);
}

View File

@ -0,0 +1,138 @@
use itertools::EitherOrBoth::{Both, Left, Right};
use itertools::Itertools;
use log::*;
use solana_exchange_api::exchange_state::*;
use solana_sdk::pubkey::Pubkey;
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::{error, fmt};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ToOrder {
pub pubkey: Pubkey,
pub info: TradeOrderInfo,
}
impl Ord for ToOrder {
fn cmp(&self, other: &Self) -> Ordering {
other.info.price.cmp(&self.info.price)
}
}
impl PartialOrd for ToOrder {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FromOrder {
pub pubkey: Pubkey,
pub info: TradeOrderInfo,
}
impl Ord for FromOrder {
fn cmp(&self, other: &Self) -> Ordering {
self.info.price.cmp(&other.info.price)
}
}
impl PartialOrd for FromOrder {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Default)]
pub struct OrderBook {
// TODO scale to x token types
to_ab: BinaryHeap<ToOrder>,
from_ab: BinaryHeap<FromOrder>,
}
impl fmt::Display for OrderBook {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"+-Order Book--------------------------+-------------------------------------+"
)?;
for (i, it) in self
.to_ab
.iter()
.zip_longest(self.from_ab.iter())
.enumerate()
{
match it {
Both(to, from) => writeln!(
f,
"| T AB {:8} for {:8}/{:8} | F AB {:8} for {:8}/{:8} |{}",
to.info.tokens,
SCALER,
to.info.price,
from.info.tokens,
SCALER,
from.info.price,
i
)?,
Left(to) => writeln!(
f,
"| T AB {:8} for {:8}/{:8} | |{}",
to.info.tokens, SCALER, to.info.price, i
)?,
Right(from) => writeln!(
f,
"| | F AB {:8} for {:8}/{:8} |{}",
from.info.tokens, SCALER, from.info.price, i
)?,
}
}
write!(
f,
"+-------------------------------------+-------------------------------------+"
)?;
Ok(())
}
}
impl OrderBook {
// TODO
// pub fn cancel(&mut self, pubkey: Pubkey) -> Result<(), Box<dyn error::Error>> {
// Ok(())
// }
pub fn push(
&mut self,
pubkey: Pubkey,
info: TradeOrderInfo,
) -> Result<(), Box<dyn error::Error>> {
check_trade(info.direction, info.tokens, info.price)?;
match info.direction {
Direction::To => {
self.to_ab.push(ToOrder { pubkey, info });
}
Direction::From => {
self.from_ab.push(FromOrder { pubkey, info });
}
}
Ok(())
}
pub fn pop(&mut self) -> Option<(ToOrder, FromOrder)> {
if let Some(pair) = Self::pop_pair(&mut self.to_ab, &mut self.from_ab) {
return Some(pair);
}
None
}
pub fn get_num_outstanding(&self) -> (usize, usize) {
(self.to_ab.len(), self.from_ab.len())
}
fn pop_pair(
to_ab: &mut BinaryHeap<ToOrder>,
from_ab: &mut BinaryHeap<FromOrder>,
) -> Option<(ToOrder, FromOrder)> {
let to = to_ab.peek()?;
let from = from_ab.peek()?;
if from.info.price < to.info.price {
debug!("Trade not viable");
return None;
}
let to = to_ab.pop()?;
let from = from_ab.pop()?;
Some((to, from))
}
}

1
bench-streamer/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

View File

@ -2,16 +2,17 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-streamer"
version = "0.12.0"
version = "0.15.0"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.32.0"
solana = { path = "../core", version = "0.12.0" }
solana-logger = { path = "../logger", version = "0.12.0" }
solana-netutil = { path = "../netutil", version = "0.12.0" }
clap = "2.33.0"
solana = { path = "../core", version = "0.15.0" }
solana-logger = { path = "../logger", version = "0.15.0" }
solana-netutil = { path = "../netutil", version = "0.15.0" }
[features]
cuda = ["solana/cuda"]
erasure = []

View File

@ -1,5 +1,5 @@
use clap::{App, Arg};
use solana::packet::{Packet, SharedPackets, BLOB_SIZE, PACKET_DATA_SIZE};
use clap::{crate_description, crate_name, crate_version, App, Arg};
use solana::packet::{Packet, Packets, BLOB_SIZE, PACKET_DATA_SIZE};
use solana::result::Result;
use solana::streamer::{receiver, PacketReceiver};
use std::cmp::max;
@ -14,19 +14,19 @@ use std::time::SystemTime;
fn producer(addr: &SocketAddr, exit: Arc<AtomicBool>) -> JoinHandle<()> {
let send = UdpSocket::bind("0.0.0.0:0").unwrap();
let msgs = SharedPackets::default();
let msgs_ = msgs.clone();
msgs.write().unwrap().packets.resize(10, Packet::default());
for w in &mut msgs.write().unwrap().packets {
let mut msgs = Packets::default();
msgs.packets.resize(10, Packet::default());
for w in &mut msgs.packets {
w.meta.size = PACKET_DATA_SIZE;
w.meta.set_addr(&addr);
}
let msgs = Arc::new(msgs);
spawn(move || loop {
if exit.load(Ordering::Relaxed) {
return;
}
let mut num = 0;
for p in &msgs_.read().unwrap().packets {
for p in &msgs.packets {
let a = p.meta.addr();
assert!(p.meta.size < BLOB_SIZE);
send.send_to(&p.data[..p.meta.size], &a).unwrap();
@ -43,7 +43,7 @@ fn sink(exit: Arc<AtomicBool>, rvs: Arc<AtomicUsize>, r: PacketReceiver) -> Join
}
let timer = Duration::new(1, 0);
if let Ok(msgs) = r.recv_timeout(timer) {
rvs.fetch_add(msgs.read().unwrap().packets.len(), Ordering::Relaxed);
rvs.fetch_add(msgs.packets.len(), Ordering::Relaxed);
}
})
}
@ -51,7 +51,9 @@ fn sink(exit: Arc<AtomicBool>, rvs: Arc<AtomicUsize>, r: PacketReceiver) -> Join
fn main() -> Result<()> {
let mut num_sockets = 1usize;
let matches = App::new("solana-bench-streamer")
let matches = App::new(crate_name!())
.about(crate_description!())
.version(crate_version!())
.arg(
Arg::with_name("num-recv-sockets")
.long("num-recv-sockets")
@ -81,7 +83,7 @@ fn main() -> Result<()> {
let (s_reader, r_reader) = channel();
read_channels.push(r_reader);
read_threads.push(receiver(Arc::new(read), &exit, s_reader, "bench-streamer"));
read_threads.push(receiver(Arc::new(read), &exit, s_reader));
}
let t_producer1 = producer(&addr, exit.clone());

3
bench-tps/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target/
/config/
/config-local/

View File

@ -2,20 +2,25 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-tps"
version = "0.12.0"
version = "0.15.0"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.32.0"
clap = "2.33.0"
log = "0.4.6"
rayon = "1.0.3"
serde_json = "1.0.39"
solana = { path = "../core", version = "0.12.0" }
solana-drone = { path = "../drone", version = "0.12.0" }
solana-logger = { path = "../logger", version = "0.12.0" }
solana-metrics = { path = "../metrics", version = "0.12.0" }
solana-sdk = { path = "../sdk", version = "0.12.0" }
solana = { path = "../core", version = "0.15.0" }
solana-client = { path = "../client", version = "0.15.0" }
solana-drone = { path = "../drone", version = "0.15.0" }
solana-logger = { path = "../logger", version = "0.15.0" }
solana-metrics = { path = "../metrics", version = "0.15.0" }
solana-netutil = { path = "../netutil", version = "0.15.0" }
solana-runtime = { path = "../runtime", version = "0.15.0" }
solana-sdk = { path = "../sdk", version = "0.15.0" }
[features]
cuda = ["solana/cuda"]
erasure = []

View File

@ -1,15 +1,16 @@
use solana_metrics;
use log::*;
use rayon::prelude::*;
use solana::client::mk_client;
use solana::contact_info::ContactInfo;
use solana::thin_client::ThinClient;
use solana::gen_keys::GenKeys;
use solana_client::perf_utils::{sample_txs, SampleStats};
use solana_drone::drone::request_airdrop_transaction;
use solana_metrics::influxdb;
use solana_metrics::datapoint_info;
use solana_sdk::client::Client;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::system_instruction;
use solana_sdk::system_transaction;
use solana_sdk::timing::timestamp;
use solana_sdk::timing::{duration_as_ms, duration_as_s};
use solana_sdk::transaction::Transaction;
@ -20,169 +21,208 @@ use std::process::exit;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::thread::Builder;
use std::time::Duration;
use std::time::Instant;
pub struct NodeStats {
/// Maximum TPS reported by this node
pub tps: f64,
/// Total transactions reported by this node
pub tx: u64,
}
pub const MAX_SPENDS_PER_TX: usize = 4;
pub const NUM_LAMPORTS_PER_ACCOUNT: u64 = 20;
pub type SharedTransactions = Arc<RwLock<VecDeque<Vec<(Transaction, u64)>>>>;
pub fn metrics_submit_lamport_balance(lamport_balance: u64) {
pub struct Config {
pub id: Keypair,
pub threads: usize,
pub thread_batch_sleep_ms: usize,
pub duration: Duration,
pub tx_count: usize,
pub sustained: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
id: Keypair::new(),
threads: 4,
thread_batch_sleep_ms: 0,
duration: Duration::new(std::u64::MAX, 0),
tx_count: 500_000,
sustained: false,
}
}
}
pub fn do_bench_tps<T>(
clients: Vec<T>,
config: Config,
gen_keypairs: Vec<Keypair>,
keypair0_balance: u64,
) -> u64
where
T: 'static + Client + Send + Sync,
{
let Config {
id,
threads,
thread_batch_sleep_ms,
duration,
tx_count,
sustained,
} = config;
let clients: Vec<_> = clients.into_iter().map(Arc::new).collect();
let client = &clients[0];
let start = gen_keypairs.len() - (tx_count * 2) as usize;
let keypairs = &gen_keypairs[start..];
let first_tx_count = client.get_transaction_count().expect("transaction count");
println!("Initial transaction count {}", first_tx_count);
let exit_signal = Arc::new(AtomicBool::new(false));
// Setup a thread per validator to sample every period
// collect the max transaction rate and total tx count seen
let maxes = Arc::new(RwLock::new(Vec::new()));
let sample_period = 1; // in seconds
println!("Sampling TPS every {} second...", sample_period);
let v_threads: Vec<_> = clients
.iter()
.map(|client| {
let exit_signal = exit_signal.clone();
let maxes = maxes.clone();
let client = client.clone();
Builder::new()
.name("solana-client-sample".to_string())
.spawn(move || {
sample_txs(&exit_signal, &maxes, sample_period, &client);
})
.unwrap()
})
.collect();
let shared_txs: SharedTransactions = Arc::new(RwLock::new(VecDeque::new()));
let shared_tx_active_thread_count = Arc::new(AtomicIsize::new(0));
let total_tx_sent_count = Arc::new(AtomicUsize::new(0));
let s_threads: Vec<_> = (0..threads)
.map(|_| {
let exit_signal = exit_signal.clone();
let shared_txs = shared_txs.clone();
let shared_tx_active_thread_count = shared_tx_active_thread_count.clone();
let total_tx_sent_count = total_tx_sent_count.clone();
let client = client.clone();
Builder::new()
.name("solana-client-sender".to_string())
.spawn(move || {
do_tx_transfers(
&exit_signal,
&shared_txs,
&shared_tx_active_thread_count,
&total_tx_sent_count,
thread_batch_sleep_ms,
&client,
);
})
.unwrap()
})
.collect();
// generate and send transactions for the specified duration
let start = Instant::now();
let mut reclaim_lamports_back_to_source_account = false;
let mut i = keypair0_balance;
let mut blockhash = Hash::default();
let mut blockhash_time = Instant::now();
while start.elapsed() < duration {
// ping-pong between source and destination accounts for each loop iteration
// this seems to be faster than trying to determine the balance of individual
// accounts
let len = tx_count as usize;
if let Ok((new_blockhash, _fee_calculator)) = client.get_new_blockhash(&blockhash) {
blockhash = new_blockhash;
} else {
if blockhash_time.elapsed().as_secs() > 30 {
panic!("Blockhash is not updating");
}
sleep(Duration::from_millis(100));
continue;
}
blockhash_time = Instant::now();
let balance = client.get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(balance);
generate_txs(
&shared_txs,
&blockhash,
&keypairs[..len],
&keypairs[len..],
threads,
reclaim_lamports_back_to_source_account,
);
// In sustained mode overlap the transfers with generation
// this has higher average performance but lower peak performance
// in tested environments.
if !sustained {
while shared_tx_active_thread_count.load(Ordering::Relaxed) > 0 {
sleep(Duration::from_millis(1));
}
}
i += 1;
if should_switch_directions(NUM_LAMPORTS_PER_ACCOUNT, i) {
reclaim_lamports_back_to_source_account = !reclaim_lamports_back_to_source_account;
}
}
// Stop the sampling threads so it will collect the stats
exit_signal.store(true, Ordering::Relaxed);
println!("Waiting for validator threads...");
for t in v_threads {
if let Err(err) = t.join() {
println!(" join() failed with: {:?}", err);
}
}
// join the tx send threads
println!("Waiting for transmit threads...");
for t in s_threads {
if let Err(err) = t.join() {
println!(" join() failed with: {:?}", err);
}
}
let balance = client.get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(balance);
compute_and_report_stats(
&maxes,
sample_period,
&start.elapsed(),
total_tx_sent_count.load(Ordering::Relaxed),
);
let r_maxes = maxes.read().unwrap();
r_maxes.first().unwrap().1.txs
}
fn metrics_submit_lamport_balance(lamport_balance: u64) {
println!("Token balance: {}", lamport_balance);
solana_metrics::submit(
influxdb::Point::new("bench-tps")
.add_tag("op", influxdb::Value::String("lamport_balance".to_string()))
.add_field("balance", influxdb::Value::Integer(lamport_balance as i64))
.to_owned(),
datapoint_info!(
"bench-tps-lamport_balance",
("balance", lamport_balance, i64)
);
}
pub fn sample_tx_count(
exit_signal: &Arc<AtomicBool>,
maxes: &Arc<RwLock<Vec<(SocketAddr, NodeStats)>>>,
first_tx_count: u64,
v: &ContactInfo,
sample_period: u64,
) {
let mut client = mk_client(&v);
let mut now = Instant::now();
let mut initial_tx_count = client.transaction_count();
let mut max_tps = 0.0;
let mut total;
let log_prefix = format!("{:21}:", v.tpu.to_string());
loop {
let tx_count = client.transaction_count();
assert!(
tx_count >= initial_tx_count,
"expected tx_count({}) >= initial_tx_count({})",
tx_count,
initial_tx_count
);
let duration = now.elapsed();
now = Instant::now();
let sample = tx_count - initial_tx_count;
initial_tx_count = tx_count;
let ns = duration.as_secs() * 1_000_000_000 + u64::from(duration.subsec_nanos());
let tps = (sample * 1_000_000_000) as f64 / ns as f64;
if tps > max_tps {
max_tps = tps;
}
if tx_count > first_tx_count {
total = tx_count - first_tx_count;
} else {
total = 0;
}
println!(
"{} {:9.2} TPS, Transactions: {:6}, Total transactions: {}",
log_prefix, tps, sample, total
);
sleep(Duration::new(sample_period, 0));
if exit_signal.load(Ordering::Relaxed) {
println!("{} Exiting validator thread", log_prefix);
let stats = NodeStats {
tps: max_tps,
tx: total,
};
maxes.write().unwrap().push((v.tpu, stats));
break;
}
}
}
/// Send loopback payment of 0 lamports and confirm the network processed it
pub fn send_barrier_transaction(
barrier_client: &mut ThinClient,
blockhash: &mut Hash,
source_keypair: &Keypair,
dest_id: &Pubkey,
) {
let transfer_start = Instant::now();
let mut poll_count = 0;
loop {
if poll_count > 0 && poll_count % 8 == 0 {
println!(
"polling for barrier transaction confirmation, attempt {}",
poll_count
);
}
*blockhash = barrier_client.get_recent_blockhash();
let signature = barrier_client
.transfer(0, &source_keypair, dest_id, blockhash)
.expect("Unable to send barrier transaction");
let confirmatiom = barrier_client.poll_for_signature(&signature);
let duration_ms = duration_as_ms(&transfer_start.elapsed());
if confirmatiom.is_ok() {
println!("barrier transaction confirmed in {} ms", duration_ms);
solana_metrics::submit(
influxdb::Point::new("bench-tps")
.add_tag(
"op",
influxdb::Value::String("send_barrier_transaction".to_string()),
)
.add_field("poll_count", influxdb::Value::Integer(poll_count))
.add_field("duration", influxdb::Value::Integer(duration_ms as i64))
.to_owned(),
);
// Sanity check that the client balance is still 1
let balance = barrier_client
.poll_balance_with_timeout(
&source_keypair.pubkey(),
&Duration::from_millis(100),
&Duration::from_secs(10),
)
.expect("Failed to get balance");
if balance != 1 {
panic!("Expected an account balance of 1 (balance: {}", balance);
}
break;
}
// Timeout after 3 minutes. When running a CPU-only leader+validator+drone+bench-tps on a dev
// machine, some batches of transactions can take upwards of 1 minute...
if duration_ms > 1000 * 60 * 3 {
println!("Error: Couldn't confirm barrier transaction!");
exit(1);
}
let new_blockhash = barrier_client.get_recent_blockhash();
if new_blockhash == *blockhash {
if poll_count > 0 && poll_count % 8 == 0 {
println!("blockhash is not advancing, still at {:?}", *blockhash);
}
} else {
*blockhash = new_blockhash;
}
poll_count += 1;
}
}
pub fn generate_txs(
fn generate_txs(
shared_txs: &SharedTransactions,
blockhash: &Hash,
source: &[Keypair],
dest: &[Keypair],
threads: usize,
reclaim: bool,
contact_info: &ContactInfo,
) {
let mut client = mk_client(contact_info);
let blockhash = client.get_recent_blockhash();
let tx_count = source.len();
println!("Signing transactions... {} (reclaim={})", tx_count, reclaim);
let signing_start = Instant::now();
@ -196,7 +236,7 @@ pub fn generate_txs(
.par_iter()
.map(|(id, keypair)| {
(
SystemTransaction::new_account(id, &keypair.pubkey(), 1, blockhash, 0),
system_transaction::create_user_account(id, &keypair.pubkey(), 1, *blockhash),
timestamp(),
)
})
@ -213,14 +253,9 @@ pub fn generate_txs(
duration_as_ms(&duration),
blockhash,
);
solana_metrics::submit(
influxdb::Point::new("bench-tps")
.add_tag("op", influxdb::Value::String("generate_txs".to_string()))
.add_field(
"duration",
influxdb::Value::Integer(duration_as_ms(&duration) as i64),
)
.to_owned(),
datapoint_info!(
"bench-tps-generate_txs",
("duration", duration_as_ms(&duration), i64)
);
let sz = transactions.len() / threads;
@ -233,22 +268,21 @@ pub fn generate_txs(
}
}
pub fn do_tx_transfers(
fn do_tx_transfers<T: Client>(
exit_signal: &Arc<AtomicBool>,
shared_txs: &SharedTransactions,
contact_info: &ContactInfo,
shared_tx_thread_count: &Arc<AtomicIsize>,
total_tx_sent_count: &Arc<AtomicUsize>,
thread_batch_sleep_ms: usize,
client: &Arc<T>,
) {
let client = mk_client(&contact_info);
loop {
if thread_batch_sleep_ms > 0 {
sleep(Duration::from_millis(thread_batch_sleep_ms as u64));
}
let txs;
{
let mut shared_txs_wl = shared_txs.write().unwrap();
let mut shared_txs_wl = shared_txs.write().expect("write lock in do_tx_transfers");
txs = shared_txs_wl.pop_front();
}
if let Some(txs0) = txs {
@ -256,7 +290,7 @@ pub fn do_tx_transfers(
println!(
"Transferring 1 unit {} times... to {}",
txs0.len(),
contact_info.tpu
client.as_ref().transactions_addr(),
);
let tx_len = txs0.len();
let transfer_start = Instant::now();
@ -265,7 +299,9 @@ pub fn do_tx_transfers(
if now > tx.1 && now - tx.1 > 1000 * 30 {
continue;
}
client.transfer_signed(&tx.0).unwrap();
client
.async_send_transaction(tx.0)
.expect("async_send_transaction in do_tx_transfers");
}
shared_tx_thread_count.fetch_add(-1, Ordering::Relaxed);
total_tx_sent_count.fetch_add(tx_len, Ordering::Relaxed);
@ -274,15 +310,10 @@ pub fn do_tx_transfers(
duration_as_ms(&transfer_start.elapsed()),
tx_len as f32 / duration_as_s(&transfer_start.elapsed()),
);
solana_metrics::submit(
influxdb::Point::new("bench-tps")
.add_tag("op", influxdb::Value::String("do_tx_transfers".to_string()))
.add_field(
"duration",
influxdb::Value::Integer(duration_as_ms(&transfer_start.elapsed()) as i64),
)
.add_field("count", influxdb::Value::Integer(tx_len as i64))
.to_owned(),
datapoint_info!(
"bench-tps-do_tx_transfers",
("duration", duration_as_ms(&transfer_start.elapsed()), i64),
("count", tx_len, i64)
);
}
if exit_signal.load(Ordering::Relaxed) {
@ -291,8 +322,8 @@ pub fn do_tx_transfers(
}
}
pub fn verify_funding_transfer(client: &mut ThinClient, tx: &Transaction, amount: u64) -> bool {
for a in &tx.account_keys[1..] {
fn verify_funding_transfer<T: Client>(client: &T, tx: &Transaction, amount: u64) -> bool {
for a in &tx.message().account_keys[1..] {
if client.get_balance(a).unwrap_or(0) >= amount {
return true;
}
@ -304,7 +335,7 @@ pub fn verify_funding_transfer(client: &mut ThinClient, tx: &Transaction, amount
/// fund the dests keys by spending all of the source keys into MAX_SPENDS_PER_TX
/// on every iteration. This allows us to replay the transfers because the source is either empty,
/// or full
pub fn fund_keys(client: &mut ThinClient, source: &Keypair, dests: &[Keypair], lamports: u64) {
pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Keypair], lamports: u64) {
let total = lamports * dests.len() as u64;
let mut funded: Vec<(&Keypair, u64)> = vec![(source, total)];
let mut notfunded: Vec<&Keypair> = dests.iter().collect();
@ -348,7 +379,10 @@ pub fn fund_keys(client: &mut ThinClient, source: &Keypair, dests: &[Keypair], l
.map(|(k, m)| {
(
k.clone(),
SystemTransaction::new_move_many(k, &m, Hash::default(), 0),
Transaction::new_unsigned_instructions(system_instruction::transfer_many(
&k.pubkey(),
&m,
)),
)
})
.collect();
@ -358,7 +392,7 @@ pub fn fund_keys(client: &mut ThinClient, source: &Keypair, dests: &[Keypair], l
while !to_fund_txs.is_empty() {
let receivers = to_fund_txs
.iter()
.fold(0, |len, (_, tx)| len + tx.instructions.len());
.fold(0, |len, (_, tx)| len + tx.message().instructions.len());
println!(
"{} {} to {} in {} txs",
@ -372,7 +406,7 @@ pub fn fund_keys(client: &mut ThinClient, source: &Keypair, dests: &[Keypair], l
to_fund_txs.len(),
);
let blockhash = client.get_recent_blockhash();
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
// re-sign retained to_fund_txes with updated blockhash
to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
@ -380,13 +414,19 @@ pub fn fund_keys(client: &mut ThinClient, source: &Keypair, dests: &[Keypair], l
});
to_fund_txs.iter().for_each(|(_, tx)| {
client.transfer_signed(&tx).expect("transfer");
client.async_send_transaction(tx.clone()).expect("transfer");
});
// retry anything that seems to have dropped through cracks
// again since these txs are all or nothing, they're fine to
// retry
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, &tx, amount));
for _ in 0..10 {
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, &tx, amount));
if to_fund_txs.is_empty() {
break;
}
sleep(Duration::from_millis(100));
}
tries += 1;
}
@ -397,13 +437,13 @@ pub fn fund_keys(client: &mut ThinClient, source: &Keypair, dests: &[Keypair], l
}
}
pub fn airdrop_lamports(
client: &mut ThinClient,
pub fn airdrop_lamports<T: Client>(
client: &T,
drone_addr: &SocketAddr,
id: &Keypair,
tx_count: u64,
) {
let starting_balance = client.poll_get_balance(&id.pubkey()).unwrap_or(0);
let starting_balance = client.get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(starting_balance);
println!("starting balance {}", starting_balance);
@ -416,11 +456,18 @@ pub fn airdrop_lamports(
id.pubkey(),
);
let blockhash = client.get_recent_blockhash();
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
match request_airdrop_transaction(&drone_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => {
let signature = client.transfer_signed(&transaction).unwrap();
client.poll_for_signature(&signature).unwrap();
let signature = client.async_send_transaction(transaction).unwrap();
client
.poll_for_signature_confirmation(&signature, 1)
.unwrap_or_else(|_| {
panic!(
"Error requesting airdrop: to addr: {:?} amount: {}",
drone_addr, airdrop_amount
)
})
}
Err(err) => {
panic!(
@ -430,7 +477,7 @@ pub fn airdrop_lamports(
}
};
let current_balance = client.poll_get_balance(&id.pubkey()).unwrap_or_else(|e| {
let current_balance = client.get_balance(&id.pubkey()).unwrap_or_else(|e| {
println!("airdrop error {}", e);
starting_balance
});
@ -449,8 +496,8 @@ pub fn airdrop_lamports(
}
}
pub fn compute_and_report_stats(
maxes: &Arc<RwLock<Vec<(SocketAddr, NodeStats)>>>,
fn compute_and_report_stats(
maxes: &Arc<RwLock<Vec<(String, SampleStats)>>>,
sample_period: u64,
tx_send_elapsed: &Duration,
total_tx_send_count: usize,
@ -464,17 +511,14 @@ pub fn compute_and_report_stats(
println!("---------------------+---------------+--------------------");
for (sock, stats) in maxes.read().unwrap().iter() {
let maybe_flag = match stats.tx {
let maybe_flag = match stats.txs {
0 => "!!!!!",
_ => "",
};
println!(
"{:20} | {:13.2} | {} {}",
(*sock).to_string(),
stats.tps,
stats.tx,
maybe_flag
sock, stats.tps, stats.txs, maybe_flag
);
if stats.tps == 0.0 {
@ -485,27 +529,33 @@ pub fn compute_and_report_stats(
if stats.tps > max_of_maxes {
max_of_maxes = stats.tps;
}
if stats.tx > max_tx_count {
max_tx_count = stats.tx;
if stats.txs > max_tx_count {
max_tx_count = stats.txs;
}
}
if total_maxes > 0.0 {
let num_nodes_with_tps = maxes.read().unwrap().len() - nodes_with_zero_tps;
let average_max = total_maxes / num_nodes_with_tps as f64;
let average_max = total_maxes / num_nodes_with_tps as f32;
println!(
"\nAverage max TPS: {:.2}, {} nodes had 0 TPS",
average_max, nodes_with_zero_tps
);
}
let total_tx_send_count = total_tx_send_count as u64;
let drop_rate = if total_tx_send_count > max_tx_count {
(total_tx_send_count - max_tx_count) as f64 / total_tx_send_count as f64
} else {
0.0
};
println!(
"\nHighest TPS: {:.2} sampling period {}s max transactions: {} clients: {} drop rate: {:.2}",
max_of_maxes,
sample_period,
max_tx_count,
maxes.read().unwrap().len(),
(total_tx_send_count as u64 - max_tx_count) as f64 / total_tx_send_count as f64,
drop_rate,
);
println!(
"\tAverage TPS: {}",
@ -516,13 +566,73 @@ pub fn compute_and_report_stats(
// First transfer 3/4 of the lamports to the dest accounts
// then ping-pong 1/4 of the lamports back to the other account
// this leaves 1/4 lamport buffer in each account
pub fn should_switch_directions(num_lamports_per_account: u64, i: u64) -> bool {
fn should_switch_directions(num_lamports_per_account: u64, i: u64) -> bool {
i % (num_lamports_per_account / 4) == 0 && (i >= (3 * num_lamports_per_account) / 4)
}
pub fn generate_keypairs(seed_keypair: &Keypair, count: usize) -> Vec<Keypair> {
let mut seed = [0u8; 32];
seed.copy_from_slice(&seed_keypair.to_bytes()[..32]);
let mut rnd = GenKeys::new(seed);
let mut total_keys = 0;
let mut target = count;
while target > 1 {
total_keys += target;
// Use the upper bound for this division otherwise it may not generate enough keys
target = (target + MAX_SPENDS_PER_TX - 1) / MAX_SPENDS_PER_TX;
}
rnd.gen_n_keypairs(total_keys as u64)
}
pub fn generate_and_fund_keypairs<T: Client>(
client: &T,
drone_addr: Option<SocketAddr>,
funding_pubkey: &Keypair,
tx_count: usize,
lamports_per_account: u64,
) -> (Vec<Keypair>, u64) {
info!("Creating {} keypairs...", tx_count * 2);
let mut keypairs = generate_keypairs(funding_pubkey, tx_count * 2);
info!("Get lamports...");
// Sample the first keypair, see if it has lamports, if so then resume.
// This logic is to prevent lamport loss on repeated solana-bench-tps executions
let last_keypair_balance = client
.get_balance(&keypairs[tx_count * 2 - 1].pubkey())
.unwrap_or(0);
if lamports_per_account > last_keypair_balance {
let extra = lamports_per_account - last_keypair_balance;
let total = extra * (keypairs.len() as u64);
if client.get_balance(&funding_pubkey.pubkey()).unwrap_or(0) < total {
airdrop_lamports(client, &drone_addr.unwrap(), funding_pubkey, total);
}
info!("adding more lamports {}", extra);
fund_keys(client, funding_pubkey, &keypairs, extra);
}
// 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys.
keypairs.truncate(2 * tx_count);
(keypairs, last_keypair_balance)
}
#[cfg(test)]
mod tests {
use super::*;
use solana::cluster_info::FULLNODE_PORT_RANGE;
use solana::local_cluster::{ClusterConfig, LocalCluster};
use solana::validator::ValidatorConfig;
use solana_client::thin_client::create_client;
use solana_drone::drone::run_local_drone;
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_sdk::client::SyncClient;
use solana_sdk::genesis_block::create_genesis_block;
use std::sync::mpsc::channel;
#[test]
fn test_switch_directions() {
assert_eq!(should_switch_directions(20, 0), false);
@ -537,4 +647,79 @@ mod tests {
assert_eq!(should_switch_directions(20, 100), true);
assert_eq!(should_switch_directions(20, 101), false);
}
#[test]
fn test_bench_tps_local_cluster() {
solana_logger::setup();
let validator_config = ValidatorConfig::default();
const NUM_NODES: usize = 1;
let cluster = LocalCluster::new(&ClusterConfig {
node_stakes: vec![999_990; NUM_NODES],
cluster_lamports: 2_000_000,
validator_config,
..ClusterConfig::default()
});
let drone_keypair = Keypair::new();
cluster.transfer(&cluster.funding_keypair, &drone_keypair.pubkey(), 1_000_000);
let (addr_sender, addr_receiver) = channel();
run_local_drone(drone_keypair, addr_sender, None);
let drone_addr = addr_receiver.recv_timeout(Duration::from_secs(2)).unwrap();
let mut config = Config::default();
config.tx_count = 100;
config.duration = Duration::from_secs(5);
let client = create_client(
(cluster.entry_point_info.rpc, cluster.entry_point_info.tpu),
FULLNODE_PORT_RANGE,
);
let lamports_per_account = 100;
let (keypairs, _keypair_balance) = generate_and_fund_keypairs(
&client,
Some(drone_addr),
&config.id,
config.tx_count,
lamports_per_account,
);
let total = do_bench_tps(vec![client], config, keypairs, 0);
assert!(total > 100);
}
#[test]
fn test_bench_tps_bank_client() {
let (genesis_block, id) = create_genesis_block(10_000);
let bank = Bank::new(&genesis_block);
let clients = vec![BankClient::new(bank)];
let mut config = Config::default();
config.id = id;
config.tx_count = 10;
config.duration = Duration::from_secs(5);
let (keypairs, _keypair_balance) =
generate_and_fund_keypairs(&clients[0], None, &config.id, config.tx_count, 20);
do_bench_tps(clients, config, keypairs, 0);
}
#[test]
fn test_bench_tps_fund_keys() {
let (genesis_block, id) = create_genesis_block(10_000);
let bank = Bank::new(&genesis_block);
let client = BankClient::new(bank);
let tx_count = 10;
let lamports = 20;
let (keypairs, _keypair_balance) =
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports);
for kp in &keypairs {
// TODO: This should be >= lamports, but fails at the moment
assert_ne!(client.get_balance(&kp.pubkey()).unwrap(), 0);
}
}
}

View File

@ -2,13 +2,13 @@ use std::net::SocketAddr;
use std::process::exit;
use std::time::Duration;
use clap::{crate_version, App, Arg, ArgMatches};
use clap::{crate_description, crate_name, crate_version, App, Arg, ArgMatches};
use solana_drone::drone::DRONE_PORT;
use solana_sdk::signature::{read_keypair, Keypair, KeypairUtil};
/// Holds the configuration for a single run of the benchmark
pub struct Config {
pub network_addr: SocketAddr,
pub entrypoint_addr: SocketAddr,
pub drone_addr: SocketAddr,
pub id: Keypair,
pub threads: usize,
@ -17,14 +17,12 @@ pub struct Config {
pub tx_count: usize,
pub thread_batch_sleep_ms: usize,
pub sustained: bool,
pub reject_extra_nodes: bool,
pub converge_only: bool,
}
impl Default for Config {
fn default() -> Config {
Config {
network_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)),
drone_addr: SocketAddr::from(([127, 0, 0, 1], DRONE_PORT)),
id: Keypair::new(),
threads: 4,
@ -33,23 +31,21 @@ impl Default for Config {
tx_count: 500_000,
thread_batch_sleep_ms: 0,
sustained: false,
reject_extra_nodes: false,
converge_only: false,
}
}
}
/// Defines and builds the CLI args for a run of the benchmark
pub fn build_args<'a, 'b>() -> App<'a, 'b> {
App::new("solana-bench-tps")
App::new(crate_name!()).about(crate_description!())
.version(crate_version!())
.arg(
Arg::with_name("network")
Arg::with_name("entrypoint")
.short("n")
.long("network")
.long("entrypoint")
.value_name("HOST:PORT")
.takes_value(true)
.help("Rendezvous with the network at this gossip entry point; defaults to 127.0.0.1:8001"),
.help("Rendezvous with the cluster at this entry point; defaults to 127.0.0.1:8001"),
)
.arg(
Arg::with_name("drone")
@ -57,7 +53,7 @@ pub fn build_args<'a, 'b>() -> App<'a, 'b> {
.long("drone")
.value_name("HOST:PORT")
.takes_value(true)
.help("Location of the drone; defaults to network:DRONE_PORT"),
.help("Location of the drone; defaults to entrypoint:DRONE_PORT"),
)
.arg(
Arg::with_name("identity")
@ -75,11 +71,6 @@ pub fn build_args<'a, 'b>() -> App<'a, 'b> {
.takes_value(true)
.help("Wait for NUM nodes to converge"),
)
.arg(
Arg::with_name("reject-extra-nodes")
.long("reject-extra-nodes")
.help("Require exactly `num-nodes` on convergence. Appropriate only for internal networks"),
)
.arg(
Arg::with_name("threads")
.short("t")
@ -95,11 +86,6 @@ pub fn build_args<'a, 'b>() -> App<'a, 'b> {
.takes_value(true)
.help("Seconds to run benchmark, then exit; default is forever"),
)
.arg(
Arg::with_name("converge-only")
.long("converge-only")
.help("Exit immediately after converging"),
)
.arg(
Arg::with_name("sustained")
.long("sustained")
@ -130,15 +116,15 @@ pub fn build_args<'a, 'b>() -> App<'a, 'b> {
pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
let mut args = Config::default();
if let Some(addr) = matches.value_of("network") {
args.network_addr = addr.parse().unwrap_or_else(|e| {
eprintln!("failed to parse network: {}", e);
if let Some(addr) = matches.value_of("entrypoint") {
args.entrypoint_addr = solana_netutil::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse entrypoint address: {}", e);
exit(1)
});
}
if let Some(addr) = matches.value_of("drone") {
args.drone_addr = addr.parse().unwrap_or_else(|e| {
args.drone_addr = solana_netutil::parse_host_port(addr).unwrap_or_else(|e| {
eprintln!("failed to parse drone address: {}", e);
exit(1)
});
@ -176,8 +162,6 @@ pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
}
args.sustained = matches.is_present("sustained");
args.converge_only = matches.is_present("converge-only");
args.reject_extra_nodes = matches.is_present("reject-extra-nodes");
args
}

View File

@ -1,47 +1,35 @@
mod bench;
mod cli;
use crate::bench::*;
use solana::client::mk_client;
use solana::gen_keys::GenKeys;
use solana::gossip_service::discover;
use solana_metrics;
use solana_sdk::signature::{Keypair, KeypairUtil};
use std::collections::VecDeque;
use crate::bench::{do_bench_tps, generate_and_fund_keypairs, Config, NUM_LAMPORTS_PER_ACCOUNT};
use solana::gossip_service::{discover_cluster, get_clients};
use std::process::exit;
use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::thread::Builder;
use std::time::Duration;
use std::time::Instant;
fn main() {
solana_logger::setup();
solana_metrics::set_panic_hook("bench-tps");
let matches = cli::build_args().get_matches();
let cfg = cli::extract_args(&matches);
let cli_config = cli::extract_args(&matches);
let cli::Config {
network_addr: network,
entrypoint_addr,
drone_addr,
id,
threads,
thread_batch_sleep_ms,
num_nodes,
duration,
tx_count,
thread_batch_sleep_ms,
sustained,
reject_extra_nodes,
converge_only,
} = cfg;
} = cli_config;
let nodes = discover(&network, num_nodes).unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1);
});
println!("Connecting to the cluster");
let (nodes, _replicators) =
discover_cluster(&entrypoint_addr, num_nodes).unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1);
});
if nodes.len() < num_nodes {
eprintln!(
"Error: Insufficient nodes discovered. Expecting {} or more",
@ -49,201 +37,25 @@ fn main() {
);
exit(1);
}
if reject_extra_nodes && nodes.len() > num_nodes {
eprintln!(
"Error: Extra nodes discovered. Expecting exactly {}",
num_nodes
);
exit(1);
}
if converge_only {
return;
}
let cluster_entrypoint = nodes[0].clone(); // Pick the first node, why not?
let clients = get_clients(&nodes);
let mut client = mk_client(&cluster_entrypoint);
let mut barrier_client = mk_client(&cluster_entrypoint);
let mut seed = [0u8; 32];
seed.copy_from_slice(&id.public_key_bytes()[..32]);
let mut rnd = GenKeys::new(seed);
println!("Creating {} keypairs...", tx_count * 2);
let mut total_keys = 0;
let mut target = tx_count * 2;
while target > 0 {
total_keys += target;
target /= MAX_SPENDS_PER_TX;
}
let gen_keypairs = rnd.gen_n_keypairs(total_keys as u64);
let barrier_source_keypair = Keypair::new();
let barrier_dest_id = Keypair::new().pubkey();
println!("Get lamports...");
let num_lamports_per_account = 20;
// Sample the first keypair, see if it has lamports, if so then resume
// to avoid lamport loss
let keypair0_balance = client
.poll_get_balance(&gen_keypairs.last().unwrap().pubkey())
.unwrap_or(0);
if num_lamports_per_account > keypair0_balance {
let extra = num_lamports_per_account - keypair0_balance;
let total = extra * (gen_keypairs.len() as u64);
airdrop_lamports(&mut client, &drone_addr, &id, total);
println!("adding more lamports {}", extra);
fund_keys(&mut client, &id, &gen_keypairs, extra);
}
let start = gen_keypairs.len() - (tx_count * 2) as usize;
let keypairs = &gen_keypairs[start..];
airdrop_lamports(&mut barrier_client, &drone_addr, &barrier_source_keypair, 1);
println!("Get last ID...");
let mut blockhash = client.get_recent_blockhash();
println!("Got last ID {:?}", blockhash);
let first_tx_count = client.transaction_count();
println!("Initial transaction count {}", first_tx_count);
let exit_signal = Arc::new(AtomicBool::new(false));
// Setup a thread per validator to sample every period
// collect the max transaction rate and total tx count seen
let maxes = Arc::new(RwLock::new(Vec::new()));
let sample_period = 1; // in seconds
println!("Sampling TPS every {} second...", sample_period);
let v_threads: Vec<_> = nodes
.into_iter()
.map(|v| {
let exit_signal = exit_signal.clone();
let maxes = maxes.clone();
Builder::new()
.name("solana-client-sample".to_string())
.spawn(move || {
sample_tx_count(&exit_signal, &maxes, first_tx_count, &v, sample_period);
})
.unwrap()
})
.collect();
let shared_txs: SharedTransactions = Arc::new(RwLock::new(VecDeque::new()));
let shared_tx_active_thread_count = Arc::new(AtomicIsize::new(0));
let total_tx_sent_count = Arc::new(AtomicUsize::new(0));
let s_threads: Vec<_> = (0..threads)
.map(|_| {
let exit_signal = exit_signal.clone();
let shared_txs = shared_txs.clone();
let cluster_entrypoint = cluster_entrypoint.clone();
let shared_tx_active_thread_count = shared_tx_active_thread_count.clone();
let total_tx_sent_count = total_tx_sent_count.clone();
Builder::new()
.name("solana-client-sender".to_string())
.spawn(move || {
do_tx_transfers(
&exit_signal,
&shared_txs,
&cluster_entrypoint,
&shared_tx_active_thread_count,
&total_tx_sent_count,
thread_batch_sleep_ms,
);
})
.unwrap()
})
.collect();
// generate and send transactions for the specified duration
let start = Instant::now();
let mut reclaim_lamports_back_to_source_account = false;
let mut i = keypair0_balance;
while start.elapsed() < duration {
let balance = client.poll_get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(balance);
// ping-pong between source and destination accounts for each loop iteration
// this seems to be faster than trying to determine the balance of individual
// accounts
let len = tx_count as usize;
generate_txs(
&shared_txs,
&keypairs[..len],
&keypairs[len..],
threads,
reclaim_lamports_back_to_source_account,
&cluster_entrypoint,
);
// In sustained mode overlap the transfers with generation
// this has higher average performance but lower peak performance
// in tested environments.
if !sustained {
while shared_tx_active_thread_count.load(Ordering::Relaxed) > 0 {
sleep(Duration::from_millis(100));
}
}
// It's not feasible (would take too much time) to confirm each of the `tx_count / 2`
// transactions sent by `generate_txs()` so instead send and confirm a single transaction
// to validate the network is still functional.
send_barrier_transaction(
&mut barrier_client,
&mut blockhash,
&barrier_source_keypair,
&barrier_dest_id,
);
i += 1;
if should_switch_directions(num_lamports_per_account, i) {
reclaim_lamports_back_to_source_account = !reclaim_lamports_back_to_source_account;
}
}
// Stop the sampling threads so it will collect the stats
exit_signal.store(true, Ordering::Relaxed);
println!("Waiting for validator threads...");
for t in v_threads {
if let Err(err) = t.join() {
println!(" join() failed with: {:?}", err);
}
}
// join the tx send threads
println!("Waiting for transmit threads...");
for t in s_threads {
if let Err(err) = t.join() {
println!(" join() failed with: {:?}", err);
}
}
let balance = client.poll_get_balance(&id.pubkey()).unwrap_or(0);
metrics_submit_lamport_balance(balance);
compute_and_report_stats(
&maxes,
sample_period,
&start.elapsed(),
total_tx_sent_count.load(Ordering::Relaxed),
let (keypairs, keypair_balance) = generate_and_fund_keypairs(
&clients[0],
Some(drone_addr),
&id,
tx_count,
NUM_LAMPORTS_PER_ACCOUNT,
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_switch_directions() {
assert_eq!(should_switch_directions(20, 0), false);
assert_eq!(should_switch_directions(20, 1), false);
assert_eq!(should_switch_directions(20, 14), false);
assert_eq!(should_switch_directions(20, 15), true);
assert_eq!(should_switch_directions(20, 16), false);
assert_eq!(should_switch_directions(20, 19), false);
assert_eq!(should_switch_directions(20, 20), true);
assert_eq!(should_switch_directions(20, 21), false);
assert_eq!(should_switch_directions(20, 99), false);
assert_eq!(should_switch_directions(20, 100), true);
assert_eq!(should_switch_directions(20, 101), false);
}
let config = Config {
id,
threads,
thread_batch_sleep_ms,
duration,
tx_count,
sustained,
};
do_bench_tps(clients, config, keypairs, keypair_balance);
}

View File

@ -1,248 +0,0 @@
#![feature(test)]
extern crate rand;
extern crate test;
use bincode::{deserialize, serialize_into, serialized_size};
use rand::{thread_rng, Rng};
use solana_runtime::append_vec::{
deserialize_account, get_serialized_size, serialize_account, AppendVec,
};
use solana_sdk::account::Account;
use solana_sdk::signature::{Keypair, KeypairUtil};
use std::env;
use std::io::Cursor;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, RwLock};
use std::thread::spawn;
use test::Bencher;
const START_SIZE: u64 = 4 * 1024 * 1024;
const INC_SIZE: u64 = 1 * 1024 * 1024;
macro_rules! align_up {
($addr: expr, $align: expr) => {
($addr + ($align - 1)) & !($align - 1)
};
}
fn get_append_vec_bench_path(path: &str) -> PathBuf {
let out_dir = env::var("OUT_DIR").unwrap_or_else(|_| "target".to_string());
let mut buf = PathBuf::new();
buf.push(&format!("{}/{}", out_dir, path));
buf
}
#[bench]
fn append_vec_atomic_append(bencher: &mut Bencher) {
let path = get_append_vec_bench_path("bench_append");
let mut vec = AppendVec::<AtomicUsize>::new(&path, true, START_SIZE, INC_SIZE);
bencher.iter(|| {
if vec.append(AtomicUsize::new(0)).is_none() {
assert!(vec.grow_file().is_ok());
assert!(vec.append(AtomicUsize::new(0)).is_some());
}
});
std::fs::remove_file(path).unwrap();
}
#[bench]
fn append_vec_atomic_random_access(bencher: &mut Bencher) {
let path = get_append_vec_bench_path("bench_ra");
let mut vec = AppendVec::<AtomicUsize>::new(&path, true, START_SIZE, INC_SIZE);
let size = 1_000_000;
for _ in 0..size {
if vec.append(AtomicUsize::new(0)).is_none() {
assert!(vec.grow_file().is_ok());
assert!(vec.append(AtomicUsize::new(0)).is_some());
}
}
bencher.iter(|| {
let index = thread_rng().gen_range(0, size as u64);
vec.get(index * std::mem::size_of::<AtomicUsize>() as u64);
});
std::fs::remove_file(path).unwrap();
}
#[bench]
fn append_vec_atomic_random_change(bencher: &mut Bencher) {
let path = get_append_vec_bench_path("bench_rax");
let mut vec = AppendVec::<AtomicUsize>::new(&path, true, START_SIZE, INC_SIZE);
let size = 1_000_000;
for k in 0..size {
if vec.append(AtomicUsize::new(k)).is_none() {
assert!(vec.grow_file().is_ok());
assert!(vec.append(AtomicUsize::new(k)).is_some());
}
}
bencher.iter(|| {
let index = thread_rng().gen_range(0, size as u64);
let atomic1 = vec.get(index * std::mem::size_of::<AtomicUsize>() as u64);
let current1 = atomic1.load(Ordering::Relaxed);
assert_eq!(current1, index as usize);
let next = current1 + 1;
let mut index = vec.append(AtomicUsize::new(next));
if index.is_none() {
assert!(vec.grow_file().is_ok());
index = vec.append(AtomicUsize::new(next));
}
let atomic2 = vec.get(index.unwrap());
let current2 = atomic2.load(Ordering::Relaxed);
assert_eq!(current2, next);
});
std::fs::remove_file(path).unwrap();
}
#[bench]
fn append_vec_atomic_random_read(bencher: &mut Bencher) {
let path = get_append_vec_bench_path("bench_read");
let mut vec = AppendVec::<AtomicUsize>::new(&path, true, START_SIZE, INC_SIZE);
let size = 1_000_000;
for _ in 0..size {
if vec.append(AtomicUsize::new(0)).is_none() {
assert!(vec.grow_file().is_ok());
assert!(vec.append(AtomicUsize::new(0)).is_some());
}
}
bencher.iter(|| {
let index = thread_rng().gen_range(0, size);
let atomic1 = vec.get((index * std::mem::size_of::<AtomicUsize>()) as u64);
let current1 = atomic1.load(Ordering::Relaxed);
assert_eq!(current1, 0);
});
std::fs::remove_file(path).unwrap();
}
#[bench]
fn append_vec_concurrent_lock_append(bencher: &mut Bencher) {
let path = get_append_vec_bench_path("bench_lock_append");
let vec = Arc::new(RwLock::new(AppendVec::<AtomicUsize>::new(
&path, true, START_SIZE, INC_SIZE,
)));
let vec1 = vec.clone();
let size = 1_000_000;
let count = Arc::new(AtomicUsize::new(0));
let count1 = count.clone();
spawn(move || loop {
let mut len = count.load(Ordering::Relaxed);
{
let rlock = vec1.read().unwrap();
loop {
if rlock.append(AtomicUsize::new(0)).is_none() {
break;
}
len = count.fetch_add(1, Ordering::Relaxed);
}
if len >= size {
break;
}
}
{
let mut wlock = vec1.write().unwrap();
if len >= size {
break;
}
assert!(wlock.grow_file().is_ok());
}
});
bencher.iter(|| {
let _rlock = vec.read().unwrap();
let len = count1.load(Ordering::Relaxed);
assert!(len < size * 2);
});
std::fs::remove_file(path).unwrap();
}
#[bench]
fn append_vec_concurrent_get_append(bencher: &mut Bencher) {
let path = get_append_vec_bench_path("bench_get_append");
let vec = Arc::new(RwLock::new(AppendVec::<AtomicUsize>::new(
&path, true, START_SIZE, INC_SIZE,
)));
let vec1 = vec.clone();
let size = 1_000_000;
let count = Arc::new(AtomicUsize::new(0));
let count1 = count.clone();
spawn(move || loop {
let mut len = count.load(Ordering::Relaxed);
{
let rlock = vec1.read().unwrap();
loop {
if rlock.append(AtomicUsize::new(0)).is_none() {
break;
}
len = count.fetch_add(1, Ordering::Relaxed);
}
if len >= size {
break;
}
}
{
let mut wlock = vec1.write().unwrap();
if len >= size {
break;
}
assert!(wlock.grow_file().is_ok());
}
});
bencher.iter(|| {
let rlock = vec.read().unwrap();
let len = count1.load(Ordering::Relaxed);
if len > 0 {
let index = thread_rng().gen_range(0, len);
rlock.get((index * std::mem::size_of::<AtomicUsize>()) as u64);
}
});
std::fs::remove_file(path).unwrap();
}
#[bench]
fn bench_account_serialize(bencher: &mut Bencher) {
let num: usize = 1000;
let account = Account::new(2, 100, &Keypair::new().pubkey());
let len = get_serialized_size(&account);
let ser_len = align_up!(len + std::mem::size_of::<u64>(), std::mem::size_of::<u64>());
let mut memory = vec![0; num * ser_len];
bencher.iter(|| {
for i in 0..num {
let start = i * ser_len;
serialize_account(&mut memory[start..start + ser_len], &account, len);
}
});
// make sure compiler doesn't delete the code.
let index = thread_rng().gen_range(0, num);
if memory[index] != 0 {
println!("memory: {}", memory[index]);
}
let start = index * ser_len;
let new_account = deserialize_account(&memory[start..start + ser_len], 0, num * len).unwrap();
assert_eq!(new_account, account);
}
#[bench]
fn bench_account_serialize_bincode(bencher: &mut Bencher) {
let num: usize = 1000;
let account = Account::new(2, 100, &Keypair::new().pubkey());
let len = serialized_size(&account).unwrap() as usize;
let mut memory = vec![0u8; num * len];
bencher.iter(|| {
for i in 0..num {
let start = i * len;
let cursor = Cursor::new(&mut memory[start..start + len]);
serialize_into(cursor, &account).unwrap();
}
});
// make sure compiler doesn't delete the code.
let index = thread_rng().gen_range(0, len);
if memory[index] != 0 {
println!("memory: {}", memory[index]);
}
let start = index * len;
let new_account: Account = deserialize(&memory[start..start + len]).unwrap();
assert_eq!(new_account, account);
}

View File

@ -1,241 +0,0 @@
#![feature(test)]
extern crate test;
use rand::{thread_rng, Rng};
use rayon::prelude::*;
use solana::banking_stage::{create_test_recorder, BankingStage};
use solana::cluster_info::ClusterInfo;
use solana::cluster_info::Node;
use solana::packet::to_packets_chunked;
use solana::poh_recorder::WorkingBankEntries;
use solana::service::Service;
use solana_runtime::bank::Bank;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::hash::hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{KeypairUtil, Signature};
use solana_sdk::system_transaction::SystemTransaction;
use solana_sdk::timing::{DEFAULT_TICKS_PER_SLOT, MAX_RECENT_BLOCKHASHES};
use std::iter;
use std::sync::atomic::Ordering;
use std::sync::mpsc::{channel, Receiver};
use std::sync::{Arc, RwLock};
use std::time::Duration;
use test::Bencher;
fn check_txs(receiver: &Receiver<WorkingBankEntries>, ref_tx_count: usize) {
let mut total = 0;
loop {
let entries = receiver.recv_timeout(Duration::new(1, 0));
if let Ok((_, entries)) = entries {
for (entry, _) in &entries {
total += entry.transactions.len();
}
} else {
break;
}
if total >= ref_tx_count {
break;
}
}
assert_eq!(total, ref_tx_count);
}
#[bench]
#[ignore]
fn bench_banking_stage_multi_accounts(bencher: &mut Bencher) {
let num_threads = BankingStage::num_threads() as usize;
// a multiple of packet chunk 2X duplicates to avoid races
let txes = 192 * 50 * num_threads * 2;
let mint_total = 1_000_000_000_000;
let (genesis_block, mint_keypair) = GenesisBlock::new(mint_total);
let (verified_sender, verified_receiver) = channel();
let bank = Arc::new(Bank::new(&genesis_block));
let dummy = SystemTransaction::new_move(
&mint_keypair,
&mint_keypair.pubkey(),
1,
genesis_block.hash(),
0,
);
let transactions: Vec<_> = (0..txes)
.into_par_iter()
.map(|_| {
let mut new = dummy.clone();
let from: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
let to: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
new.account_keys[0] = Pubkey::new(&from[0..32]);
new.account_keys[1] = Pubkey::new(&to[0..32]);
new.signatures = vec![Signature::new(&sig[0..64])];
new
})
.collect();
// fund all the accounts
transactions.iter().for_each(|tx| {
let fund = SystemTransaction::new_move(
&mint_keypair,
&tx.account_keys[0],
mint_total / txes as u64,
genesis_block.hash(),
0,
);
let x = bank.process_transaction(&fund);
x.unwrap();
});
//sanity check, make sure all the transactions can execute sequentially
transactions.iter().for_each(|tx| {
let res = bank.process_transaction(&tx);
assert!(res.is_ok(), "sanity test transactions");
});
bank.clear_signatures();
//sanity check, make sure all the transactions can execute in parallel
let res = bank.process_transactions(&transactions);
for r in res {
assert!(r.is_ok(), "sanity parallel execution");
}
bank.clear_signatures();
let verified: Vec<_> = to_packets_chunked(&transactions.clone(), 192)
.into_iter()
.map(|x| {
let len = x.read().unwrap().packets.len();
(x, iter::repeat(1).take(len).collect())
})
.collect();
let (exit, poh_recorder, poh_service, signal_receiver) = create_test_recorder(&bank);
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
let cluster_info = Arc::new(RwLock::new(cluster_info));
let _banking_stage = BankingStage::new(&cluster_info, &poh_recorder, verified_receiver);
poh_recorder.lock().unwrap().set_bank(&bank);
let mut id = genesis_block.hash();
for _ in 0..(MAX_RECENT_BLOCKHASHES * DEFAULT_TICKS_PER_SLOT as usize) {
id = hash(&id.as_ref());
bank.register_tick(&id);
}
let half_len = verified.len() / 2;
let mut start = 0;
bencher.iter(move || {
// make sure the transactions are still valid
bank.register_tick(&genesis_block.hash());
for v in verified[start..start + half_len].chunks(verified.len() / num_threads) {
verified_sender.send(v.to_vec()).unwrap();
}
check_txs(&signal_receiver, txes / 2);
bank.clear_signatures();
start += half_len;
start %= verified.len();
});
exit.store(true, Ordering::Relaxed);
poh_service.join().unwrap();
}
#[bench]
#[ignore]
fn bench_banking_stage_multi_programs(bencher: &mut Bencher) {
let progs = 4;
let num_threads = BankingStage::num_threads() as usize;
// a multiple of packet chunk 2X duplicates to avoid races
let txes = 96 * 100 * num_threads * 2;
let mint_total = 1_000_000_000_000;
let (genesis_block, mint_keypair) = GenesisBlock::new(mint_total);
let (verified_sender, verified_receiver) = channel();
let bank = Arc::new(Bank::new(&genesis_block));
let dummy = SystemTransaction::new_move(
&mint_keypair,
&mint_keypair.pubkey(),
1,
genesis_block.hash(),
0,
);
let transactions: Vec<_> = (0..txes)
.into_par_iter()
.map(|_| {
let mut new = dummy.clone();
let from: Vec<u8> = (0..32).map(|_| thread_rng().gen()).collect();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
let to: Vec<u8> = (0..32).map(|_| thread_rng().gen()).collect();
new.account_keys[0] = Pubkey::new(&from[0..32]);
new.account_keys[1] = Pubkey::new(&to[0..32]);
let prog = new.instructions[0].clone();
for i in 1..progs {
//generate programs that spend to random keys
let to: Vec<u8> = (0..32).map(|_| thread_rng().gen()).collect();
let to_key = Pubkey::new(&to[0..32]);
new.account_keys.push(to_key);
assert_eq!(new.account_keys.len(), i + 2);
new.instructions.push(prog.clone());
assert_eq!(new.instructions.len(), i + 1);
new.instructions[i].accounts[1] = 1 + i as u8;
assert_eq!(new.key(i, 1), Some(&to_key));
assert_eq!(
new.account_keys[new.instructions[i].accounts[1] as usize],
to_key
);
}
assert_eq!(new.instructions.len(), progs);
new.signatures = vec![Signature::new(&sig[0..64])];
new
})
.collect();
transactions.iter().for_each(|tx| {
let fund = SystemTransaction::new_move(
&mint_keypair,
&tx.account_keys[0],
mint_total / txes as u64,
genesis_block.hash(),
0,
);
bank.process_transaction(&fund).unwrap();
});
//sanity check, make sure all the transactions can execute sequentially
transactions.iter().for_each(|tx| {
let res = bank.process_transaction(&tx);
assert!(res.is_ok(), "sanity test transactions");
});
bank.clear_signatures();
//sanity check, make sure all the transactions can execute in parallel
let res = bank.process_transactions(&transactions);
for r in res {
assert!(r.is_ok(), "sanity parallel execution");
}
bank.clear_signatures();
let verified: Vec<_> = to_packets_chunked(&transactions.clone(), 96)
.into_iter()
.map(|x| {
let len = x.read().unwrap().packets.len();
(x, iter::repeat(1).take(len).collect())
})
.collect();
let (exit, poh_recorder, poh_service, signal_receiver) = create_test_recorder(&bank);
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
let cluster_info = Arc::new(RwLock::new(cluster_info));
let _banking_stage = BankingStage::new(&cluster_info, &poh_recorder, verified_receiver);
poh_recorder.lock().unwrap().set_bank(&bank);
let mut id = genesis_block.hash();
for _ in 0..(MAX_RECENT_BLOCKHASHES * DEFAULT_TICKS_PER_SLOT as usize) {
id = hash(&id.as_ref());
bank.register_tick(&id);
}
let half_len = verified.len() / 2;
let mut start = 0;
bencher.iter(move || {
// make sure the transactions are still valid
bank.register_tick(&genesis_block.hash());
for v in verified[start..start + half_len].chunks(verified.len() / num_threads) {
verified_sender.send(v.to_vec()).unwrap();
}
check_txs(&signal_receiver, txes / 2);
bank.clear_signatures();
start += half_len;
start %= verified.len();
});
exit.store(true, Ordering::Relaxed);
poh_service.join().unwrap();
}

1
book/.gitattributes vendored Normal file
View File

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

View File

@ -0,0 +1,19 @@
+------------------------------------------------------------------+
| |
| +-----------------+ Neighborhood 0 +-----------------+ |
| | +--------------------->+ | |
| | Validator 1 | | Validator 2 | |
| | +<---------------------+ | |
| +--------+-+------+ +------+-+--------+ |
| | | | | |
| | +-----------------------------+ | | |
| | +------------------------+------+ | |
| | | | | |
+------------------------------------------------------------------+
| | | |
v v v v
+---------+------+---+ +-+--------+---------+
| | | |
| Neighborhood 1 | | Neighborhood 2 |
| | | |
+--------------------+ +--------------------+

View File

@ -0,0 +1,15 @@
+--------------+
| |
+------------+ Leader +------------+
| | | |
| +--------------+ |
v v
+------------+----------------------------------------+------------+
| |
| +-----------------+ Neighborhood 0 +-----------------+ |
| | +--------------------->+ | |
| | Validator 1 | | Validator 2 | |
| | +<---------------------+ | |
| +-----------------+ +-----------------+ |
| |
+------------------------------------------------------------------+

View File

@ -1,28 +1,18 @@
+--------------+
| |
+------------+ Leader +------------+
| | | |
| +--------------+ |
v v
+--------+--------+ +--------+--------+
| +--------------------->+ |
+-----------------+ Validator 1 | | Validator 2 +-------------+
| | +<---------------------+ | |
| +------+-+-+------+ +---+-+-+---------+ |
| | | | | | | |
| | | | | | | |
| +---------------------------------------------+ | | |
| | | | | | | |
| | | | | +----------------------+ | |
| | | | | | | |
| | | | +--------------------------------------------+ |
| | | | | | | |
| | | +----------------------+ | | |
| | | | | | | |
v v v v v v v v
+--------------------+ +--------------------+ +--------------------+ +--------------------+
| | | | | | | |
| Neighborhood 1 | | Neighborhood 2 | | Neighborhood 3 | | Neighborhood 4 |
| | | | | | | |
+--------------------+ +--------------------+ +--------------------+ +--------------------+
+--------------------+
| |
+--------+ Neighborhood 0 +----------+
| | | |
| +--------------------+ |
v v
+---------+----------+ +----------+---------+
| | | |
| Neighborhood 1 | | Neighborhood 2 |
| | | |
+---+-----+----------+ +----------+-----+---+
| | | |
v v v v
+------------------+-+ +-+------------------+ +------------------+-+ +-+------------------+
| | | | | | | |
| Neighborhood 3 | | Neighborhood 4 | | Neighborhood 5 | | Neighborhood 6 |
| | | | | | | |
+--------------------+ +--------------------+ +--------------------+ +--------------------+

View File

@ -0,0 +1,30 @@
msc {
hscale="2.2";
VoteSigner,
Validator,
Cluster,
StakerX,
StakerY;
|||;
Validator box Validator [label="boot.."];
VoteSigner <:> Validator [label="register\n\n(optional)"];
Validator => Cluster [label="VoteState::Initialize(VoteSigner)"];
StakerX => Cluster [label="StakeState::Delegate(Validator)"];
StakerY => Cluster [label="StakeState::Delegate(Validator)"];
|||;
Validator box Cluster [label="\nvalidate\n"];
Validator => VoteSigner [label="sign(vote)"];
VoteSigner >> Validator [label="signed vote"];
Validator => Cluster [label="gossip(vote)"];
...;
... ;
Validator abox Validator [label="\nmax\nlockout\n"];
|||;
StakerX => Cluster [label="StakeState::RedeemCredits()"];
StakerY => Cluster [label="StakeState::RedeemCredits()"] ;
}

View File

@ -1,16 +1,17 @@
.-------------------------------------------.
| TPU .-------------. |
| | PoH Service | |
| `--------+----` |
| ^ | |
| | v |
| .-------. .-----------. .-+-------. | .------------.
.---------. | | Fetch | | SigVerify | | Banking | | | Broadcast |
| Clients |--->| Stage |->| Stage |->| Stage |------>| Service |
`---------` | | | | | | | | | |
| `-------` `-----------` `----+----` | `------------`
| | |
`---------------------------------|---------`
.-------------.
| PoH Service |
`--------+----`
^ |
.------------------------------|----|--------------------.
| TPU | v |
| .-------. .-----------. .-+-------. .-----------. | .------------.
.---------. | | Fetch | | SigVerify | | Banking | | Broadcast | | | Downstream |
| Clients |--->| Stage |->| Stage |->| Stage |->| Stage |---->| Validators |
`---------` | | | | | | | | | | | |
| `-------` `-----------` `----+----` `-----------` | `------------`
| | |
`---------------------------------|----------------------`
|
v
.------.

View File

@ -0,0 +1,60 @@
.------------.
| Upstream |
| Validators |
`----+-------`
|
|
.-----------------------------------.
| Validator | |
| v |
| .-----------. .------------. |
.--------. | | Fetch | | Repair | |
| Client +---->| Stage | | Stage | |
`--------` | `---+-------` `----+-------` |
| | | |
| v v |
| .-----------. .------------. |
| | TPU |<-->| Blockstore | |
| | | | | |
| `-----------` `----+-------` |
| | |
| v |
| .------------. |
| | Multicast | |
| | Stage | |
| `----+-------` |
| | |
`-----------------------------------`
|
v
.------------.
| Downstream |
| Validators |
`------------`
.------------.
| PoH |
| Service |
`-------+----`
^ |
| |
.-----------------------------------.
| TPU | | |
| | v |
.-------. | .-----------. .---+--------. | .------------.
| Fetch +---->| SigVerify +--->| Banking |<--->| Blockstore |
| Stage | | | Stage | | Stage | | | |
`-------` | `-----------` `-----+------` | `------------`
| | |
| | |
`-----------------------------------`
|
v
.------------.
| Banktree |
| |
`------------`

View File

@ -1,5 +1,5 @@
.--------------------------------------.
| Fullnode |
| Validator |
| |
.--------. | .-------------------. |
| |---->| | |
@ -25,6 +25,6 @@
| | | | | | | Downstream | |
| | .--+--. .-------+---. | | | Validators | |
`-------->| TPU +---->| Broadcast +--------------->| | |
| `-----` | Service | | | `------------` |
| `-----` | Stage | | | `------------` |
| `-----------` | `------------------`
`--------------------------------------`

View File

@ -3,16 +3,4 @@ set -e
cd "$(dirname "$0")"
cargo_install_unless() {
declare crate=$1
shift
"$@" > /dev/null 2>&1 || \
cargo install "$crate"
}
export PATH=$CARGO_HOME/bin:$PATH
cargo_install_unless mdbook mdbook --help
cargo_install_unless svgbob_cli svgbob --help
make -j"$(nproc)"

View File

@ -1,7 +1,8 @@
BOB_SRCS=$(wildcard art/*.bob)
MSC_SRCS=$(wildcard art/*.msc)
MD_SRCS=$(wildcard src/*.md)
SVG_IMGS=$(BOB_SRCS:art/%.bob=src/img/%.svg)
SVG_IMGS=$(BOB_SRCS:art/%.bob=src/img/%.svg) $(MSC_SRCS:art/%.msc=src/img/%.svg)
all: html/index.html
@ -17,6 +18,10 @@ src/img/%.svg: art/%.bob
@mkdir -p $(@D)
svgbob < $< > $@
src/img/%.svg: art/%.msc
@mkdir -p $(@D)
mscgen -T svg -i $< -o $@
src/%.md: %.md
@mkdir -p $(@D)
@cp $< $@

View File

@ -19,9 +19,10 @@
- [Data Plane Fanout](data-plane-fanout.md)
- [Ledger Replication](ledger-replication.md)
- [Secure Vote Signing](vote-signing.md)
- [Staking Delegation and Rewards](stake-delegation-and-rewards.md)
- [Stake Delegation and Rewards](stake-delegation-and-rewards.md)
- [Performance Metrics](performance-metrics.md)
- [Anatomy of a Fullnode](fullnode.md)
- [Anatomy of a Validator](validator.md)
- [TPU](tpu.md)
- [TVU](tvu.md)
- [Blocktree](blocktree.md)
@ -34,14 +35,10 @@
- [JavaScript API](javascript-api.md)
- [solana-wallet CLI](wallet.md)
- [Proposed Architectural Changes](proposals.md)
- [Accepted Design Proposals](proposals.md)
- [Ledger Replication](ledger-replication-to-implement.md)
- [Secure Vote Signing](vote-signing-to-implement.md)
- [Staking Rewards](staking-rewards.md)
- [Fork Selection](fork-selection.md)
- [Reliable Vote Transmission](reliable-vote-transmission.md)
- [Persistent Account Storage](persistent-account-storage.md)
- [Leader to Leader Transition](leader-leader-transition.md)
- [Cluster Economics](ed_overview.md)
- [Validation-client Economics](ed_validation_client_economics.md)
- [State-validation Protocol-based Rewards](ed_vce_state_validation_protocol_based_rewards.md)
@ -53,7 +50,20 @@
- [Replication-client Reward Auto-delegation](ed_rce_replication_client_reward_auto_delegation.md)
- [Economic Sustainability](ed_economic_sustainability.md)
- [Attack Vectors](ed_attack_vectors.md)
- [Economic Design MVP](ed_mvp.md)
- [References](ed_references.md)
- [Leader-to-Validator Transition](leader-validator-transition.md)
- [Cluster Test Framework](cluster-test-framework.md)
- [Credit-only Accounts](credit-only-credit-debit-accounts.md)
- [Deterministic Transaction Fees](transaction-fees.md)
- [Validator](validator-proposal.md)
- [Implemented Design Proposals](implemented-proposals.md)
- [Fork Selection](fork-selection.md)
- [Leader-to-Leader Transition](leader-leader-transition.md)
- [Leader-to-Validator Transition](leader-validator-transition.md)
- [Testnet Participation](testnet-participation.md)
- [Testing Programs](testing-programs.md)
- [Reliable Vote Transmission](reliable-vote-transmission.md)
- [Persistent Account Storage](persistent-account-storage.md)
- [Cluster Software Installation and Updates](installer.md)
- [Passive Stake Delegation and Rewards](passive-stake-delegation-and-rewards.md)

View File

@ -12,7 +12,7 @@ To run a blockstreamer, include the argument `no-signer` and (optional)
`blockstream` socket location:
```bash
$ ./multinode-demo/fullnode-x.sh --no-signer --blockstream <SOCKET>
$ ./multinode-demo/validator-x.sh --no-signer --blockstream <SOCKET>
```
The stream will output a series of JSON objects:

View File

@ -20,7 +20,7 @@ least amount of internal plumbing exposed to the test.
Tests are provided an entry point, which is a `contact_info::ContactInfo`
structure, and a keypair that has already been funded.
Each node in the cluster is configured with a `fullnode::FullnodeConfig` at boot
Each node in the cluster is configured with a `fullnode::ValidatorConfig` at boot
time. At boot time this configuration specifies any extra cluster configuration
required for the test. The cluster should boot with the configuration when it
is run in-process or in a data center.
@ -51,28 +51,28 @@ At test start, the cluster has already been established and is fully connected.
The test can discover most of the available nodes over a few second.
```rust,ignore
use crate::gossip_service::discover;
use crate::gossip_service::discover_nodes;
// Discover the cluster over a few seconds.
let cluster_nodes = discover(&entry_point_info, num_nodes);
let cluster_nodes = discover_nodes(&entry_point_info, num_nodes);
```
## Cluster Configuration
To enable specific scenarios, the cluster needs to be booted with special
configurations. These configurations can be captured in
`fullnode::FullnodeConfig`.
`fullnode::ValidatorConfig`.
For example:
```rust,ignore
let mut fullnode_config = FullnodeConfig::default();
fullnode_config.rpc_config.enable_fullnode_exit = true;
let mut validator_config = ValidatorConfig::default();
validator_config.rpc_config.enable_fullnode_exit = true;
let local = LocalCluster::new_with_config(
num_nodes,
10_000,
100,
&fullnode_config
&validator_config
);
```
@ -86,9 +86,9 @@ advertised gossip nodes.
Configure the RPC service:
```rust,ignore
let mut fullnode_config = FullnodeConfig::default();
fullnode_config.rpc_config.enable_rpc_gossip_push = true;
fullnode_config.rpc_config.enable_rpc_gossip_refresh_active_set = true;
let mut validator_config = ValidatorConfig::default();
validator_config.rpc_config.enable_rpc_gossip_push = true;
validator_config.rpc_config.enable_rpc_gossip_refresh_active_set = true;
```
Wire the RPCs and write a new test:
@ -99,10 +99,10 @@ pub fn test_large_invalid_gossip_nodes(
funding_keypair: &Keypair,
num_nodes: usize,
) {
let cluster = discover(&entry_point_info, num_nodes);
let cluster = discover_nodes(&entry_point_info, num_nodes);
// Poison the cluster.
let mut client = mk_client(&entry_point_info);
let client = create_client(entry_point_info.client_facing_addr(), FULLNODE_PORT_RANGE);
for _ in 0..(num_nodes * 100) {
client.gossip_push(
cluster_info::invalid_contact_info()
@ -112,7 +112,7 @@ pub fn test_large_invalid_gossip_nodes(
// Force refresh of the active set.
for node in &cluster {
let mut client = mk_client(&node);
let client = create_client(node.client_facing_addr(), FULLNODE_PORT_RANGE);
client.gossip_refresh_active_set();
}

View File

@ -28,7 +28,7 @@ its copy.
## Joining a Cluster
Fullnodes and replicators enter the cluster via registration messages sent to
Validators and replicators enter the cluster via registration messages sent to
its *control plane*. The control plane is implemented using a *gossip*
protocol, meaning that a node may register with any existing node, and expect
its registration to propagate to all nodes in the cluster. The time it takes

View File

@ -0,0 +1,140 @@
# Credit-Only Accounts
This design covers the handling of credit-only and credit-debit accounts in the
[runtime](runtime.md). Accounts already distinguish themselves as credit-only or
credit-debit based on the program ID specified by the transaction's instruction.
Programs must treat accounts that are not owned by them as credit-only.
To identify credit-only accounts by program id would require the account to be
fetched and loaded from disk. This operation is expensive, and while it is
occurring, the runtime would have to reject any transactions referencing the same
account.
The proposal introduces a `num_readonly_accounts` field to the transaction
structure, and removes the `program_ids` dedicated vector for program accounts.
This design doesn't change the runtime transaction processing rules.
Programs still can't write or spend accounts that they do not own, but it
allows the runtime to optimistically take the correct lock for each account
specified in the transaction before loading the accounts from storage.
Accounts selected as credit-debit by the transaction can still be treated as
credit-only by the instructions.
## Runtime handling
credit-only accounts have the following properties:
* Can be deposited into: Deposits can be implemented as a simple `atomic_add`.
* read-only access to account data.
Instructions that debit or modify the credit-only account data will fail.
## Account Lock Optimizations
The Accounts module keeps track of current locked accounts in the runtime,
which separates credit-only accounts from the credit-debit accounts. The credit-only
accounts can be cached in memory and shared between all the threads executing
transactions.
The current runtime can't predict whether an account is credit-only or credit-debit when
the transaction account keys are locked at the start of the transaction
processing pipeline. Accounts referenced by the transaction have not been
loaded from the disk yet.
An ideal design would cache the credit-only accounts while they are referenced by
any transaction moving through the runtime, and release the cache when the last
transaction exits the runtime.
## Credit-only accounts and read-only account data
Credit-only account data can be treated as read-only. Credit-debit
account data is treated as read-write.
## Transaction changes
To enable the possibility of caching accounts only while they are in the
runtime, the Transaction structure should be changed in the following way:
* `program_ids: Vec<Pubkey>` - This vector is removed. Program keys can be
placed at the end of the `account_keys` vector within the `num_readonly_accounts`
number set to the number of programs.
* `num_readonly_accounts: u8` - The number of keys from the **end** of the
transaction's `account_keys` array that is credit-only.
The following possible accounts are present in an transaction:
* paying account
* RW accounts
* R accounts
* Program IDs
The paying account must be credit-debit, and program IDs must be credit-only. The
first account in the `account_keys` array is always the account that pays for
the transaction fee, therefore it cannot be credit-only. For these reasons the
credit-only accounts are all grouped together at the end of the `account_keys`
vector. Counting credit-only accounts from the end allow for the default `0`
value to still be functionally correct, since a transaction will succeed with
all credit-debit accounts.
Since accounts can only appear once in the transaction's `account_keys` array,
an account can only be credit-only or credit-debit in a single transaction, not
both. The runtime treats a transaction as one atomic unit of execution. If any
instruction needs credit-debit access to an account, a copy needs to be made. The
write lock is held for the entire time the transaction is being processed by
the runtime.
## Starvation
Read locks for credit-only accounts can keep the runtime from executing
transactions requesting a write lock to a credit-debit account.
When a request for a write lock is made while a read lock is open, the
transaction requesting the write lock should be cached. Upon closing the read
lock, the pending transactions can be pushed through the runtime.
While a pending write transaction exists, any additional read lock requests for
that account should fail. It follows that any other write lock requests will also
fail. Currently, clients must retransmit when a transaction fails because of
a pending transaction. This approach would mimic that behavior as closely as
possible while preventing write starvation.
## Program execution with credit-only accounts
Before handing off the accounts to program execution, the runtime can mark each
account in each instruction as a credit-only account. The credit-only accounts can
be passed as references without an extra copy. The transaction will abort on a
write to credit-only.
An alternative is to detect writes to credit-only accounts and fail the
transactions before commit.
## Alternative design
This design attempts to cache a credit-only account after loading without the use
of a transaction-specified credit-only accounts list. Instead, the credit-only
accounts are held in a reference-counted table inside the runtime as the
transactions are processed.
1. Transaction accounts are locked.
a. If the account is present in the credit-only' table, the TX does not fail.
The pending state for this TX is marked NeedReadLock.
2. Transaction accounts are loaded.
a. Transaction accounts that are credit-only increase their reference
count in the `credit-only` table.
b. Transaction accounts that need a write lock and are present in the
`credit-only` table fail.
3. Transaction accounts are unlocked.
a. Decrement the `credit-only` lock table reference count; remove if its 0
b. Remove from the `lock` set if the account is not in the `credit-only`
table.
The downside with this approach is that if the `lock` set mutex is released
between lock and load to allow better pipelining of transactions, a request for
a credit-only account may fail. Therefore, this approach is not suitable for
treating programs as credit-only accounts.
Holding the accounts lock mutex while fetching the account from disk would
potentially have a significant performance hit on the runtime. Fetching from
disk is expected to be slow, but can be parallelized between multiple disks.

View File

@ -5,16 +5,15 @@ broadcast transaction blobs to all nodes in a very quick and efficient manner.
In order to establish the fanout, 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.
as propagating the data on to a small set of nodes in other neighborhoods.
This way each node only has to communicate with a small number of nodes.
During its slot, the leader node distributes blobs between the validator nodes
in one neighborhood (layer 1). Each validator shares its data within its
neighborhood, but also retransmits the blobs to one node in each of multiple
neighborhoods in the next layer (layer 2). The layer-2 nodes each share their
data with their neighborhood peers, and retransmit to nodes in the next layer,
etc, until all nodes in the cluster have received all the blobs.
<img alt="Two layer cluster" src="img/data-plane.svg" class="center"/>
in the first neighborhood (layer 0). Each validator shares its data within its
neighborhood, but also retransmits the blobs to one node in some neighborhoods
in the next layer (layer 1). The layer-1 nodes each share their data with their
neighborhood peers, and retransmit to nodes in the next layer, etc, until all
nodes in the cluster have received all the blobs.
## Neighborhood Assignment - Weighted Selection
@ -23,48 +22,50 @@ cluster is divided into neighborhoods. To achieve this, all the recognized
validator nodes (the TVU peers) are sorted by stake and stored in a list. This
list is then indexed in different ways to figure out neighborhood boundaries and
retransmit peers. For example, the leader will simply select the first nodes to
make up layer 1. These will automatically be the highest stake holders, allowing
the heaviest votes to come back to the leader first. Layer-1 and lower-layer
nodes use the same logic to find their neighbors and lower layer peers.
make up layer 0. These will automatically be the highest stake holders, allowing
the heaviest votes to come back to the leader first. Layer-0 and lower-layer
nodes use the same logic to find their neighbors and next layer peers.
## Layer and Neighborhood Structure
The current leader makes its initial broadcasts to at most `DATA_PLANE_FANOUT`
nodes. If this layer 1 is smaller than the number of nodes in the cluster, then
nodes. If this layer 0 is smaller than the number of nodes in the cluster, then
the data plane fanout mechanism adds layers below. Subsequent layers follow
these constraints to determine layer-capacity: Each neighborhood contains
`NEIGHBORHOOD_SIZE` nodes and each layer may have up to `DATA_PLANE_FANOUT/2`
neighborhoods.
`DATA_PLANE_FANOUT` nodes. Layer-0 starts with 1 neighborhood with fanout nodes.
The number of nodes in each additional layer grows by a factor of fanout.
As mentioned above, each node in a layer only has to broadcast its blobs to its
neighbors and to exactly 1 node in each next-layer neighborhood, instead of to
every TVU peer in the cluster. In the default mode, each layer contains
`DATA_PLANE_FANOUT/2` neighborhoods. The retransmit mechanism also supports a
second, `grow`, mode of operation that squares the number of neighborhoods
allowed each layer. This dramatically reduces the number of layers needed to
support a large cluster, but can also have a negative impact on the network
pressure on each node in the lower layers. A good way to think of the default
mode (when `grow` is disabled) is to imagine it as chain of layers, where the
leader sends blobs to layer-1 and then layer-1 to layer-2 and so on, the `layer
capacities` remain constant, so all layers past layer-2 will have the same
number of nodes until the whole cluster is covered. When `grow` is enabled, this
becomes a traditional fanout where layer-3 will have the square of the number of
nodes in layer-2 and so on.
neighbors and to exactly 1 node in some next-layer neighborhoods,
instead of to every TVU peer in the cluster. A good way to think about this is,
layer-0 starts with 1 neighborhood with fanout nodes, layer-1 adds "fanout"
neighborhoods, each with fanout nodes and layer-2 will have
`fanout * number of nodes in layer-1` and so on.
This way each node only has to communicate with a maximum of `2 * DATA_PLANE_FANOUT - 1` nodes.
The following diagram shows how the Leader sends blobs with a Fanout of 2 to
Neighborhood 0 in Layer 0 and how the nodes in Neighborhood 0 share their data
with each other.
<img alt="Leader sends blobs to Neighborhood 0 in Layer 0" src="img/data-plane-seeding.svg" class="center"/>
The following diagram shows how Neighborhood 0 fans out to Neighborhoods 1 and 2.
<img alt="Neighborhood 0 Fanout to Neighborhood 1 and 2" src="img/data-plane-fanout.svg" class="center"/>
Finally, the following diagram shows a two layer cluster with a Fanout of 2.
<img alt="Two layer cluster with a Fanout of 2" src="img/data-plane.svg" class="center"/>
#### Configuration Values
`DATA_PLANE_FANOUT` - Determines the size of layer 1. Subsequent
layers have `DATA_PLANE_FANOUT/2` neighborhoods when `grow` is inactive.
`NEIGHBORHOOD_SIZE` - The number of nodes allowed in a neighborhood.
`DATA_PLANE_FANOUT` - Determines the size of layer 0. Subsequent
layers grow by a factor of `DATA_PLANE_FANOUT`.
The number of nodes in a neighborhood is equal to the fanout value.
Neighborhoods will fill to capacity before new ones are added, i.e if a
neighborhood isn't full, it _must_ be the last one.
`GROW_LAYER_CAPACITY` - Whether or not retransmit should be behave like a
_traditional fanout_, i.e if each additional layer should have growing
capacities. When this mode is disabled (default), all layers after layer 1 have
the same capacity, keeping the network pressure on all nodes equal.
Currently, configuration is set when the cluster is launched. In the future,
these parameters may be hosted on-chain, allowing modification on the fly as the
cluster sizes change.
@ -72,13 +73,10 @@ cluster sizes change.
## Neighborhoods
The following diagram shows how two neighborhoods in different layers interact.
What this diagram doesn't capture is that each neighbor actually receives
blobs from one validator per neighborhood above it. This means that, to
cripple a neighborhood, enough nodes (erasure codes +1 per neighborhood) from
the layer above need to fail. Since multiple neighborhoods exist in the upper
layer and a node will receive blobs from a node in each of those neighborhoods,
we'd need a big network failure in the upper layers to end up with incomplete
data.
To cripple a neighborhood, enough nodes (erasure codes +1) from the neighborhood
above need to fail. Since each neighborhood receives blobs from multiple nodes
in a neighborhood in the upper layer, we'd need a big network failure in the upper
layers to end up with incomplete data.
<img alt="Inner workings of a neighborhood"
src="img/data-plane-neighborhood.svg" class="center"/>

View File

@ -10,7 +10,7 @@ client's account.
A drone is a simple signing service. It listens for requests to sign
*transaction data*. Once received, the drone validates the request however it
sees fit. It may, for example, only accept transaction data with a
`SystemInstruction::Move` instruction transferring only up to a certain amount
`SystemInstruction::Transfer` instruction transferring only up to a certain amount
of tokens. If the drone accepts the transaction, it returns an `Ok(Signature)`
where `Signature` is a signature of the transaction data using the drone's
private key. If it rejects the transaction data, it returns a `DroneError`
@ -76,7 +76,7 @@ beyond a certain *age*.
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 `Move` operation requires two public keys (each 32 bytes) and a
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.

12
book/src/ed_mvp.md Normal file
View File

@ -0,0 +1,12 @@
## Proposed MVP of Economic Design
The preceeding sections, outlined in the [Economic Design Overview](ed_overview.md), describe a long-term vision of a sustainable Solana economy. Of course, we don't expect the final implementation to perfectly match what has been described above. We intend to fully engage with network stakeholders throughout the implementation phases (i.e. pre-testnet, testnet, mainnet) to ensure the system supports, and is representative of, the various network participants' interests. The first step toward this goal, however, is outlining a some desired MVP economic features to be available for early pre-testnet and testnet participants. Below is a rough sketch outlining basic economic functionality from which a more complete and functional system can be developed.
### MVP Economic Features
* Faucet to deliver testnet SOLs to validators for staking and dapp development.
* Mechanism by which validators are rewarded in proportion to their stake. Interest rate mechansism (i.e. to be determined by total % staked) to come later.
* Ability to delegate tokens to validator nodes.
* Replicators to receive fixed, arbitrary reward for submitting validated PoReps. Reward size mechanism (i.e. PoRep reward as a function of total ledger redundancy) to come later.
* Pooling of replicator PoRep transaction fees and weighted distribution to validators based on PoRep verification (see [Replication-validation Transaction Fees](ed_vce_replication_validation_transaction_fees.md). It will be useful to test this protection against attacks on testnet.
* Nice-to-have: auto-delegation of replicator rewards to validator.

View File

@ -8,7 +8,7 @@ These protocol-based rewards, to be distributed to participating validation and
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 (be it a state execution or proof-of-replication verification). A mechanism for continuous and long-term funding of the mining pool through a pre-dedicated portion of transaction fees is also discussed below.
A high-level schematic of Solanas crypto-economic design is shown below in **Figure 1**. The specifics of validation-client economics are described in sections: [Validation-client Economics](ed_validation_client_economics.md), [State-validation Protocol-based Rewards](ed_vce_state_validation_protocol_based_rewards.md), [State-validation Transaction Fees](ed_vce_state_validation_transaction_fees.md) and [Replication-validation Transaction Fees](ed_vce_replication_validation_transaction_fees.md). Also, the chapter titled [Validation Stake Delegation](ed_vce_validation_stake_delegation.md) closes with a discussion of validator delegation opportunties and marketplace. The [Replication-client Economics](ed_replication_client_economics.md) chapter will review the Solana network design for global ledger storage/redundancy and replicator-client economics ([Storage-replication rewards](ed_rce_storage_replication_rewards.md)) along with a replicator-to-validator delegation mechanism designed to aide participant on-boarding into the Solana economy discussed in [Replication-client Reward Auto-delegation](ed_rce_replication_client_reward_auto_delegation.md). The [Economic Sustainability](ed_economic_sustainability.md) section dives deeper into Solanas design for long-term economic sustainability and outlines the constraints and conditions for a self-sustaining economy. Finally, in chapter [Attack Vectors](ed_attack_vectors.md), various attack vectors will be described and potential vulnerabilities explored and parameterized.
A high-level schematic of Solanas crypto-economic design is shown below in **Figure 1**. The specifics of validation-client economics are described in sections: [Validation-client Economics](ed_validation_client_economics.md), [State-validation Protocol-based Rewards](ed_vce_state_validation_protocol_based_rewards.md), [State-validation Transaction Fees](ed_vce_state_validation_transaction_fees.md) and [Replication-validation Transaction Fees](ed_vce_replication_validation_transaction_fees.md). Also, the chapter titled [Validation Stake Delegation](ed_vce_validation_stake_delegation.md) closes with a discussion of validator delegation opportunties and marketplace. The [Replication-client Economics](ed_replication_client_economics.md) chapter will review the Solana network design for global ledger storage/redundancy and replicator-client economics ([Storage-replication rewards](ed_rce_storage_replication_rewards.md)) along with a replicator-to-validator delegation mechanism designed to aide participant on-boarding into the Solana economy discussed in [Replication-client Reward Auto-delegation](ed_rce_replication_client_reward_auto_delegation.md). The [Economic Sustainability](ed_economic_sustainability.md) section dives deeper into Solanas design for long-term economic sustainability and outlines the constraints and conditions for a self-sustaining economy. An outline of features for an MVP economic design is discussed in the [Economic Design MVP](ed_mvp.md) section. Finally, in chapter [Attack Vectors](ed_attack_vectors.md), various attack vectors will be described and potential vulnerabilities explored and parameterized.
<!-- ![img alt text](solana_economic_design.png) -->
<p style="text-align:center;"><img src="img/solana_economic_design.png" alt="== Solana Economic Design Diagram ==" width="800"/></p>

View File

@ -47,8 +47,8 @@ nodes are started
$ cargo build --all
```
The network is initialized with a genesis ledger and fullnode configuration files.
These files can be generated by running the following script.
The network is initialized with a genesis ledger generated by running the
following script.
```bash
$ ./multinode-demo/setup.sh
@ -69,7 +69,7 @@ $ ./multinode-demo/drone.sh
### Singlenode Testnet
Before you start a fullnode, make sure you know the IP address of the machine you
Before you start a validator, make sure you know the IP address of the machine you
want to be the bootstrap leader for the demo, and make sure that udp ports 8000-10000 are
open on all the machines you want to test with.
@ -86,10 +86,10 @@ The drone does not need to be running for subsequent leader starts.
### Multinode Testnet
To run a multinode testnet, after starting a leader node, spin up some
additional full nodes in separate shells:
additional validators in separate shells:
```bash
$ ./multinode-demo/fullnode-x.sh
$ ./multinode-demo/validator-x.sh
```
To run a performance-enhanced full node on Linux,
@ -99,7 +99,7 @@ your system:
```bash
$ ./fetch-perf-libs.sh
$ SOLANA_CUDA=1 ./multinode-demo/bootstrap-leader.sh
$ SOLANA_CUDA=1 ./multinode-demo/fullnode-x.sh
$ SOLANA_CUDA=1 ./multinode-demo/validator.sh
```
### Testnet Client Demo
@ -145,7 +145,7 @@ Generally we are using `debug` for infrequent debug messages, `trace` for potent
messages and `info` for performance-related logging.
You can also attach to a running process with GDB. The leader's process is named
_solana-fullnode_:
_solana-validator_:
```bash
$ sudo gdb
@ -161,7 +161,7 @@ This will dump all the threads stack traces into gdb.txt
In this example the client connects to our public testnet. To run validators on the testnet you would need to open udp ports `8000-10000`.
```bash
$ ./multinode-demo/client.sh --network $(dig +short testnet.solana.com):8001 --duration 60
$ ./multinode-demo/client.sh --entrypoint testnet.solana.com:8001 --duration 60
```
You can observe the effects of your client's transactions on our [dashboard](https://metrics.solana.com:3000/d/testnet/testnet-hud?orgId=2&from=now-30m&to=now&refresh=5s&var-testnet=testnet)

View File

@ -1,6 +1,6 @@
# Gossip Service
The Gossip Service acts as a gateway to nodes in the control plane. Fullnodes
The Gossip Service acts as a gateway to nodes in the control plane. Validators
use the service to ensure information is available to all other nodes in a cluster.
The service broadcasts information using a gossip protocol.
@ -116,8 +116,8 @@ Just like *pull message*, nodes are selected into the active set based on weight
## Notable differences from PlumTree
The active push protocol described here is based on (Plum
Tree)[https://haslab.uminho.pt/jop/files/lpr07a.pdf]. The main differences are:
The active push protocol described here is based on [Plum
Tree](https://haslab.uminho.pt/jop/files/lpr07a.pdf). The main differences are:
* Push messages have a wallclock that is signed by the originator. Once the
wallclock expires the message is dropped. A hop limit is difficult to implement

View File

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

213
book/src/installer.md Normal file
View File

@ -0,0 +1,213 @@
## Cluster Software Installation and Updates
Currently users are required to build the solana cluster software themselves
from the git repository and manually update it, which is error prone and
inconvenient.
This document proposes an easy to use software install and updater that can be
used to deploy pre-built binaries for supported platforms. Users may elect to
use binaries supplied by Solana or any other party they trust. Deployment of
updates is managed using an on-chain update manifest program.
### Motivating Examples
#### Fetch and run a pre-built installer using a bootstrap curl/shell script
The easiest install method for supported platforms:
```bash
$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.13.0/install/solana-install-init.sh | sh
```
This script will check github for the latest tagged release and download and run the
`solana-install` binary from there.
If additional arguments need to be specified during the installation, the
following shell syntax is used:
```bash
$ init_args=.... # arguments for `solana-installer init ...`
$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.13.0/install/solana-install-init.sh | sh -s - ${init_args}
```
#### Fetch and run a pre-built installer from a Github release
With a well-known release URL, a pre-built binary can be obtained for supported
platforms:
```bash
$ curl -o solana-install https://github.com/solana-labs/solana/releases/download/v0.13.0/solana-install-x86_64-apple-darwin
$ chmod +x ./solana-install
$ ./solana-install --help
```
#### Build and run the installer from source
If a pre-built binary is not available for a given platform, building the
installer from source is always an option:
```bash
$ git clone https://github.com/solana-labs/solana.git
$ cd solana/install
$ cargo run -- --help
```
#### Deploy a new update to a cluster
Given a solana release tarball (as created by `ci/publish-tarball.sh`) that has already been uploaded to a publicly accessible URL,
the following commands will deploy the update:
```bash
$ solana-keygen -o update-manifest.json # <-- only generated once, the public key is shared with users
$ solana-install deploy http://example.com/path/to/solana-release.tar.bz2 update-manifest.json
```
#### Run a validator node that auto updates itself
```bash
$ solana-install init --pubkey 92DMonmBYXwEMHJ99c9ceRSpAmk9v6i3RdvDdXaVcrfj # <-- pubkey is obtained from whoever is deploying the updates
$ export PATH=~/.local/share/solana-install/bin:$PATH
$ solana-keygen ... # <-- runs the latest solana-keygen
$ solana-install run solana-validator ... # <-- runs a validator, restarting it as necesary when an update is applied
```
### On-chain Update Manifest
An update manifest is used to advertise the deployment of new release tarballs
on a solana cluster. The update manifest is stored using the `config` program,
and each update manifest account describes a logical update channel for a given
target triple (eg, `x86_64-apple-darwin`). The account public key is well-known
between the entity deploying new updates and users consuming those updates.
The update tarball itself is hosted elsewhere, off-chain and can be fetched from
the specified `download_url`.
```rust,ignore
use solana_sdk::signature::Signature;
/// Information required to download and apply a given update
pub struct UpdateManifest {
pub timestamp_secs: u64, // When the release was deployed in seconds since UNIX EPOCH
pub download_url: String, // Download URL to the release tar.bz2
pub download_sha256: String, // SHA256 digest of the release tar.bz2 file
}
/// Userdata of an Update Manifest program Account.
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
pub struct SignedUpdateManifest {
pub manifest: UpdateManifest,
pub manifest_signature: Signature,
}
```
Note that the `manifest` field itself contains a corresponding signature
(`manifest_signature`) to guard against man-in-the-middle attacks between the
`solana-install` tool and the solana cluster RPC API.
To guard against rollback attacks, `solana-install` will refuse to install an
update with an older `timestamp_secs` than what is currently installed.
### Release Archive Contents
A release archive is expected to be a tar file compressed with
bzip2 with the following internal structure:
* `/version.yml` - a simple YAML file containing the field `"target"` - the
target tuple. Any additional fields are ignored.
* `/bin/` -- directory containing available programs in the release.
`solana-install` will symlink this directory to
`~/.local/share/solana-install/bin` for use by the `PATH` environment
variable.
* `...` -- any additional files and directories are permitted
### solana-install Tool
The `solana-install` tool is used by the user to install and update their cluster software.
It manages the following files and directories in the user's home directory:
* `~/.config/solana/install/config.yml` - user configuration and information about currently installed software version
* `~/.local/share/solana/install/bin` - a symlink to the current release. eg, `~/.local/share/solana-update/<update-pubkey>-<manifest_signature>/bin`
* `~/.local/share/solana/install/releases/<download_sha256>/` - contents of a release
#### Command-line Interface
```manpage
solana-install 0.13.0
The solana cluster software installer
USAGE:
solana-install [OPTIONS] <SUBCOMMAND>
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --config <PATH> Configuration file to use [default: /Users/mvines/Library/Preferences/solana/install.yml]
SUBCOMMANDS:
deploy deploys a new update
help Prints this message or the help of the given subcommand(s)
info displays information about the current installation
init initializes a new installation
run Runs a program while periodically checking and applying software updates
update checks for an update, and if available downloads and applies it
```
```manpage
solana-install-init
initializes a new installation
USAGE:
solana-install init [OPTIONS]
FLAGS:
-h, --help Prints help information
OPTIONS:
-d, --data_dir <PATH> Directory to store install data [default: /Users/mvines/Library/Application Support/solana]
-u, --url <URL> JSON RPC URL for the solana cluster [default: https://api.testnet.solana.com/]
-p, --pubkey <PUBKEY> Public key of the update manifest [default: 9XX329sPuskWhH4DQh6k16c87dHKhXLBZTL3Gxmve8Gp]
```
```manpage
solana-install-info
displays information about the current installation
USAGE:
solana-install info [FLAGS]
FLAGS:
-h, --help Prints help information
-l, --local only display local information, don't check the cluster for new updates
```
```manpage
solana-install-deploy
deploys a new update
USAGE:
solana-install deploy <download_url> <update_manifest_keypair>
FLAGS:
-h, --help Prints help information
ARGS:
<download_url> URL to the solana release archive
<update_manifest_keypair> Keypair file for the update manifest (/path/to/keypair.json)
```
```manpage
solana-install-update
checks for an update, and if available downloads and applies it
USAGE:
solana-install update
FLAGS:
-h, --help Prints help information
```
```manpage
solana-install-run
Runs a program while periodically checking and applying software updates
USAGE:
solana-install run <program_name> [program_arguments]...
FLAGS:
-h, --help Prints help information
ARGS:
<program_name> program to run
<program_arguments>... arguments to supply to the program
The program will be restarted upon a successful software update
```

View File

@ -24,9 +24,13 @@ Methods
* [confirmTransaction](#confirmtransaction)
* [getAccountInfo](#getaccountinfo)
* [getBalance](#getbalance)
* [getClusterNodes](#getclusternodes)
* [getRecentBlockhash](#getrecentblockhash)
* [getSignatureStatus](#getsignaturestatus)
* [getSlotLeader](#getslotleader)
* [getNumBlocksSinceSignatureConfirmation](#getnumblockssincesignatureconfirmation)
* [getTransactionCount](#gettransactioncount)
* [getEpochVoteAccounts](#getepochvoteaccounts)
* [requestAirdrop](#requestairdrop)
* [sendTransaction](#sendtransaction)
* [startSubscriptionChannel](#startsubscriptionchannel)
@ -113,6 +117,30 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
---
### getClusterNodes
Returns information about all the nodes participating in the cluster
##### Parameters:
None
##### Results:
The result field will be an array of JSON objects, each with the following sub fields:
* `id` - Node identifier, as base-58 encoded string
* `gossip` - Gossip network address for the node
* `tpu` - TPU network address for the node
* `rpc` - JSON RPC network address for the node, or `null` if the JSON RPC service is not enabled
##### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":[{"gossip":"10.239.6.48:8001","id":"9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ","rpc":"10.239.6.48:8899","tpu":"10.239.6.48:8856"}],"id":1}
```
---
### getAccountInfo
Returns all information associated with the account of provided Pubkey
@ -124,7 +152,7 @@ The result field will be a JSON object with the following sub fields:
* `lamports`, number of lamports assigned to this account, as a signed 64-bit integer
* `owner`, array of 32 bytes representing the program this account has been assigned to
* `userdata`, array of bytes representing any userdata associated with the account
* `data`, array of bytes representing any data associated with the account
* `executable`, boolean indicating if the account contains a program (and is strictly read-only)
* `loader`, array of 32 bytes representing the loader for this program (if `executable`), otherwise all
@ -134,19 +162,22 @@ The result field will be a JSON object with the following sub fields:
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["2gVkYWexTHR5Hb2aLeQN3tnngvWzisFKXDUPrgMHpdST"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":{"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"userdata":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
{"jsonrpc":"2.0","result":{"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"id":1}
```
---
### getRecentBlockhash
Returns a recent block hash from the ledger
Returns a recent block hash from the ledger, and a fee schedule that can be used
to compute the cost of submitting a transaction using it.
##### Parameters:
None
##### Results:
An array consisting of
* `string` - a Hash as base-58 encoded string
* `FeeCalculator object` - the fee schedule for this block hash
##### Example:
```bash
@ -154,7 +185,7 @@ None
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC","id":1}
{"jsonrpc":"2.0","result":["GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",{"lamportsPerSignature": 0}],"id":1}
```
---
@ -168,12 +199,10 @@ events.
* `string` - Signature of Transaction to confirm, as base-58 encoded string
##### Results:
* `string` - Transaction status:
* `Confirmed` - Transaction was successful
* `SignatureNotFound` - Unknown transaction
* `ProgramRuntimeError` - An error occurred in the program that processed this Transaction
* `AccountInUse` - Another Transaction had a write lock one of the Accounts specified in this Transaction. The Transaction may succeed if retried
* `GenericFailure` - Some other error occurred. **Note**: In the future new Transaction statuses may be added to this list. It's safe to assume that all new statuses will be more specific error conditions that previously presented as `GenericFailure`
* `null` - Unknown transaction
* `object` - Transaction status:
* `"Ok": null` - Transaction was successful
* `"Err": <ERR>` - Transaction failed with TransactionError <ERR> [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14)
##### Example:
```bash
@ -184,7 +213,48 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "
{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}
```
-----
### getSlotLeader
Returns the current slot leader
##### Parameters:
None
##### Results:
* `string` - Node Id as base-58 encoded string
##### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getSlotLeader"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":"ENvAW7JScgYq6o4zKZwewtkzzJgDzuJAFxYasvmEQdpS","id":1}
```
-----
### getNumBlocksSinceSignatureConfirmation
Returns the current number of blocks since signature has been confirmed.
##### Parameters:
* `string` - Signature of Transaction to confirm, as base-58 encoded string
##### Results:
* `integer` - count, as unsigned 64-bit integer
##### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getNumBlocksSinceSignatureConfirmation", "params":["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":8,"id":1}
```
---
### getTransactionCount
Returns the current Transaction count from the ledger
@ -205,6 +275,39 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
---
### getEpochVoteAccounts
Returns the account info and associated stake for all the voting accounts in the current epoch.
##### Parameters:
None
##### Results:
An array consisting of vote accounts:
* `string` - the vote account's Pubkey as base-58 encoded string
* `integer` - the stake, in lamports, delegated to this vote account
* `VoteState` - the vote account's state
Each VoteState will be a JSON object with the following sub fields:
* `votes`, array of most recent vote lockouts
* `node_pubkey`, the pubkey of the node that votes using this account
* `authorized_voter_pubkey`, the pubkey of the authorized vote signer for this account
* `commission`, a 32-bit integer used as a fraction (commission/MAX_U32) for rewards payout
* `root_slot`, the most recent slot this account has achieved maximum lockout
* `credits`, credits accrued by this account for reaching lockouts
##### Example:
```bash
// Request
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochVoteAccounts"}' http://localhost:8899
// Result
{"jsonrpc":"2.0","result":[[[84,115,89,23,41,83,221,72,58,23,53,245,195,188,140,161,242,189,200,164,139,214,12,180,84,161,28,151,24,243,159,125],10000000,{"authorized_voter_pubkey":[84,115,89,23,41,83,221,72,58,23,53,245,195,188,140,161,242,189,200,164,139,214,12,180,84,161,28,151,24,243,159,125],"commission":0,"credits":0,"node_pubkey":[49,139,227,211,47,39,69,86,131,244,160,144,228,169,84,143,142,253,83,81,212,110,254,12,242,71,219,135,30,60,157,213],"root_slot":null,"votes":[{"confirmation_count":1,"slot":0}]}]],"id":1}
```
---
### requestAirdrop
Requests an airdrop of lamports to a Pubkey
@ -250,15 +353,25 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
After connect to the RPC PubSub websocket at `ws://<ADDRESS>/`:
- Submit subscription requests to the websocket using the methods below
- Multiple subscriptions may be active at once
- All subscriptions take an optional `confirmations` parameter, which defines
how many confirmed blocks the node should wait before sending a notification.
The greater the number, the more likely the notification is to represent
consensus across the cluster, and the less likely it is to be affected by
forking or rollbacks. If unspecified, the default value is 0; the node will
send a notification as soon as it witnesses the event. The maximum
`confirmations` wait length is the cluster's `MAX_LOCKOUT_HISTORY`, which
represents the economic finality of the chain.
---
### accountSubscribe
Subscribe to an account to receive notifications when the lamports or userdata
Subscribe to an account to receive notifications when the lamports or data
for a given account public key changes
##### Parameters:
* `string` - account Pubkey, as base-58 encoded string
* `integer` - optional, number of confirmed blocks to wait before notification.
Default: 0, Max: `MAX_LOCKOUT_HISTORY` (greater integers rounded down)
##### Results:
* `integer` - Subscription id (needed to unsubscribe)
@ -268,13 +381,15 @@ for a given account public key changes
// Request
{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12"]}
{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", 15]}
// Result
{"jsonrpc": "2.0","result": 0,"id": 1}
```
##### Notification Format:
```bash
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"userdata":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
{"jsonrpc": "2.0","method": "accountNotification", "params": {"result": {"executable":false,"loader":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"owner":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"lamports":1,"data":[3,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,53,48,45,48,49,45,48,49,84,48,48,58,48,48,58,48,48,90,252,10,7,28,246,140,88,177,98,82,10,227,89,81,18,30,194,101,199,16,11,73,133,20,246,62,114,39,20,113,189,32,50,0,0,0,0,0,0,0,247,15,36,102,167,83,225,42,133,127,82,34,36,224,207,130,109,230,224,188,163,33,213,13,5,117,211,251,65,159,197,51,0,0,0,0,0,0]},"subscription":0}}
```
---
@ -300,11 +415,13 @@ Unsubscribe from account change notifications
---
### programSubscribe
Subscribe to a program to receive notifications when the lamports or userdata
Subscribe to a program to receive notifications when the lamports or data
for a given account owned by the program changes
##### Parameters:
* `string` - program_id Pubkey, as base-58 encoded string
* `integer` - optional, number of confirmed blocks to wait before notification.
Default: 0, Max: `MAX_LOCKOUT_HISTORY` (greater integers rounded down)
##### Results:
* `integer` - Subscription id (needed to unsubscribe)
@ -314,6 +431,8 @@ for a given account owned by the program changes
// Request
{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["9gZbPtbtHrs6hEWgd6MbVY9VPFtS5Z8xKtnYwA2NynHV"]}
{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["9gZbPtbtHrs6hEWgd6MbVY9VPFtS5Z8xKtnYwA2NynHV", 15]}
// Result
{"jsonrpc": "2.0","result": 0,"id": 1}
```
@ -322,7 +441,7 @@ for a given account owned by the program changes
* `string` - account Pubkey, as base-58 encoded string
* `object` - account info JSON object (see [getAccountInfo](#getaccountinfo) for field details)
```bash
{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"userdata":[1,1,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",{"executable":false,"lamports":1,"owner":[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"data":[1,1,1,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,50,48,49,56,45,49,50,45,50,52,84,50,51,58,53,57,58,48,48,90,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,55,89,0,0,0,0,50,0,0,0,0,0,0,0,235,233,39,152,15,44,117,176,41,89,100,86,45,61,2,44,251,46,212,37,35,118,163,189,247,84,27,235,178,62,45,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}],"subscription":0}}
```
---
@ -353,6 +472,8 @@ On `signatureNotification`, the subscription is automatically cancelled
##### Parameters:
* `string` - Transaction Signature, as base-58 encoded string
* `integer` - optional, number of confirmed blocks to wait before notification.
Default: 0, Max: `MAX_LOCKOUT_HISTORY` (greater integers rounded down)
##### Results:
* `integer` - subscription id (needed to unsubscribe)
@ -362,6 +483,8 @@ On `signatureNotification`, the subscription is automatically cancelled
// Request
{"jsonrpc":"2.0", "id":1, "method":"signatureSubscribe", "params":["2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b"]}
{"jsonrpc":"2.0", "id":1, "method":"signatureSubscribe", "params":["2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b", 15]}
// Result
{"jsonrpc": "2.0","result": 0,"id": 1}
```

View File

@ -57,7 +57,7 @@ Forwarding is preferred, as it would minimize network congestion, allowing the
cluster to advertise higher TPS capacity.
## Fullnode Loop
## Validator Loop
The PoH Recorder manages the transition between modes. Once a ledger is
replayed, the validator can run until the recorder indicates it should be

View File

@ -2,6 +2,12 @@
Replication behavior yet to be implemented.
### Storage epoch
The storage epoch should be the number of slots which results in around 100GB-1TB of
ledger to be generated for replicators to store. Replicators will start storing ledger
when a given fork has a high probability of not being rolled back.
### Validator behavior
3. Every NUM\_KEY\_ROTATION\_TICKS it also validates samples received from
@ -37,3 +43,100 @@ transacation proves the validator incorrectly validated a fake storage proof.
The replicator is rewarded and the validator's staking balance is slashed or
frozen.
### Storage proof contract logic
Each replicator and validator will have their own storage account. The validator's
account would be separate from their gossip id similiar to their vote account.
These should be implemented as two programs one which handles the validator as the keysigner
and one for the replicator. In that way when the programs reference other accounts, they
can check the program id to ensure it is a validator or replicator account they are
referencing.
#### SubmitMiningProof
```rust,ignore
SubmitMiningProof {
slot: u64,
sha_state: Hash,
signature: Signature,
};
keys = [replicator_keypair]
```
Replicators create these after mining their stored ledger data for a certain hash value.
The slot is the end slot of the segment of ledger they are storing, the sha\_state
the result of the replicator using the hash function to sample their encrypted ledger segment.
The signature is the signature that was created when they signed a PoH value for the
current storage epoch. The list of proofs from the current storage epoch should be saved
in the account state, and then transfered to a list of proofs for the previous epoch when
the epoch passes. In a given storage epoch a given replicator should only submit proofs
for one segment.
The program should have a list of slots which are valid storage mining slots.
This list should be maintained by keeping track of slots which are rooted slots in which a significant
portion of the network has voted on with a high lockout value, maybe 32-votes old. Every SLOTS\_PER\_SEGMENT
number of slots would be added to this set. The program should check that the slot is in this set. The set can
be maintained by receiving a AdvertiseStorageRecentBlockHash and checking with its bank/locktower state.
The program should do a signature verify check on the signature, public key from the transaction submitter and the message of
the previous storage epoch PoH value.
#### ProofValidation
```rust,ignore
ProofValidation {
proof_mask: Vec<ProofStatus>,
}
keys = [validator_keypair, replicator_keypair(s) (unsigned)]
```
A validator will submit this transaction to indicate that a set of proofs for a given
segment are valid/not-valid or skipped where the validator did not look at it. The
keypairs for the replicators that it looked at should be referenced in the keys so the program
logic can go to those accounts and see that the proofs are generated in the previous epoch. The
sampling of the storage proofs should be verified ensuring that the correct proofs are skipped by
the validator according to the logic outlined in the validator behavior of sampling.
The included replicator keys will indicate the the storage samples which are being referenced; the
length of the proof\_mask should be verified against the set of storage proofs in the referenced
replicator account(s), and should match with the number of proofs submitted in the previous storage
epoch in the state of said replicator account.
#### ClaimStorageReward
```rust,ignore
ClaimStorageReward {
}
keys = [validator_keypair or replicator_keypair, validator/replicator_keypairs (unsigned)]
```
Replicators and validators will use this transaction to get paid tokens from a program state
where SubmitStorageProof, ProofValidation and ChallengeProofValidations are in a state where
proofs have been submitted and validated and there are no ChallengeProofValidations referencing
those proofs. For a validator, it should reference the replicator keypairs to which it has validated
proofs in the relevant epoch. And for a replicator it should reference validator keypairs for which it
has validated and wants to be rewarded.
#### ChallengeProofValidation
```rust,ignore
ChallengeProofValidation {
proof_index: u64,
hash_seed_value: Vec<u8>,
}
keys = [replicator_keypair, validator_keypair]
```
This transaction is for catching lazy validators who are not doing the work to validate proofs.
A replicator will submit this transaction when it sees a validator has approved a fake SubmitMiningProof
transaction. Since the replicator is a light client not looking at the full chain, it will have to ask
a validator or some set of validators for this information maybe via RPC call to obtain all ProofValidations for
a certain segment in the previous storage epoch. The program will look in the validator account
state see that a ProofValidation is submitted in the previous storage epoch and hash the hash\_seed\_value and
see that the hash matches the SubmitMiningProof transaction and that the validator marked it as valid. If so,
then it will save the challenge to the list of challenges that it has in its state.
#### AdvertiseStorageRecentBlockhash
```rust,ignore
AdvertiseStorageRecentBlockhash {
hash: Hash,
slot: u64,
}
```
Validators and replicators will submit this to indicate that a new storage epoch has passed and that the
storage proofs which are current proofs should now be for the previous epoch. Other transactions should
check to see that the epoch that they are referencing is accurate according to current chain state.

View File

@ -31,7 +31,7 @@ core. The total space required for verification is `1_ledger_segment +
Validators for PoRep are the same validators that are verifying transactions.
They have some stake that they have put up as collateral that ensures that
their work is honest. If you can prove that a validator verified a fake PoRep,
then the validators stake can be slashed.
then the validator will not receive a reward for that storage epoch.
Replicators are specialized *light clients*. They download a part of the ledger
and store it, and provide PoReps of storing the ledger. For each verified PoRep
@ -53,7 +53,7 @@ changes to determine what rate it can validate storage proofs.
### Constants
1. NUM\_STORAGE\_ENTRIES: Number of entries in a segment of ledger data. The
1. SLOTS\_PER\_SEGMENT: Number of slots in a segment of ledger data. The
unit of storage for a replicator.
2. NUM\_KEY\_ROTATION\_TICKS: Number of ticks to save a PoH value and cause a
key generation for the section of ledger just generated and the rotation of
@ -77,7 +77,7 @@ height.
3. Validator generates a storage proof confirmation transaction.
4. The storage proof confirmation transaction is integrated into the ledger.
6. Validator responds to RPC interfaces for what the last storage epoch PoH
value is and its entry\_height.
value is and its slot.
### Replicator behavior
@ -95,10 +95,10 @@ is:
- (d) replicator can subscribe to an abbreviated transaction stream to
generate the information itself
2. A replicator obtains the PoH hash corresponding to the last key rotation
along with its entry\_height.
along with its slot.
3. The replicator signs the PoH hash with its keypair. That signature is the
seed used to pick the segment to replicate and also the encryption key. The
replicator mods the signature with the entry\_height to get which segment to
replicator mods the signature with the slot to get which segment to
replicate.
4. The replicator retrives the ledger by asking peer validators and
replicators. See 6.5.
@ -118,9 +118,9 @@ current leader and it is put onto the ledger.
### Finding who has a given block of ledger
1. Validators monitor the transaction stream for storage mining proofs, and
keep a mapping of ledger segments by entry\_height to public keys. When it sees
keep a mapping of ledger segments by slot to public keys. When it sees
a storage mining proof it updates this mapping and provides an RPC interface
which takes an entry\_height and hands back a list of public keys. The client
which takes a slot and hands back a list of public keys. The client
then looks up in their cluster\_info table to see which network address that
corresponds to and sends a repair request to retrieve the necessary blocks of
ledger.

View File

@ -0,0 +1,212 @@
# Stake Delegation and Reward
This design proposal focuses on the software architecture for the on-chain
voting and staking programs. Incentives for staking is covered in [staking
rewards](staking-rewards.md).
The current architecture requires a vote for each delegated stake from the
validator, and therefore does not scale to allow replicator clients to
automatically delegate their rewards.
The design proposes a new set of programs for voting and stake delegation, The
proposed programs allow many stake accounts to passively earn rewards with a
single validator vote without permission or active involvement from the
validator.
## Current Design Problems
In the current design each staker creates their own VoteState, and assigns a
**delegate** in the VoteState that can submit votes. Since the validator has to
actively vote for each stake delegated to it, validators can censor stakes by
not voting for them.
The number of votes is equal to the number of stakers, and not the number of
validators. Replicator clients are expected to delegate their replication
rewards as they are earned, and therefore the number of stakes is expected to be
large compared to the number of validators in a long running cluster.
## Proposed changes to the current design.
The general idea is that instead of the staker, the validator will own the
VoteState program. In this proposal the VoteState program is there to track
validator votes, count validator generated credits and to provide any
additional validator specific state. The VoteState program is not aware of any
stakes delegated to it, and has no staking weight.
The rewards generated are proportional to the amount of lamports staked. In
this proposal stake state is stored as part of the StakeState program. This
program is owned by the staker only. Lamports stored in this program are the
stake. Unlike the current design, this program contains a new field to indicate
which VoteState program the stake is delegated to.
### VoteState
VoteState is the current state of all the votes the **delegate** has submitted
to the bank. VoteState contains the following state information:
* votes - The submitted votes data structure.
* credits - The total number of rewards this vote program has generated over its
lifetime.
* root\_slot - The last slot to reach the full lockout commitment necessary for
rewards.
* commission - The commission taken by this VoteState for any rewards claimed by
staker's StakeState accounts. This is the percentage ceiling of the reward.
* Account::lamports - The accumulated lamports from the commission. These do not
count as stakes.
* `authorized_vote_signer` - Only this identity is authorized to submit votes, and
this field can only modified by this entity
### VoteInstruction::Initialize
* `account[0]` - RW - The VoteState
`VoteState::authorized_vote_signer` is initialized to `account[0]`
other VoteState members defaulted
### VoteInstruction::AuthorizeVoteSigner(Pubkey)
* `account[0]` - RW - The VoteState
`VoteState::authorized_vote_signer` is set to to `Pubkey`, instruction must by
signed by Pubkey
### StakeState
A StakeState takes one of two forms, StakeState::Delegate and StakeState::MiningPool.
### StakeState::Delegate
StakeState is the current delegation preference of the **staker**. StakeState
contains the following state information:
* Account::lamports - The staked 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.
### StakeState::MiningPool
There are two approaches to the mining pool. The bank could allow the
StakeState program to bypass the token balance check, or a program representing
the mining pool could run on the network. To avoid a single network wide lock,
the pool can be split into several mining pools. This design focuses on using a
StakeState::MiningPool as the cluster wide mining pools.
* 256 StakeState::MiningPool are initialized, each with 1/256 number of mining pool
tokens stored as `Account::lamports`.
The stakes and the MiningPool are accounts that are owned by the same `Stake`
program.
### StakeInstruction::Initialize
* `account[0]` - RW - The StakeState::Delegate instance.
`StakeState::Delegate::credits_observed` is initialized to `VoteState::credits`.
`StakeState::Delegate::voter_pubkey` is initialized to `account[1]`
* `account[1]` - R - The VoteState instance.
### StakeInstruction::RedeemVoteCredits
The VoteState program and the StakeState programs maintain a lifetime counter
of total rewards generated and claimed. Therefore an explicit `Clear`
instruction is not necessary. When claiming rewards, the total lamports
deposited into the StakeState and as validator commission is proportional to
`VoteState::credits - StakeState::credits_observed`.
* `account[0]` - RW - The StakeState::MiningPool instance that will fulfill the
reward.
* `account[1]` - RW - The StakeState::Delegate instance that is redeeming votes
credits.
* `account[2]` - R - The VoteState instance, must be the same as
`StakeState::voter_pubkey`
Reward is payed out for the difference between `VoteState::credits` to
`StakeState::Delgate.credits_observed`, and `credits_observed` is updated to
`VoteState::credits`. The commission is deposited into the `VoteState` token
balance, and the reward is deposited to the `StakeState::Delegate` token balance. The
reward and the commission is weighted by the `StakeState::lamports` divided by total lamports staked.
The Staker or the owner of the Stake program sends a transaction with this
instruction to claim the reward.
Any random MiningPool can be used to redeem the credits.
```rust,ignore
let credits_to_claim = vote_state.credits - stake_state.credits_observed;
stake_state.credits_observed = vote_state.credits;
```
`credits_to_claim` is used to compute the reward and commission, and
`StakeState::Delegate::credits_observed` is updated to the latest
`VoteState::credits` value.
### Collecting network fees into the MiningPool
At the end of the block, before the bank is frozen, but after it processed all
the transactions for the block, a virtual instruction is executed to collect
the transaction fees.
* A portion of the fees are deposited into the leader's account.
* A portion of the fees are deposited into the smallest StakeState::MiningPool
account.
### Benefits
* Single vote for all the stakers.
* Clearing of the credit variable is not necessary for claiming rewards.
* Each delegated stake can claim its rewards independently.
* Commission for the work is deposited when a reward is claimed by the delegated
stake.
This proposal would benefit from the `read-only` accounts proposal to allow for
many rewards to be claimed concurrently.
## Passive Delegation
Any number of instances of StakeState::Delegate programs can delegate to a single
VoteState program without an interactive action from the identity controlling
the VoteState program or submitting votes to the program.
The total stake allocated to a VoteState program can be calculated by the sum of
all the StakeState programs that have the VoteState pubkey as the
`StakeState::Delegate::voter_pubkey`.
## Example Callflow
<img alt="Passive Staking Callflow" src="img/passive-staking-callflow.svg" class="center"/>
## Future work
Validators may want to split the stake delegated to them amongst many validator
nodes since stake is used as weight in the network control and data planes. One
way to implement this would be for the StakeState to delegate to a pool of
validators instead of a single one.
Instead of a single `vote_pubkey` and `credits_observed` entry in the StakeState
program, the program can be initialized with a vector of tuples.
```rust,ignore
Voter {
voter_pubkey: Pubkey,
credits_observed: u64,
weight: u8,
}
```
* voters: Vec<Voter> - Array of VoteState accounts that are voting rewards with
this stake.
A StakeState program would claim a fraction of the reward from each voter in
the `voters` array, and each voter would be delegated a fraction of the stake.

View File

@ -0,0 +1,29 @@
# Performance Metrics
Solana cluster performance is measured as average number of transactions per second
that the network can sustain (TPS). And, how long it takes for a transaction to be
confirmed by super majority of the cluster (Confirmation Time).
Each cluster node maintains various counters that are incremented on certain events.
These counters are periodically uploaded to a cloud based database. Solana's metrics
dashboard fetches these counters, and computes the performance metrics and displays
it on the dashboard.
## TPS
The leader node's banking stage maintains a count of transactions that it recorded.
The dashboard displays the count averaged over 2 second period in the TPS time series
graph. The dashboard also shows per second mean, maximum and total TPS as a running
counter.
## Confirmation Time
Each validator node maintains a list of active ledger forks that are visible to the node.
A fork is considered to be frozen when the node has received and processed all entries
corresponding to the fork. A fork is considered to be confirmed when it receives cumulative
super majority vote, and when one of its children forks is frozen.
The node assigns a timestamp to every new fork, and computes the time it took to confirm
the fork. This time is reflected as validator confirmation time in performance metrics.
The performance dashboard displays the average of each validator node's confirmation time
as a time series graph.

View File

@ -3,8 +3,8 @@
A client *app* interacts with a Solana cluster by sending it *transactions*
with one or more *instructions*. The Solana *runtime* passes those instructions
to user-contributed *programs*. An instruction might, for example, tell a
program to move *lamports* from one *account* to another or create an interactive
contract that governs how lamports are moved. Instructions are executed
program to transfer *lamports* from one *account* to another or create an interactive
contract that governs how lamports are transfered. Instructions are executed
atomically. If any instruction is invalid, any changes made within the
transaction are discarded.

View File

@ -40,7 +40,7 @@ retransmitted twice around the network.
4. CrdsValue for vote should look like this ``` Votes(Vec<Transaction>) ```
Each vote transaction should maintain a `wallclock` in its userdata. The merge
Each vote transaction should maintain a `wallclock` in its data. The merge
strategy for Votes will keep the last N set of votes as configured by the local
client. For push/pull the vector is traversed recursively and each Transaction
is treated as an individual CrdsValue with its own local wallclock and

View File

@ -0,0 +1,51 @@
# Repair Service
The RepairService is in charge of retrieving missing blobs that failed to be delivered by primary communication protocols like Avalanche. It is in charge of managing the protocols described below in the `Repair Protocols` section below.
# Challenges:
1) Validators can fail to receive particular blobs due to network failures
2) Consider a scenario where blocktree contains the set of slots {1, 3, 5}. Then Blocktree receives blobs for some slot 7, where for each of the blobs b, b.parent == 6, so then the parent-child relation 6 -> 7 is stored in blocktree. However, there is no way to chain these slots to any of the existing banks in Blocktree, and thus the `Blob Repair` protocol will not repair these slots. If these slots happen to be part of the main chain, this will halt replay progress on this node.
3) Validators that find themselves behind the cluster by an entire epoch struggle/fail to catch up because they do not have a leader schedule for future epochs. If nodes were to blindly accept repair blobs in these future epochs, this exposes nodes to spam.
# Repair Protocols
The repair protocol makes best attempts to progress the forking structure of Blocktree.
The different protocol strategies to address the above challenges:
1. Blob Repair (Addresses Challenge #1):
This is the most basic repair protocol, with the purpose of detecting and filling "holes" in the ledger. Blocktree tracks the latest root slot. RepairService will then periodically iterate every fork in blocktree starting from the root slot, sending repair requests to validators for any missing blobs. It will send at most some `N` repair reqeusts per iteration.
Note: Validators will only accept blobs within the current verifiable epoch (epoch the validator has a leader schedule for).
2. Preemptive Slot Repair (Addresses Challenge #2):
The goal of this protocol is to discover the chaining relationship of "orphan" slots that do not currently chain to any known fork.
* Blocktree will track the set of "orphan" slots in a separate column family.
* RepairService will periodically make `RequestOrphan` requests for each of the orphans in blocktree.
`RequestOrphan(orphan)` request - `orphan` is the orphan slot that the requestor wants to know the parents of
`RequestOrphan(orphan)` response - The highest blobs for each of the first `N` parents of the requested `orphan`
On receiving the responses `p`, where `p` is some blob in a parent slot, validators will:
* Insert an empty `SlotMeta` in blocktree for `p.slot` if it doesn't already exist.
* If `p.slot` does exist, update the parent of `p` based on `parents`
Note: that once these empty slots are added to blocktree, the `Blob Repair` protocol should attempt to fill those slots.
Note: Validators will only accept responses containing blobs within the current verifiable epoch (epoch the validator has a leader schedule for).
3. Repairmen (Addresses Challenge #3):
This part of the repair protocol is the primary mechanism by which new nodes joining the cluster catch up after loading a snapshot. This protocol works in a "forward" fashion, so validators can verify every blob that they receive against a known leader schedule.
Each validator advertises in gossip:
* Current root
* The set of all completed slots in the confirmed epochs (an epoch that was calculated based on a bank <= current root) past the current root
Observers of this gossip message with higher epochs (repairmen) send blobs to catch the lagging node up with the rest of the cluster. The repairmen are responsible for sending the slots within the epochs that are confrimed by the advertised `root` in gossip. The repairmen divide the responsibility of sending each of the missing slots in these epochs based on a random seed (simple blob.index iteration by N, seeded with the repairman's node_pubkey). Ideally, each repairman in an N node cluster (N nodes whose epochs are higher than that of the repairee) sends 1/N of the missing blobs. Both data and coding blobs for missing slots are sent. Repairmen do not send blobs again to the same validator until they see the message in gossip updated, at which point they perform another iteration of this protocol.
Gossip messages are updated every time a validator receives a complete slot within the epoch. Completed slots are detected by blocktree and sent over a channel to RepairService. It is important to note that we know that by the time a slot X is complete, the epoch schedule must exist for the epoch that contains slot X because WindowService will reject blobs for unconfirmed epochs. When a newly completed slot is detected, we also update the current root if it has changed since the last update. The root is made available to RepairService through Blocktree, which holds the latest root.

View File

@ -6,7 +6,7 @@ separating program code from the state it operates on, the runtime is able to
choreograph concurrent access. Transactions accessing only credit-only
accounts are executed in parallel whereas transactions accessing writable
accounts are serialized. The runtime interacts with the program through an
entrypoint with a well-defined interface. The userdata stored in an account is
entrypoint with a well-defined interface. The data stored in an account is
an opaque type, an array of bytes. The program has full control over its
contents.
@ -42,7 +42,7 @@ programs can be executed in parallel.
The runtime enforces the following rules:
1. Only the *owner* program may modify the contents of an account. This means
that upon assignment userdata vector is guaranteed to be zero.
that upon assignment data vector is guaranteed to be zero.
2. Total balances on all the accounts is equal before and after execution of a
transaction.
@ -59,24 +59,24 @@ accounts.
## SystemProgram Interface
The interface is best described by the `Instruction::userdata` that the user
The interface is best described by the `Instruction::data` that the user
encodes.
* `CreateAccount` - This allows the user to create an account with an allocated
userdata array and assign it to a Program.
data array and assign it to a Program.
* `Assign` - Allows the user to assign an existing account to a program.
* `Move` - Moves lamports between accounts.
* `Transfer` - Transfers lamports between accounts.
## Program State Security
For blockchain to function correctly, the program code must be resilient to user
inputs. That is why in this design the program specific code is the only code
that can change the state of the userdata byte array in the Accounts that are
that can change the state of the data byte array in the Accounts that are
assigned to it. It is also the reason why `Assign` or `CreateAccount` must zero
out the userdata. Otherwise there would be no possible way for the program to
distinguish the recently assigned account userdata from a natively generated
out the data. Otherwise there would be no possible way for the program to
distinguish the recently assigned account data from a natively generated
state transition without some additional metadata from the runtime to indicate
that this memory is assigned instead of natively generated.
@ -94,12 +94,12 @@ instruction can be composed into a single transaction with the call to the
program itself.
* `CreateAccount` and `Assign` guarantee that when account is assigned to the
program, the Account's userdata is zero initialized.
program, the Account's data is zero initialized.
* Once assigned to program an Account cannot be reassigned.
* Runtime guarantees that a program's code is the only code that can modify
Account userdata that the Account is assigned to.
Account data that the Account is assigned to.
* Runtime guarantees that the program can only spend lamports that are in
accounts that are assigned to it.

View File

@ -1,68 +1,195 @@
# Stake Delegation and Rewards
Stakers are rewarded for helping validate the ledger. They do it by delegating
their stake to fullnodes. Those fullnodes do the legwork and send votes to the
stakers' staking accounts. The rest of the cluster uses those stake-weighted
votes to select a block when forks arise. Both the fullnode and staker need
some economic incentive to play their part. The fullnode needs to be
compensated for its hardware and the staker needs to be compensated for risking
getting its stake slashed. The economics are covered in [staking
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](staking-rewards.md). This chapter, on the other hand, describes the
underlying mechanics of its implementation.
## Vote and Rewards accounts
## Basic Besign
The rewards process is split into two on-chain programs. The Vote program
solves the problem of making stakes slashable. The Rewards account acts as
custodian of the rewards pool. It is responsible for paying out each staker
once the staker proves to the Rewards program that it participated in
validating the ledger.
The general idea is that the validator owns a Vote account. The Vote account
tracks validator votes, counts validator generated credits, and provides any
additional validator specific state. The Vote account is not aware of any
stakes delegated to it and has no staking weight.
The Vote account contains the following state information:
A separate Stake account (created by a staker) names a Vote account to which the
stake is delegated. Rewards generated are proportional to the amount of
lamports staked. The Stake account is owned by the staker only. Lamports
stored in this account are the stake.
* votes - The submitted votes.
## Passive Delegation
* `delegate_id` - An identity that may operate with the weight of this
account's stake. It is typically the identity of a fullnode, but may be any
identity involved in stake-weighted computations.
Any number of Stake accounts can delegate to a single
Vote account without an interactive action from the identity controlling
the Vote account or submitting votes to the account.
* `authorized_voter_id` - Only this identity is authorized to submit votes.
The total stake allocated to a Vote account can be calculated by the sum of
all the Stake accounts that have the Vote account pubkey as the
`StakeState::Delegate::voter_pubkey`.
* `credits` - The amount of unclaimed rewards.
## Vote and Stake accounts
* `root_slot` - The last slot to reach the full lockout commitment necessary
for rewards.
The rewards process is split into two on-chain programs. The Vote program solves
the problem of making stakes slashable. The Stake account acts as custodian of
the rewards pool, and provides passive delegation. The Stake program is
responsible for paying out each staker once the staker proves to the Stake
program that its delegate has participated in validating the ledger.
The Rewards program is stateless and pays out reward when a staker submits its
Vote account to the program. Claiming a reward requires a transaction that
includes the following instructions:
### VoteState
1. `RewardsInstruction::RedeemVoteCredits`
2. `VoteInstruction::ClearCredits`
VoteState is the current state of all the votes the validator has submitted to
the network. VoteState contains the following state information:
The Rewards program transfers lamports from the Rewards account to the Vote
account's public key. The Rewards program also ensures that the `ClearCredits`
instruction follows the `RedeemVoteCredits` instruction, such that a staker may
not claim rewards for the same work more than once.
* votes - The submitted votes data structure.
* credits - The total number of rewards this vote program has generated over its
lifetime.
* root\_slot - The last slot to reach the full lockout commitment necessary for
rewards.
* commission - The commission taken by this VoteState for any rewards claimed by
staker's Stake accounts. This is the percentage ceiling of the reward.
* Account::lamports - The accumulated lamports from the commission. These do not
count as stakes.
* `authorized_vote_signer` - Only this identity is authorized to submit votes. This field can only modified by this identity.
### VoteInstruction::Initialize
* `account[0]` - RW - The VoteState
`VoteState::authorized_vote_signer` is initialized to `account[0]`
other VoteState members defaulted
### VoteInstruction::AuthorizeVoteSigner(Pubkey)
* `account[0]` - RW - The VoteState
`VoteState::authorized_vote_signer` is set to to `Pubkey`, instruction must by
signed by Pubkey
### VoteInstruction::Vote(Vec<Vote>)
* `account[0]` - RW - The VoteState
`VoteState::lockouts` and `VoteState::credits` are updated according to voting lockout rules see [Fork Selection](fork-selection.md)
### Delegating Stake
* `account[1]` - RO - A list of some N most recent slots and their hashes for the vote to be verified against.
`VoteInstruction::DelegateStake` allows the staker to choose a fullnode to
validate the ledger on its behalf. By being a delegate, the fullnode is
entitled to collect transaction fees when its is leader. The larger the stake,
the more often the fullnode will be able to collect those fees.
### Authorizing a Vote Signer
### StakeState
A StakeState takes one of two forms, StakeState::Delegate and StakeState::MiningPool.
### StakeState::Delegate
StakeState is the current delegation preference of the **staker**. StakeState
contains the following state information:
* Account::lamports - The staked 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.
### StakeState::MiningPool
There are two approaches to the mining pool. The bank could allow the
StakeState program to bypass the token balance check, or a program representing
the mining pool could run on the network. To avoid a single network wide lock,
the pool can be split into several mining pools. This design focuses on using
StakeState::MiningPool instances as the cluster wide mining pools.
* 256 StakeState::MiningPool are initialized, each with 1/256 number of mining pool
tokens stored as `Account::lamports`.
The stakes and the MiningPool are accounts that are owned by the same `Stake`
program.
### StakeInstruction::Initialize
* `account[0]` - RW - The StakeState::Delegate instance.
`StakeState::Delegate::credits_observed` is initialized to `VoteState::credits`.
`StakeState::Delegate::voter_pubkey` is initialized to `account[1]`
* `account[1]` - R - The VoteState instance.
### StakeInstruction::RedeemVoteCredits
The Staker or the owner of the Stake account sends a transaction with this
instruction to claim rewards.
The Vote account and the Stake account pair maintain a lifetime counter
of total rewards generated and claimed. When claiming rewards, the total lamports
deposited into the Stake account and as validator commission is proportional to
`VoteState::credits - StakeState::credits_observed`.
* `account[0]` - RW - The StakeState::MiningPool instance that will fulfill the
reward.
* `account[1]` - RW - The StakeState::Delegate instance that is redeeming votes
credits.
* `account[2]` - R - The VoteState instance, must be the same as
`StakeState::voter_pubkey`
Reward is paid out for the difference between `VoteState::credits` to
`StakeState::Delgate.credits_observed`, and `credits_observed` is updated to
`VoteState::credits`. The commission is deposited into the Vote account token
balance, and the reward is deposited to the Stake account token balance.
The total lamports paid is a percentage-rate of the lamports staked muiltplied by
the ratio of rewards being redeemed to rewards that could have been generated
during the rate period.
Any random MiningPool can be used to redeem the credits.
```rust,ignore
let credits_to_claim = vote_state.credits - stake_state.credits_observed;
stake_state.credits_observed = vote_state.credits;
```
`credits_to_claim` is used to compute the reward and commission, and
`StakeState::Delegate::credits_observed` is updated to the latest
`VoteState::credits` value.
## Collecting network fees into the MiningPool
At the end of the block, before the bank is frozen, but after it processed all
the transactions for the block, a virtual instruction is executed to collect
the transaction fees.
* A portion of the fees are deposited into the leader's account.
* A portion of the fees are deposited into the smallest StakeState::MiningPool
account.
## Authorizing a Vote Signer
`VoteInstruction::AuthorizeVoter` allows a staker to choose a signing service
for its votes. That service is responsible for ensuring the vote won't cause
the staker to be slashed.
## Limitations
## Benefits of the design
Many stakers may delegate their stakes to the same fullnode. The fullnode must
send a separate vote to each staking account. If there are far more stakers
than fullnodes, that's a lot of network traffic. An alternative design might
have fullnodes submit each vote to just one account and then have each staker
submit that account along with their own to collect its reward.
* Single vote for all the stakers.
* Clearing of the credit variable is not necessary for claiming rewards.
* Each delegated stake can claim its rewards independently.
* Commission for the work is deposited when a reward is claimed by the delegated
stake.
This proposal would benefit from the `read-only` accounts proposal to allow for
many rewards to be claimed concurrently.
## Example Callflow
<img alt="Passive Staking Callflow" src="img/passive-staking-callflow.svg" class="center"/>

View File

@ -1,8 +1,8 @@
# Staking Rewards
Initial Proof of Stake (PoS) (i.e. using in-protocol asset, SOL, to provide
secure consensus) design ideas outlined here. Solana will implement a proof of
stake reward/security scheme for node validators in the cluster. The purpose is
A Proof of Stake (PoS), (i.e. using in-protocol asset, SOL, to provide
secure consensus) design is outlined here. Solana implements a proof of
stake reward/security scheme for validator nodes in the cluster. The purpose is
threefold:
- Align validator incentives with that of the greater cluster through
@ -64,7 +64,7 @@ capital-at-risk to prevent a logical/optimal strategy of multiple chain voting.
We intend to implement slashing rules which, if broken, result some amount of
the offending validator's deposited stake to be removed from circulation. Given
the ordering properties of the PoH data structure, we believe we can simplify
our slashing rules to the level of a voting lockout time assigned per vote.
our slashing rules to the level of a voting lockout time assigned per vote.
I.e. Each vote has an associated lockout time (PoH duration) that represents a
duration by any additional vote from that validator must be in a PoH that
@ -110,7 +110,7 @@ in a slashable amount as a function of either:
1. the fraction of validators, out of the total validator pool, that were also
slashed during the same time period (ala Casper)
2. the amount of time since the vote was cast (e.g. a linearly increasing % of
total deposited as slashable amount over time), or both.
total deposited as slashable amount over time), or both.
This is an area currently under exploration

View File

@ -15,39 +15,43 @@ reasons:
* The cluster rolled back the ledger
* A validator responded to queries maliciously
### The Transact Trait
### The AsyncClient and SyncClient Traits
To troubleshoot, the application should retarget a lower-level component, where
fewer errors are possible. Retargeting can be done with different
implementations of the Transact trait.
implementations of the AsyncClient and SyncClient traits.
When Futures 0.3.0 is released, the Transact trait may look like this:
Components implement the following primary methods:
```rust,ignore
trait Transact {
async fn send_transactions(txs: &[Transaction]) -> Vec<Result<(), BankError>>;
trait AsyncClient {
fn async_send_transaction(&self, transaction: Transaction) -> io::Result<Signature>;
}
trait SyncClient {
fn get_signature_status(&self, signature: &Signature) -> Result<Option<transaction::Result<()>>>;
}
```
Users send transactions and asynchrounously await their results.
Users send transactions and asynchrounously and synchrounously await results.
#### Transact with Clusters
#### ThinClient for Clusters
The highest level implementation targets a Solana cluster, which may be a
deployed testnet or a local cluster running on a development machine.
The highest level implementation, ThinClient, targets a Solana cluster, which
may be a deployed testnet or a local cluster running on a development machine.
#### Transact with the TPU
#### TpuClient for the TPU
The next level is the TPU implementation of Transact. At the TPU level, the
application sends transactions over Rust channels, where there can be no
surprises from network queues or dropped packets. The TPU implements all
"normal" transaction errors. It does signature verification, may report
The next level is the TPU implementation, which is not yet implemented. At the
TPU level, the application sends transactions over Rust channels, where there
can be no surprises from network queues or dropped packets. The TPU implements
all "normal" transaction errors. It does signature verification, may report
account-in-use errors, and otherwise results in the ledger, complete with proof
of history hashes.
### Low-level testing
### Testing with the Bank
#### BankClient for the Bank
Below the TPU level is the Bank. The Bank doesn't do signature verification or
generate a ledger. The Bank is a convenient layer at which to test new on-chain

View File

@ -0,0 +1,199 @@
## Testnet Participation
This document describes how to participate in the testnet as a
validator node.
Please note some of the information and instructions described here may change
in future releases.
### Overview
The testnet features a validator running at testnet.solana.com, which
serves as the entrypoint to the cluster for your validator.
Additionally there is a blockexplorer available at
[http://testnet.solana.com/](http://testnet.solana.com/).
The testnet is configured to reset the ledger daily, or sooner
should the hourly automated cluster sanity test fail.
There is a **#validator-support** Discord channel available to reach other
testnet participants, [https://discord.gg/pquxPsq](https://discord.gg/pquxPsq).
Also we'd love it if you choose to register your validator node with us at
[https://forms.gle/LfFscZqJELbuUP139](https://forms.gle/LfFscZqJELbuUP139).
### Machine Requirements
Since the testnet is not intended for stress testing of max transaction
throughput, a higher-end machine with a GPU is not necessary to participate.
However ensure the machine used is not behind a residential NAT to avoid NAT
traversal issues. A cloud-hosted machine works best. **Ensure that IP ports
8000 through 10000 are not blocked for Internet inbound and outbound traffic.**
Prebuilt binaries are available for Linux x86_64 (Ubuntu 18.04 recommended).
MacOS or WSL users may build from source.
For a performance testnet with many transactions we have some preliminary recomended setups:
| | Low end | Medium end | High end | Notes |
| --- | ---------|------------|----------| -- |
| CPU | AMD Threadripper 1900x | AMD Threadripper 2920x | AMD Threadripper 2950x | Consider a 10Gb-capable motherboard with as many PCIe lanes and m.2 slots as possible. |
| RAM | 16GB | 32GB | 64GB | |
| OS Drive | Samsung 860 Evo 2TB | Samsung 860 Evo 4TB | Samsung 860 Evo 4TB | Or equivalent SSD |
| Accounts Drive(s) | None | Samsung 970 Pro 1TB | 2x Samsung 970 Pro 1TB | |
| GPU | 4x Nvidia 1070 or 2x Nvidia 1080 Ti or 2x Nvidia 2070 | 2x Nvidia 2080 Ti | 4x Nvidia 2080 Ti | Any number of cuda-capable GPUs are supported on Linux platforms. |
#### Confirm The Testnet Is Reachable
Before attaching a validator node, sanity check that the cluster is accessible
to your machine by running some simple commands. If any of the commands fail,
please retry 5-10 minutes later to confirm the testnet is not just restarting
itself before debugging further.
Fetch the current transaction count over JSON RPC:
```bash
$ curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"getTransactionCount"}' http://testnet.solana.com:8899
```
Inspect the blockexplorer at [http://testnet.solana.com/](http://testnet.solana.com/) for activity.
View the [metrics dashboard](
https://metrics.solana.com:3000/d/testnet-beta/testnet-monitor-beta?var-testnet=testnet)
for more detail on cluster activity.
### Validator Setup
#### Obtaining The Software
##### Bootstrap with `solana-install`
The `solana-install` tool can be used to easily install and upgrade the cluster
software on Linux x86_64 systems.
```bash
$ export SOLANA_RELEASE=v0.14.2 # skip this line to install the latest release
$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.14.0/install/solana-install-init.sh | sh -s
```
Alternatively build the `solana-install` program from source and run the
following command to obtain the same result:
```bash
$ solana-install init
```
After a successful install, `solana-install update` may be used to easily update the cluster
software to a newer version.
##### Download Prebuilt Binaries
Binaries are available for Linux x86_64 systems.
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
archive:
```bash
$ tar jxf solana-release-x86_64-unknown-linux-gnu.tar.bz2
$ cd solana-release/
$ export PATH=$PWD/bin:$PATH
```
##### Build From Source
If you are unable to use the prebuilt binaries or prefer to build it yourself
from source, navigate to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
and download the **Source Code** archive. Extract the code and build the
binaries with:
```bash
$ ./scripts/cargo-install-all.sh .
$ export PATH=$PWD/bin:$PATH
```
### Starting The Validator
Sanity check that you are able to interact with the cluster by receiving a small
airdrop of lamports from the testnet drone:
```bash
$ solana-wallet airdrop 123
$ solana-wallet balance
```
Also try running following command to join the gossip network and view all the other nodes in the cluster:
```bash
$ solana-gossip --entrypoint testnet.solana.com:8001 spy
# Press ^C to exit
```
Now configure a key pair for your validator by running:
```bash
$ solana-keygen -o validator-keypair.json
```
Then use one of the following commands, depending on your installation
choice, to start the node:
If this is a `solana-install`-installation:
```bash
$ clear-config.sh
$ validator.sh --identity validator-keypair.json --poll-for-new-genesis-block testnet.solana.com
```
Alternatively, the `solana-install run` command can be used to run the validator
node while periodically checking for and applying software updates:
```bash
$ clear-config.sh
$ solana-install run validator.sh -- --identity validator-keypair.json --poll-for-new-genesis-block testnet.solana.com
```
If you built from source:
```bash
$ USE_INSTALL=1 ./multinode-demo/clear-config.sh
$ USE_INSTALL=1 ./multinode-demo/validator.sh --identity validator-keypair.json --poll-for-new-genesis-block testnet.solana.com
```
#### Controlling local network port allocation
By default the validator will dynamically select available network ports in the
8000-10000 range, and may be overridden with `--dynamic-port-range`. For
example, `validator.sh --dynamic-port-range 11000-11010 ...` will restrict the
validator to ports 11000-11011.
### Validator Monitoring
When `validator.sh` starts, it will output a validator configuration that looks
similar to:
```bash
======================[ validator configuration ]======================
identity pubkey: 4ceWXsL3UJvn7NYZiRkw7NsryMpviaKBDYr8GK7J61Dm
vote pubkey: 2ozWvfaXQd1X6uKh8jERoRGApDqSqcEy6fF1oN13LL2G
ledger: ...
accounts: ...
======================================================================
```
The **identity pubkey** for your validator can also be found by running:
```bash
$ solana-keygen pubkey validator-keypair.json
```
From another console, confirm the IP address and **identity pubkey** of your validator is visible in the
gossip network by running:
```bash
$ solana-gossip --entrypoint testnet.solana.com:8001 spy
```
Provide the **vote pubkey** to the `solana-wallet show-vote-account` command to view
the recent voting activity from your validator:
```bash
$ solana-wallet -n testnet.solana.com show-vote-account 2ozWvfaXQd1X6uKh8jERoRGApDqSqcEy6fF1oN13LL2G
```
The vote pubkey for the validator can also be found by running:
```bash
# If this is a `solana-install`-installation run:
$ solana-keygen pubkey ~/.local/share/solana/install/active_release/config-local/validator-vote-keypair.json
# Otherwise run:
$ solana-keygen pubkey ./config-local/validator-vote-keypair.json
```
### Sharing Metrics From Your Validator
If you have obtained a metrics username/password from the Solana maintainers to
help us monitor the health of the testnet, please perform the following steps
before starting the validator to activate metrics reporting:
```bash
export u="username obtained from the Solana maintainers"
export p="password obtained from the Solana maintainers"
export SOLANA_METRICS_CONFIG="db=testnet,u=${u:?},p=${p:?}"
source scripts/configure-metrics.sh
```

View File

@ -0,0 +1,59 @@
# Deterministic Transaction Fees
Transactions currently include a fee field that indicates the maximum fee field
a slot leader is permitted to charge to process a transaction. The cluster, on
the other hand, agrees on a minimum fee. If the network is congested, the slot
leader may prioritize the transactions offering higher fees. That means the
client won't know how much was collected until the transaction is confirmed by
the cluster and the remaining balance is checked. It smells of exactly what we
dislike about Ethereum's "gas", non-determinism.
## Implementation Status
This design is not yet implemented, but is written as though it has been. Once
implemented, delete this comment.
### Congestion-driven fees
Each validator uses *signatures per slot* (SPS) to estimate network congestion
and *SPS target* to estimate the desired processing capacity of the cluster.
The validator learns the SPS target from the genesis block, whereas it
calculates SPS from the ledger data in the previous epoch.
### Calculating fees
The client uses the JSON RPC API to query the cluster for the current fee
parameters. Those parameters are tagged with a blockhash and remain valid
until that blockhash is old enough to be rejected by the slot leader.
Before sending a transaction to the cluster, a client may submit the
transaction and fee account data to an SDK module called the *fee calculator*.
So long as the client's SDK version matches the slot leader's version, the
client is assured that its account will be changed exactly the same number of
lamports as returned by the fee calculator.
### Fee Parameters
In the first implementation of this design, the only fee parameter is
`lamports_per_signature`. The more signatures the cluster needs to verify, the
higher the fee. The exact number of lamports is determined by the ratio of SPS
to the SPS target. The cluster lowers `lamports_per_signature` when SPS is
below the target and raises it when at or above the target.
Future parameters might include:
* `lamports_per_pubkey` - cost to load an account
* `lamports_per_slot_distance` - higher cost to load very old accounts
* `lamports_per_byte` - cost per size of account loaded
* `lamports_per_bpf_instruction` - cost to run a program
### Attacks
#### Hijacking the SPS Target
A group of validators can centralize the cluster if they can convince it to
raise the SPS Target above a point where the rest of the validators can keep
up. Raising the target will cause fees to drop, presumably creating more demand
and therefore higher TPS. If the validator doesn't have hardware that can
process that many transactions that fast, its confirmation votes will
eventually get so long that the cluster will be forced to boot it.

View File

@ -0,0 +1,56 @@
# Anatomy of a Validator
## History
When we first started Solana, the goal was to de-risk our TPS claims. We knew
that between optimistic concurrency control and sufficiently long leader slots,
that PoS consensus was not the biggest risk to TPS. It was GPU-based signature
verification, software pipelining and concurrent banking. Thus, the TPU was
born. After topping 100k TPS, we split the team into one group working toward
710k TPS and another to flesh out the validator pipeline. Hence, the TVU was
born. The current architecture is a consequence of incremental development with
that ordering and project priorities. It is not a reflection of what we ever
believed was the most technically elegant cross-section of those technologies.
In the context of leader rotation, the strong distinction between leading and
validating is blurred.
## Difference between validating and leading
The fundamental difference between the pipelines is when the PoH is present. In
a leader, we process transactions, removing bad ones, and then tag the result
with a PoH hash. In the validator, we verify that hash, peel it off, and
process the transactions in exactly the same way. The only difference is that
if a validator sees a bad transaction, it can't simply remove it like the
leader does, because that would cause the PoH hash to change. Instead, it
rejects the whole block. The other difference between the pipelines is what
happens *after* banking. The leader broadcasts entries to downstream validators
whereas the validator will have already done that in RetransmitStage, which is
a confirmation time optimization. The validation pipeline, on the other hand,
has one last step. Any time it finishes processing a block, it needs to weigh
any forks it's observing, possibly cast a vote, and if so, reset its PoH hash
to the block hash it just voted on.
## Proposed Design
We unwrap the many abstraction layers and build a single pipeline that can
toggle leader mode on whenever the validator's ID shows up in the leader
schedule.
<img alt="Validator block diagram" src="img/validator-proposal.svg" class="center"/>
## Notable changes
* No threads are shut down to switch out of leader mode. Instead, FetchStage
should forward transactions to the next leader.
* Hoist FetchStage and BroadcastStage out of TPU
* Blocktree renamed to Blockstore
* BankForks renamed to Banktree
* TPU moves to new socket-free crate called solana-tpu.
* TPU's BankingStage absorbs ReplayStage
* TVU goes away
* New RepairStage absorbs Blob Fetch Stage and repair requests
* JSON RPC Service is optional - used for debugging. It should instead be part
of a separate `solana-blockstreamer` executable.
* New MulticastStage absorbs retransmit part of RetransmitStage
* MulticastStage downstream of Blockstore

View File

@ -1,10 +1,10 @@
# Anatomy of a Fullnode
# Anatomy of a Validator
<img alt="Fullnode block diagrams" src="img/fullnode.svg" class="center"/>
<img alt="Validator block diagrams" src="img/validator.svg" class="center"/>
## Pipelining
The fullnodes make extensive use of an optimization common in CPU design,
The validators make extensive use of an optimization common in CPU design,
called *pipelining*. Pipelining is the right tool for the job when there's a
stream of input data that needs to be processed by a sequence of steps, and
there's different hardware responsible for each. The quintessential example is
@ -19,9 +19,9 @@ dryer and the first is being folded. In this way, one can make progress on
three loads of laundry simultaneously. Given infinite loads, the pipeline will
consistently complete a load at the rate of the slowest stage in the pipeline.
## Pipelining in the Fullnode
## Pipelining in the Validator
The fullnode contains two pipelined processes, one used in leader mode called
The validator contains two pipelined processes, one used in leader mode called
the TPU and one used in validator mode called the TVU. In both cases, the
hardware being pipelined is the same, the network input, the GPU cards, the CPU
cores, writes to disk, and the network output. What it does with that hardware

View File

@ -41,7 +41,7 @@ $ solana-wallet balance
$ solana-wallet confirm <TX_SIGNATURE>
// Return
"Confirmed" / "Not found"
"Confirmed" / "Not found" / "Transaction failed with error <ERR>"
```
#### Deploy program
@ -352,4 +352,3 @@ ARGS:
<PUBKEY> The pubkey of recipient
<PROCESS_ID> The process id of the transfer to unlock
```

View File

@ -12,8 +12,12 @@ if [[ -d target/perf-libs ]]; then
exit 1
fi
set -x
git clone git@github.com:solana-labs/solana-perf-libs.git target/perf-libs
cd target/perf-libs
make -j"$(nproc)"
make DESTDIR=. install
(
set -x
git clone git@github.com:solana-labs/solana-perf-libs.git target/perf-libs
cd target/perf-libs
make -j"$(nproc)"
make DESTDIR=. install
)
./fetch-perf-libs.sh

View File

@ -1,20 +0,0 @@
#!/usr/bin/env bash
#
# Audits project dependencies for security vulnerabilities
#
set -e
cd "$(dirname "$0")/.."
source ci/_
cargo_install_unless() {
declare crate=$1
shift
"$@" > /dev/null 2>&1 || \
_ cargo install "$crate"
}
cargo_install_unless cargo-audit cargo audit --version
_ cargo audit

View File

@ -2,22 +2,24 @@ steps:
- command: "ci/shellcheck.sh"
name: "shellcheck"
timeout_in_minutes: 5
- command: "ci/docker-run.sh solanalabs/rust:1.32.0 ci/test-checks.sh"
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-checks.sh"
name: "checks"
timeout_in_minutes: 15
- wait
- command: "ci/test-stable-perf.sh"
name: "stable-perf"
timeout_in_minutes: 20
artifact_paths: "log-*.txt"
agents:
- "queue=cuda"
- command: "ci/test-bench.sh"
name: "bench"
timeout_in_minutes: 20
- command: "ci/docker-run.sh solanalabs/rust:1.32.0 ci/test-stable.sh"
timeout_in_minutes: 60
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-stable.sh"
name: "stable"
timeout_in_minutes: 20
- command: "ci/docker-run.sh solanalabs/rust-nightly:2019-01-31 ci/test-coverage.sh"
timeout_in_minutes: 40
artifact_paths: "log-*.txt"
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-coverage.sh"
name: "coverage"
timeout_in_minutes: 20
# TODO: Fix and re-enable test-large-network.sh

View File

@ -1,17 +1,26 @@
#!/usr/bin/env bash
#
# Outputs the current crate version
# Outputs the current crate version from a given Cargo.toml
#
set -e
cd "$(dirname "$0")"/..
Cargo_toml=$1
[[ -n $Cargo_toml ]] || {
echo "Usage: $0 path/to/Cargo.toml"
exit 0
}
[[ -r $Cargo_toml ]] || {
echo "Error: unable to read $Cargo_toml"
exit 1
}
while read -r name equals value _; do
if [[ $name = version && $equals = = ]]; then
echo "${value//\"/}"
exit 0
fi
done < <(cat Cargo.toml)
done < <(cat "$Cargo_toml")
echo Unable to locate version in Cargo.toml 1>&2
exit 1

View File

@ -4,11 +4,8 @@ ARG date
RUN set -x \
&& rustup install nightly-$date \
&& rustup show \
&& mv /usr/local/rustup/toolchains/nightly-$date-* \
/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu \
&& rustup show \
&& rustc --version \
&& cargo --version \
&& rustc +nightly --version \
&& cargo +nightly --version
&& cargo install grcov \
&& rustc +nightly-$date --version \
&& cargo +nightly-$date --version

View File

@ -19,7 +19,7 @@ To update the pinned version:
to confirm the new nightly image builds. Fix any issues as needed
1. Run `docker login` to enable pushing images to Docker Hub, if you're authorized.
1. Run `CI=true ci/docker-rust-nightly/build.sh YYYY-MM-DD` to push the new nightly image to dockerhub.com.
1. Modify the `solanalabs/rust-nightly:YYYY-MM-DD` reference in `ci/buildkite.yml` from the previous to
1. Modify the `solanalabs/rust-nightly:YYYY-MM-DD` reference in `ci/rust-version.sh` from the previous to
new *YYYY-MM-DD* value, send a PR with this change and any codebase adjustments needed.
## Troubleshooting

View File

@ -1,6 +1,6 @@
# Note: when the rust version is changed also modify
# ci/buildkite.yml to pick up the new image tag
FROM rust:1.32.0
FROM rust:1.34.0
RUN set -x \
&& apt update \
@ -17,12 +17,15 @@ RUN set -x \
lcov \
libclang-common-7-dev \
llvm-7 \
mscgen \
rsync \
sudo \
\
&& rm -rf /var/lib/apt/lists/* \
&& rustup component add rustfmt \
&& rustup component add clippy \
&& rm -rf /var/lib/apt/lists/* \
&& cargo install cargo-audit \
&& cargo install svgbob_cli \
&& cargo install mdbook \
&& rustc --version \
&& cargo --version

View File

@ -8,5 +8,5 @@ docker build -t solanalabs/rust .
read -r rustc version _ < <(docker run solanalabs/rust rustc --version)
[[ $rustc = rustc ]]
docker tag solanalabs/rust:latest solanalabs/rust:"$version"
docker push solanalabs/rust
docker push solanalabs/rust:"$version"
docker push solanalabs/rust:latest

View File

@ -24,9 +24,9 @@ fi
build() {
$genPipeline && return
ci/version-check-with-upgrade.sh stable
_ scripts/ulimit-n.sh
_ cargo build --all
source ci/rust-version.sh stable
source scripts/ulimit-n.sh
_ cargo +$rust_stable build --all
}
runTest() {
@ -51,20 +51,11 @@ runTest() {
build
runTest "Leader rotation off" \
"ci/localnet-sanity.sh -i 128 -b"
runTest "Leader rotation off, restart" \
"ci/localnet-sanity.sh -i 128 -k 16 -b"
runTest "Leader rotation off, incremental restart, extra node" \
"ci/localnet-sanity.sh -i 128 -k 16 -R -x -b"
runTest "Leader rotation on" \
runTest "basic" \
"ci/localnet-sanity.sh -i 128"
runTest "Leader rotation on, restart" \
runTest "restart" \
"ci/localnet-sanity.sh -i 128 -k 16"
runTest "Leader rotation on, incremental restart, extra node" \
runTest "incremental restart, extra node" \
"ci/localnet-sanity.sh -i 128 -k 16 -R -x"

View File

@ -7,7 +7,7 @@ restartInterval=never
rollingRestart=false
maybeNoLeaderRotation=
extraNodes=0
walletRpcEndpoint=
walletRpcPort=:8899
usage() {
exitcode=0
@ -27,7 +27,7 @@ Start a local cluster and run sanity on it
nodes (at the cadence specified by -k). When disabled all
nodes will be first killed then restarted (default: $rollingRestart)
-b - Disable leader rotation
-x - Add an extra fullnode (may be supplied multiple times)
-x - Add an extra validator (may be supplied multiple times)
-r - Select the RPC endpoint hosted by a node that starts as
a validator node. If unspecified the RPC endpoint hosted by
the bootstrap leader will be used.
@ -55,13 +55,13 @@ while getopts "ch?i:k:brxR" opt; do
restartInterval=$OPTARG
;;
b)
maybeNoLeaderRotation="--no-leader-rotation"
maybeNoLeaderRotation="--stake 0"
;;
x)
extraNodes=$((extraNodes + 1))
;;
r)
walletRpcEndpoint="--rpc-port 18899"
walletRpcPort=":18899"
;;
R)
rollingRestart=true
@ -78,20 +78,22 @@ source scripts/configure-metrics.sh
nodes=(
"multinode-demo/drone.sh"
"multinode-demo/bootstrap-leader.sh \
$maybeNoLeaderRotation \
--enable-rpc-exit \
--no-restart \
--init-complete-file init-complete-node1.log"
"multinode-demo/fullnode.sh \
"multinode-demo/validator.sh \
$maybeNoLeaderRotation \
--enable-rpc-exit \
--no-restart \
--init-complete-file init-complete-node2.log \
--rpc-port 18899"
)
for i in $(seq 1 $extraNodes); do
nodes+=(
"multinode-demo/fullnode.sh \
-X dyn$i \
"multinode-demo/validator.sh \
--no-restart \
--label dyn$i \
--init-complete-file init-complete-node$((2 + i)).log \
$maybeNoLeaderRotation"
)
@ -167,13 +169,11 @@ startNodes() {
killNode() {
declare pid=$1
echo "kill $pid"
set +e
if kill "$pid"; then
echo "Waiting for $pid to exit..."
wait "$pid"
else
echo "^^^ +++"
echo "Warning: unable to kill $pid"
echo "$pid exited with $?"
fi
set -e
}
@ -197,10 +197,11 @@ killNodes() {
# Give the nodes a splash of time to cleanly exit before killing them
sleep 2
echo "--- Killing nodes"
echo "--- Killing nodes: ${pids[*]}"
for pid in "${pids[@]}"; do
killNode "$pid"
done
echo "done killing nodes"
pids=()
}
@ -255,7 +256,7 @@ rollingNodeRestart() {
}
verifyLedger() {
for ledger in bootstrap-leader fullnode; do
for ledger in bootstrap-leader validator; do
echo "--- $ledger ledger verification"
(
source multinode-demo/common.sh
@ -293,7 +294,7 @@ flag_error() {
}
if ! $skipSetup; then
multinode-demo/setup.sh
multinode-demo/setup.sh --hashes-per-tick auto
else
verifyLedger
fi
@ -305,14 +306,10 @@ while [[ $iteration -le $iterations ]]; do
(
source multinode-demo/common.sh
set -x
client_id=/tmp/client-id.json-$$
$solana_keygen -o $client_id || exit $?
$solana_bench_tps \
--identity $client_id \
--num-nodes $numNodes \
--reject-extra-nodes \
--converge-only || exit $?
rm -rf $client_id
client_keypair=/tmp/client-id.json-$$
$solana_keygen -o $client_keypair || exit $?
$solana_gossip spy --num-nodes-exactly $numNodes || exit $?
rm -rf $client_keypair
) || flag_error
echo "--- RPC API: bootstrap-leader getTransactionCount ($iteration)"
@ -326,7 +323,7 @@ while [[ $iteration -le $iterations ]]; do
cat log-transactionCount.txt
) || flag_error
echo "--- RPC API: fullnode getTransactionCount ($iteration)"
echo "--- RPC API: validator getTransactionCount ($iteration)"
(
set -x
curl --retry 5 --retry-delay 2 --retry-connrefused \
@ -367,8 +364,7 @@ while [[ $iteration -le $iterations ]]; do
}
(
set -x
# shellcheck disable=SC2086 # Don't want to double quote $walletRpcEndpoint
timeout 60s scripts/wallet-sanity.sh $walletRpcEndpoint
timeout 60s scripts/wallet-sanity.sh --url http://127.0.0.1"$walletRpcPort"
) || flag_error_if_no_leader_rotation
iteration=$((iteration + 1))

View File

@ -13,19 +13,24 @@ declare prints=(
'println!'
'eprint!'
'eprintln!'
'dbg!'
)
# Parts of the tree that are expected to be print free
declare print_free_tree=(
'core/src'
'drone'
'metrics'
'netutil'
'runtime'
'sdk'
'drone/src'
'metrics/src'
'netutil/src'
'runtime/src'
'sdk/src'
'programs/vote_api/src'
'programs/vote_program/src'
'programs/stake_api/src'
'programs/stake_program/src'
)
if _ git grep "${prints[@]/#/-e }" -- "${print_free_tree[@]}"; then
if _ git --no-pager grep -n --max-depth=0 "${prints[@]/#/-e }" -- "${print_free_tree[@]}"; then
exit 1
fi
@ -34,7 +39,21 @@ fi
# Default::default()
#
# Ref: https://github.com/solana-labs/solana/issues/2630
if _ git grep 'Default::default()' -- '*.rs'; then
if _ git --no-pager grep -n 'Default::default()' -- '*.rs'; then
exit 1
fi
# Let's keep a .gitignore for every crate, ensure it's got
# /target/ in it
declare gitignores_ok=true
for i in $(git --no-pager ls-files \*/Cargo.toml ); do
dir=$(dirname "$i")
if [[ ! -f $dir/.gitignore ]]; then
echo 'error: nits.sh .gitnore missing for crate '"$dir" >&2
gitignores_ok=false
elif ! grep -q -e '^/target/$' "$dir"/.gitignore; then
echo 'error: nits.sh "/target/" apparently missing from '"$dir"'/.gitignore' >&2
gitignores_ok=false
fi
done
"$gitignores_ok"

View File

@ -2,15 +2,7 @@
set -e
cd "$(dirname "$0")/.."
eval "$(ci/channel-info.sh)"
if [[ $BUILDKITE_BRANCH = "$STABLE_CHANNEL" ]]; then
CHANNEL=stable
elif [[ $BUILDKITE_BRANCH = "$EDGE_CHANNEL" ]]; then
CHANNEL=edge
elif [[ $BUILDKITE_BRANCH = "$BETA_CHANNEL" ]]; then
CHANNEL=beta
fi
echo --- Creating tarball
(

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
source ci/semver_bash/semver.sh
# List of internal crates to publish
#
@ -11,28 +11,37 @@ cd "$(dirname "$0")/.."
# here. (TODO: figure the crate ordering dynamically)
#
CRATES=(
kvstore
logger
netutil
sdk
keygen
metrics
client
drone
programs/{budget,bpf_loader,native_loader,noop,system,vote}
programs/{budget_api,config_api,stake_api,storage_api,token_api,vote_api,exchange_api}
programs/{vote_program,budget_program,bpf_loader,config_program,exchange_program,failure_program}
programs/{noop_program,stake_program,storage_program,token_program}
runtime
vote-signer
core
fullnode
validator
genesis
gossip
ledger-tool
wallet
runtime
install
)
# Only package/publish if this is a tagged release
[[ -n $TRIGGERED_BUILDKITE_TAG ]] || {
echo TRIGGERED_BUILDKITE_TAG unset, skipped
exit 0
}
semverParseInto "$TRIGGERED_BUILDKITE_TAG" MAJOR MINOR PATCH SPECIAL
expectedCrateVersion="$MAJOR.$MINOR.$PATCH$SPECIAL"
[[ -n "$CRATES_IO_TOKEN" ]] || {
echo CRATES_IO_TOKEN undefined
exit 1
@ -46,13 +55,17 @@ for crate in "${CRATES[@]}"; do
exit 1
fi
echo "-- $crate"
# TODO: Ensure the published version matches the contents of
# TRIGGERED_BUILDKITE_TAG
grep -q "^version = \"$expectedCrateVersion\"$" "$crate"/Cargo.toml || {
echo "Error: $crate/Cargo.toml version is not $expectedCrateVersion"
exit 1
}
(
set -x
# TODO: the rocksdb package does not build with the stock rust docker image,
# so use the solana rust docker image until this is resolved upstream
ci/docker-run.sh solanalabs/rust:1.31.0 bash -exc "cd $crate; $cargoCommand"
source ci/rust-version.sh
ci/docker-run.sh "$rust_stable_docker_image" bash -exc "cd $crate; $cargoCommand"
#ci/docker-run.sh rust bash -exc "cd $crate; $cargoCommand"
)
done

View File

@ -45,11 +45,7 @@ beta)
CHANNEL_BRANCH=$BETA_CHANNEL
;;
stable)
if [[ -n $BETA_CHANNEL_LATEST_TAG ]]; then
CHANNEL_BRANCH=$BETA_CHANNEL
else
CHANNEL_BRANCH=$STABLE_CHANNEL
fi
CHANNEL_BRANCH=$STABLE_CHANNEL
;;
*)
echo "Error: Invalid PUBLISH_CHANNEL=$PUBLISH_CHANNEL"

View File

@ -11,10 +11,13 @@ fi
eval "$(ci/channel-info.sh)"
TAG=
if [[ -n "$BUILDKITE_TAG" ]]; then
CHANNEL_OR_TAG=$BUILDKITE_TAG
TAG="$BUILDKITE_TAG"
elif [[ -n "$TRIGGERED_BUILDKITE_TAG" ]]; then
CHANNEL_OR_TAG=$TRIGGERED_BUILDKITE_TAG
TAG="$TRIGGERED_BUILDKITE_TAG"
else
CHANNEL_OR_TAG=$CHANNEL
fi
@ -24,54 +27,103 @@ if [[ -z $CHANNEL_OR_TAG ]]; then
exit 1
fi
case "$(uname)" in
Darwin)
TARGET=x86_64-apple-darwin
;;
Linux)
TARGET=x86_64-unknown-linux-gnu
;;
*)
TARGET=unknown-unknown-unknown
;;
esac
echo --- Creating tarball
(
set -x
rm -rf solana-release/
mkdir solana-release/
COMMIT="$(git rev-parse HEAD)"
(
echo "$CHANNEL_OR_TAG"
git rev-parse HEAD
) > solana-release/version.txt
echo "channel: $CHANNEL_OR_TAG"
echo "commit: $COMMIT"
echo "target: $TARGET"
) > solana-release/version.yml
scripts/cargo-install-all.sh solana-release
source ci/rust-version.sh stable
scripts/cargo-install-all.sh +"$rust_stable" solana-release
rm -rf target/perf-libs
./fetch-perf-libs.sh
mkdir solana-release/target
cp -a target/perf-libs solana-release/target/
# shellcheck source=/dev/null
source ./target/perf-libs/env.sh
(
cd fullnode
cargo install --path . --features=cuda --root ../solana-release-cuda
cd validator
cargo +"$rust_stable" install --path . --features=cuda --root ../solana-release-cuda
)
cp solana-release-cuda/bin/solana-fullnode solana-release/bin/solana-fullnode-cuda
cp solana-release-cuda/bin/solana-validator solana-release/bin/solana-validator-cuda
cp -a scripts multinode-demo solana-release/
tar jvcf solana-release.tar.bz2 solana-release/
# Add a wrapper script for validator.sh
# TODO: Remove multinode/... from tarball
cat > solana-release/bin/validator.sh <<'EOF'
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"/..
export USE_INSTALL=1
exec multinode-demo/validator.sh "$@"
EOF
chmod +x solana-release/bin/validator.sh
# Add a wrapper script for clear-config.sh
# TODO: Remove multinode/... from tarball
cat > solana-release/bin/clear-config.sh <<'EOF'
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"/..
export USE_INSTALL=1
exec multinode-demo/clear-validator-config.sh "$@"
EOF
chmod +x solana-release/bin/clear-config.sh
tar jvcf solana-release-$TARGET.tar.bz2 solana-release/
cp solana-release/bin/solana-install solana-install-$TARGET
)
echo --- Saving build artifacts
source ci/upload-ci-artifact.sh
upload-ci-artifact solana-release.tar.bz2
upload-ci-artifact solana-release-$TARGET.tar.bz2
if [[ -n $DO_NOT_PUBLISH_TAR ]]; then
echo Skipped due to DO_NOT_PUBLISH_TAR
exit 0
fi
echo --- AWS S3 Store
(
set -x
$DRYRUN docker run \
--rm \
--env AWS_ACCESS_KEY_ID \
--env AWS_SECRET_ACCESS_KEY \
--volume "$PWD:/solana" \
eremite/aws-cli:2018.12.18 \
/usr/bin/s3cmd --acl-public put /solana/solana-release.tar.bz2 \
s3://solana-release/"$CHANNEL_OR_TAG"/solana-release.tar.bz2
for file in solana-release-$TARGET.tar.bz2 solana-install-$TARGET; do
echo --- AWS S3 Store: $file
(
set -x
$DRYRUN docker run \
--rm \
--env AWS_ACCESS_KEY_ID \
--env AWS_SECRET_ACCESS_KEY \
--volume "$PWD:/solana" \
eremite/aws-cli:2018.12.18 \
/usr/bin/s3cmd --acl-public put /solana/"$file" s3://release.solana.com/"$CHANNEL_OR_TAG"/"$file"
echo Published to:
$DRYRUN ci/format-url.sh http://solana-release.s3.amazonaws.com/"$CHANNEL_OR_TAG"/solana-release.tar.bz2
)
echo Published to:
$DRYRUN ci/format-url.sh http://release.solana.com/"$CHANNEL_OR_TAG"/"$file"
)
if [[ -n $TAG ]]; then
ci/upload-github-release-asset.sh $file
fi
done
echo --- ok

View File

@ -1,20 +0,0 @@
#!/usr/bin/env bash
#
# Run the entire buildkite CI pipeline locally for pre-testing before sending a
# Github pull request
#
set -e
cd "$(dirname "$0")/.."
BKRUN=ci/node_modules/.bin/bkrun
if [[ ! -x $BKRUN ]]; then
(
set -x
cd ci/
npm install bkrun
)
fi
set -x
exec ./ci/node_modules/.bin/bkrun ci/buildkite.yml

45
ci/rust-version.sh Normal file
View File

@ -0,0 +1,45 @@
#
# This file maintains the rust versions for use by CI.
#
# Build with stable rust, updating the stable toolchain if necessary:
# $ source ci/rust-version.sh stable
# $ cargo +"$rust_stable" build
#
# Build with nightly rust, updating the nightly toolchain if necessary:
# $ source ci/rust-version.sh nightly
# $ cargo +"$rust_nightly" build
#
# Obtain the environment variables without any automatic toolchain updating:
# $ source ci/rust-version.sh
#
export rust_stable=1.34.0
export rust_stable_docker_image=solanalabs/rust:1.34.0
export rust_nightly=nightly-2019-05-01
export rust_nightly_docker_image=solanalabs/rust-nightly:2019-05-01
[[ -z $1 ]] || (
rustup_install() {
declare toolchain=$1
if ! cargo +"$toolchain" -V; then
rustup install "$toolchain"
cargo +"$toolchain" -V
fi
}
set -e
cd "$(dirname "${BASH_SOURCE[0]}")"
case $1 in
stable)
rustup_install "$rust_stable"
;;
nightly)
rustup_install "$rust_nightly"
;;
*)
echo "Note: ignoring unknown argument: $1"
;;
esac
)

View File

@ -24,7 +24,7 @@ source ci/_
source ci/upload-ci-artifact.sh
eval "$(ci/channel-info.sh)"
ci/version-check-with-upgrade.sh nightly
source ci/rust-version.sh nightly
set -o pipefail
export RUST_BACKTRACE=1
@ -39,19 +39,34 @@ fi
BENCH_FILE=bench_output.log
BENCH_ARTIFACT=current_bench_results.log
_ cargo +nightly bench ${V:+--verbose} \
-- -Z unstable-options --format=json | tee "$BENCH_FILE"
# Ensure all dependencies are built
_ cargo +$rust_nightly build --all --release
# Remove "BENCH_FILE", if it exists so that the following commands can append
rm -f "$BENCH_FILE"
# Run sdk benches
_ cargo +$rust_nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run runtime benches
_ cargo +$rust_nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run core benches
_ cargo +$rust_nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run bpf benches
echo --- program/bpf
(
set -x
cd programs/bpf
cargo +nightly bench ${V:+--verbose} --features=bpf_c \
-- -Z unstable-options --format=json --nocapture | tee -a ../../../"$BENCH_FILE"
)
_ cargo +$rust_nightly bench --manifest-path programs/bpf/Cargo.toml ${V:+--verbose} --features=bpf_c \
-- -Z unstable-options --format=json --nocapture | tee -a "$BENCH_FILE"
_ cargo +nightly run --release --package solana-upload-perf \
-- "$BENCH_FILE" "$TARGET_BRANCH" "$UPLOAD_METRICS" > "$BENCH_ARTIFACT"
# TODO: debug why solana-upload-perf takes over 30 minutes to complete.
exit 0
_ cargo +$rust_nightly run --release --package solana-upload-perf \
-- "$BENCH_FILE" "$TARGET_BRANCH" "$UPLOAD_METRICS" | tee "$BENCH_ARTIFACT"
upload-ci-artifact "$BENCH_FILE"
upload-ci-artifact "$BENCH_ARTIFACT"

View File

@ -4,15 +4,15 @@ set -e
cd "$(dirname "$0")/.."
source ci/_
ci/version-check.sh stable
source ci/rust-version.sh stable
export RUST_BACKTRACE=1
export RUSTFLAGS="-D warnings"
_ cargo fmt --all -- --check
_ cargo clippy --all -- --version
_ cargo clippy --all -- --deny=warnings
_ ci/audit.sh
_ cargo +"$rust_stable" fmt --all -- --check
_ cargo +"$rust_stable" clippy --all -- --version
_ cargo +"$rust_stable" clippy --all -- --deny=warnings
_ cargo +"$rust_stable" audit
_ ci/nits.sh
_ book/build.sh

View File

@ -21,7 +21,6 @@ ci/affects-files.sh \
}
source ci/upload-ci-artifact.sh
ci/version-check-with-upgrade.sh nightly
source scripts/ulimit-n.sh
scripts/coverage.sh

View File

@ -4,12 +4,11 @@ set -e
here=$(dirname "$0")
cd "$here"/..
# This job doesn't run within a container, try once to upgrade tooling on a
# version check failure
ci/version-check-with-upgrade.sh stable
source ci/rust-version.sh stable
export RUST_BACKTRACE=1
rm -rf target/perf-libs
./fetch-perf-libs.sh
export LD_LIBRARY_PATH=$PWD/target/perf-libs:$LD_LIBRARY_PATH
@ -39,4 +38,4 @@ fi
set -x
export SOLANA_DYNAMIC_NODES=120
exec cargo test --release --features=erasure test_multi_node_dynamic_network -- --ignored
exec cargo +"$rust_stable" test --release --features=erasure test_multi_node_dynamic_network -- --ignored

View File

@ -10,7 +10,8 @@ annotate() {
}
}
ci/version-check-with-upgrade.sh stable
source ci/rust-version.sh stable
export RUST_BACKTRACE=1
export RUSTFLAGS="-D warnings"
source scripts/ulimit-n.sh
@ -24,9 +25,8 @@ case $testName in
test-stable)
echo "Executing $testName"
_ cargo build --all ${V:+--verbose}
_ cargo test --all ${V:+--verbose} -- --nocapture --test-threads=1
_ cargo test --manifest-path programs/system/Cargo.toml
_ cargo +"$rust_stable" build --all ${V:+--verbose}
_ cargo +"$rust_stable" test --all ${V:+--verbose} -- --nocapture --test-threads=1
;;
test-stable-perf)
echo "Executing $testName"
@ -41,14 +41,15 @@ test-stable-perf)
^sdk/ \
|| {
annotate --style info \
"Skipped test-stable-perf as no relavant files were modified"
"Skipped test-stable-perf as no relevant files were modified"
exit 0
}
# BPF program tests
_ make -C programs/bpf/c tests
_ programs/bpf/rust/noop/build.sh # Must be built out of band
_ cargo test --manifest-path programs/bpf/Cargo.toml --no-default-features --features=bpf_c,bpf_rust
_ cargo +"$rust_stable" test \
--manifest-path programs/bpf/Cargo.toml \
--no-default-features --features=bpf_c,bpf_rust
# Run root package tests with these features
ROOT_FEATURES=erasure,chacha
@ -60,6 +61,7 @@ test-stable-perf)
# is not yet loaded.
sudo --non-interactive ./net/scripts/enable-nvidia-persistence-mode.sh
rm -rf target/perf-libs
./fetch-perf-libs.sh
# shellcheck source=/dev/null
source ./target/perf-libs/env.sh
@ -67,20 +69,8 @@ test-stable-perf)
fi
# Run root package library tests
_ cargo build --all ${V:+--verbose} --features="$ROOT_FEATURES"
_ cargo test --all --lib ${V:+--verbose} --features="$ROOT_FEATURES" -- --nocapture --test-threads=1
_ cargo test --manifest-path programs/system/Cargo.toml
# Run root package integration tests
for test in tests/*.rs; do
test=${test##*/} # basename x
test=${test%.rs} # basename x .rs
(
export RUST_LOG="$test"=trace,$RUST_LOG
_ cargo test --all ${V:+--verbose} --features="$ROOT_FEATURES" --test="$test" \
-- --test-threads=1 --nocapture
)
done
_ cargo +"$rust_stable" build --all ${V:+--verbose} --features="$ROOT_FEATURES"
_ cargo +"$rust_stable" test --manifest-path=core/Cargo.toml ${V:+--verbose} --features="$ROOT_FEATURES" -- --nocapture --test-threads=1
;;
*)
echo "Error: Unknown test: $testName"

View File

@ -14,21 +14,25 @@ source ci/upload-ci-artifact.sh
[[ -n $ITERATION_WAIT ]] || ITERATION_WAIT=300
[[ -n $NUMBER_OF_NODES ]] || NUMBER_OF_NODES="10 25 50 100"
[[ -n $LEADER_CPU_MACHINE_TYPE ]] ||
LEADER_CPU_MACHINE_TYPE="n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100"
LEADER_CPU_MACHINE_TYPE="--machine-type n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100"
[[ -n $CLIENT_COUNT ]] || CLIENT_COUNT=2
[[ -n $TESTNET_TAG ]] || TESTNET_TAG=testnet-automation
[[ -n $TESTNET_ZONE ]] || TESTNET_ZONE=us-west1-b
[[ -n $TESTNET_ZONES ]] || TESTNET_ZONES="us-west1-b"
[[ -n $CHANNEL ]] || CHANNEL=beta
[[ -n $ADDITIONAL_FLAGS ]] || ADDITIONAL_FLAGS=""
TESTNET_CLOUD_ZONES=(); while read -r -d, ; do TESTNET_CLOUD_ZONES+=( "$REPLY" ); done <<< "${TESTNET_ZONES},"
launchTestnet() {
declare nodeCount=$1
echo --- setup "$nodeCount" node test
# shellcheck disable=SC2068
net/gce.sh create \
-b \
-d pd-ssd \
-n "$nodeCount" -c "$CLIENT_COUNT" \
-G "$LEADER_CPU_MACHINE_TYPE" \
-p "$TESTNET_TAG" -z "$TESTNET_ZONE"
-p "$TESTNET_TAG" ${TESTNET_CLOUD_ZONES[@]/#/-z } "$ADDITIONAL_FLAGS"
echo --- configure database
net/init-metrics.sh -e
@ -43,37 +47,39 @@ launchTestnet() {
echo --- wait "$ITERATION_WAIT" seconds to complete test
sleep "$ITERATION_WAIT"
set -x
declare q_mean_tps='
SELECT round(mean("sum_count")) AS "mean_tps" FROM (
SELECT sum("count") AS "sum_count"
FROM "testnet-automation"."autogen"."counter-banking_stage-process_transactions"
FROM "testnet-automation"."autogen"."banking_stage-record_transactions"
WHERE time > now() - 300s GROUP BY time(1s)
)'
declare q_max_tps='
SELECT round(max("sum_count")) AS "max_tps" FROM (
SELECT sum("count") AS "sum_count"
FROM "testnet-automation"."autogen"."counter-banking_stage-process_transactions"
FROM "testnet-automation"."autogen"."banking_stage-record_transactions"
WHERE time > now() - 300s GROUP BY time(1s)
)'
declare q_mean_confirmation='
SELECT round(mean("duration_ms")) as "mean_confirmation"
FROM "testnet-automation"."autogen"."leader-confirmation"
FROM "testnet-automation"."autogen"."validator-confirmation"
WHERE time > now() - 300s'
declare q_max_confirmation='
SELECT round(max("duration_ms")) as "max_confirmation"
FROM "testnet-automation"."autogen"."leader-confirmation"
FROM "testnet-automation"."autogen"."validator-confirmation"
WHERE time > now() - 300s'
declare q_99th_confirmation='
SELECT round(percentile("duration_ms", 99)) as "99th_confirmation"
FROM "testnet-automation"."autogen"."leader-confirmation"
FROM "testnet-automation"."autogen"."validator-confirmation"
WHERE time > now() - 300s'
curl -G "https://metrics.solana.com:8086/query?u=${INFLUX_USERNAME}&p=${INFLUX_PASSWORD}" \
--data-urlencode "db=$INFLUX_DATABASE" \
curl -G "${INFLUX_HOST}/query?u=ro&p=topsecret" \
--data-urlencode "db=testnet-automation" \
--data-urlencode "q=$q_mean_tps;$q_max_tps;$q_mean_confirmation;$q_max_confirmation;$q_99th_confirmation" |
python ci/testnet-automation-json-parser.py >>TPS"$nodeCount".log

View File

@ -10,13 +10,20 @@ bootstrapFullNodeMachineType=
clientNodeCount=0
additionalFullNodeCount=10
publicNetwork=false
skipSetup=false
stopNetwork=false
reuseLedger=false
skipCreate=false
skipStart=false
externalNode=false
failOnValidatorBootupFailure=true
tarChannelOrTag=edge
delete=false
enableGpu=false
bootDiskType=""
leaderRotation=true
blockstreamer=false
deployUpdateManifest=true
fetchLogs=true
maybeHashesPerTick=
usage() {
exitcode=0
@ -25,13 +32,14 @@ usage() {
echo "Error: $*"
fi
cat <<EOF
usage: $0 [name] [cloud] [zone] [options...]
usage: $0 -p network-name -C cloud -z zone1 [-z zone2] ... [-z zoneN] [options...]
Deploys a CD testnet
name - name of the network
cloud - cloud provider to use (gce, ec2)
zone - cloud provider zone to deploy the network into
mandatory arguments:
-p [network-name] - name of the network
-C [cloud] - cloud provider to use (gce, ec2)
-z [zone] - cloud provider zone to deploy the network into. Must specify at least one zone
options:
-t edge|beta|stable|vX.Y.Z - Deploy the latest tarball release for the
@ -42,14 +50,23 @@ Deploys a CD testnet
-c [number] - Number of client bencher nodes (default: $clientNodeCount)
-u - Include a Blockstreamer (default: $blockstreamer)
-P - Use public network IP addresses (default: $publicNetwork)
-G - Enable GPU, and set count/type of GPUs to use (e.g n1-standard-16 --accelerator count=4,type=nvidia-tesla-k80)
-G - Enable GPU, and set count/type of GPUs to use (e.g n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100)
-g - Enable GPU (default: $enableGpu)
-b - Disable leader rotation
-a [address] - Set the bootstrap fullnode's external IP address to this GCE address
-d [disk-type] - Specify a boot disk type (default None) Use pd-ssd to get ssd on GCE.
-D - Delete the network
-r - Reuse existing node/ledger configuration from a
previous |start| (ie, don't run ./multinode-demo/setup.sh).
-x - External node. Default: false
-e - Skip create. Assume the nodes have already been created
-s - Skip start. Nodes will still be created or configured, but network software will not be started.
-S - Stop network software without tearing down nodes.
-f - Discard validator nodes that didn't bootup successfully
-w - Skip time-consuming "bells and whistles" that are
unnecessary for a high-node count demo testnet
--hashes-per-tick NUM_HASHES|sleep|auto
- Override the default --hashes-per-tick for the cluster
Note: the SOLANA_METRICS_CONFIG environment variable is used to configure
metrics
@ -57,19 +74,37 @@ EOF
exit $exitcode
}
netName=$1
cloudProvider=$2
zone=$3
[[ -n $netName ]] || usage
[[ -n $cloudProvider ]] || usage "Cloud provider not specified"
[[ -n $zone ]] || usage "Zone not specified"
shift 3
zone=()
while getopts "h?p:Pn:c:t:gG:a:Dbd:ru" opt; do
shortArgs=()
while [[ -n $1 ]]; do
if [[ ${1:0:2} = -- ]]; then
if [[ $1 = --hashes-per-tick ]]; then
maybeHashesPerTick="$1 $2"
shift 2
else
usage "Unknown long option: $1"
fi
else
shortArgs+=("$1")
shift
fi
done
while getopts "h?p:Pn:c:t:gG:a:Dd:rusxz:p:C:Sfew" opt "${shortArgs[@]}"; do
case $opt in
h | \?)
usage
;;
p)
netName=$OPTARG
;;
C)
cloudProvider=$OPTARG
;;
z)
zone+=("$OPTARG")
;;
P)
publicNetwork=true
;;
@ -89,9 +124,6 @@ while getopts "h?p:Pn:c:t:gG:a:Dbd:ru" opt; do
;;
esac
;;
b)
leaderRotation=false
;;
g)
enableGpu=true
;;
@ -109,17 +141,40 @@ while getopts "h?p:Pn:c:t:gG:a:Dbd:ru" opt; do
delete=true
;;
r)
skipSetup=true
reuseLedger=true
;;
e)
skipCreate=true
;;
s)
skipStart=true
;;
x)
externalNode=true
;;
f)
failOnValidatorBootupFailure=false
;;
u)
blockstreamer=true
;;
S)
stopNetwork=true
;;
w)
fetchLogs=false
deployUpdateManifest=false
;;
*)
usage "Error: unhandled option: $opt"
usage "Unknown option: $opt"
;;
esac
done
[[ -n $netName ]] || usage
[[ -n $cloudProvider ]] || usage "Cloud provider not specified"
[[ -n ${zone[*]} ]] || usage "At least one zone must be specified"
shutdown() {
exitcode=$?
@ -140,9 +195,25 @@ trap shutdown EXIT INT
set -x
if ! $skipSetup; then
# Build a string to pass zone opts to $cloudProvider.sh: "-z zone1 -z zone2 ..."
zone_args=()
for val in "${zone[@]}"; do
zone_args+=("-z $val")
done
if $stopNetwork; then
skipCreate=true
fi
if $delete; then
skipCreate=false
fi
# Create the network
if ! $skipCreate; then
echo "--- $cloudProvider.sh delete"
time net/"$cloudProvider".sh delete -z "$zone" -p "$netName"
# shellcheck disable=SC2068
time net/"$cloudProvider".sh delete ${zone_args[@]} -p "$netName" ${externalNode:+-x}
if $delete; then
exit 0
fi
@ -150,11 +221,12 @@ if ! $skipSetup; then
echo "--- $cloudProvider.sh create"
create_args=(
-p "$netName"
-z "$zone"
-a "$bootstrapFullNodeAddress"
-c "$clientNodeCount"
-n "$additionalFullNodeCount"
)
# shellcheck disable=SC2206
create_args+=(${zone_args[@]})
if $blockstreamer; then
create_args+=(-u)
@ -172,25 +244,38 @@ if ! $skipSetup; then
fi
fi
if ! $leaderRotation; then
create_args+=(-b)
fi
if $publicNetwork; then
create_args+=(-P)
fi
if $externalNode; then
create_args+=(-x)
fi
if ! $failOnValidatorBootupFailure; then
create_args+=(-f)
fi
time net/"$cloudProvider".sh create "${create_args[@]}"
else
echo "--- $cloudProvider.sh config"
config_args=(
-p "$netName"
-z "$zone"
)
# shellcheck disable=SC2206
config_args+=(${zone_args[@]})
if $publicNetwork; then
config_args+=(-P)
fi
if $externalNode; then
config_args+=(-x)
fi
if ! $failOnValidatorBootupFailure; then
config_args+=(-f)
fi
time net/"$cloudProvider".sh config "${config_args[@]}"
fi
net/init-metrics.sh -e
@ -198,39 +283,60 @@ net/init-metrics.sh -e
echo "+++ $cloudProvider.sh info"
net/"$cloudProvider".sh info
echo --- net.sh start
maybeRejectExtraNodes=
if ! $publicNetwork; then
maybeRejectExtraNodes="-o rejectExtraNodes"
fi
maybeNoValidatorSanity=
if [[ -n $NO_VALIDATOR_SANITY ]]; then
maybeNoValidatorSanity="-o noValidatorSanity"
fi
maybeNoLedgerVerify=
if [[ -n $NO_LEDGER_VERIFY ]]; then
maybeNoLedgerVerify="-o noLedgerVerify"
fi
maybeSkipSetup=
if $skipSetup; then
maybeSkipSetup="-r"
if $stopNetwork; then
echo --- net.sh stop
time net/net.sh stop
exit 0
fi
ok=true
(
if $skipSetup; then
# TODO: Enable rolling updates
#op=update
op=restart
else
op=start
if ! $skipStart; then
(
if $skipCreate; then
# TODO: Enable rolling updates
#op=update
op=restart
else
op=start
fi
echo "--- net.sh $op"
args=("$op" -t "$tarChannelOrTag")
if ! $publicNetwork; then
args+=(-o rejectExtraNodes)
fi
if [[ -n $NO_VALIDATOR_SANITY ]]; then
args+=(-o noValidatorSanity)
fi
if [[ -n $NO_LEDGER_VERIFY ]]; then
args+=(-o noLedgerVerify)
fi
if [[ -n $maybeHashesPerTick ]]; then
# shellcheck disable=SC2206 # Do not want to quote $maybeHashesPerTick
args+=($maybeHashesPerTick)
fi
if $reuseLedger; then
args+=(-r)
fi
if ! $failOnValidatorBootupFailure; then
args+=(-F)
fi
# shellcheck disable=SC2154 # SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_unknown_linux_gnu comes from .buildkite/env/
if $deployUpdateManifest && [[ -n $SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_unknown_linux_gnu ]]; then
echo "$SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_unknown_linux_gnu" > update_manifest_keypair.json
args+=(-i update_manifest_keypair.json)
fi
# shellcheck disable=SC2086 # Don't want to double quote the $maybeXYZ variables
time net/net.sh "${args[@]}"
) || ok=false
if $fetchLogs; then
net/net.sh logs
fi
fi
# shellcheck disable=SC2086 # Don't want to double quote maybeRejectExtraNodes
time net/net.sh $op -t "$tarChannelOrTag" \
$maybeSkipSetup $maybeRejectExtraNodes $maybeNoValidatorSanity $maybeNoLedgerVerify
) || ok=false
net/net.sh logs
$ok

View File

@ -42,20 +42,32 @@ steps:
value: "testnet-beta"
- label: "testnet-beta-perf"
value: "testnet-beta-perf"
- label: "testnet-demo"
value: "testnet-demo"
- select: "Operation"
key: "testnet-operation"
default: "sanity-or-restart"
options:
- label: "Sanity check. Restart network on failure"
value: "sanity-or-restart"
- label: "Start (or restart) the network"
- label: "Create testnet and then start software. If the testnet already exists it will be deleted and re-created"
value: "create-and-start"
- label: "Create testnet, but do not start software. If the testnet already exists it will be deleted and re-created"
value: "create"
- label: "Start network software on an existing testnet. If software is already running it will be restarted"
value: "start"
- label: "Update the network software. Restart network on failure"
value: "update-or-restart"
- label: "Stop the network"
- label: "Stop network software without deleting testnet nodes"
value: "stop"
- label: "Update the network software. Restart network software on failure"
value: "update-or-restart"
- label: "Sanity check. Restart network software on failure"
value: "sanity-or-restart"
- label: "Sanity check only"
value: "sanity"
- label: "Delete the testnet"
value: "delete"
- label: "Enable/unlock the testnet"
value: "enable"
- label: "Delete and then lock the testnet from further operation until it is re-enabled"
value: "disable"
- command: "ci/$(basename "$0")"
agents:
- "queue=$BUILDKITE_AGENT_META_DATA_QUEUE"
@ -64,13 +76,58 @@ EOF
exit 0
fi
export SOLANA_METRICS_CONFIG="db=$TESTNET,$SOLANA_METRICS_PARTIAL_CONFIG"
echo "SOLANA_METRICS_CONFIG: $SOLANA_METRICS_CONFIG"
source scripts/configure-metrics.sh
ci/channel-info.sh
eval "$(ci/channel-info.sh)"
EC2_ZONES=(
us-west-1a
us-west-2a
us-east-1a
us-east-2a
sa-east-1a
eu-west-1a
eu-west-2a
eu-central-1a
ap-northeast-2a
ap-southeast-2a
ap-south-1a
ca-central-1a
)
# GCE zones with _lots_ of quota
GCE_ZONES=(
us-west1-a
us-central1-a
us-east1-b
europe-west4-a
us-west1-b
us-central1-b
us-east1-c
europe-west4-b
us-west1-c
us-east1-d
europe-west4-c
)
# GCE zones with enough quota for one CPU-only fullnode
GCE_LOW_QUOTA_ZONES=(
asia-east2-a
asia-northeast1-b
asia-northeast2-b
asia-south1-c
asia-southeast1-b
australia-southeast1-b
europe-north1-a
europe-west2-b
europe-west3-c
europe-west6-a
northamerica-northeast1-a
southamerica-east1-b
)
case $TESTNET in
testnet-edge|testnet-edge-perf)
CHANNEL_OR_TAG=edge
@ -80,14 +137,21 @@ testnet-beta|testnet-beta-perf)
CHANNEL_OR_TAG=beta
CHANNEL_BRANCH=$BETA_CHANNEL
;;
testnet|testnet-perf)
if [[ -n $BETA_CHANNEL_LATEST_TAG ]]; then
CHANNEL_OR_TAG=$BETA_CHANNEL_LATEST_TAG
CHANNEL_BRANCH=$BETA_CHANNEL
else
CHANNEL_OR_TAG=$STABLE_CHANNEL_LATEST_TAG
CHANNEL_BRANCH=$STABLE_CHANNEL
fi
testnet)
CHANNEL_OR_TAG=$STABLE_CHANNEL_LATEST_TAG
CHANNEL_BRANCH=$STABLE_CHANNEL
: "${EC2_NODE_COUNT:=10}"
: "${GCE_NODE_COUNT:=}"
;;
testnet-perf)
CHANNEL_OR_TAG=$STABLE_CHANNEL_LATEST_TAG
CHANNEL_BRANCH=$STABLE_CHANNEL
;;
testnet-demo)
CHANNEL_OR_TAG=beta
CHANNEL_BRANCH=$BETA_CHANNEL
: "${GCE_NODE_COUNT:=150}"
: "${GCE_LOW_QUOTA_NODE_COUNT:=70}"
;;
*)
echo "Error: Invalid TESTNET=$TESTNET"
@ -95,9 +159,34 @@ testnet|testnet-perf)
;;
esac
if [[ $BUILDKITE_BRANCH != "$CHANNEL_BRANCH" ]]; then
(
cat <<EOF
EC2_ZONE_ARGS=()
for val in "${EC2_ZONES[@]}"; do
EC2_ZONE_ARGS+=("-z $val")
done
GCE_ZONE_ARGS=()
for val in "${GCE_ZONES[@]}"; do
GCE_ZONE_ARGS+=("-z $val")
done
GCE_LOW_QUOTA_ZONE_ARGS=()
for val in "${GCE_LOW_QUOTA_ZONES[@]}"; do
GCE_LOW_QUOTA_ZONE_ARGS+=("-z $val")
done
if [[ -n $TESTNET_DB_HOST ]]; then
SOLANA_METRICS_PARTIAL_CONFIG="host=$TESTNET_DB_HOST,$SOLANA_METRICS_PARTIAL_CONFIG"
fi
export SOLANA_METRICS_CONFIG="db=$TESTNET,$SOLANA_METRICS_PARTIAL_CONFIG"
echo "SOLANA_METRICS_CONFIG: $SOLANA_METRICS_CONFIG"
source scripts/configure-metrics.sh
if [[ -n $TESTNET_TAG ]]; then
CHANNEL_OR_TAG=$TESTNET_TAG
else
if [[ $BUILDKITE_BRANCH != "$CHANNEL_BRANCH" ]]; then
(
cat <<EOF
steps:
- trigger: "$BUILDKITE_PIPELINE_SLUG"
async: true
@ -107,19 +196,24 @@ steps:
env:
TESTNET: "$TESTNET"
TESTNET_OP: "$TESTNET_OP"
TESTNET_DB_HOST: "$TESTNET_DB_HOST"
EC2_NODE_COUNT: "$EC2_NODE_COUNT"
GCE_NODE_COUNT: "$GCE_NODE_COUNT"
GCE_LOW_QUOTA_NODE_COUNT: "$GCE_LOW_QUOTA_NODE_COUNT"
EOF
) | buildkite-agent pipeline upload
exit 0
) | buildkite-agent pipeline upload
exit 0
fi
fi
sanity() {
echo "--- sanity $TESTNET"
case $TESTNET in
testnet-edge)
(
set -x
ci/testnet-sanity.sh edge-testnet-solana-com ec2 us-west-1a
NO_LEDGER_VERIFY=1 \
ci/testnet-sanity.sh edge-testnet-solana-com ec2 us-west-1a
)
;;
testnet-edge-perf)
@ -134,7 +228,8 @@ sanity() {
testnet-beta)
(
set -x
ci/testnet-sanity.sh beta-testnet-solana-com ec2 us-west-1a
NO_LEDGER_VERIFY=1 \
ci/testnet-sanity.sh beta-testnet-solana-com ec2 us-west-1a
)
;;
testnet-beta-perf)
@ -149,8 +244,19 @@ sanity() {
testnet)
(
set -x
ci/testnet-sanity.sh testnet-solana-com ec2 us-west-1a
#ci/testnet-sanity.sh testnet-solana-com gce us-east1-c
ok=true
if [[ -n $EC2_NODE_COUNT ]]; then
NO_LEDGER_VERIFY=1 \
ci/testnet-sanity.sh testnet-solana-com ec2 "${EC2_ZONES[0]}" || ok=false
elif [[ -n $GCE_NODE_COUNT ]]; then
NO_LEDGER_VERIFY=1 \
ci/testnet-sanity.sh testnet-solana-com gce "${GCE_ZONES[0]}" || ok=false
else
echo "Error: no EC2 or GCE nodes"
ok=false
fi
$ok
)
;;
testnet-perf)
@ -163,6 +269,22 @@ sanity() {
#ci/testnet-sanity.sh perf-testnet-solana-com ec2 us-east-1a
)
;;
testnet-demo)
(
set -x
ok=true
if [[ -n $GCE_NODE_COUNT ]]; then
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-sanity.sh demo-testnet-solana-com gce "${GCE_ZONES[0]}" -f || ok=false
else
echo "Error: no GCE nodes"
ok=false
fi
$ok
)
;;
*)
echo "Error: Invalid TESTNET=$TESTNET"
exit 1
@ -170,26 +292,39 @@ sanity() {
esac
}
deploy() {
declare maybeCreate=$1
declare maybeStart=$2
declare maybeStop=$3
declare maybeDelete=$4
start() {
declare maybeDelete=$1
if [[ -z $maybeDelete ]]; then
echo "--- start $TESTNET"
echo "--- deploy \"$maybeCreate\" \"$maybeStart\" \"$maybeStop\" \"$maybeDelete\""
# Create or recreate the nodes
if [[ -z $maybeCreate ]]; then
skipCreate=skip
else
echo "--- stop $TESTNET"
skipCreate=""
fi
# Start or restart the network software on the nodes
if [[ -z $maybeStart ]]; then
skipStart=skip
else
skipStart=""
fi
declare maybeReuseLedger=$2
case $TESTNET in
testnet-edge)
(
set -x
NO_VALIDATOR_SANITY=1 \
RUST_LOG=solana=info \
ci/testnet-deploy.sh edge-testnet-solana-com ec2 us-west-1a \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P -a eipalloc-0ccd4f2239886fa94 \
${maybeReuseLedger:+-r} \
${maybeDelete:+-D}
ci/testnet-deploy.sh -p edge-testnet-solana-com -C ec2 -z us-west-1a \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P -a eipalloc-0ccd4f2239886fa94 \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--hashes-per-tick auto
)
;;
testnet-edge-perf)
@ -197,23 +332,27 @@ start() {
set -x
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh edge-perf-testnet-solana-com ec2 us-west-2b \
RUST_LOG=solana=warn \
ci/testnet-deploy.sh -p edge-perf-testnet-solana-com -C ec2 -z us-west-2b \
-g -t "$CHANNEL_OR_TAG" -c 2 \
-b \
${maybeReuseLedger:+-r} \
${maybeDelete:+-D}
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--hashes-per-tick auto
)
;;
testnet-beta)
(
set -x
NO_VALIDATOR_SANITY=1 \
RUST_LOG=solana=info \
ci/testnet-deploy.sh beta-testnet-solana-com ec2 us-west-1a \
ci/testnet-deploy.sh -p beta-testnet-solana-com -C ec2 -z us-west-1a \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P -a eipalloc-0f286cf8a0771ce35 \
-b \
${maybeReuseLedger:+-r} \
${maybeDelete:+-D}
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--hashes-per-tick auto
)
;;
testnet-beta-perf)
@ -221,27 +360,42 @@ start() {
set -x
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh beta-perf-testnet-solana-com ec2 us-west-2b \
RUST_LOG=solana=warn \
ci/testnet-deploy.sh -p beta-perf-testnet-solana-com -C ec2 -z us-west-2b \
-g -t "$CHANNEL_OR_TAG" -c 2 \
-b \
${maybeReuseLedger:+-r} \
${maybeDelete:+-D}
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--hashes-per-tick auto
)
;;
testnet)
(
set -x
NO_VALIDATOR_SANITY=1 \
RUST_LOG=solana=info \
ci/testnet-deploy.sh testnet-solana-com ec2 us-west-1a \
-t "$CHANNEL_OR_TAG" -n 3 -c 0 -u -P -a eipalloc-0fa502bf95f6f18b2 \
-b \
${maybeReuseLedger:+-r} \
${maybeDelete:+-D}
#ci/testnet-deploy.sh testnet-solana-com gce us-east1-c \
# -t "$CHANNEL_OR_TAG" -n 3 -c 0 -P -a testnet-solana-com \
# ${maybeReuseLedger:+-r} \
# ${maybeDelete:+-D}
if [[ -n $GCE_NODE_COUNT ]] || [[ -n $skipStart ]]; then
maybeSkipStart="skip"
fi
# shellcheck disable=SC2068
ci/testnet-deploy.sh -p testnet-solana-com -C ec2 ${EC2_ZONE_ARGS[@]} \
-t "$CHANNEL_OR_TAG" -n "$EC2_NODE_COUNT" -c 0 -u -P -f -a eipalloc-0fa502bf95f6f18b2 \
${skipCreate:+-e} \
${maybeSkipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D}
if [[ -n $GCE_NODE_COUNT ]]; then
# shellcheck disable=SC2068
ci/testnet-deploy.sh -p testnet-solana-com -C gce ${GCE_ZONE_ARGS[@]} \
-t "$CHANNEL_OR_TAG" -n "$GCE_NODE_COUNT" -c 0 -P -f \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
-x
fi
)
;;
testnet-perf)
@ -249,18 +403,50 @@ start() {
set -x
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh perf-testnet-solana-com gce us-west1-b \
-G "n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100" \
RUST_LOG=solana=warn \
ci/testnet-deploy.sh -p perf-testnet-solana-com -C gce -z us-west1-b \
-G "--machine-type n1-standard-16 --accelerator count=2,type=nvidia-tesla-v100" \
-t "$CHANNEL_OR_TAG" -c 2 \
-b \
-d pd-ssd \
${maybeReuseLedger:+-r} \
${maybeDelete:+-D}
#ci/testnet-deploy.sh perf-testnet-solana-com ec2 us-east-1a \
# -g \
# -t "$CHANNEL_OR_TAG" -c 2 \
# ${maybeReuseLedger:+-r} \
# ${maybeDelete:+-D}
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--hashes-per-tick auto
)
;;
testnet-demo)
(
set -x
if [[ -n $GCE_LOW_QUOTA_NODE_COUNT ]] || [[ -n $skipStart ]]; then
maybeSkipStart="skip"
fi
# shellcheck disable=SC2068
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh -p demo-testnet-solana-com -C gce ${GCE_ZONE_ARGS[@]} \
-t "$CHANNEL_OR_TAG" -n "$GCE_NODE_COUNT" -c 0 -P -u -f -w \
-a demo-testnet-solana-com \
${skipCreate:+-e} \
${maybeSkipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--hashes-per-tick auto
if [[ -n $GCE_LOW_QUOTA_NODE_COUNT ]]; then
# shellcheck disable=SC2068
NO_LEDGER_VERIFY=1 \
NO_VALIDATOR_SANITY=1 \
ci/testnet-deploy.sh -p demo-testnet-solana-com2 -C gce ${GCE_LOW_QUOTA_ZONE_ARGS[@]} \
-t "$CHANNEL_OR_TAG" -n "$GCE_LOW_QUOTA_NODE_COUNT" -c 0 -P -f -x -w \
${skipCreate:+-e} \
${skipStart:+-s} \
${maybeStop:+-S} \
${maybeDelete:+-D} \
--hashes-per-tick auto
fi
)
;;
*)
@ -270,44 +456,107 @@ start() {
esac
}
ENABLED_LOCKFILE="${HOME}/${TESTNET}.is_enabled"
create-and-start() {
deploy create start
}
create() {
deploy create
}
start() {
deploy "" start
}
stop() {
start delete
deploy "" ""
}
delete() {
deploy "" "" "" delete
}
enable_testnet() {
touch "${ENABLED_LOCKFILE}"
echo "+++ $TESTNET now enabled"
}
disable_testnet() {
rm -f "${ENABLED_LOCKFILE}"
echo "+++ $TESTNET now disabled"
}
is_testnet_enabled() {
if [[ ! -f ${ENABLED_LOCKFILE} ]]; then
echo "+++ ${TESTNET} is currently disabled. Enable ${TESTNET} by running ci/testnet-manager.sh with \$TESTNET_OP=enable, then re-run with current settings."
exit 0
fi
}
case $TESTNET_OP in
sanity)
sanity
enable)
enable_testnet
;;
disable)
disable_testnet
delete
;;
create-and-start)
is_testnet_enabled
create-and-start
;;
create)
is_testnet_enabled
create
;;
start)
is_testnet_enabled
start
;;
stop)
is_testnet_enabled
stop
;;
sanity)
is_testnet_enabled
sanity
;;
delete)
is_testnet_enabled
delete
;;
update-or-restart)
if start "" update; then
is_testnet_enabled
if start; then
echo Update successful
else
echo "+++ Update failed, restarting the network"
$metricsWriteDatapoint "testnet-manager update-failure=1"
start
create-and-start
fi
;;
sanity-or-restart)
is_testnet_enabled
if sanity; then
echo Pass
else
echo "+++ Sanity failed, updating the network"
$metricsWriteDatapoint "testnet-manager sanity-failure=1"
if start "" update; then
echo Update successful
# TODO: Restore attempt to restart the cluster before recreating it
# See https://github.com/solana-labs/solana/issues/3774
if false; then
if start; then
echo Update successful
else
echo "+++ Update failed, restarting the network"
$metricsWriteDatapoint "testnet-manager update-failure=1"
create-and-start
fi
else
echo "+++ Update failed, restarting the network"
$metricsWriteDatapoint "testnet-manager update-failure=1"
start
create-and-start
fi
fi
;;
*)
echo "Error: Invalid TESTNET_OP=$TESTNET_OP"
exit 1
;;
esac
echo --- fin

View File

@ -11,13 +11,13 @@ usage() {
echo "Error: $*"
fi
cat <<EOF
usage: $0 [name] [cloud] [zone]
usage: $0 [name] [cloud] [zone1] ... [zoneN]
Sanity check a CD testnet
Sanity check a testnet
name - name of the network
cloud - cloud provider to use (gce, ec2)
zone - cloud provider zone of the network
name - name of the network
cloud - cloud provider to use (gce, ec2)
zone1 .. zoneN - cloud provider zones to check
Note: the SOLANA_METRICS_CONFIG environment variable is used to configure
metrics
@ -27,10 +27,10 @@ EOF
netName=$1
cloudProvider=$2
zone=$3
[[ -n $netName ]] || usage ""
[[ -n $cloudProvider ]] || usage "Cloud provider not specified"
[[ -n $zone ]] || usage "Zone not specified"
shift 2
[[ -n $1 ]] || usage "zone1 not specified"
shutdown() {
exitcode=$?
@ -48,20 +48,24 @@ shutdown() {
exit $exitcode
}
rm -rf net/{log,-sanity}
rm -f net/config/config
trap shutdown EXIT INT
set -x
echo "--- $cloudProvider.sh config"
timeout 5m net/"$cloudProvider".sh config -p "$netName" -z "$zone"
net/init-metrics.sh -e
echo "+++ $cloudProvider.sh info"
net/"$cloudProvider".sh info
echo --- net.sh sanity
ok=true
timeout 5m net/net.sh sanity \
${NO_LEDGER_VERIFY:+-o noLedgerVerify} \
${NO_VALIDATOR_SANITY:+-o noValidatorSanity} \
${REJECT_EXTRA_NODES:+-o rejectExtraNodes} || ok=false
for zone in "$@"; do
echo "--- $cloudProvider config [$zone]"
timeout 5m net/"$cloudProvider".sh config -p "$netName" -z "$zone"
net/init-metrics.sh -e
echo "+++ $cloudProvider.sh info"
net/"$cloudProvider".sh info
echo "--- net.sh sanity [$cloudProvider:$zone]"
ok=true
timeout 5m net/net.sh sanity \
${NO_LEDGER_VERIFY:+-o noLedgerVerify} \
${NO_VALIDATOR_SANITY:+-o noValidatorSanity} \
${REJECT_EXTRA_NODES:+-o rejectExtraNodes} \
$zone || ok=false
net/net.sh logs
$ok
net/net.sh logs
$ok
done

View File

@ -0,0 +1,50 @@
#!/usr/bin/env bash
#
# Uploads one or more files to a github release
#
# Prerequisites
# 1) GITHUB_TOKEN defined in the environment
# 2) TAG defined in the environment
#
set -e
REPO_SLUG=solana-labs/solana
if [[ -z $1 ]]; then
echo No files specified
exit 1
fi
if [[ -z $GITHUB_TOKEN ]]; then
echo Error: GITHUB_TOKEN not defined
exit 1
fi
if [[ -n $BUILDKITE_TAG ]]; then
TAG=$BUILDKITE_TAG
elif [[ -n $TRIGGERED_BUILDKITE_TAG ]]; then
TAG=$TRIGGERED_BUILDKITE_TAG
fi
if [[ -z $TAG ]]; then
echo Error: TAG not defined
exit 1
fi
releaseId=$( \
curl -s "https://api.github.com/repos/$REPO_SLUG/releases/tags/$TAG" \
| grep -m 1 \"id\": \
| sed -ne 's/^[^0-9]*\([0-9]*\),$/\1/p' \
)
echo "Github release id for $TAG is $releaseId"
for file in "$@"; do
echo "--- Uploading $file to tag $TAG of $REPO_SLUG"
curl \
--data-binary @"$file" \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Content-Type: application/octet-stream" \
"https://uploads.github.com/repos/$REPO_SLUG/releases/$releaseId/assets?name=$(basename "$file")"
echo
done

View File

@ -1,10 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
channel=${1:-stable}
if ! ./version-check.sh "$channel"; then
rustup install "$channel"
./version-check.sh "$channel"
fi

View File

@ -1,37 +0,0 @@
#!/usr/bin/env bash
set -e
require() {
declare expectedProgram="$1"
declare expectedVersion="$2"
shift 2
read -r program version _ < <($expectedProgram "$@" -V)
declare ok=true
[[ $program = "$expectedProgram" ]] || ok=false
[[ $version =~ $expectedVersion ]] || ok=false
echo "Found $program $version"
if ! $ok; then
echo Error: expected "$expectedProgram $expectedVersion"
exit 1
fi
}
case ${1:-stable} in
nightly)
require rustc 1.34.[0-9]+-nightly +nightly
require cargo 1.34.[0-9]+-nightly +nightly
;;
stable)
require rustc 1.32.[0-9]+
require cargo 1.32.[0-9]+
;;
*)
echo Error: unknown argument: "$1"
exit 1
;;
esac
exit 0

1
client/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

26
client/Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
name = "solana-client"
version = "0.15.0"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
homepage = "https://solana.com/"
license = "Apache-2.0"
edition = "2018"
[dependencies]
bincode = "1.1.4"
bs58 = "0.2.0"
log = "0.4.2"
jsonrpc-core = "10.1.0"
reqwest = "0.9.17"
serde = "1.0.89"
serde_derive = "1.0.91"
serde_json = "1.0.39"
solana-netutil = { path = "../netutil", version = "0.15.0" }
solana-sdk = { path = "../sdk", version = "0.15.0" }
[dev-dependencies]
jsonrpc-core = "10.1.0"
jsonrpc-http-server = "10.1.0"
solana-logger = { path = "../logger", version = "0.15.0" }

View File

@ -0,0 +1,50 @@
use crate::rpc_request;
use solana_sdk::transaction::TransactionError;
use std::{fmt, io};
#[derive(Debug)]
pub enum ClientError {
Io(io::Error),
Reqwest(reqwest::Error),
RpcError(rpc_request::RpcError),
SerdeJson(serde_json::error::Error),
TransactionError(TransactionError),
}
impl fmt::Display for ClientError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "solana client error")
}
}
impl std::error::Error for ClientError {}
impl From<io::Error> for ClientError {
fn from(err: io::Error) -> ClientError {
ClientError::Io(err)
}
}
impl From<reqwest::Error> for ClientError {
fn from(err: reqwest::Error) -> ClientError {
ClientError::Reqwest(err)
}
}
impl From<rpc_request::RpcError> for ClientError {
fn from(err: rpc_request::RpcError) -> ClientError {
ClientError::RpcError(err)
}
}
impl From<serde_json::error::Error> for ClientError {
fn from(err: serde_json::error::Error) -> ClientError {
ClientError::SerdeJson(err)
}
}
impl From<TransactionError> for ClientError {
fn from(err: TransactionError) -> ClientError {
ClientError::TransactionError(err)
}
}

View File

@ -0,0 +1,11 @@
use crate::client_error::ClientError;
use crate::rpc_request::RpcRequest;
pub(crate) trait GenericRpcClientRequest {
fn send(
&self,
request: &RpcRequest,
params: Option<serde_json::Value>,
retries: usize,
) -> Result<serde_json::Value, ClientError>;
}

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