Compare commits

..

226 Commits

Author SHA1 Message Date
Trent Nelson
838aaee144 CLI: Factor out offline helpers (bp #12382) 2020-09-24 04:41:30 +00:00
mergify[bot]
c0e44b624e Docs: Set realistic stake warm-up expectations for validators (#12436)
(cherry picked from commit 215bbe85d8)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-09-24 03:01:38 +00:00
mergify[bot]
41ca59ea0e Move dropping AppendVecs outside lock (#12408) (#12429)
* Move drop outside lock

Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 55be8d4016)

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-23 23:03:44 +00:00
mergify[bot]
a76e175fd0 RpcClient::get_multiple_accounts() now works (#12427)
(cherry picked from commit ff890c173c)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-23 21:56:23 +00:00
Tyera Eulberg
35a1ab981c v1.3: Backport block time updates (#12423)
* Submit a vote timestamp every vote (#10630)

* Submit a timestamp for every vote

* Submit at most one vote timestamp per second

* Submit a timestamp for every new vote

Co-authored-by: Tyera Eulberg <tyera@solana.com>

* Timestamp first vote (#11856)

* Cache block time in Blockstore (#11955)

* Add blockstore column to cache block times

* Add method to cache block time

* Add service to cache block time

* Update rpc getBlockTime to use new method, and refactor blockstore slightly

* Return block_time with confirmed block, if available

* Add measure and warning to cache-block-time

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-23 13:54:49 -06:00
mergify[bot]
0f3a555af5 Document getConfirmedSignaturesForAddress2 until param (#12424) (#12425)
(cherry picked from commit a713e3c92d)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-23 19:47:00 +00:00
mergify[bot]
5366a3c887 Fix solana-tokens check_payer_balances for distribute-stake (bp #12380) (#12403)
* Fix solana-tokens check_payer_balances for distribute-stake (#12380)

* Handle distribute-stakes properly

* Remove dry-run gating for balance checks

* Reword and simplify InsufficientFunds errors

* Split up test and add helpers

* Rename sol_for_fees -> unlocked_sol

* Refactor distribute_allocations to collect Messages

* Clippy

* Clean up dangling bids

(cherry picked from commit 6563726f22)

# Conflicts:
#	tokens/src/commands.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-09-23 05:27:01 +00:00
Trent Nelson
486b657fca validator: Add --require-tower stub arg 2020-09-23 05:01:12 +00:00
mergify[bot]
e545bdcb51 Bump spl-token (bp #12395) (#12400)
* Bump spl-token (#12395)

(cherry picked from commit e1a212fb79)

# Conflicts:
#	Cargo.lock
#	account-decoder/Cargo.toml
#	core/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-09-23 01:08:20 +00:00
mergify[bot]
65e4aac306 Add blockstore column to store performance sampling data (bp #12251) (#12393)
* Add blockstore column to store performance sampling data (#12251)

* Add blockstore column to store performance sampling data

* introduce timer and write performance metrics to blockstore

* introduce getRecentPerformanceSamples rpc

* only run on rpc nodes enabled with transaction history

* add unit tests for get_recent_performance_samples

* remove RpcResponse from rpc call

* refactor to use Instant::now and elapsed for timer

* switch to root bank and ensure not negative subraction

* Add PerfSamples to purge/compaction

* refactor to use Instant::now and elapsed for timer

* switch to root bank and ensure not negative subraction

* remove duplicate constants

Co-authored-by: Tyera Eulberg <tyera@solana.com>
(cherry picked from commit 65a6bfad09)

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

* merge cherry pick of 65a6bfad0

Co-authored-by: Josh <josh.hundley@gmail.com>
2020-09-22 22:00:51 +00:00
mergify[bot]
339e72d8d2 Simplify cli node version output, display semver only by default (#12386)
(cherry picked from commit 4fa443becf)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-22 08:07:28 +00:00
mergify[bot]
0f3208dece Cleanup and feature gate instruction processing (#12359) (#12384)
(cherry picked from commit 22d8b3c3f8)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-09-22 06:19:14 +00:00
mergify[bot]
a85a2839e4 Add way to look at tx instructions (#11943) (#12375)
Co-authored-by: sakridge <sakridge@gmail.com>
2020-09-22 00:59:46 +00:00
mergify[bot]
4fc9f12d7b CLI: Drop unused runtime dep (#12374)
(cherry picked from commit 6767264aa1)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-09-21 20:38:44 +00:00
mergify[bot]
8af90c9c08 Add keccak-secp256k1 instruction (#11839) (#12368)
* Implement keccak-secp256k1 instruction

Verifies eth addreses with ecrecover function

* Move secp256k1 test

Co-authored-by: sakridge <sakridge@gmail.com>
2020-09-21 18:09:05 +00:00
mergify[bot]
7db0464d1b Bind to correct RPC addresses (#12358)
(cherry picked from commit 65b247a922)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-20 08:33:07 +00:00
Michael Vines
bc774e3ea6 Bump version to v1.3.13 2020-09-20 05:40:32 +00:00
Michael Vines
64af712723 Use validator_config for RPC address instead of cluster_info for port verification checks 2020-09-20 02:27:35 +00:00
Michael Vines
ea2611f3a9 Document that testnet has a faucet 2020-09-19 17:41:13 -07:00
mergify[bot]
a26e1f62bb validator/ cleanup (bp #12340) (#12352)
* validator/ cleanup

(cherry picked from commit 1a03afccb1)

# Conflicts:
#	core/src/validator.rs

* Move TestValidator into its own module

(cherry picked from commit 208dd1de3a)

# Conflicts:
#	core/src/validator.rs
#	tokens/tests/commands.rs

* Rebase

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-19 22:45:09 +00:00
mergify[bot]
54b87b34c3 Add get_token_account methods (#12346) (#12349)
(cherry picked from commit 28f2c15597)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-19 03:53:51 +00:00
mergify[bot]
12327c8683 Improve error message when .config/solana/id.json is not found (#12345)
(cherry picked from commit 0ed7b0561e)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-19 00:44:16 +00:00
Trent Nelson
86554c4945 Docs: Add SPL Token exchange integration (bp #12303) 2020-09-19 00:37:25 +00:00
Tyera Eulberg
95ed3641c6 Add blocktime column to blockstore (#12336) 2020-09-18 21:42:45 +00:00
mergify[bot]
83c775cee8 Unbreak 'Listening for Deposits' section (#12338) (#12339)
(cherry picked from commit 06906413ef)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-18 21:19:15 +00:00
mergify[bot]
9fbbb7b044 SendTransactionServices now exit their thread on channel drop instead of by a flag (bp #12333) (#12335)
* Give the duplicate send_transaction_service a different thread name

(cherry picked from commit 75c3690ccd)

* SendTransactionServices now exit their thread on channel drop instead of by a flag

(cherry picked from commit c4913e3c9e)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-18 18:32:06 +00:00
mergify[bot]
7656034bd4 Fix blockstore processor squash (#12319) (#12323)
(cherry picked from commit 3533e11786)

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-18 05:34:37 +00:00
mergify[bot]
3ede265ff9 Add Pack and COption to sdk (bp #12294) (#12322)
* Add Pack and COption to sdk (#12294)

* Add COption to sdk

* Add Pack to sdk

* Except program_option from nits check

* No Default::default

(cherry picked from commit 58542cf7f6)

# Conflicts:
#	ci/nits.sh

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-09-18 04:31:09 +00:00
mergify[bot]
a20e954a16 Restore --expected-shred-version argument for mainnet-beta (#12300)
(cherry picked from commit 9410eab2af)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-17 01:20:25 +00:00
mergify[bot]
1f69b125ce Remove client resends (#12290) (#12296)
* Remove resends from client send_tx methods

* Retry status queries until blockhash expires

(cherry picked from commit a79790dea6)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-17 01:01:40 +00:00
mergify[bot]
0196c83846 Fix panic in BanksServer (#12293) (#12295)
Fixes #12167

(cherry picked from commit 3ecb390b10)

Co-authored-by: Greg Fitzgerald <greg@solana.com>
2020-09-17 00:36:30 +00:00
Justin Starry
37175d0cdf Fix off-by-one max payload checks
(cherry picked from commit f6cda2579f)
2020-09-16 17:05:09 -07:00
mergify[bot]
a6e73acfa4 Rework snapshot download logic to be more forgiving when --expected-shred-version is not provided (#12289)
(cherry picked from commit 98cfe92745)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-16 21:37:57 +00:00
mergify[bot]
f00c504555 RPC: Limit request payload size to 50kB (#12287)
(cherry picked from commit 32dcce0ac1)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-09-16 21:26:31 +00:00
mergify[bot]
19eb73d645 docs: Fix 'Description will go into a meta tag in head' meta tag (bp #12277) (#12279)
* Fix 'Description will go into a meta tag in head' meta tag

(cherry picked from commit 5d682d2e05)

* Update index.js

(cherry picked from commit c231bb7154)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-16 16:56:26 +00:00
mergify[bot]
d35dc79ee7 RPC sendTransaction now returns transaction logs on simulation failure (bp #12267) (#12276)
* RPC sendTransaction now returns transaction logs on simulation failure

(cherry picked from commit 749208fa32)

* Remove stale comment

(cherry picked from commit c6eea94edc)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-16 16:45:09 +00:00
mergify[bot]
2316846c53 solana-tokens: Add capability to perform the same transfer to a batch of recipients (bp #12259) (#12266)
* solana-tokens: Add capability to perform the same transfer to a batch of recipients (#12259)

* Add transfer-amount argument, use simplified input-csv

* Add transfer-amount to readme

(cherry picked from commit a48cc073cf)

# Conflicts:
#	tokens/src/commands.rs
#	tokens/tests/commands.rs

* Fix build

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-09-16 06:21:40 +00:00
mergify[bot]
c77fe54629 CLI: Use Base58 encoding rather than deprecated Binary for TX decode (#12265)
(cherry picked from commit 83f93fed02)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-09-16 05:43:38 +00:00
mergify[bot]
953c40a9e3 Improve solana-tokens UX (#12253) (#12260)
* Fix computed banks port

* Readme incorrect

* Return error if csv cannot be read

* Move column headers over columns

* Add dry-run check for sender/fee-payer balances

* Use clap requires method for paired args

* Write transaction-log anytime outfile is specified

* Replace campaign-name with required db-path

* Remove bids

* Exclude new_stake_account_address from logs for non-stake distributions

* Fix readme

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-16 04:50:55 +00:00
mergify[bot]
c10f14d60b Add lockups via solana-tokens (bp #11782) (#12263)
* Add lockups via solana-tokens (#11782)

* Allow stake distributions to update lockups

* Reorg

* Add lockup test

* Fix clippy warning

(cherry picked from commit 5553732ae2)

# Conflicts:
#	tokens/Cargo.toml
#	tokens/src/commands.rs
#	tokens/src/main.rs

* Fix build

Co-authored-by: Greg Fitzgerald <greg@solana.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-09-16 03:33:39 +00:00
mergify[bot]
c3c3872f8d validator-info get/set no longer crash on invalid account data (#12258)
(cherry picked from commit 56282f0c01)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-16 01:17:45 +00:00
mergify[bot]
c539526f1e Add memory allocation support for C programs (#12254) (#12256)
(cherry picked from commit 5ab4109b7e)

Co-authored-by: Jack May <jack@solana.com>
2020-09-16 00:49:36 +00:00
mergify[bot]
8ea4c1c2c0 Friendlier error message for mapping failures (#12213) (#12255)
(cherry picked from commit 3d4b9bb00d)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-09-16 00:21:11 +00:00
mergify[bot]
557fee8183 Make noop a real noop (bp #12196) (#12247)
* Make noop a real noop (#12196)

* Make noop a real noop

* nudge

(cherry picked from commit 555252f435)

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-09-15 23:16:15 +00:00
mergify[bot]
1957e960ac Add BPF test program instruction monitoring (bp #11984) (#12248)
* Add BPF test program instruction monitoring (#11984)


(cherry picked from commit fab2d44abd)

* fix conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-09-15 23:16:01 +00:00
mergify[bot]
11ff80c64b Cache re-usable work performed by the loader (bp #12135) (#12216)
* Cache re-usable work performed by the loader (#12135)

(cherry picked from commit 3278d78f08)

# Conflicts:
#	programs/bpf/Cargo.toml
#	programs/bpf/tests/programs.rs
#	programs/bpf_loader/Cargo.toml

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-09-15 21:25:32 +00:00
Ryo Onodera
7267257073 Bump version to v1.3.12 (#12249) 2020-09-15 20:15:03 +00:00
mergify[bot]
f107b9b423 Really skip private rpc port reachable checks (#12239) (#12241)
(cherry picked from commit b85e8497b5)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-15 17:43:23 +00:00
mergify[bot]
1354a0c1a3 Drop the recommendation that --expected-shred-version be set by validators (#12244)
`--expected-shred-version` is another knob for users to get wrong and is
documentation that can get stale due to cluster restarts.  Turns out
it's also generally not required anymore either because:
1. The cluster entrypoint can always be expected to be using the correct
   shred version, and that shred version will be adopted by the new node
   (earlier this was not the case when the `solana-gossip spy` node on
   mainnet-beta.solana.com:8001 ran with shred version 0)
2. On a cluster restart, `--expected-bank-hash` is a much stronger
   assertion that the validator is starting from the correct place (and
   didn't exist when `--expected-shred-version` was first recommended)

(cherry picked from commit 4ada4d43f2)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-15 17:41:36 +00:00
Ryo Onodera
52ee9155b5 Bump version to v1.3.11 (#12238) 2020-09-15 10:25:22 +00:00
mergify[bot]
65a1884c7b Enable stricter check on rent-exempt accounts on testnet (#12224) (#12226)
(cherry picked from commit 241e6f1ecf)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-15 08:07:23 +00:00
mergify[bot]
c1a9c826f3 Enable retirement of rent collect in Bank::deposit() on testnet (#12223) (#12227)
(cherry picked from commit 629572831b)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-15 07:53:36 +00:00
mergify[bot]
d9d8ec480a Enable eager-rent-collect-across-gapped-epochs bugfix (#12219) (#12222)
(cherry picked from commit 7d48339b7c)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-15 06:14:35 +00:00
mergify[bot]
b5c7ad3a9b Add new validator options for running in more restrictive environments (bp #12191) (#12218)
* Add --restricted-repair-only-mode flag

(cherry picked from commit 63a67f415e)

* Add --gossip-validator argument

(cherry picked from commit daae638781)

* Documenet how to reduce validator port exposure

(cherry picked from commit c8f03c7f6d)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-15 04:26:23 +00:00
mergify[bot]
771ff65fb4 Faucet: Improve error handling (#12215)
(cherry picked from commit af2262cbba)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-09-15 01:31:02 +00:00
mergify[bot]
a5bf59b92a patches default impl for crds filter (#12199) (#12200)
In CrdsFilter.mask all bits after mask_bits are set to 1:
https://github.com/solana-labs/solana/blob/555252f4/core/src/crds_gossip_pull.rs#L65
However the default implementation, sets both mask and mask_bits to zero
which is inconsistent with CrdsFilter::compute_mask for a mask_bits of
zero.

This commit changes the default implementation by setting mask to
`!0u64` (i.e all bits set to one). As a result, for the default crds
filter, `test_mask` will always return true, whereas previously it was
always returning false.
https://github.com/solana-labs/solana/blob/555252f4/core/src/crds_gossip_pull.rs#L85

This is only used in tests and benchmarks, but causes some benchmarks to
be misleading by short circuiting in this line:
https://github.com/solana-labs/solana/blob/555252f4/core/src/crds_gossip_pull.rs#L429

(cherry picked from commit d6ec03f13c)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-09-13 14:10:42 +00:00
mergify[bot]
8dc019ae98 Gate pointer alignment enforcement (bp #12176) (#12188)
* Gate pointer alignment enforcement (#12176)

(cherry picked from commit ae7b15f062)

# Conflicts:
#	programs/bpf/tests/programs.rs

* Fix conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-09-12 00:06:39 +00:00
mergify[bot]
61dcab8c07 Update commitment options (#12173) (#12189)
(cherry picked from commit 3c69cd6d61)

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-11 19:24:16 +00:00
mergify[bot]
640bf7015f Check bank capitalization (bp #11927) (#12184)
* Check bank capitalization (#11927)

* Check bank capitalization

* Simplify and unify capitalization calculation

* Improve and add tests

* Avoid overflow and inhibit automatic restart

* Fix test

* Tweak checked sum for cap. and add tests

* Fix broken build after merge conflicts..

* Rename to ClusterType

* Rename confusing method

* Clarify comment

* Verify cap. in rent and inflation tests

Co-authored-by: Stephen Akridge <sakridge@gmail.com>
(cherry picked from commit de4a613610)

# Conflicts:
#	Cargo.lock
#	accounts-bench/Cargo.toml

* Fix conflict 1/2

* Fix conflict 2/2

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-11 18:04:10 +00:00
mergify[bot]
db1f57162a Fix propagation on startup from snapshot (#12177) (#12182)
(cherry picked from commit 9c490e06b0)

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-11 10:04:55 +00:00
mergify[bot]
bbddffa805 solana-validator --rpc-bind-address argument now works as expected (bp #12168) (#12174)
* `solana-validator --rpc-bind-address` argument now works as expected

(cherry picked from commit 6f325d4594)

* Update bootstrap-validator.sh

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-10 22:02:50 +00:00
mergify[bot]
61cf432477 Update commitment options (#12171) (#12172)
(cherry picked from commit 361e5322e4)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-10 13:55:48 -06:00
mergify[bot]
9396618c12 Calc size ahead of time to alloc once (#12154) (#12169)
(cherry picked from commit fd47d38e59)

Co-authored-by: Jack May <jack@solana.com>
2020-09-10 19:17:20 +00:00
mergify[bot]
398f12dcc5 Program subscriptions now properly check results len and token program id (#12139) (#12141)
(cherry picked from commit 4431080066)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-09 22:23:11 +00:00
mergify[bot]
796624adf9 uses rust intrinsics to convert hashes to u64 (#12097) (#12133)
(cherry picked from commit 28f2fa3fd5)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-09-09 16:33:15 +00:00
mergify[bot]
f6e266eff0 Activate new bpf loader on devnet (#12124)
(cherry picked from commit f54941fa15)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-09 05:48:18 +00:00
mergify[bot]
ed237af4d8 Prevent unbound memory growth by blockstore_processor (#12110) (#12122)
* Prevent unbound memory growth by blockstore_processor

* Promote log to info! considering infrequency

* Exclude the time of freeing from interval...

* Skip not-shrinkable slots even if forced

* Add comment

(cherry picked from commit c274e26eb8)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-09 04:09:27 +00:00
Michael Vines
415c80c204 Bump version to v1.3.10 2020-09-09 01:29:39 +00:00
mergify[bot]
e45f1df5dd Reduce cap by rent's leftover as temporary measure (#12111) (#12118)
* Reduce cap by rent's leftover as temporary measure

* Reset testnet cap. on start and more logs

(cherry picked from commit 5b2442d54e)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-08 20:02:46 +00:00
mergify[bot]
d26a809f1f getMinimumBalanceForRentExemption now only responds to valid account lengths (#12116)
(cherry picked from commit 9e96180ce4)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-08 18:50:22 +00:00
mergify[bot]
d1fdc96969 Add support for deprecated loader (bp #11946) (#12114)
* Add support for deprecated loader (#11946)


(cherry picked from commit ae0fd3043a)

* fix version

Co-authored-by: Jack May <jack@solana.com>
2020-09-08 18:41:29 +00:00
mergify[bot]
a5cad340ed Forward transactions to the expected leader instead of your own TPU port (bp #12004) (#12108)
* Forward transactions to the expected leader instead of your own TPU port (#12004)

* Use PoHRecorder to send to the right leader

* cleanup

* fmt

* clippy

* Cleanup, fix bug

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

# Conflicts:
#	banks-server/Cargo.toml

* Update Cargo.toml

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-08 16:51:33 +00:00
Ryo Onodera
2341394e8b Rename to ClusterType and restore devnet compat. (manual bp) (#12069)
* Rename to ClusterType and restore devnet compat.

* De-duplicate parse code and add comments

* Adjust default Devnet genesis & reduce it in tests
2020-09-08 23:54:54 +09:00
mergify[bot]
180224114a Fix RPC transaction method configs serialization (#12100) (#12102)
(cherry picked from commit 9940870c89)

Co-authored-by: Justin Starry <justin@solana.com>
2020-09-08 06:12:26 +00:00
Justin Starry
58312655b4 Fix signature subscription panic (#12077) (#12092) 2020-09-07 10:31:25 +00:00
mergify[bot]
f3f86f43ee Compress snapshot archive within the validator to reduce system dependencies, and default to zstd compression (bp #12085) (#12087)
* Compress snapshot archive within the validator to reduce system dependencies

(cherry picked from commit d3750b47d2)

* Default snapshot compression to zstd instead of bzip2 for quicker snapshot generation

(cherry picked from commit 9ade73841f)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-07 06:55:38 +00:00
mergify[bot]
aac38516da cli: add block and first-available-block commands (bp #12083) (#12084)
* Add first-available-block command

(cherry picked from commit 6677996369)

* Add block command

(cherry picked from commit 27752c4e4d)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-06 20:53:44 +00:00
mergify[bot]
cd139b8185 Fix bad predicate with malformed gossip votes (#12072) (#12078)
(cherry picked from commit eabc63cdcd)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-06 05:35:00 +00:00
mergify[bot]
6a74bc1297 validator: Add --enable-bigtable-ledger-upload flag (bp #12040) (#12057)
* Add --enable-bigtable-ledger-upload flag

(cherry picked from commit d8e2038dda)

* Relocate BigTable uploader to ledger/ crate

(cherry picked from commit 91a56caed2)

# Conflicts:
#	ledger/Cargo.toml

* Cargo.lock

(cherry picked from commit 2b8a521562)

* Add BigTableUploadService

(cherry picked from commit bc7731b969)

* Add BigTableUploadService

(cherry picked from commit bafdcf24f5)

* Add exit flag for bigtable upload operations

(cherry picked from commit d3611f74c8)

* Remove dead code

(cherry picked from commit cd3c134b58)

* Request correct access

(cherry picked from commit 4ba43c29ce)

* Add LARGEST_CONFIRMED_ROOT_UPLOAD_DELAY

(cherry picked from commit b64fb295a1)

* Resolve merge conflicts

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-05 17:09:32 +00:00
mergify[bot]
e9a2dd0bc1 Add --show-transactions flag to transaction-history command (#12071)
(cherry picked from commit 2332dd774f)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-05 16:52:38 +00:00
mergify[bot]
feed960ef3 Bigtable bug fixes (#12058) (#12060)
* Accommodate stricted get_bincode_cell in get_confirmed_signatures_for_address

* Sort signatures newest-oldest, even within slot

(cherry picked from commit 879c98efeb)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-05 03:31:35 +00:00
mergify[bot]
ae8acada8c Add unlock epochs for blake3 (#12054) (#12056)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit a13efc52b3)

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-04 23:33:53 +00:00
mergify[bot]
357a341db5 Bump getMultipleAccounts input limit (#12050) (#12052)
(cherry picked from commit 954b017f85)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-04 18:58:45 +00:00
mergify[bot]
d0f715cb23 adds new CrdsFilterSet type for Vec<CrdsFilter> (#12029) (#12048)
(cherry picked from commit 114c211b66)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-09-04 14:10:12 +00:00
mergify[bot]
0fc0378347 fix solana-install syntax (#12043)
```
solana-install info
solana-install deploy
solana-install update
solana-install run
```

(cherry picked from commit 38f36a7a7a)

Co-authored-by: pk <4514654+pkrasam@users.noreply.github.com>
2020-09-04 05:40:47 +00:00
mergify[bot]
aa3bdd3730 Revert signature-notification format change (bp #12032) (#12038)
* Revert signature-notification format change (#12032)

* Use untagged RpcSignatureResult enum to avoid breaking downstream consumers of current signature subscriptions

* Clean up client duplication

* Clippy

(cherry picked from commit 39246f9dd7)

# Conflicts:
#	core/src/rpc_pubsub.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-09-04 01:34:49 +00:00
mergify[bot]
962aed0961 Mark a withdraw authority as non-circulating (#12033) (#12036)
(cherry picked from commit 2c091e4fca)

Co-authored-by: Greg Fitzgerald <greg@solana.com>
2020-09-04 00:46:10 +00:00
Josh
bd76810623 Bump version to 1.3.9 (#12034) 2020-09-03 16:55:24 -07:00
mergify[bot]
58fe45f3e5 Don't query modern Ledger wallet app version with deprecated payload size (#12031)
(cherry picked from commit dff8242887)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-09-03 21:55:55 +00:00
mergify[bot]
01a9360dbe builds crds filters without looping over filters (#11998) (#12028)
(cherry picked from commit bc7adb97ed)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-09-03 21:44:00 +00:00
mergify[bot]
f44d9d770a Rpc: add getMultipleAccounts endpoint (bp #12005) (#12024)
* Rpc: add getMultipleAccounts endpoint (#12005)

* Add rpc endpoint to return the state of multiple accounts from the same bank

* Add docs

* Review comments: Dedupe account code, default to base64, add max const

* Add get_multiple_accounts to rpc-client

(cherry picked from commit b22de369b7)

* Use new_response for consistency

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-09-03 19:52:46 +00:00
mergify[bot]
79d9d28e7d Update token amounts in parsed instructions to retain full precision (#12020) (#12022)
(cherry picked from commit b940da4040)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-03 19:22:24 +00:00
mergify[bot]
d273d1acb2 Fix forwarding calculation (#12014) (#12019)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit 3f39ab1e04)

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-03 10:36:56 +00:00
mergify[bot]
991f188f23 Fix test (#12013) (#12017)
(cherry picked from commit 36a294aae0)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-03 17:16:59 +09:00
mergify[bot]
8f02fdcc11 Purge storage rewards from accounts db for testnet (#11996) (#12011)
* Purge storage rewards from accounts db for testnet

* Fix test failing only on stable

(cherry picked from commit fb71ee60aa)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-03 08:01:37 +00:00
mergify[bot]
3e78850331 Move forward token2 native mint testnet epoch (#12007) (#12010)
(cherry picked from commit 4b1cb51a3e)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-03 07:48:55 +00:00
mergify[bot]
f29a741582 Clarify comments and names in inflation code (#11977) (#12008)
(cherry picked from commit 89bca6110a)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-03 06:47:13 +00:00
mergify[bot]
3e6052faca Bigtable method to return a single row of data (#11999) (#12002)
(cherry picked from commit b041afe1be)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-02 21:01:58 +00:00
mergify[bot]
0b0710d522 Use conventional special self notation (#11990) (#11997)
(cherry picked from commit 46aac4819a)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-02 11:59:16 +00:00
mergify[bot]
2f3fced8a8 Switch account hashing to blake3 (#11969) (#11992)
* Switch account hashing to blake3

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

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-02 08:40:07 +00:00
mergify[bot]
a5832366a7 Detect and notify when deserializable shreds are available (bp #11816) (#11988)
* Detect and notify when deserializable shreds are available (#11816)

* Add logic to check for complete data ranges

* Add RPC signature notification

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

# Conflicts:
#	accounts-bench/Cargo.toml
#	core/src/rpc_pubsub.rs

* Fix conflicts

Co-authored-by: carllin <wumu727@gmail.com>
Co-authored-by: Carl <carl@solana.com>
2020-09-02 06:38:10 +00:00
mergify[bot]
f26ff6d6b2 Docs.rs version replacement (#11981) (#11982)
(cherry picked from commit b720921c83)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-09-01 13:52:57 -06:00
mergify[bot]
57f149e415 Ensure that the spl-token 2 native mint account is owned by the spl-token 2 program. (#11974)
Workaround for https://github.com/solana-labs/solana-program-library/issues/374 until spl-token 3 is shipped

(cherry picked from commit 7341e60043)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-09-01 18:16:22 +00:00
mergify[bot]
8ece3847f9 Add tests for the Debug and activation Vecs (#11926) (#11968)
* Add tests for the Debug and activation Vecs

* Rename a bit

(cherry picked from commit 11ac4eb21d)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-09-01 09:54:27 +00:00
mergify[bot]
0d23ad00b1 Update to rayon 1.4.0 (#11898) (#11902)
(cherry picked from commit c4253dc0f9)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-09-01 04:53:39 +00:00
mergify[bot]
d9684f99c3 Remove log (#11949) (#11961)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit 7641b60a2b)

Co-authored-by: carllin <wumu727@gmail.com>
2020-09-01 01:05:20 +00:00
mergify[bot]
6ea9c249d7 Add missing backslash to solana-validator command (#11958)
(cherry picked from commit a19f696a42)

Co-authored-by: Richard Ayotte <rich.ayotte@gmail.com>
2020-08-31 23:43:22 +00:00
mergify[bot]
1e02069f86 Increase message_processor logging to error level (#11945) (#11948)
(cherry picked from commit 9b9d559312)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-08-31 21:26:35 +00:00
mergify[bot]
b179ed0b90 Remove encrypted secrets not required by the main public CI (bp #11942) (#11944)
* Remove unused GEOLOCATION_API_KEY

(cherry picked from commit f78594dfc1)

* Remove secrets not required by the main public CI

(cherry picked from commit 278f2fe078)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-31 18:59:52 +00:00
mergify[bot]
eb65ff750e Simplify get_programs(), specify a real Preview activation epoch for new BPFLoader (#11930)
(cherry picked from commit f385af25e5)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-31 17:21:07 +00:00
Michael Vines
663dc9959f Bump version to v1.3.8 2020-08-31 10:18:42 -07:00
mergify[bot]
53ed6a2298 Fix use-deprecated-loader arg (#11921) (#11929)
(cherry picked from commit 6234909373)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-31 09:53:34 +00:00
mergify[bot]
47962f3e80 Use DNS for devnet/testnet entrypoints (#11922)
(cherry picked from commit e4d7e1fe3f)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-31 07:53:02 +00:00
Michael Vines
d3a16e4e13 Bump RPC banks up 1 port to avoid web3.js wss port conflict
(cherry picked from commit f8bb93a0f4)
2020-08-30 23:56:19 -07:00
Michael Vines
250f5a8196 Add new trusted validator for testnet 2020-08-30 22:51:42 -07:00
Michael Vines
83a17acc17 Add methods to adjust rent burn percentage, and hashes per tick 2020-08-30 16:50:43 -07:00
Michael Vines
ed34b930e5 modify-genesis now writes elsewhere and produces a full genesis.tar.bz2 2020-08-30 16:47:27 -07:00
Michael Vines
95816f7db9 Add ability to fork a local cluster from the latest mainnet-beta snapshot 2020-08-30 16:47:18 -07:00
mergify[bot]
e652c27142 Add bank-hash subcommand (#11915)
(cherry picked from commit a07980536a)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-30 19:05:04 +00:00
mergify[bot]
0811cb2966 Fix get_parsed_token_accounts (#11907) (#11909)
(cherry picked from commit 60c7ac6f95)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-29 19:53:05 +00:00
Michael Vines
311b419f8a Bump version to v1.3.7 2020-08-29 11:42:14 -07:00
Michael Vines
acb992c3be Update to spl-token 2 2020-08-29 09:23:20 -07:00
Tyera Eulberg
61aca235a3 Bump spl-token version 2020-08-29 03:24:36 -06:00
mergify[bot]
bad0709ff1 Update to token pack/unpack changes (bp #11900) (#11903)
* Update to token pack/unpack changes (#11900)

(cherry picked from commit 2eff9a19c3)

# Conflicts:
#	account-decoder/Cargo.toml
#	core/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-08-29 05:46:07 +00:00
mergify[bot]
2a649e990d Update spl-token to v2.0 (bp #11884) (#11897)
* Update spl-token to v2.0 (#11884)

* Update account-decoder to spl-token v2.0

* Update transaction-status to spl-token v2.0

* Update rpc to spl-token v2.0

* Update getTokenSupply to pull from Mint directly

* Fixup to spl-token v2.0.1

(cherry picked from commit 76be36c9ce)

# Conflicts:
#	Cargo.lock
#	account-decoder/Cargo.toml
#	core/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-08-28 23:36:53 +00:00
mergify[bot]
1a25889f72 Take v0.19.3 of perf libs which improves sigverify perf 2x (#11894) (#11895)
(cherry picked from commit 9393dce1ff)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-08-28 20:37:26 +00:00
Trent Nelson
e15dca6961 Update devnet cluster docs since reboot 2020-08-28 10:36:11 -07:00
mergify[bot]
bb12f48014 Add SolFlare as stake-supporting wallet (#11891) (#11892)
Co-authored-by: publish-docs.sh <maintainers@solana.com>
(cherry picked from commit 8ba3a33129)

Co-authored-by: Dan Albert <dan@solana.com>
2020-08-28 16:17:24 +00:00
Jon Cinque
c6416fca6e Bump version to 1.3.6 (#11890) 2020-08-28 16:58:59 +02:00
Jack May
2f5d60bef7 Update epoch gating (#11880) 2020-08-27 21:17:45 -07:00
mergify[bot]
ef1a9df507 Small cleaning around consensus/bank_forks (#11873) (#11881)
(cherry picked from commit d8c529a9b8)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-28 01:06:21 +00:00
mergify[bot]
d2611f54a0 Make ledger-tool accounts print rent_epoch and slot (#11845) (#11870)
(cherry picked from commit 57174cdabe)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-27 04:49:24 +00:00
mergify[bot]
6117f8d64e Add SolFlare guide to docs (#11843) (#11868)
(cherry picked from commit 36e8441149)

Co-authored-by: Dan Albert <dan@solana.com>
2020-08-26 23:13:43 +00:00
mergify[bot]
67d9faaefc Bump compute budget (#11864) (#11867)
* Bump compute budget

* nudge

(cherry picked from commit ea179ad762)

Co-authored-by: Jack May <jack@solana.com>
2020-08-26 23:12:01 +00:00
mergify[bot]
aaa551ca7c Merge pull request #11857 from mvines/cache (#11863)
ci: cargo-target-cache is now channel specific
(cherry picked from commit 5c7080c1f4)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-26 19:50:06 +00:00
mergify[bot]
85df8cb4c5 Accounts hash calculation metrics (#11433) (#11860)
(cherry picked from commit 770d3d383c)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-08-26 19:31:52 +00:00
mergify[bot]
65f189d932 Rpc: Filter accounts with invalid mints from get_parsed_token_accounts (#11844) (#11859)
* Filter out accounts with invalid mints from get_parsed_token_accounts

* Explicit docs

(cherry picked from commit 1988ee9cd6)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-26 19:02:48 +00:00
mergify[bot]
99001f7f2e Bump MacOS nofile recommendation message (#11835)
(cherry picked from commit 8841c3398c)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-08-25 19:57:08 +00:00
mergify[bot]
39eeb0142e Add SystemInstruction::CreateAccount support to CPI (bp #11649) (#11831)
* Add SystemInstruction::CreateAccount support to CPI (#11649)

(cherry picked from commit e9b610b8df)

# Conflicts:
#	programs/bpf_loader/src/syscalls.rs
#	runtime/src/bank.rs
#	sdk/src/instruction.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-08-25 19:52:27 +00:00
mergify[bot]
d5d1a344c3 Switch programs activation to whole-set based gating (bp #11750) (#11837)
* Switch programs activation to whole-set based gating (#11750)

* Implement Debug for MessageProcessor

* Switch from delta-based gating to whole-set gating

* Remove dbg!

* Fix clippy

* Clippy

* Add test

* add loader to stable operating mode at proper epoch

* refresh_programs_and_inflation after ancestor setup

* Callback via snapshot; avoid account re-add; Debug

* Fix test

* Fix test and fix the past history

* Make callback management stricter and cleaner

* Fix test

* Test overwrite and frozen for native programs

* Test epoch callback with genesis-programs

* Add assertions for parent bank

* Add tests and some minor cleaning

* Remove unsteady assertion...

* Fix test...

* Fix DOS

* Skip ensuring account by dual (whole/delta) gating

* Fix frozen abi implementation...

* Move compute budget constatnt init back into bank

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
(cherry picked from commit db4bbb3569)

# Conflicts:
#	genesis-programs/src/lib.rs

* Fix conflicts

Co-authored-by: Jack May <jack@solana.com>
Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-25 19:00:41 +00:00
mergify[bot]
62e3c084d3 Update system tuning and docs (bp #11680) (#11830)
* Sync FD limit and max maps to 500k

(cherry picked from commit 11951eb009)

* Expand system tuning docs

(cherry picked from commit 5354df8c1c)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-08-25 17:13:27 +00:00
mergify[bot]
3027ceb53a Document how to validate account pubkey (#11821) (#11833)
(cherry picked from commit 2c5366f259)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-25 17:11:09 +00:00
mergify[bot]
4e604e1211 Add (hidden) --use-deprecated-loader flag to solana deploy (#11828)
(cherry picked from commit de736e00ad)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-25 16:56:29 +00:00
mergify[bot]
6749bfd1d2 Gate aligned program heap (bp #11808) (#11814)
* Gate aligned program heap (#11808)


(cherry picked from commit c2e5dae7ba)

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-08-25 15:57:15 +00:00
mergify[bot]
d05b39c4f6 Specify loader when bootstrapping bpf programs (#11571) (#11822)
(cherry picked from commit 0a94e7e7fa)

Co-authored-by: Jack May <jack@solana.com>
2020-08-25 07:56:11 -07:00
mergify[bot]
c8e1fbd568 Update comment (#11826) (#11827)
(cherry picked from commit dbd079f54c)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-25 14:48:00 +00:00
mergify[bot]
ad36ddedf1 CPI support for bpf_loader_deprecated (bp #11695) (#11824)
* CPI support for bpf_loader_deprecated (#11695)

(cherry picked from commit 46830124f8)

# Conflicts:
#	programs/bpf_loader/src/syscalls.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-08-25 11:02:06 +00:00
mergify[bot]
08bece7651 More efficient padding (#11656) (#11823)
(cherry picked from commit f1ba2387d3)

Co-authored-by: Jack May <jack@solana.com>
2020-08-25 10:10:59 +00:00
mergify[bot]
f162c6d1d0 Align host addresses (bp #11384) (#11817)
* Align host addresses (#11384)

* Align host addresses

* support new program abi

* update epoch rollout

* Enforce aligned pointers in cross-program invocations

(cherry picked from commit 9290e561e1)

# Conflicts:
#	core/src/validator.rs
#	genesis-programs/src/lib.rs
#	programs/bpf_loader/src/deprecated.rs
#	programs/bpf_loader/src/lib.rs
#	sdk/src/entrypoint_native.rs
#	sdk/src/lib.rs

* resolve conflicts

* nudge

Co-authored-by: Jack May <jack@solana.com>
2020-08-25 07:23:20 +00:00
mergify[bot]
f3904b5765 sdk: Make PubKey::create_program_address available in program unit tests (bp #11745) (#11810)
* sdk: Make PubKey::create_program_address available in program unit tests (#11745)

* sdk: Make PubKey::create_program_address available in program unit tests

This finishes the work started in #11604 to have
`create_program_address` available when `target_arch` is not `bpf` and
`program` is enabled.  Otherwise, there is an undefined reference error
to `sol_create_program_address`, which is only defined in `bpf`.

A small test to simply call the function has been added in order to catch
the problem in the future.

The default dependency to `solana-sdk/default` doesn't cause a problem with
existing programs since `build.sh` always specifies
`--no-default-features`, and programs in `solana-program-library` all
use it too.

* Add `default-features = false` for inter-program dependencies

Fix the build error found during CI.  The `--no-default-features` flag
only applies to the top-level package, and not to dependencies.  A program that
depends on another program, i.e. `128bit` which depends on `128bit_dep`,
must specify `default-features = false` when including that package,
otherwise the `bpf` build will try to pull in default packages, which
includes `std`.

(cherry picked from commit 9a366281d3)

# Conflicts:
#	programs/bpf/rust/128bit/Cargo.toml
#	programs/bpf/rust/invoke/Cargo.toml
#	programs/bpf/rust/many_args/Cargo.toml
#	programs/bpf/rust/param_passing/Cargo.toml

* resolve conflicts

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
Co-authored-by: Jack May <jack@solana.com>
2020-08-24 20:41:54 +00:00
mergify[bot]
67bf7515a7 Aligned program heap (#11657) (#11812)
(cherry picked from commit f8606fca4f)

Co-authored-by: Jack May <jack@solana.com>
2020-08-24 20:12:58 +00:00
mergify[bot]
0dcbc6d4d1 The constraints on compute power a program can consume is limited only to its instruction count (bp #11717) (#11800)
* The constraints on compute power a program can consume is limited only to its instruction count (#11717)

(cherry picked from commit 8d362f682b)

# Conflicts:
#	programs/bpf/Cargo.toml
#	programs/bpf_loader/Cargo.toml
#	programs/bpf_loader/src/lib.rs
#	programs/bpf_loader/src/syscalls.rs
#	runtime/src/bank.rs
#	sdk/src/instruction.rs

* Resolve conflicts

* nudge

Co-authored-by: Jack May <jack@solana.com>
2020-08-24 17:27:40 +00:00
mergify[bot]
79a2ccabb4 Return an error from create_program_address syscall (bp #11658) (#11789)
* Return an error from create_program_address syscall (#11658)

(cherry picked from commit 750e5344f1)

# Conflicts:
#	programs/bpf_loader/src/syscalls.rs

* resolve conflicts

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-08-24 04:30:29 +00:00
mergify[bot]
f5e583ef0d solana-gossip spy can now be given an identity keypair (--identity argument) (#11797)
(cherry picked from commit a1e2357d12)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-23 01:14:42 +00:00
mergify[bot]
132550cd7a RPC: Allow the sendTransaction preflight commitment level to be configured (bp #11792) (#11794)
* Allow the sendTransaction preflight commitment level to be configured

(cherry picked from commit b660704faa)

* rebase

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-22 16:41:25 +00:00
Michael Vines
08a789323f Fix typo 2020-08-22 09:22:41 -07:00
mergify[bot]
2d9781b101 Add option for repairing only from trusted validators (#11752) (#11773)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit c8d67aa8eb)

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-21 20:40:37 -07:00
mergify[bot]
6540d3c63e Make BPF Loader static (bp #11516) (#11790)
* Make BPF Loader static (#11516)

(cherry picked from commit 7c736f71fe)

# Conflicts:
#	Cargo.lock
#	core/Cargo.toml
#	core/src/lib.rs
#	core/src/validator.rs
#	genesis-programs/src/lib.rs
#	programs/bpf_loader/src/deprecated.rs
#	programs/bpf_loader/src/lib.rs
#	sdk/src/entrypoint_native.rs
#	sdk/src/lib.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2020-08-22 01:54:50 +00:00
mergify[bot]
a227b813d8 Feature check CPI up front (#11652) (#11787)
(cherry picked from commit 4196686acf)

Co-authored-by: Jack May <jack@solana.com>
2020-08-22 01:27:33 +00:00
mergify[bot]
2b4e0abb43 fix region checks (#11651) (#11785)
(cherry picked from commit 768b386f0a)

Co-authored-by: Jack May <jack@solana.com>
2020-08-22 01:14:13 +00:00
mergify[bot]
cdf6ff7907 Fix filter_crds_values output alignment with the inputs (#11734) (#11781)
(cherry picked from commit 418b483af6)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2020-08-21 20:56:26 +00:00
mergify[bot]
6775e01747 Add StakeInstruction::AuthorizeWithSeed (#11700) (#11779)
* Add StakeInstruction::AuthorizeWithSeed

* chore: add authorize-with-seed to web.js

* fix: add address_owner

* Add SystemInstruction::TransferWithSeed

* Update ABI hash

* chore: better variable names

* Add AuthorizeWithSeedArgs

* Reorder and rename arguments for clarity

(cherry picked from commit f02a78d8ff)

Co-authored-by: Greg Fitzgerald <greg@solana.com>
2020-08-21 19:39:36 +00:00
mergify[bot]
4be9d5030d Squash supermajority root on blockstore replay at startup (#11727) (#11765)
(cherry picked from commit f7adb68599)

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-21 08:20:09 +00:00
carllin
a9f914da8e Cleanup test utilities (#11766)
* Add voting utility

* Add blockstore utility

Co-authored-by: Carl <carl@solana.com>
2020-08-21 06:52:01 +00:00
mergify[bot]
096375584b Rpc: Return error if block does not exist (#11743) (#11749)
* Return error if block does not exist

* Update docs

(cherry picked from commit 747f8d5877)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-20 23:26:55 +00:00
mergify[bot]
d3ab1ec9cf Do not delete any ledger when --limit-ledger-size is not provided (#11741)
(cherry picked from commit ea88bbdc33)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-20 19:27:48 +00:00
mergify[bot]
e41d9c87c5 Bump spl-token to clean up magic number (bp #11726) (#11738)
* Bump spl-token to clean up magic number (#11726)

(cherry picked from commit 2fd2aceeb2)

# Conflicts:
#	account-decoder/Cargo.toml
#	core/Cargo.toml

* Fix conflicts and toml order

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-08-20 18:02:28 +00:00
Greg Fitzgerald
e938925b95 Add BanksClient (#11721)
Cherry-picked from #10728, but without the changes to solana-tokens
2020-08-19 22:24:24 -06:00
mergify[bot]
6c03e6c4b5 Allow votes to timestamp subsequent slots with the same timestamp (#11715) (#11720)
(cherry picked from commit b1bc901a66)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-20 00:40:04 +00:00
Trent Nelson
abce60efdf Bump version to 1.3.5 2020-08-19 20:19:34 +00:00
mergify[bot]
b36510a565 Skip grace blocks if previous leader was on different fork (#11679) (#11709)
* Start leader blocks if previous leader was on different fork

* Fix test

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

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-19 09:29:08 +00:00
mergify[bot]
a8220ae653 The end_slot argument to purge is now optional (#11707)
(cherry picked from commit d1500ae229)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-19 04:41:54 +00:00
mergify[bot]
2c642d4639 Filter push/pulls from spies (#11620) (#11703)
* Filter push/pulls from spies

* Don't pull from peers with shred version == 0, don't push to people with shred_version == 0

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

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-19 03:20:43 +00:00
mergify[bot]
04eb35e679 Remove old signatureSubscribe info (#11704) (#11706)
(cherry picked from commit 35828e8fe7)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-19 02:44:29 +00:00
mergify[bot]
8738241567 Get index (#11694) (#11697)
(cherry picked from commit 55ce2ebd53)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-18 18:54:17 +00:00
Justin Starry
0ef9185c9e Fully enable cross program support in mainnet-beta
(cherry picked from commit 9e89a963d9)
2020-08-18 06:39:24 -07:00
mergify[bot]
e41004f185 rpc: rework binary encoding. BREAKING CHANGE (bp #11646) (#11674)
* Add base64 (binary64) encoding for getConfirmedTransaction/getConfirmedBlock

(cherry picked from commit b5f3ced860)

* decode-transaction now supports binary64

(cherry picked from commit 2ebc68a9e2)

# Conflicts:
#	cli/src/cli.rs

* Rework UiAccountData encode/decode such that it works from Rust

(cherry picked from commit 757e147b3b)

# Conflicts:
#	account-decoder/src/lib.rs
#	cli/src/cli.rs

* Rename Binary64 to Base64.  Establish Base58 encoding

(cherry picked from commit adc984a225)

# Conflicts:
#	account-decoder/src/lib.rs

* Remove "binary" encoding. Document "encoding" as required

(cherry picked from commit e5281157fa)

* resolve conflicts

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-18 02:53:10 +00:00
mergify[bot]
41cad9ccd5 Faucet: Add per-request cap (#11665) (#11669)
* Add per-request cap; also use clap-utils

* Clean up arg names and take cap inputs as SOL

(cherry picked from commit 71d5409b3b)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-18 01:00:11 +00:00
mergify[bot]
d9ae092637 Re-do rent collection check on rent-exempt account (bp #11349) (#11655)
* Re-do rent collection check on rent-exempt account (#11349)

* wip: re-do rent collection check on rent-exempt account

* Let's see how the ci goes

* Restore previous code

* Well, almost all new changes are revertable

* Update doc

* Add test and gating

* Fix tests

* Fix tests, especially avoid to change abi...

* Fix more tests...

* Fix snapshot restore

* Align to _new_ with better uninitialized detection

(cherry picked from commit 23fa84b322)

# Conflicts:
#	core/src/rpc_subscriptions.rs

* Fix conflicts

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-17 07:20:24 +00:00
mergify[bot]
9015e47cc5 Rpc: Add until parameter for getConfirmedSignaturesForAddress2 (#11644) (#11648)
* Refactor bigtable apis to accept start and end keys

* Make helper fn to deserialize cell data

* Refactor get_confirmed_signatures_for_address to use get_row_data range

* Add until param to get_confirmed_signatures_for_address

* Add until param to blockstore api

* Plumb until through client/cli

* Simplify client params

(cherry picked from commit 6c5b8f324a)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-15 17:59:35 +00:00
mergify[bot]
15b92e9c8d Bigtable: Use index to filter address-signatures correctly (#11622) (#11643)
* Use index to filter address-signatures correctly

* Pull additional keys to account for filtered records

* Clarify variable name

(cherry picked from commit 820af533a4)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-14 21:02:13 +00:00
Trent Nelson
c72bd900cd Bump version to 1.3.4 2020-08-14 18:29:46 +00:00
mergify[bot]
ecb75ccdcf short_vec::decode_len() returns wrong size for aliased values (bp #11624) (#11631)
* Add failing test for decoding ShortU16 alias values

(cherry picked from commit 338f66f9aa)

* Factor out ShortU16 deser vistor logic to helper

(cherry picked from commit 6222fbcc66)

* Reimplement decode_len() with ShortU16 vistor helper

(cherry picked from commit 30dbe257cf)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-08-14 15:33:00 +00:00
mergify[bot]
cf22e7a273 Restore CLI usage page (#11619) (#11621)
Co-authored-by: publish-docs.sh <maintainers@solana.com>
(cherry picked from commit 6194a29875)

Co-authored-by: Dan Albert <dan@solana.com>
2020-08-13 22:17:47 +00:00
mergify[bot]
4f7bfbdbe9 RPC: getConfirmedSignaturesForAddress2 only returns confirmed signatures (#11615) (#11618)
* Add failing test case

* Limit to only rooted slots

(cherry picked from commit 99fb36fe45)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-13 18:19:54 +00:00
mergify[bot]
011e325359 Ensure highest_confirmed_root only grows (#11596) (#11608)
* Split out commitment-cache update for unit testing

* Add failing test

* Ensure highest_confirmed_root only grows

(cherry picked from commit 4da1e9833c)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-13 08:13:00 +00:00
mergify[bot]
ba05852475 generate_pull_response optimization (#11597) (#11606)
(cherry picked from commit f519fdecc2)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-08-13 06:53:45 +00:00
mergify[bot]
8ee656edde Return blockstore signatures-for-address despite bigtable error (#11594) (#11599)
(cherry picked from commit b1e452f876)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-13 01:12:16 +00:00
mergify[bot]
311d9a56c4 Add incoming pull response counter (#11591) (#11592)
(cherry picked from commit 54137e3446)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-08-12 22:17:50 +00:00
mergify[bot]
b9f46fd904 Fix assertion failure (#11572) (#11590)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit 473b5249e3)

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-12 20:19:54 +00:00
mergify[bot]
39f2d346b8 Fix typo: epoch => slot... (#11573) (#11580)
(cherry picked from commit 51e818ad64)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-12 09:27:01 +00:00
Trent Nelson
4a27bfa2fe Bump version to 1.3.3 2020-08-12 00:43:50 +00:00
mergify[bot]
69e53ec92a Gossip log (#11555) (#11562)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit 1b238dd63e)

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-11 22:55:18 +00:00
mergify[bot]
b8ac76066c Move cluster slots update to separate thread (#11523) (#11558)
* Add cluster_slots_service

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

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-11 21:24:34 +00:00
mergify[bot]
1a1d7744bd Add getTokenLargestAccounts to docs (#11560) (#11564)
(cherry picked from commit 697a0e2947)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-11 21:21:35 +00:00
mergify[bot]
61af485732 filter out old gossip pull requests (#11448) (#11553)
* init

* builds

* stats

* revert

* tests

* clippy

* add some jitter

* shorter jitter timer

* update

* fixup! update

* use saturating_sub

* fix filters

(cherry picked from commit 713851b68d)

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
2020-08-11 19:42:32 +00:00
mergify[bot]
6a60d7bf8e Adapt RpcClient to recent token method changes (#11519) (#11548)
* Avoid skip_serializing_if since that breaks deserialization

* Adapt RpcClient to recent token method changes

(cherry picked from commit 17645ee20c)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-11 17:31:57 +00:00
mergify[bot]
53e917b54f Fix bad rent in Bank::deposit as if since epoch 0 (#10468) (#11539)
* Fix bad rent in Bank::deposit as if since epoch 0

* Remove redundant predicate

* Rename

* Start to add tests with some cleanup

* Forgot to add refactor code...

* Enchance test

* Really fix rent timing in deposit with robust test

* Simplify new behavior by disabling rent altogether

(cherry picked from commit 6c242f3fec)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-08-11 16:20:06 +00:00
mergify[bot]
4d49c99ac9 Fix simulateTransaction JSON-RPC docs (#11533) (#11535)
(cherry picked from commit f12fc66a69)

Co-authored-by: Justin Starry <justin@solana.com>
2020-08-11 10:26:20 +00:00
mergify[bot]
83597a5ce1 Fix solana CLI deploy (#11520) (#11530)
* Refresh blockhash for program writes and finalize transactions

* Refactor to use current api, eliminating an rpc call

* Review comment

(cherry picked from commit c0d6761f63)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-11 09:52:11 +00:00
mergify[bot]
1589a41178 Add config param to specify offset/length for single and program account info (bp #11515) (#11518)
* Add config param to specify offset/length for single and program account info (#11515)

* Add config param to specify dataSlice for account info and program accounts

* Use match instead of if

(cherry picked from commit 88ca04dbdb)

# Conflicts:
#	cli/src/cli.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-08-11 00:03:18 +00:00
mergify[bot]
23a381b995 Fix parsing of spl-token Mint (#11512) (#11514)
* Add failing test

* Fix jsonParsed mint

(cherry picked from commit da210ddd51)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-10 21:51:20 +00:00
mergify[bot]
eb7ac42b2e Return account data size with parsed accounts (#11506) (#11511)
(cherry picked from commit 1925b0bd0b)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-10 20:09:13 +00:00
mergify[bot]
88cf5e79f5 Unified signature for create_program_address (#11460) (#11509)
(cherry picked from commit 140b2392f6)

Co-authored-by: Jack May <jack@solana.com>
2020-08-10 18:31:51 +00:00
mergify[bot]
520453e1f3 Blockstore address signatures: handle slots that cross primary indexes, and refactor get_confirmed_signatures_for_address2 (#11497) (#11508)
* Freeze address-signature index in the middle of slot to show failure case

* Secondary filter on signature

* Use AddressSignatures iterator instead of manually decrementing slots

* Remove unused method

* Add metrics

* Add transaction-status-index doccumentation

(cherry picked from commit de5fb3ba0e)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-10 17:43:00 +00:00
mergify[bot]
27815555a1 Fallback to base64 account encoding if json parse fails (#11483) (#11488)
* Fallback to base64 account encoding if json parse fails

* Remove default binary conversion

(cherry picked from commit ebc45bd73f)

Co-authored-by: Justin Starry <justin@solana.com>
2020-08-09 16:15:09 +00:00
mergify[bot]
3e483314b6 Decode native-program and sysvar accounts (bp #11463) (#11485)
* Decode native-program and sysvar accounts (#11463)

* Pass pubkey in to account-decoder for sysvars

* Decode sysvar accounts

* Decode config accounts; move validator-info lower

* Decode stake accounts

* Review comments

* Stringify any account lamports and epochs that can be set to u64::MAX

(cherry picked from commit a9f76862fb)

# Conflicts:
#	Cargo.lock
#	account-decoder/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-08-09 09:18:17 +00:00
mergify[bot]
8a67504578 Add Binary64 option for account data (#11474) (#11481)
* Add Binary64 option for account data

* Decode into binary64

* Reword docs

(cherry picked from commit 068d23f298)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-08-09 06:50:24 +00:00
mergify[bot]
a1b238280b Return delegated amount as UiTokenAmount (#11475) (#11477)
* Return delegated amount as UiTokenAmount

* Omit delegate and delegatedAmount when none

(cherry picked from commit 88d8d3d02a)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-09 00:01:01 +00:00
Trent Nelson
f9e07f575e Bump version to v1.3.2 2020-08-08 06:26:20 +00:00
Trent Nelson
c8bad57455 Bump version to v1.3.1 2020-08-07 19:21:41 -06:00
mergify[bot]
71654c0457 Fix cbindgen compatibility (#11455) (#11459)
(cherry picked from commit 5a7e99f283)

Co-authored-by: Jack May <jack@solana.com>
2020-08-07 23:44:49 +00:00
mergify[bot]
f9d6fb48a4 Send votes from banking stage to vote listener (#11434) (#11454)
*  Send votes from banking stage to vote listener

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

Co-authored-by: carllin <wumu727@gmail.com>
2020-08-07 19:45:40 +00:00
mergify[bot]
fa9aa0a1d7 Token Accounts: return ui_amount, decimals with decoded account (#11407) (#11453)
* Return ui_amount, decimals from token client methods

* Return ui_amount, decimals in RPC jsonParsed token accounts

* Fixup docs

* Return ui_amount, decimals in pubsub jsonParsed token accounts

* Remove unnecessary duplicate struct

* StringAmount rename

(cherry picked from commit b7c2681903)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-07 19:05:35 +00:00
mergify[bot]
9758ebfc99 Only run web3.js/explorer CI when targeting master branch (#11440)
(cherry picked from commit a3165c6a61)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-08-07 06:24:42 +00:00
mergify[bot]
8be23a2bb2 Add address-based lower bound to get_confirmed_signatures_for_address2 loop (#11426) (#11432)
(cherry picked from commit 5530ee4c95)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-07 00:06:44 +00:00
mergify[bot]
4ff9a6910d Fix blockstore empty panic (#11423) (#11430)
* Add panicking test

* Add failing test: fresh transaction-status column shouldn't point at valid root 0

* Prevent transaction status match outside of primary-index bounds

* Initialize transaction-status and address-signature primer entries with Slot::MAX

* Revert "Add failing test: fresh transaction-status column shouldn't point at valid root 0"

This reverts commit cbad2a9fae.

* Revert "Initialize transaction-status and address-signature primer entries with Slot::MAX"

This reverts commit ffaeac0669.

(cherry picked from commit 1061b50665)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-08-06 23:39:01 +00:00
mergify[bot]
fd192e3641 Link fix (#11368) (#11425)
* fixes logo

* cleans up homepage on docs

* adds icon files and tightens margins

* cleans up sidenav, adds top nav items

* fixes a link

* removes icon files

Co-authored-by: Dan Albert <dan@solana.com>
(cherry picked from commit 14dcaaee6c)

Co-authored-by: Raj Gokal <rajivgokal@gmail.com>
2020-08-06 19:37:04 +00:00
mergify[bot]
a8de467ef8 Realloc not supported (#11418)
(cherry picked from commit bc4c5c5a97)

Co-authored-by: Jack May <jack@solana.com>
2020-08-06 16:24:14 +00:00
Michael Vines
1a186beb5c Update lib.rs
(cherry picked from commit 5a63c9d535)
2020-08-06 07:58:05 -07:00
Michael Vines
66a21ed65e Enable cross program support in mainnet-beta epoch 63
(cherry picked from commit c9b1d08218)
2020-08-06 07:58:05 -07:00
mergify[bot]
1a42a40492 RPC: Plug getConfirmedSignaturesForAddress2 into bigtable storage (bp #11395) (#11406)
* Plug getConfirmedSignaturesForAddress2 into bigtable storage

(cherry picked from commit 4222932e08)

* Upgrade help description

(cherry picked from commit 9abb7db5f8)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-06 07:14:46 +00:00
mergify[bot]
5841e4d665 Long-term ledger storage with BigTable (bp #11222) (#11392)
* ledger-storage-bigtable boilerplate

(cherry picked from commit 9d2293bb32)

* $ wget https://pki.goog/roots.pem -O pki-goog-roots.pem

(cherry picked from commit 1617a025ce)

* Add access_token module

(cherry picked from commit 59d266a111)

* Add root_ca_certificate

(cherry picked from commit faa016e4b7)

* Add build-proto

(cherry picked from commit c31e1f5bf0)

* UiTransactionEncoding is now copy

(cherry picked from commit 494968be66)

* Increase timeout

(cherry picked from commit 57dfebc5ba)

* Add build-proto/build.sh output

(cherry picked from commit 54dae6ba2c)

* Supress doctest errors

(cherry picked from commit 019c75797d)

* Add compression

(cherry picked from commit 243e05d59f)

* Add bigtable

(cherry picked from commit 6e0353965a)

* Add configuration info

(cherry picked from commit 98cca1e774)

* Add ledger-tool bigtable subcommands

(cherry picked from commit f9049d6ee4)

# Conflicts:
#	ledger-tool/Cargo.toml

* Make room for tokio 0.2

(cherry picked from commit b876fb84ba)

# Conflicts:
#	core/Cargo.toml

* Setup a tokio 0.2 runtime for RPC usage

(cherry picked from commit 0e02740565)

# Conflicts:
#	core/Cargo.toml

* Plumb Bigtable ledger storage into the RPC subsystem

(cherry picked from commit dfae9a9864)

# Conflicts:
#	core/Cargo.toml

* Add RPC transaction history design

(cherry picked from commit e56ea138c7)

* Simplify access token refreshing

(cherry picked from commit 1f7af14386)

* Report block status more frequently

(cherry picked from commit 22c46ebf96)

* after -> before

(cherry picked from commit 227ea934ff)

* Rebase

* Cargo.lock

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-06 04:06:44 +00:00
mergify[bot]
6542a04521 Mark token-specific rpcs as unstable (#11402)
(cherry picked from commit 7430896c79)

Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-08-06 04:00:18 +00:00
mergify[bot]
5c27009758 Force program address off the curve (#11323) (#11398)
(cherry picked from commit 03263c850a)

Co-authored-by: Jack May <jack@solana.com>
2020-08-06 01:00:42 +00:00
mergify[bot]
888f3522d8 Add getConfirmedSignaturesForAddress2 RPC method (bp #11259) (#11394)
* Add getConfirmedSignaturesForAddress2 RPC method

(cherry picked from commit 1b2276520b)

* Reimplement transaction-history command with getConfirmedSignaturesForAddress2

(cherry picked from commit 087fd32ce3)

* Rework get_confirmed_signatures_for_address2

(cherry picked from commit a11f137810)

* Rename startAfter to before

(cherry picked from commit 02c0981ecf)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-08-05 22:47:50 +00:00
980 changed files with 41563 additions and 108171 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -1,6 +1,5 @@
{
"_public_key": "ae29f4f7ad2fc92de70d470e411c8426d5d48db8817c9e3dae574b122192335f",
"_comment": "These credentials are encrypted and pose no risk",
"environment": {
"CODECOV_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:3K68mE38LJ2RB98VWmjuNLFBNn1XTGR4:cR4r05/TOZQKmEZp1v4CSgUJtC6QJiOaL85QjXW0qZ061fMnsBA8AtAPMDoDq4WCGOZM1A==]"
}

View File

@@ -31,9 +31,4 @@ export CARGO_TARGET_CACHE=$HOME/cargo-target-cache/"$CHANNEL"-"$BUILDKITE_LABEL"
mkdir -p "$CARGO_TARGET_CACHE"/target
rsync -a --delete --link-dest="$CARGO_TARGET_CACHE" "$CARGO_TARGET_CACHE"/target .
# Don't reuse BPF target build artifacts due to incremental build issues with
# `std:
# "found possibly newer version of crate `std` which `xyz` depends on
rm -rf target/bpfel-unknown-unknown
)

46
.github/stale.yml vendored
View File

@@ -1,3 +1,11 @@
only: pulls
# Number of days of inactivity before a pull request becomes stale
daysUntilStale: 7
# Number of days of inactivity before a stale pull request is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- security
@@ -6,34 +14,12 @@ exemptLabels:
# Label to use when marking a pull request as stale
staleLabel: stale
pulls:
# Number of days of inactivity before a pull request becomes stale
daysUntilStale: 7
# Comment to post when marking a pull request as stale. Set to `false` to disable
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.
# Number of days of inactivity before a stale pull request is closed
daysUntilClose: 7
# Comment to post when marking a pull request as stale. Set to `false` to disable
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.
# Comment to post when closing a stale pull request. Set to `false` to disable
closeComment: >
This stale pull request has been automatically closed.
Thank you for your contributions.
issues:
# Number of days of inactivity before a issue becomes stale
daysUntilStale: 365
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Comment to post when marking a issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This stale issue has been automatically closed.
Thank you for your contributions.
# Comment to post when closing a stale pull request. Set to `false` to disable
closeComment: >
This stale pull request has been automatically closed.
Thank you for your contributions.

2
.gitignore vendored
View File

@@ -14,8 +14,6 @@
/config/
.cache
# log files
*.log
log-*.txt

View File

@@ -50,6 +50,22 @@ pull_request_rules:
label:
add:
- automerge
- name: v1.1 backport
conditions:
- label=v1.1
actions:
backport:
ignore_conflicts: true
branches:
- v1.1
- name: v1.2 backport
conditions:
- label=v1.2
actions:
backport:
ignore_conflicts: true
branches:
- v1.2
- name: v1.3 backport
conditions:
- label=v1.3
@@ -58,27 +74,3 @@ pull_request_rules:
ignore_conflicts: true
branches:
- v1.3
- name: v1.4 backport
conditions:
- label=v1.4
actions:
backport:
ignore_conflicts: true
branches:
- v1.4
- name: v1.5 backport
conditions:
- label=v1.5
actions:
backport:
ignore_conflicts: true
branches:
- v1.5
- name: v1.6 backport
conditions:
- label=v1.6
actions:
backport:
ignore_conflicts: true
branches:
- v1.6

View File

@@ -34,8 +34,6 @@ jobs:
- stable
install:
- source ci/rust-version.sh
- PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
- readlink -f .
script:
- source ci/env.sh
- ci/publish-tarball.sh
@@ -126,8 +124,6 @@ jobs:
- ~/.npm
before_install:
- source ci/env.sh
- .travis/channel_restriction.sh edge beta || travis_terminate 0
- .travis/affects.sh docs/ .travis || travis_terminate 0
- cd docs/
- source .travis/before_install.sh

View File

@@ -1,19 +0,0 @@
#!/usr/bin/env bash
#
# Only proceed if we are on one of the channels passed in, or a tag build
#
set -ex
[[ -n $CI_TAG ]] && exit 0
eval "$(ci/channel-info.sh)"
for acceptable_channel in "$@"; do
if [[ "$CHANNEL" == "$acceptable_channel" ]]; then
exit 0
fi
done
echo "Not running from one of the following channels: $*"
exit 1

View File

@@ -232,7 +232,7 @@ confused with 3-letter acronyms.
Solana's architecture is described by docs generated from markdown files in
the `docs/src/` directory, maintained by an *editor* (currently @garious). To
add a design proposal, you'll need to include it in the
[Accepted Design Proposals](https://docs.solana.com/proposals/accepted-design-proposals)
[Accepted Design Proposals](https://docs.solana.com/proposals)
section of the Solana docs. Here's the full process:
1. Propose a design by creating a PR that adds a markdown document to the

2040
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,10 +16,10 @@ members = [
"dos",
"download-utils",
"faucet",
"frozen-abi",
"perf",
"validator",
"genesis",
"genesis-programs",
"gossip",
"install",
"keygen",
@@ -31,14 +31,12 @@ members = [
"merkle-tree",
"stake-o-matic",
"storage-bigtable",
"storage-proto",
"streamer",
"measure",
"metrics",
"net-shaper",
"notifier",
"poh-bench",
"program-test",
"programs/secp256k1",
"programs/bpf_loader",
"programs/budget",
@@ -53,10 +51,7 @@ members = [
"remote-wallet",
"ramp-tps",
"runtime",
"runtime/store-tool",
"sdk",
"sdk/cargo-build-bpf",
"sdk/cargo-test-bpf",
"scripts",
"stake-accounts",
"stake-monitor",
@@ -67,6 +62,7 @@ members = [
"upload-perf",
"net-utils",
"version",
"vote-signer",
"cli",
"rayon-threadlimit",
"watchtower",

View File

@@ -19,7 +19,7 @@ $ source $HOME/.cargo/env
$ rustup component add rustfmt
```
Please sure you are always using the latest stable rust version by running:
If your rustc version is lower than 1.39.0, please update it:
```bash
$ rustup update
@@ -29,7 +29,7 @@ On Linux systems you may need to install libssl-dev, pkg-config, zlib1g-dev, etc
```bash
$ sudo apt-get update
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang make
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang
```
## **2. Download the source code.**
@@ -59,11 +59,10 @@ $ cargo test
```
### Starting a local testnet
Start your own testnet locally, instructions are in the [online docs](https://docs.solana.com/cluster/bench-tps).
Start your own testnet locally, instructions are in the [online docs](https://docs.solana.com/bench-tps).
### Accessing the remote development cluster
* `devnet` - stable public cluster for development accessible via
devnet.solana.com. Runs 24/7. Learn more about the [public clusters](https://docs.solana.com/clusters)
### Accessing the remote testnet
* `testnet` - public stable testnet accessible via devnet.solana.com. Runs 24/7
# Benchmarking
@@ -108,5 +107,3 @@ send us that patch!
# Disclaimer
All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment.
Any content produced by Solana, or developer resources that Solana provides, are for educational and inspiration purposes only. Solana does not encourage, induce or sanction the deployment of any such applications in violation of applicable laws or regulations.

View File

@@ -107,15 +107,11 @@ Alternatively use the Github UI.
1. If the Cargo.toml version field is **0.12.3**, then the release tag must be **v0.12.3**
1. Make sure the Target Branch field matches the branch you want to make a release on.
1. If you want to release v0.12.0, the target branch must be v0.12
1. Fill the release notes.
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). Engineering Lead can provide summary contents for release notes if needed.
1. If this is a patch release, review all the commits since the previous release on this branch and add details as needed.
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). Engineering Lead can provide summary contents for release notes if needed. If this is a patch release, review all the commits since the previous release on this branch and add details as needed.
1. Click "Save Draft", then confirm the release notes look good and the tag name and branch are correct.
1. Ensure all desired commits (usually backports) are landed on the branch by now.
1. Ensure the release is marked **"This is a pre-release"**. This flag will need to be be removed manually after confirming the the Linux binary artifacts appear at a later step.
1. Go back into edit the release and click "Publish release" while being marked as a pre-release.
1. Confirm there is new git tag with intended version number at the intended revision after running `git fetch` locally.
1. Ensure the release is marked **"This is a pre-release"**. This flag will then need to be be removed once the the Linux binary artifacts appear later.
1. Go back into edit the release and click "Publish release" when ready.
### Update release branch with the next patch version
@@ -135,8 +131,7 @@ Alternatively use the Github UI.
1. Open a PR against origin/vX.Y and then merge the PR after passing CI.
### Prepare for the next release
1. Go to [GitHub Releases](https://github.com/solana-labs/solana/releases) and create a new draft release for `X.Y.Z+1` with empty release notes. This allows people to incrementally add new release notes until it's time for the next release
1. Also, point the branch field to the same branch and mark the relese as **"This is a pre-release"**.
1. Go to [GitHub Releases](https://github.com/solana-labs/solana/releases) and create a new draft release for `X.Y.Z+1` with empty release nodes. This allows people to incrementally add new release notes until it's time for the next release
1. Go to the [Github Milestones](https://github.com/solana-labs/solana/milestones). Create a new milestone for the `X.Y.Z+1`, move over
unresolved issues still in the `X.Y.Z` milestone, then close the `X.Y.Z` milestone.
@@ -152,5 +147,5 @@ appearing. To check for progress:
[Crates.io](https://crates.io/crates/solana) should have an updated Solana version. This can take 2-3 hours, and sometimes fails in the `solana-secondary` job.
If this happens and the error is non-fatal, click "Retry" on the "publish crate" job
### Update software on devnet.solana.com/testnet.solana.com/mainnet-beta.solana.com
### Update software on devnet.solana.com/testnet.solama.com/mainnet-beta.solana.com
See the documentation at https://github.com/solana-labs/cluster-ops/

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-account-decoder"
version = "1.5.3"
version = "1.3.13"
description = "Solana account decoder"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -18,13 +18,12 @@ lazy_static = "1.4.0"
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-config-program = { path = "../programs/config", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-stake-program = { path = "../programs/stake", version = "1.5.3" }
solana-vote-program = { path = "../programs/vote", version = "1.5.3" }
spl-token-v2-0 = { package = "spl-token", version = "=3.0.1", features = ["no-entrypoint"] }
solana-config-program = { path = "../programs/config", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-stake-program = { path = "../programs/stake", version = "1.3.13" }
solana-vote-program = { path = "../programs/vote", version = "1.3.13" }
spl-token-v2-0 = { package = "spl-token", version = "2.0.6", features = ["skip-no-mangle"] }
thiserror = "1.0"
zstd = "0.5.1"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -12,14 +12,9 @@ pub mod parse_token;
pub mod parse_vote;
pub mod validator_info;
use {
crate::parse_account_data::{parse_account_data, AccountAdditionalData, ParsedAccount},
solana_sdk::{account::Account, clock::Epoch, fee_calculator::FeeCalculator, pubkey::Pubkey},
std::{
io::{Read, Write},
str::FromStr,
},
};
use crate::parse_account_data::{parse_account_data, AccountAdditionalData, ParsedAccount};
use solana_sdk::{account::Account, clock::Epoch, fee_calculator::FeeCalculator, pubkey::Pubkey};
use std::str::FromStr;
pub type StringAmount = String;
@@ -49,8 +44,6 @@ pub enum UiAccountEncoding {
Base58,
Base64,
JsonParsed,
#[serde(rename = "base64+zstd")]
Base64Zstd,
}
impl UiAccount {
@@ -73,19 +66,6 @@ impl UiAccount {
base64::encode(slice_data(&account.data, data_slice_config)),
encoding,
),
UiAccountEncoding::Base64Zstd => {
let mut encoder = zstd::stream::write::Encoder::new(Vec::new(), 0).unwrap();
match encoder
.write_all(slice_data(&account.data, data_slice_config))
.and_then(|()| encoder.finish())
{
Ok(zstd_data) => UiAccountData::Binary(base64::encode(zstd_data), encoding),
Err(_) => UiAccountData::Binary(
base64::encode(slice_data(&account.data, data_slice_config)),
UiAccountEncoding::Base64,
),
}
}
UiAccountEncoding::JsonParsed => {
if let Ok(parsed_data) =
parse_account_data(pubkey, &account.owner, &account.data, additional_data)
@@ -112,16 +92,6 @@ impl UiAccount {
UiAccountData::Binary(blob, encoding) => match encoding {
UiAccountEncoding::Base58 => bs58::decode(blob).into_vec().ok(),
UiAccountEncoding::Base64 => base64::decode(blob).ok(),
UiAccountEncoding::Base64Zstd => base64::decode(blob)
.ok()
.map(|zstd_data| {
let mut data = vec![];
zstd::stream::read::Decoder::new(zstd_data.as_slice())
.and_then(|mut reader| reader.read_to_end(&mut data))
.map(|_| data)
.ok()
})
.flatten(),
UiAccountEncoding::Binary | UiAccountEncoding::JsonParsed => None,
},
}?;
@@ -209,25 +179,4 @@ mod test {
});
assert_eq!(slice_data(&data, slice_config), &[] as &[u8]);
}
#[test]
fn test_base64_zstd() {
let encoded_account = UiAccount::encode(
&Pubkey::default(),
Account {
data: vec![0; 1024],
..Account::default()
},
UiAccountEncoding::Base64Zstd,
None,
None,
);
assert!(matches!(
encoded_account.data,
UiAccountData::Binary(_, UiAccountEncoding::Base64Zstd)
));
let decoded_account = encoded_account.decode().unwrap();
assert_eq!(decoded_account.data, vec![0; 1024]);
}
}

View File

@@ -81,7 +81,7 @@ pub fn parse_account_data(
) -> Result<ParsedAccount, ParseAccountError> {
let program_name = PARSABLE_PROGRAM_IDS
.get(program_id)
.ok_or(ParseAccountError::ProgramNotParsable)?;
.ok_or_else(|| ParseAccountError::ProgramNotParsable)?;
let additional_data = additional_data.unwrap_or_default();
let parsed_json = match program_name {
ParsableAccount::Config => serde_json::to_value(parse_config(data, pubkey)?)?,
@@ -111,14 +111,14 @@ mod test {
#[test]
fn test_parse_account_data() {
let account_pubkey = solana_sdk::pubkey::new_rand();
let other_program = solana_sdk::pubkey::new_rand();
let account_pubkey = Pubkey::new_rand();
let other_program = Pubkey::new_rand();
let data = vec![0; 4];
assert!(parse_account_data(&account_pubkey, &other_program, &data, None).is_err());
let vote_state = VoteState::default();
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
let versioned = VoteStateVersions::new_current(vote_state);
let versioned = VoteStateVersions::Current(Box::new(vote_state));
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
let parsed = parse_account_data(
&account_pubkey,

View File

@@ -117,7 +117,7 @@ mod test {
}))
.unwrap(),
};
let info_pubkey = solana_sdk::pubkey::new_rand();
let info_pubkey = Pubkey::new_rand();
let validator_info_config_account = create_config_account(
vec![(validator_info::id(), false), (info_pubkey, true)],
&validator_info,

View File

@@ -134,6 +134,7 @@ impl From<Delegation> for UiDelegation {
mod test {
use super::*;
use bincode::serialize;
use solana_sdk::pubkey::Pubkey;
#[test]
fn test_parse_stake() {
@@ -144,8 +145,8 @@ mod test {
StakeAccountType::Uninitialized
);
let pubkey = solana_sdk::pubkey::new_rand();
let custodian = solana_sdk::pubkey::new_rand();
let pubkey = Pubkey::new_rand();
let custodian = Pubkey::new_rand();
let authorized = Authorized::auto(&pubkey);
let lockup = Lockup {
unix_timestamp: 0,
@@ -179,7 +180,7 @@ mod test {
})
);
let voter_pubkey = solana_sdk::pubkey::new_rand();
let voter_pubkey = Pubkey::new_rand();
let stake = Stake {
delegation: Delegation {
voter_pubkey,

View File

@@ -105,7 +105,6 @@ pub enum SysvarAccountType {
pub struct UiClock {
pub slot: Slot,
pub epoch: Epoch,
pub epoch_start_timestamp: UnixTimestamp,
pub leader_schedule_epoch: Epoch,
pub unix_timestamp: UnixTimestamp,
}
@@ -115,7 +114,6 @@ impl From<Clock> for UiClock {
Self {
slot: clock.slot,
epoch: clock.epoch,
epoch_start_timestamp: clock.epoch_start_timestamp,
leader_schedule_epoch: clock.leader_schedule_epoch,
unix_timestamp: clock.unix_timestamp,
}
@@ -214,13 +212,15 @@ pub struct UiStakeHistoryEntry {
mod test {
use super::*;
use solana_sdk::{
account::create_account, fee_calculator::FeeCalculator, hash::Hash,
sysvar::recent_blockhashes::IterItem,
fee_calculator::FeeCalculator,
hash::Hash,
sysvar::{recent_blockhashes::IterItem, Sysvar},
};
use std::iter::FromIterator;
#[test]
fn test_parse_sysvars() {
let clock_sysvar = create_account(&Clock::default(), 1);
let clock_sysvar = Clock::default().create_account(1);
assert_eq!(
parse_sysvar(&clock_sysvar.data, &sysvar::clock::id()).unwrap(),
SysvarAccountType::Clock(UiClock::default()),
@@ -233,13 +233,13 @@ mod test {
first_normal_epoch: 1,
first_normal_slot: 12,
};
let epoch_schedule_sysvar = create_account(&epoch_schedule, 1);
let epoch_schedule_sysvar = epoch_schedule.create_account(1);
assert_eq!(
parse_sysvar(&epoch_schedule_sysvar.data, &sysvar::epoch_schedule::id()).unwrap(),
SysvarAccountType::EpochSchedule(epoch_schedule),
);
let fees_sysvar = create_account(&Fees::default(), 1);
let fees_sysvar = Fees::default().create_account(1);
assert_eq!(
parse_sysvar(&fees_sysvar.data, &sysvar::fees::id()).unwrap(),
SysvarAccountType::Fees(UiFees::default()),
@@ -249,10 +249,9 @@ mod test {
let fee_calculator = FeeCalculator {
lamports_per_signature: 10,
};
let recent_blockhashes: RecentBlockhashes = vec![IterItem(0, &hash, &fee_calculator)]
.into_iter()
.collect();
let recent_blockhashes_sysvar = create_account(&recent_blockhashes, 1);
let recent_blockhashes =
RecentBlockhashes::from_iter(vec![IterItem(0, &hash, &fee_calculator)].into_iter());
let recent_blockhashes_sysvar = recent_blockhashes.create_account(1);
assert_eq!(
parse_sysvar(
&recent_blockhashes_sysvar.data,
@@ -270,13 +269,13 @@ mod test {
exemption_threshold: 2.0,
burn_percent: 5,
};
let rent_sysvar = create_account(&rent, 1);
let rent_sysvar = rent.create_account(1);
assert_eq!(
parse_sysvar(&rent_sysvar.data, &sysvar::rent::id()).unwrap(),
SysvarAccountType::Rent(rent.into()),
);
let rewards_sysvar = create_account(&Rewards::default(), 1);
let rewards_sysvar = Rewards::default().create_account(1);
assert_eq!(
parse_sysvar(&rewards_sysvar.data, &sysvar::rewards::id()).unwrap(),
SysvarAccountType::Rewards(UiRewards::default()),
@@ -284,7 +283,7 @@ mod test {
let mut slot_hashes = SlotHashes::default();
slot_hashes.add(1, hash);
let slot_hashes_sysvar = create_account(&slot_hashes, 1);
let slot_hashes_sysvar = slot_hashes.create_account(1);
assert_eq!(
parse_sysvar(&slot_hashes_sysvar.data, &sysvar::slot_hashes::id()).unwrap(),
SysvarAccountType::SlotHashes(vec![UiSlotHashEntry {
@@ -295,7 +294,7 @@ mod test {
let mut slot_history = SlotHistory::default();
slot_history.add(42);
let slot_history_sysvar = create_account(&slot_history, 1);
let slot_history_sysvar = slot_history.create_account(1);
assert_eq!(
parse_sysvar(&slot_history_sysvar.data, &sysvar::slot_history::id()).unwrap(),
SysvarAccountType::SlotHistory(UiSlotHistory {
@@ -311,7 +310,7 @@ mod test {
deactivating: 3,
};
stake_history.add(1, stake_history_entry.clone());
let stake_history_sysvar = create_account(&stake_history, 1);
let stake_history_sysvar = stake_history.create_account(1);
assert_eq!(
parse_sysvar(&stake_history_sysvar.data, &sysvar::stake_history::id()).unwrap(),
SysvarAccountType::StakeHistory(vec![UiStakeHistoryEntry {
@@ -320,7 +319,7 @@ mod test {
}]),
);
let bad_pubkey = solana_sdk::pubkey::new_rand();
let bad_pubkey = Pubkey::new_rand();
assert!(parse_sysvar(&stake_history_sysvar.data, &bad_pubkey).is_err());
let bad_data = vec![0; 4];

View File

@@ -4,9 +4,7 @@ use crate::{
};
use solana_sdk::pubkey::Pubkey;
use spl_token_v2_0::{
solana_program::{
program_option::COption, program_pack::Pack, pubkey::Pubkey as SplTokenPubkey,
},
solana_sdk::{program_option::COption, program_pack::Pack, pubkey::Pubkey as SplTokenPubkey},
state::{Account, AccountState, Mint, Multisig},
};
use std::str::FromStr;
@@ -23,16 +21,6 @@ pub fn spl_token_v2_0_native_mint() -> Pubkey {
Pubkey::from_str(&spl_token_v2_0::native_mint::id().to_string()).unwrap()
}
// A helper function to convert a solana_sdk::pubkey::Pubkey to spl_sdk::pubkey::Pubkey
pub fn spl_token_v2_0_pubkey(pubkey: &Pubkey) -> SplTokenPubkey {
SplTokenPubkey::from_str(&pubkey.to_string()).unwrap()
}
// A helper function to convert a spl_sdk::pubkey::Pubkey to solana_sdk::pubkey::Pubkey
pub fn pubkey_from_spl_token_v2_0(pubkey: &SplTokenPubkey) -> Pubkey {
Pubkey::from_str(&pubkey.to_string()).unwrap()
}
pub fn parse_token(
data: &[u8],
mint_decimals: Option<u8>,
@@ -166,31 +154,6 @@ pub struct UiTokenAmount {
pub amount: StringAmount,
}
impl UiTokenAmount {
pub fn real_number_string(&self) -> String {
let decimals = self.decimals as usize;
if decimals > 0 {
let amount = u64::from_str(&self.amount).unwrap_or(0);
// Left-pad zeros to decimals + 1, so we at least have an integer zero
let mut s = format!("{:01$}", amount, decimals + 1);
// Add the decimal point (Sorry, "," locales!)
s.insert(s.len() - decimals, '.');
s
} else {
self.amount.clone()
}
}
pub fn real_number_string_trimmed(&self) -> String {
let s = self.real_number_string();
let zeros_trimmed = s.trim_end_matches('0');
let decimal_trimmed = zeros_trimmed.trim_end_matches('.');
decimal_trimmed.to_string()
}
}
pub fn token_amount_to_ui_amount(amount: u64, decimals: u8) -> UiTokenAmount {
// Use `amount_to_ui_amount()` once spl_token is bumped to a version that supports it: https://github.com/solana-labs/solana-program-library/pull/211
let amount_decimals = amount as f64 / 10_usize.pow(decimals as u32) as f64;
@@ -333,20 +296,4 @@ mod test {
Some(expected_mint_pubkey)
);
}
#[test]
fn test_ui_token_amount_real_string() {
let token_amount = token_amount_to_ui_amount(1, 0);
assert_eq!(&token_amount.real_number_string(), "1");
assert_eq!(&token_amount.real_number_string_trimmed(), "1");
let token_amount = token_amount_to_ui_amount(1, 9);
assert_eq!(&token_amount.real_number_string(), "0.000000001");
assert_eq!(&token_amount.real_number_string_trimmed(), "0.000000001");
let token_amount = token_amount_to_ui_amount(1_000_000_000, 9);
assert_eq!(&token_amount.real_number_string(), "1.000000000");
assert_eq!(&token_amount.real_number_string_trimmed(), "1");
let token_amount = token_amount_to_ui_amount(1_234_567_890, 3);
assert_eq!(&token_amount.real_number_string(), "1234567.890");
assert_eq!(&token_amount.real_number_string_trimmed(), "1234567.89");
}
}

View File

@@ -128,13 +128,11 @@ mod test {
fn test_parse_vote() {
let vote_state = VoteState::default();
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
let versioned = VoteStateVersions::new_current(vote_state);
let versioned = VoteStateVersions::Current(Box::new(vote_state));
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
let expected_vote_state = UiVoteState {
node_pubkey: Pubkey::default().to_string(),
authorized_withdrawer: Pubkey::default().to_string(),
..UiVoteState::default()
};
let mut expected_vote_state = UiVoteState::default();
expected_vote_state.node_pubkey = Pubkey::default().to_string();
expected_vote_state.authorized_withdrawer = Pubkey::default().to_string();
assert_eq!(
parse_vote(&vote_account_data).unwrap(),
VoteAccountType::Vote(expected_vote_state)

View File

@@ -2,20 +2,19 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-accounts-bench"
version = "1.5.3"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
publish = false
[dependencies]
log = "0.4.11"
log = "0.4.6"
rayon = "1.4.0"
solana-logger = { path = "../logger", version = "1.5.3" }
solana-runtime = { path = "../runtime", version = "1.5.3" }
solana-measure = { path = "../measure", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-version = { path = "../version", version = "1.5.3" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-runtime = { path = "../runtime", version = "1.3.13" }
solana-measure = { path = "../measure", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-version = { path = "../version", version = "1.3.13" }
rand = "0.7.0"
clap = "2.33.1"
crossbeam-channel = "0.4"

View File

@@ -2,11 +2,13 @@ use clap::{crate_description, crate_name, value_t, App, Arg};
use rayon::prelude::*;
use solana_measure::measure::Measure;
use solana_runtime::{
accounts::{create_test_accounts, update_accounts_bench, Accounts},
accounts::{create_test_accounts, update_accounts, Accounts},
accounts_index::Ancestors,
};
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
use std::{collections::HashSet, env, fs, path::PathBuf};
use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
solana_logger::setup();
@@ -54,8 +56,7 @@ fn main() {
if fs::remove_dir_all(path.clone()).is_err() {
println!("Warning: Couldn't remove {:?}", path);
}
let accounts =
Accounts::new_with_config(vec![path], &ClusterType::Testnet, HashSet::new(), false);
let accounts = Accounts::new(vec![path], &ClusterType::Testnet);
println!("Creating {} accounts", num_accounts);
let mut create_time = Measure::start("create accounts");
let pubkeys: Vec<_> = (0..num_slots)
@@ -87,20 +88,17 @@ fn main() {
for x in 0..iterations {
if clean {
let mut time = Measure::start("clean");
accounts.accounts_db.clean_accounts(None);
accounts.accounts_db.clean_accounts();
time.stop();
println!("{}", time);
for slot in 0..num_slots {
update_accounts_bench(&accounts, &pubkeys, ((x + 1) * num_slots + slot) as u64);
update_accounts(&accounts, &pubkeys, ((x + 1) * num_slots + slot) as u64);
accounts.add_root((x * num_slots + slot) as u64);
}
} else {
let mut pubkeys: Vec<Pubkey> = vec![];
let mut time = Measure::start("hash");
let hash = accounts
.accounts_db
.update_accounts_hash(0, &ancestors, true)
.0;
let hash = accounts.accounts_db.update_accounts_hash(0, &ancestors).0;
time.stop();
println!("hash: {} {}", hash, time);
create_test_accounts(&accounts, &mut pubkeys, 1, 0);

View File

@@ -2,28 +2,27 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-banking-bench"
version = "1.5.3"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
publish = false
[dependencies]
clap = "2.33.1"
crossbeam-channel = "0.4"
log = "0.4.11"
log = "0.4.6"
rand = "0.7.0"
rayon = "1.4.0"
solana-core = { path = "../core", version = "1.5.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.3" }
solana-streamer = { path = "../streamer", version = "1.5.3" }
solana-perf = { path = "../perf", version = "1.5.3" }
solana-ledger = { path = "../ledger", version = "1.5.3" }
solana-logger = { path = "../logger", version = "1.5.3" }
solana-runtime = { path = "../runtime", version = "1.5.3" }
solana-measure = { path = "../measure", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-version = { path = "../version", version = "1.5.3" }
solana-core = { path = "../core", version = "1.3.13" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-streamer = { path = "../streamer", version = "1.3.13" }
solana-perf = { path = "../perf", version = "1.3.13" }
solana-ledger = { path = "../ledger", version = "1.3.13" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-runtime = { path = "../runtime", version = "1.3.13" }
solana-measure = { path = "../measure", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-version = { path = "../version", version = "1.3.13" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -17,11 +17,10 @@ use solana_ledger::{
};
use solana_measure::measure::Measure;
use solana_perf::packet::to_packets_chunked;
use solana_runtime::{
accounts_background_service::ABSRequestSender, bank::Bank, bank_forks::BankForks,
};
use solana_runtime::{bank::Bank, bank_forks::BankForks};
use solana_sdk::{
hash::Hash,
pubkey::Pubkey,
signature::Keypair,
signature::Signature,
system_transaction,
@@ -70,7 +69,7 @@ fn make_accounts_txs(
hash: Hash,
same_payer: bool,
) -> Vec<Transaction> {
let to_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = Pubkey::new_rand();
let payer_key = Keypair::new();
let dummy = system_transaction::transfer(&payer_key, &to_pubkey, 1, hash);
(0..total_num_transactions)
@@ -79,9 +78,9 @@ fn make_accounts_txs(
let mut new = dummy.clone();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
if !same_payer {
new.message.account_keys[0] = solana_sdk::pubkey::new_rand();
new.message.account_keys[0] = Pubkey::new_rand();
}
new.message.account_keys[1] = solana_sdk::pubkey::new_rand();
new.message.account_keys[1] = Pubkey::new_rand();
new.signatures = vec![Signature::new(&sig[0..64])];
new
})
@@ -242,7 +241,7 @@ fn main() {
let base_tx_count = bank.transaction_count();
let mut txs_processed = 0;
let mut root = 1;
let collector = solana_sdk::pubkey::new_rand();
let collector = Pubkey::new_rand();
let config = Config {
packets_per_batch: packets_per_chunk,
chunk_len,
@@ -325,7 +324,7 @@ fn main() {
poh_recorder.lock().unwrap().set_bank(&bank);
assert!(poh_recorder.lock().unwrap().bank().is_some());
if bank.slot() > 32 {
bank_forks.set_root(root, &ABSRequestSender::default(), None);
bank_forks.set_root(root, &None, None);
root += 1;
}
debug!(

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-client"
version = "1.5.3"
version = "1.3.13"
description = "Solana banks client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -9,18 +9,18 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
async-trait = "0.1.36"
bincode = "1.3.1"
futures = "0.3"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
tarpc = { version = "0.23.0", features = ["full"] }
tokio = { version = "0.3.5", features = ["full"] }
solana-banks-interface = { path = "../banks-interface", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
tarpc = { version = "0.21.0", features = ["full"] }
tokio = "0.2"
tokio-serde = { version = "0.6", features = ["bincode"] }
[dev-dependencies]
solana-runtime = { path = "../runtime", version = "1.5.3" }
solana-banks-server = { path = "../banks-server", version = "1.5.3" }
solana-runtime = { path = "../runtime", version = "1.3.13" }
solana-banks-server = { path = "../banks-server", version = "1.3.13" }
[lib]
crate-type = ["lib"]

View File

@@ -5,250 +5,165 @@
//! but they are undocumented, may change over time, and are generally more
//! cumbersome to use.
use futures::{future::join_all, Future, FutureExt};
pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus};
use async_trait::async_trait;
use futures::future::join_all;
pub use solana_banks_interface::{BanksClient, TransactionStatus};
use solana_banks_interface::{BanksRequest, BanksResponse};
use solana_sdk::{
account::{from_account, Account},
clock::Slot,
commitment_config::CommitmentLevel,
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
rent::Rent,
signature::Signature,
sysvar,
transaction::{self, Transaction},
transport,
account::Account, clock::Slot, commitment_config::CommitmentLevel,
fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::Signature,
transaction::Transaction, transport,
};
use std::io::{self, Error, ErrorKind};
use tarpc::{
client::{self, channel::RequestDispatch, NewClient},
context::{self, Context},
rpc::{ClientMessage, Response},
client, context,
rpc::{transport::channel::UnboundedChannel, ClientMessage, Response},
serde_transport::tcp,
Transport,
};
use tokio::{net::ToSocketAddrs, time::Duration};
use tokio_serde::formats::Bincode;
// This exists only for backward compatibility
pub trait BanksClientExt {}
#[derive(Clone)]
pub struct BanksClient {
inner: TarpcClient,
}
impl BanksClient {
#[allow(clippy::new_ret_no_self)]
pub fn new<C>(
config: client::Config,
transport: C,
) -> NewClient<TarpcClient, RequestDispatch<BanksRequest, BanksResponse, C>>
where
C: Transport<ClientMessage<BanksRequest>, Response<BanksResponse>>,
{
TarpcClient::new(config, transport)
}
pub fn send_transaction_with_context(
&mut self,
ctx: Context,
transaction: Transaction,
) -> impl Future<Output = io::Result<()>> + '_ {
self.inner.send_transaction_with_context(ctx, transaction)
}
pub fn get_fees_with_commitment_and_context(
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, Slot)>> + '_ {
self.inner
.get_fees_with_commitment_and_context(ctx, commitment)
}
pub fn get_transaction_status_with_context(
&mut self,
ctx: Context,
signature: Signature,
) -> impl Future<Output = io::Result<Option<TransactionStatus>>> + '_ {
self.inner
.get_transaction_status_with_context(ctx, signature)
}
pub fn get_slot_with_context(
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<Slot>> + '_ {
self.inner.get_slot_with_context(ctx, commitment)
}
pub fn process_transaction_with_commitment_and_context(
&mut self,
ctx: Context,
transaction: Transaction,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<Option<transaction::Result<()>>>> + '_ {
self.inner
.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
}
pub fn get_account_with_commitment_and_context(
&mut self,
ctx: Context,
address: Pubkey,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<Option<Account>>> + '_ {
self.inner
.get_account_with_commitment_and_context(ctx, address, commitment)
}
#[async_trait]
pub trait BanksClientExt {
/// Send a transaction and return immediately. The server will resend the
/// transaction until either it is accepted by the cluster or the transaction's
/// blockhash expires.
pub fn send_transaction(
&mut self,
transaction: Transaction,
) -> impl Future<Output = io::Result<()>> + '_ {
self.send_transaction_with_context(context::current(), transaction)
}
/// Return the fee parameters associated with a recent, rooted blockhash. The cluster
/// will use the transaction's blockhash to look up these same fee parameters and
/// use them to calculate the transaction fee.
pub fn get_fees(
&mut self,
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, Slot)>> + '_ {
self.get_fees_with_commitment_and_context(context::current(), CommitmentLevel::Root)
}
/// Return the cluster rent
pub fn get_rent(&mut self) -> impl Future<Output = io::Result<Rent>> + '_ {
self.get_account(sysvar::rent::id()).map(|result| {
let rent_sysvar = result?
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Rent sysvar not present"))?;
from_account::<Rent>(&rent_sysvar).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "Failed to deserialize Rent sysvar")
})
})
}
async fn send_transaction(&mut self, transaction: Transaction) -> io::Result<()>;
/// Return a recent, rooted blockhash from the server. The cluster will only accept
/// transactions with a blockhash that has not yet expired. Use the `get_fees`
/// method to get both a blockhash and the blockhash's last valid slot.
pub fn get_recent_blockhash(&mut self) -> impl Future<Output = io::Result<Hash>> + '_ {
self.get_fees().map(|result| Ok(result?.1))
}
async fn get_recent_blockhash(&mut self) -> io::Result<Hash>;
/// Return the fee parameters associated with a recent, rooted blockhash. The cluster
/// will use the transaction's blockhash to look up these same fee parameters and
/// use them to calculate the transaction fee.
async fn get_fees(&mut self) -> io::Result<(FeeCalculator, Hash, Slot)>;
/// Send a transaction and return after the transaction has been rejected or
/// reached the given level of commitment.
pub fn process_transaction_with_commitment(
async fn process_transaction_with_commitment(
&mut self,
transaction: Transaction,
commitment: CommitmentLevel,
) -> impl Future<Output = transport::Result<()>> + '_ {
let mut ctx = context::current();
ctx.deadline += Duration::from_secs(50);
self.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
.map(|result| match result? {
None => {
Err(Error::new(ErrorKind::TimedOut, "invalid blockhash or fee-payer").into())
}
Some(transaction_result) => Ok(transaction_result?),
})
}
) -> transport::Result<()>;
/// Send a transaction and return until the transaction has been finalized or rejected.
pub fn process_transaction(
&mut self,
transaction: Transaction,
) -> impl Future<Output = transport::Result<()>> + '_ {
self.process_transaction_with_commitment(transaction, CommitmentLevel::default())
}
pub async fn process_transactions_with_commitment(
&mut self,
transactions: Vec<Transaction>,
commitment: CommitmentLevel,
) -> transport::Result<()> {
let mut clients: Vec<_> = transactions.iter().map(|_| self.clone()).collect();
let futures = clients
.iter_mut()
.zip(transactions)
.map(|(client, transaction)| {
client.process_transaction_with_commitment(transaction, commitment)
});
let statuses = join_all(futures).await;
statuses.into_iter().collect() // Convert Vec<Result<_, _>> to Result<Vec<_>>
}
/// Send transactions and return until the transaction has been finalized or rejected.
pub fn process_transactions(
&mut self,
transactions: Vec<Transaction>,
) -> impl Future<Output = transport::Result<()>> + '_ {
self.process_transactions_with_commitment(transactions, CommitmentLevel::default())
}
/// Return the most recent rooted slot height. All transactions at or below this height
/// are said to be finalized. The cluster will not fork to a higher slot height.
pub fn get_root_slot(&mut self) -> impl Future<Output = io::Result<Slot>> + '_ {
self.get_slot_with_context(context::current(), CommitmentLevel::Root)
}
/// Return the account at the given address at the slot corresponding to the given
/// commitment level. If the account is not found, None is returned.
pub fn get_account_with_commitment(
&mut self,
address: Pubkey,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<Option<Account>>> + '_ {
self.get_account_with_commitment_and_context(context::current(), address, commitment)
}
/// Return the account at the given address at the time of the most recent root slot.
/// If the account is not found, None is returned.
pub fn get_account(
&mut self,
address: Pubkey,
) -> impl Future<Output = io::Result<Option<Account>>> + '_ {
self.get_account_with_commitment(address, CommitmentLevel::default())
}
/// Return the balance in lamports of an account at the given address at the slot
/// corresponding to the given commitment level.
pub fn get_balance_with_commitment(
&mut self,
address: Pubkey,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<u64>> + '_ {
self.get_account_with_commitment_and_context(context::current(), address, commitment)
.map(|result| Ok(result?.map(|x| x.lamports).unwrap_or(0)))
}
/// Return the balance in lamports of an account at the given address at the time
/// of the most recent root slot.
pub fn get_balance(&mut self, address: Pubkey) -> impl Future<Output = io::Result<u64>> + '_ {
self.get_balance_with_commitment(address, CommitmentLevel::default())
}
/// Send a transaction and return after the transaction has been finalized or rejected.
async fn process_transaction(&mut self, transaction: Transaction) -> transport::Result<()>;
/// Return the status of a transaction with a signature matching the transaction's first
/// signature. Return None if the transaction is not found, which may be because the
/// blockhash was expired or the fee-paying account had insufficient funds to pay the
/// transaction fee. Note that servers rarely store the full transaction history. This
/// method may return None if the transaction status has been discarded.
pub fn get_transaction_status(
async fn get_transaction_status(
&mut self,
signature: Signature,
) -> impl Future<Output = io::Result<Option<TransactionStatus>>> + '_ {
self.get_transaction_status_with_context(context::current(), signature)
}
) -> io::Result<Option<TransactionStatus>>;
/// Same as get_transaction_status, but for multiple transactions.
pub async fn get_transaction_statuses(
async fn get_transaction_statuses(
&mut self,
signatures: Vec<Signature>,
) -> io::Result<Vec<Option<TransactionStatus>>>;
/// Return the most recent rooted slot height. All transactions at or below this height
/// are said to be finalized. The cluster will not fork to a higher slot height.
async fn get_root_slot(&mut self) -> io::Result<Slot>;
/// Return the account at the given address at the time of the most recent root slot.
/// If the account is not found, None is returned.
async fn get_account(&mut self, address: Pubkey) -> io::Result<Option<Account>>;
/// Return the balance in lamports of an account at the given address at the slot
/// corresponding to the given commitment level.
async fn get_balance_with_commitment(
&mut self,
address: Pubkey,
commitment: CommitmentLevel,
) -> io::Result<u64>;
/// Return the balance in lamports of an account at the given address at the time
/// of the most recent root slot.
async fn get_balance(&mut self, address: Pubkey) -> io::Result<u64>;
}
#[async_trait]
impl BanksClientExt for BanksClient {
async fn send_transaction(&mut self, transaction: Transaction) -> io::Result<()> {
self.send_transaction_with_context(context::current(), transaction)
.await
}
async fn get_fees(&mut self) -> io::Result<(FeeCalculator, Hash, Slot)> {
self.get_fees_with_commitment_and_context(context::current(), CommitmentLevel::Root)
.await
}
async fn get_recent_blockhash(&mut self) -> io::Result<Hash> {
Ok(self.get_fees().await?.1)
}
async fn process_transaction_with_commitment(
&mut self,
transaction: Transaction,
commitment: CommitmentLevel,
) -> transport::Result<()> {
let mut ctx = context::current();
ctx.deadline += Duration::from_secs(50);
let result = self
.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
.await?;
match result {
None => Err(Error::new(ErrorKind::TimedOut, "invalid blockhash or fee-payer").into()),
Some(transaction_result) => Ok(transaction_result?),
}
}
async fn process_transaction(&mut self, transaction: Transaction) -> transport::Result<()> {
self.process_transaction_with_commitment(transaction, CommitmentLevel::default())
.await
}
async fn get_root_slot(&mut self) -> io::Result<Slot> {
self.get_slot_with_context(context::current(), CommitmentLevel::Root)
.await
}
async fn get_account(&mut self, address: Pubkey) -> io::Result<Option<Account>> {
self.get_account_with_commitment_and_context(
context::current(),
address,
CommitmentLevel::default(),
)
.await
}
async fn get_balance_with_commitment(
&mut self,
address: Pubkey,
commitment: CommitmentLevel,
) -> io::Result<u64> {
let account = self
.get_account_with_commitment_and_context(context::current(), address, commitment)
.await?;
Ok(account.map(|x| x.lamports).unwrap_or(0))
}
async fn get_balance(&mut self, address: Pubkey) -> io::Result<u64> {
self.get_balance_with_commitment(address, CommitmentLevel::default())
.await
}
async fn get_transaction_status(
&mut self,
signature: Signature,
) -> io::Result<Option<TransactionStatus>> {
self.get_transaction_status_with_context(context::current(), signature)
.await
}
async fn get_transaction_statuses(
&mut self,
signatures: Vec<Signature>,
) -> io::Result<Vec<Option<TransactionStatus>>> {
@@ -269,20 +184,15 @@ impl BanksClient {
}
}
pub async fn start_client<C>(transport: C) -> io::Result<BanksClient>
where
C: Transport<ClientMessage<BanksRequest>, Response<BanksResponse>> + Send + 'static,
{
Ok(BanksClient {
inner: TarpcClient::new(client::Config::default(), transport).spawn()?,
})
pub async fn start_client(
transport: UnboundedChannel<Response<BanksResponse>, ClientMessage<BanksRequest>>,
) -> io::Result<BanksClient> {
BanksClient::new(client::Config::default(), transport).spawn()
}
pub async fn start_tcp_client<T: ToSocketAddrs>(addr: T) -> io::Result<BanksClient> {
let transport = tcp::connect(addr, Bincode::default).await?;
Ok(BanksClient {
inner: TarpcClient::new(client::Config::default(), transport).spawn()?,
})
let transport = tcp::connect(addr, Bincode::default()).await?;
BanksClient::new(client::Config::default(), transport).spawn()
}
#[cfg(test)]
@@ -290,10 +200,10 @@ mod tests {
use super::*;
use solana_banks_server::banks_server::start_local_server;
use solana_runtime::{bank::Bank, bank_forks::BankForks, genesis_utils::create_genesis_config};
use solana_sdk::{message::Message, signature::Signer, system_instruction};
use solana_sdk::{message::Message, pubkey::Pubkey, signature::Signer, system_instruction};
use std::sync::{Arc, RwLock};
use tarpc::transport;
use tokio::{runtime::Runtime, time::sleep};
use tokio::{runtime::Runtime, time::delay_for};
#[test]
fn test_banks_client_new() {
@@ -312,14 +222,15 @@ mod tests {
&genesis.genesis_config,
))));
let bob_pubkey = solana_sdk::pubkey::new_rand();
let bob_pubkey = Pubkey::new_rand();
let mint_pubkey = genesis.mint_keypair.pubkey();
let instruction = system_instruction::transfer(&mint_pubkey, &bob_pubkey, 1);
let message = Message::new(&[instruction], Some(&mint_pubkey));
Runtime::new()?.block_on(async {
let client_transport = start_local_server(&bank_forks).await;
let mut banks_client = start_client(client_transport).await?;
let mut banks_client =
BanksClient::new(client::Config::default(), client_transport).spawn()?;
let recent_blockhash = banks_client.get_recent_blockhash().await?;
let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash);
@@ -341,13 +252,14 @@ mod tests {
))));
let mint_pubkey = &genesis.mint_keypair.pubkey();
let bob_pubkey = solana_sdk::pubkey::new_rand();
let bob_pubkey = Pubkey::new_rand();
let instruction = system_instruction::transfer(&mint_pubkey, &bob_pubkey, 1);
let message = Message::new(&[instruction], Some(&mint_pubkey));
Runtime::new()?.block_on(async {
let client_transport = start_local_server(&bank_forks).await;
let mut banks_client = start_client(client_transport).await?;
let mut banks_client =
BanksClient::new(client::Config::default(), client_transport).spawn()?;
let (_, recent_blockhash, last_valid_slot) = banks_client.get_fees().await?;
let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash);
let signature = transaction.signatures[0];
@@ -360,7 +272,7 @@ mod tests {
if root_slot > last_valid_slot {
break;
}
sleep(Duration::from_millis(100)).await;
delay_for(Duration::from_millis(100)).await;
status = banks_client.get_transaction_status(signature).await?;
}
assert!(status.unwrap().err.is_none());

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-interface"
version = "1.5.3"
version = "1.3.13"
description = "Solana banks RPC interface"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -9,13 +9,9 @@ homepage = "https://solana.com/"
edition = "2018"
[dependencies]
mio = "0.7.6"
serde = { version = "1.0.112", features = ["derive"] }
solana-sdk = { path = "../sdk", version = "1.5.3" }
tarpc = { version = "0.23.0", features = ["full"] }
[dev-dependencies]
tokio = { version = "0.3.5", features = ["full"] }
solana-sdk = { path = "../sdk", version = "1.3.13" }
tarpc = { version = "0.21.0", features = ["full"] }
[lib]
crate-type = ["lib"]

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-server"
version = "1.5.3"
version = "1.3.13"
description = "Solana banks server"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -11,14 +11,13 @@ edition = "2018"
[dependencies]
bincode = "1.3.1"
futures = "0.3"
log = "0.4.11"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "1.5.3" }
solana-runtime = { path = "../runtime", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-metrics = { path = "../metrics", version = "1.5.3" }
tarpc = { version = "0.23.0", features = ["full"] }
tokio = { version = "0.3", features = ["full"] }
log = "0.4.8"
solana-banks-interface = { path = "../banks-interface", version = "1.3.13" }
solana-runtime = { path = "../runtime", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-metrics = { path = "../metrics", version = "1.3.13" }
tarpc = { version = "0.21.0", features = ["full"] }
tokio = "0.2"
tokio-serde = { version = "0.6", features = ["bincode"] }
[lib]

View File

@@ -5,7 +5,11 @@ use futures::{
prelude::stream::{self, StreamExt},
};
use solana_banks_interface::{Banks, BanksRequest, BanksResponse, TransactionStatus};
use solana_runtime::{bank::Bank, bank_forks::BankForks, commitment::BlockCommitmentCache};
use solana_runtime::{
bank::Bank,
bank_forks::BankForks,
commitment::{BlockCommitmentCache, CommitmentSlots},
};
use solana_sdk::{
account::Account,
clock::Slot,
@@ -17,6 +21,7 @@ use solana_sdk::{
transaction::{self, Transaction},
};
use std::{
collections::HashMap,
io,
net::{Ipv4Addr, SocketAddr},
sync::{
@@ -33,7 +38,7 @@ use tarpc::{
server::{self, Channel, Handler},
transport,
};
use tokio::time::sleep;
use tokio::time::delay_for;
use tokio_serde::formats::Bincode;
#[derive(Clone)]
@@ -79,9 +84,16 @@ impl BanksServer {
let (transaction_sender, transaction_receiver) = channel();
let bank = bank_forks.read().unwrap().working_bank();
let slot = bank.slot();
let block_commitment_cache = Arc::new(RwLock::new(
BlockCommitmentCache::new_for_tests_with_slots(slot, slot),
));
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new(
HashMap::default(),
0,
CommitmentSlots {
slot,
root: 0,
highest_confirmed_slot: 0,
highest_confirmed_root: 0,
},
)));
Builder::new()
.name("solana-bank-forks-client".to_string())
.spawn(move || Self::run(&bank, transaction_receiver))
@@ -102,36 +114,23 @@ impl BanksServer {
async fn poll_signature_status(
self,
signature: &Signature,
blockhash: &Hash,
signature: Signature,
last_valid_slot: Slot,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>> {
let mut status = self
.bank(commitment)
.get_signature_status_with_blockhash(signature, blockhash);
let mut status = self.bank(commitment).get_signature_status(&signature);
while status.is_none() {
sleep(Duration::from_millis(200)).await;
delay_for(Duration::from_millis(200)).await;
let bank = self.bank(commitment);
if bank.slot() > last_valid_slot {
break;
}
status = bank.get_signature_status_with_blockhash(signature, blockhash);
status = bank.get_signature_status(&signature);
}
status
}
}
fn verify_transaction(transaction: &Transaction) -> transaction::Result<()> {
if let Err(err) = transaction.verify() {
Err(err)
} else if let Err(err) = transaction.verify_precompiles() {
Err(err)
} else {
Ok(())
}
}
#[tarpc::server]
impl Banks for BanksServer {
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
@@ -193,23 +192,19 @@ impl Banks for BanksServer {
transaction: Transaction,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>> {
if let Err(err) = verify_transaction(&transaction) {
return Some(Err(err));
}
let blockhash = &transaction.message.recent_blockhash;
let last_valid_slot = self
.bank_forks
.read()
.unwrap()
.root_bank()
.get_blockhash_last_valid_slot(blockhash)
.get_blockhash_last_valid_slot(&blockhash)
.unwrap();
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
let info =
TransactionInfo::new(signature, serialize(&transaction).unwrap(), last_valid_slot);
self.transaction_sender.send(info).unwrap();
self.poll_signature_status(&signature, blockhash, last_valid_slot, commitment)
self.poll_signature_status(signature, last_valid_slot, commitment)
.await
}

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-bench-exchange"
version = "1.5.3"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -11,28 +11,28 @@ publish = false
[dependencies]
clap = "2.33.1"
itertools = "0.9.0"
log = "0.4.11"
log = "0.4.8"
num-derive = "0.3"
num-traits = "0.2"
rand = "0.7.0"
rayon = "1.4.0"
serde_json = "1.0.56"
serde_yaml = "0.8.13"
solana-clap-utils = { path = "../clap-utils", version = "1.5.3" }
solana-core = { path = "../core", version = "1.5.3" }
solana-genesis = { path = "../genesis", version = "1.5.3" }
solana-client = { path = "../client", version = "1.5.3" }
solana-faucet = { path = "../faucet", version = "1.5.3" }
solana-exchange-program = { path = "../programs/exchange", version = "1.5.3" }
solana-logger = { path = "../logger", version = "1.5.3" }
solana-metrics = { path = "../metrics", version = "1.5.3" }
solana-net-utils = { path = "../net-utils", version = "1.5.3" }
solana-runtime = { path = "../runtime", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-version = { path = "../version", version = "1.5.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-core = { path = "../core", version = "1.3.13" }
solana-genesis = { path = "../genesis", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-faucet = { path = "../faucet", version = "1.3.13" }
solana-exchange-program = { path = "../programs/exchange", version = "1.3.13" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-metrics = { path = "../metrics", version = "1.3.13" }
solana-net-utils = { path = "../net-utils", version = "1.3.13" }
solana-runtime = { path = "../runtime", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-version = { path = "../version", version = "1.3.13" }
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "1.5.3" }
solana-local-cluster = { path = "../local-cluster", version = "1.3.13" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -163,8 +163,7 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
)
}
#[allow(clippy::field_reassign_with_default)]
pub fn extract_args(matches: &ArgMatches) -> Config {
pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
let mut args = Config::default();
args.entrypoint_addr = solana_net_utils::parse_host_port(

View File

@@ -22,17 +22,15 @@ fn test_exchange_local_cluster() {
const NUM_NODES: usize = 1;
let config = Config {
identity: Keypair::new(),
duration: Duration::from_secs(1),
fund_amount: 100_000,
threads: 1,
transfer_delay: 20, // 15
batch_size: 100, // 1000
chunk_size: 10, // 200
account_groups: 1, // 10
..Config::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,
@@ -41,7 +39,7 @@ fn test_exchange_local_cluster() {
} = config;
let accounts_in_groups = batch_size * account_groups;
let cluster = LocalCluster::new(&mut ClusterConfig {
let cluster = LocalCluster::new(&ClusterConfig {
node_stakes: vec![100_000; NUM_NODES],
cluster_lamports: 100_000_000_000_000,
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
@@ -88,21 +86,18 @@ fn test_exchange_bank_client() {
solana_logger::setup();
let (genesis_config, identity) = create_genesis_config(100_000_000_000_000);
let mut bank = Bank::new(&genesis_config);
bank.add_builtin("exchange_program", id(), process_instruction);
bank.add_builtin_program("exchange_program", id(), process_instruction);
let clients = vec![BankClient::new(bank)];
do_bench_exchange(
clients,
Config {
identity,
duration: Duration::from_secs(1),
fund_amount: 100_000,
threads: 1,
transfer_delay: 20, // 0;
batch_size: 100, // 1500;
chunk_size: 10, // 1500;
account_groups: 1, // 50;
..Config::default()
},
);
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);
}

View File

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

View File

@@ -2,36 +2,35 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-bench-tps"
version = "1.5.3"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
publish = false
[dependencies]
bincode = "1.3.1"
clap = "2.33.1"
log = "0.4.11"
log = "0.4.8"
rayon = "1.4.0"
serde_json = "1.0.56"
serde_yaml = "0.8.13"
solana-clap-utils = { path = "../clap-utils", version = "1.5.3" }
solana-core = { path = "../core", version = "1.5.3" }
solana-genesis = { path = "../genesis", version = "1.5.3" }
solana-client = { path = "../client", version = "1.5.3" }
solana-faucet = { path = "../faucet", version = "1.5.3" }
solana-logger = { path = "../logger", version = "1.5.3" }
solana-metrics = { path = "../metrics", version = "1.5.3" }
solana-measure = { path = "../measure", version = "1.5.3" }
solana-net-utils = { path = "../net-utils", version = "1.5.3" }
solana-runtime = { path = "../runtime", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-version = { path = "../version", version = "1.5.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-core = { path = "../core", version = "1.3.13" }
solana-genesis = { path = "../genesis", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-faucet = { path = "../faucet", version = "1.3.13" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-metrics = { path = "../metrics", version = "1.3.13" }
solana-measure = { path = "../measure", version = "1.3.13" }
solana-net-utils = { path = "../net-utils", version = "1.3.13" }
solana-runtime = { path = "../runtime", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-version = { path = "../version", version = "1.3.13" }
[dev-dependencies]
serial_test = "0.4.0"
serial_test_derive = "0.4.0"
solana-local-cluster = { path = "../local-cluster", version = "1.5.3" }
solana-local-cluster = { path = "../local-cluster", version = "1.3.13" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -938,12 +938,10 @@ mod tests {
let bank = Bank::new(&genesis_config);
let client = Arc::new(BankClient::new(bank));
let config = Config {
id,
tx_count: 10,
duration: Duration::from_secs(5),
..Config::default()
};
let mut config = Config::default();
config.id = id;
config.tx_count = 10;
config.duration = Duration::from_secs(5);
let keypair_count = config.tx_count * config.keypair_multiplier;
let keypairs =

View File

@@ -196,7 +196,7 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
/// * `matches` - command line arguments parsed by clap
/// # Panics
/// Panics if there is trouble parsing any of the arguments
pub fn extract_args(matches: &ArgMatches) -> Config {
pub fn extract_args<'a>(matches: &ArgMatches<'a>) -> Config {
let mut args = Config::default();
if let Some(addr) = matches.value_of("entrypoint") {

View File

@@ -15,7 +15,7 @@ fn test_bench_tps_local_cluster(config: Config) {
solana_logger::setup();
const NUM_NODES: usize = 1;
let cluster = LocalCluster::new(&mut ClusterConfig {
let cluster = LocalCluster::new(&ClusterConfig {
node_stakes: vec![999_990; NUM_NODES],
cluster_lamports: 200_000_000,
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
@@ -60,9 +60,9 @@ fn test_bench_tps_local_cluster(config: Config) {
#[test]
#[serial]
fn test_bench_tps_local_cluster_solana() {
test_bench_tps_local_cluster(Config {
tx_count: 100,
duration: Duration::from_secs(10),
..Config::default()
});
let mut config = Config::default();
config.tx_count = 100;
config.duration = Duration::from_secs(10);
test_bench_tps_local_cluster(config);
}

31
cargo
View File

@@ -1,31 +0,0 @@
#!/usr/bin/env bash
# shellcheck source=ci/rust-version.sh
here=$(dirname "$0")
source "${here}"/ci/rust-version.sh all
toolchain=
case "$1" in
stable)
# shellcheck disable=SC2054 # rust_stable is sourced from rust-version.sh
toolchain="$rust_stable"
shift
;;
nightly)
# shellcheck disable=SC2054 # rust_nightly is sourced from rust-version.sh
toolchain="$rust_nightly"
shift
;;
+*)
toolchain="${1#+}"
shift
;;
*)
# shellcheck disable=SC2054 # rust_stable is sourced from rust-version.sh
toolchain="$rust_stable"
;;
esac
set -x
exec cargo "+${toolchain}" "${@}"

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env bash
here=$(dirname "$0")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then
maybe_bpf_sdk=
fi
done
set -x
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-build-bpf/Cargo.toml -- $maybe_bpf_sdk "$@"

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
here=$(dirname "$0")
maybe_bpf_sdk="--bpf-sdk $here/sdk/bpf"
for a in "$@"; do
if [[ $a = --bpf-sdk ]]; then
maybe_bpf_sdk=
fi
done
export CARGO_BUILD_BPF="$here"/cargo-build-bpf
set -x
exec "$here"/cargo run --manifest-path "$here"/sdk/cargo-test-bpf/Cargo.toml -- $maybe_bpf_sdk "$@"

View File

@@ -47,8 +47,6 @@ sudo ./setup-new-buildkite-agent/setup-buildkite.sh
```
- Copy the pubkey contents from `~buildkite-agent/.ssh/id_ecdsa.pub` and
add the pubkey as an authorized SSH key on github.
- In net/scripts/solana-user-authorized_keys.sh
- Bug mvines to add it to the "solana-grimes" github user
- Edit `/etc/buildkite-agent/buildkite-agent.cfg` and/or `/etc/systemd/system/buildkite-agent@*` to the desired configuration of the agent(s)
- Copy `ejson` keys from another CI node at `/opt/ejson/keys/`
to the same location on the new node.

View File

@@ -175,30 +175,6 @@ EOF
"Stable-perf skipped as no relevant files were modified"
fi
# Downstream backwards compatibility
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-perf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
^scripts/build-downstream-projects.sh \
; then
cat >> "$output_file" <<"EOF"
- command: "scripts/build-downstream-projects.sh"
name: "downstream-projects"
timeout_in_minutes: 30
EOF
else
annotate --style info \
"downstream-projects skipped as no relevant files were modified"
fi
# Benches...
if affects \
.rs$ \
@@ -263,7 +239,7 @@ if [[ $BUILDKITE_BRANCH =~ ^pull ]]; then
annotate --style info --context pr-backlink \
"Github Pull Request: https://github.com/solana-labs/solana/$BUILDKITE_BRANCH"
if [[ $GITHUB_USER = "dependabot[bot]" ]]; then
if [[ $GITHUB_USER = "dependabot-preview[bot]" ]]; then
command_step dependabot "ci/dependabot-pr.sh" 5
wait_step
fi

View File

@@ -95,14 +95,12 @@ elif [[ -n $CI_BRANCH ]]; then
BRANCH="$CI_BRANCH"
fi
if [[ -z "$CHANNEL" ]]; then
if [[ $BRANCH = "$STABLE_CHANNEL" ]]; then
CHANNEL=stable
elif [[ $BRANCH = "$EDGE_CHANNEL" ]]; then
CHANNEL=edge
elif [[ $BRANCH = "$BETA_CHANNEL" ]]; then
CHANNEL=beta
fi
if [[ $BRANCH = "$STABLE_CHANNEL" ]]; then
CHANNEL=stable
elif [[ $BRANCH = "$EDGE_CHANNEL" ]]; then
CHANNEL=edge
elif [[ $BRANCH = "$BETA_CHANNEL" ]]; then
CHANNEL=beta
fi
echo EDGE_CHANNEL="$EDGE_CHANNEL"

View File

@@ -6,13 +6,13 @@ source ci/_
commit_range="$(git merge-base HEAD origin/master)..HEAD"
parsed_update_args="$(
git log "$commit_range" --author "dependabot\[bot\]" --oneline -n1 |
git log "$commit_range" --author "dependabot-preview" --oneline -n1 |
grep -o '[Bb]ump.*$' |
sed -r 's/[Bb]ump ([^ ]+) from ([^ ]+) to ([^ ]+)/-p \1:\2 --precise \3/'
)"
# relaxed_parsed_update_args is temporal measure...
relaxed_parsed_update_args="$(
git log "$commit_range" --author "dependabot\[bot\]" --oneline -n1 |
git log "$commit_range" --author "dependabot-preview" --oneline -n1 |
grep -o '[Bb]ump.*$' |
sed -r 's/[Bb]ump ([^ ]+) from [^ ]+ to ([^ ]+)/-p \1 --precise \2/'
)"

View File

@@ -1,4 +1,4 @@
FROM solanalabs/rust:1.48.0
FROM solanalabs/rust:1.45.1
ARG date
RUN set -x \

View File

@@ -20,7 +20,7 @@ To update the pinned version:
specific YYYY-MM-DD that is desired (default is today's build).
Check https://rust-lang.github.io/rustup-components-history/ for build
status
1. Update `ci/rust-version.sh` to reflect the new nightly `YYYY-MM-DD`
1. Update `ci/rust-version.sh` to reflect the new nightly `YYY-MM-DD`
1. Run `SOLANA_ALLOCATE_TTY=1 SOLANA_DOCKER_RUN_NOSETUID=1 ci/docker-run.sh --nopull solanalabs/rust-nightly:YYYY-MM-DD ci/test-checks.sh`
and `SOLANA_ALLOCATE_TTY=1 SOLANA_DOCKER_RUN_NOSETUID=1 ci/docker-run.sh --nopull solanalabs/rust-nightly:YYYY-MM-DD ci/test-coverage.sh [args]...`
to confirm the new nightly image builds. Fix any issues as needed

View File

@@ -1,6 +1,6 @@
# Note: when the rust version is changed also modify
# ci/rust-version.sh to pick up the new image tag
FROM rust:1.48.0
FROM rust:1.45.1
# Add Google Protocol Buffers for Libra's metrics library.
ENV PROTOC_VERSION 3.8.0

View File

@@ -26,9 +26,7 @@ declare print_free_tree=(
':runtime/src/**.rs'
':sdk/bpf/rust/rust-utils/**.rs'
':sdk/**.rs'
':^sdk/cargo-build-bpf/**.rs'
':^sdk/program/src/program_option.rs'
':^sdk/program/src/program_stubs.rs'
':^sdk/src/program_option.rs'
':programs/**.rs'
':^**bin**.rs'
':^**bench**.rs'

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python2.7
#
# This script figures the order in which workspace crates must be published to
# crates.io. Along the way it also ensures there are no circular dependencies
@@ -45,27 +45,21 @@ def get_packages():
sorted_dependency_graph = []
max_iterations = pow(len(dependency_graph),2)
while dependency_graph:
deleted_packages = []
if max_iterations == 0:
# One day be more helpful and find the actual cycle for the user...
sys.exit('Error: Circular dependency suspected between these packages: \n {}\n'.format('\n '.join(dependency_graph.keys())))
max_iterations -= 1
for package, dependencies in dependency_graph.items():
if package in deleted_packages:
continue
for dependency in dependencies:
if dependency in dependency_graph:
break
else:
deleted_packages.append(package)
del dependency_graph[package]
sorted_dependency_graph.append((package, manifest_path[package]))
dependency_graph = {p: d for p, d in dependency_graph.items() if not p in deleted_packages }
return sorted_dependency_graph
for package, manifest in get_packages():
print(os.path.relpath(manifest))
print os.path.relpath(manifest)

View File

@@ -16,12 +16,21 @@ fi
[[ -f bpf-sdk.tar.bz2 ]]
)
source ci/upload-ci-artifact.sh
echo --- AWS S3 Store
if [[ -z $CHANNEL_OR_TAG ]]; then
echo Skipped
else
upload-s3-artifact "/solana/bpf-sdk.tar.bz2" "s3://solana-sdk/$CHANNEL_OR_TAG/bpf-sdk.tar.bz2"
(
set -x
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/bpf-sdk.tar.bz2 \
s3://solana-sdk/"$CHANNEL_OR_TAG"/bpf-sdk.tar.bz2
)
fi
exit 0

View File

@@ -4,8 +4,6 @@ cd "$(dirname "$0")/.."
source ci/semver_bash/semver.sh
source ci/rust-version.sh stable
cargo="$(readlink -f ./cargo)"
# shellcheck disable=SC2086
is_crate_version_uploaded() {
name=$1
@@ -40,7 +38,7 @@ for Cargo_toml in $Cargo_tomls; do
crate_name=$(grep -m 1 '^name = ' "$Cargo_toml" | cut -f 3 -d ' ' | tr -d \")
if grep -q "^publish = false" "$Cargo_toml"; then
echo "$crate_name is marked as unpublishable"
echo "$crate_name is is marked as unpublishable"
continue
fi
@@ -68,11 +66,11 @@ for Cargo_toml in $Cargo_tomls; do
(
set -x
rm -rf crate-test
"$cargo" stable init crate-test
cargo +"$rust_stable" init crate-test
cd crate-test/
echo "${crate_name} = \"${expectedCrateVersion}\"" >> Cargo.toml
echo "[workspace]" >> Cargo.toml
"$cargo" stable check
cargo +"$rust_stable" check
) && really_uploaded=1
if ((really_uploaded)); then
break;

View File

@@ -91,15 +91,17 @@ echo --- Creating release tarball
cp "${RELEASE_BASENAME}"/version.yml "${TARBALL_BASENAME}"-$TARGET.yml
)
# Maybe tarballs are platform agnostic, only publish them from the Linux build
# Metrics tarball is platform agnostic, only publish it from Linux
MAYBE_TARBALLS=
if [[ "$CI_OS_NAME" = linux ]]; then
metrics/create-metrics-tarball.sh
(
set -x
sdk/bpf/scripts/package.sh
[[ -f bpf-sdk.tar.bz2 ]]
)
MAYBE_TARBALLS="bpf-sdk.tar.bz2"
MAYBE_TARBALLS="bpf-sdk.tar.bz2 solana-metrics.tar.bz2"
fi
source ci/upload-ci-artifact.sh
@@ -113,10 +115,19 @@ for file in "${TARBALL_BASENAME}"-$TARGET.tar.bz2 "${TARBALL_BASENAME}"-$TARGET.
if [[ -n $BUILDKITE ]]; then
echo --- AWS S3 Store: "$file"
upload-s3-artifact "/solana/$file" s3://release.solana.com/"$CHANNEL_OR_TAG"/"$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 https://release.solana.com/"$CHANNEL_OR_TAG"/"$file"
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"
@@ -138,22 +149,4 @@ for file in "${TARBALL_BASENAME}"-$TARGET.tar.bz2 "${TARBALL_BASENAME}"-$TARGET.
fi
done
# Create install wrapper for release.solana.com
if [[ -n $DO_NOT_PUBLISH_TAR ]]; then
echo "Skipping publishing install wrapper"
elif [[ -n $BUILDKITE ]]; then
cat > release.solana.com-install <<EOF
SOLANA_RELEASE=$CHANNEL_OR_TAG
SOLANA_INSTALL_INIT_ARGS=$CHANNEL_OR_TAG
SOLANA_DOWNLOAD_ROOT=http://release.solana.com
EOF
cat install/solana-install-init.sh >> release.solana.com-install
echo --- AWS S3 Store: "install"
$DRYRUN upload-s3-artifact "/solana/release.solana.com-install" "s3://release.solana.com/$CHANNEL_OR_TAG/install"
echo Published to:
$DRYRUN ci/format-url.sh https://release.solana.com/"$CHANNEL_OR_TAG"/install
fi
echo --- ok

View File

@@ -18,13 +18,13 @@
if [[ -n $RUST_STABLE_VERSION ]]; then
stable_version="$RUST_STABLE_VERSION"
else
stable_version=1.48.0
stable_version=1.45.1
fi
if [[ -n $RUST_NIGHTLY_VERSION ]]; then
nightly_version="$RUST_NIGHTLY_VERSION"
else
nightly_version=2020-12-13
nightly_version=2020-07-27
fi

View File

@@ -7,7 +7,6 @@ SOLANA_ROOT="$HERE"/../..
source "$HERE"/utils.sh
ensure_env || exit 1
check_ssh_authorized_keys || exit 1
set -ex

View File

@@ -6,11 +6,6 @@ HERE="$(dirname "$0")"
source "$HERE"/utils.sh
ensure_env || exit 1
# This is a last ditch effort to prevent the caller from locking themselves
# out of the machine. Exiting here will likely leave the system in some
# half-configured state. To prevent this, duplicate the next line at the top
# of the entrypoint script.
check_ssh_authorized_keys || exit 1
set -xe
# Setup sshd

View File

@@ -14,33 +14,3 @@ ensure_env() {
$RC
}
# Some scripts disable SSH password logins. If no one hash setup authorized_keys
# this will result in the machine being remotely inaccessible. Check that the
# user running this script has setup their keys
check_ssh_authorized_keys() {
declare rc=false
declare user_home=
if [[ -n "$SUDO_USER" ]]; then
declare user uid gid home
declare passwd_entry
passwd_entry="$(grep "$SUDO_USER:[^:]*:$SUDO_UID:$SUDO_GID" /etc/passwd)"
IFS=: read -r user _ uid gid _ home _ <<<"$passwd_entry"
if [[ "$user" == "$SUDO_USER" && "$uid" == "$SUDO_UID" && "$gid" == "$SUDO_GID" ]]; then
user_home="$home"
fi
else
user_home="$HOME"
fi
declare authorized_keys="${user_home}/.ssh/authorized_keys"
if [[ -n "$user_home" ]]; then
[[ -s "$authorized_keys" ]] && rc=true
fi
if ! $rc; then
echo "ERROR! This script will disable SSH password logins and you don't"
echo "appear to have set up any authorized keys. Please add you SSH"
echo "public key to ${authorized_keys} before continuing!"
fi
$rc
}
check_ssh_authorized_keys

View File

@@ -6,8 +6,7 @@ source ci/_
source ci/upload-ci-artifact.sh
eval "$(ci/channel-info.sh)"
cargo="$(readlink -f "./cargo")"
source ci/rust-version.sh all
set -o pipefail
export RUST_BACKTRACE=1
@@ -28,35 +27,35 @@ test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
# Ensure all dependencies are built
_ "$cargo" nightly build --release
_ cargo +$rust_nightly build --release
# Remove "BENCH_FILE", if it exists so that the following commands can append
rm -f "$BENCH_FILE"
# Run sdk benches
_ "$cargo" nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
_ cargo +$rust_nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run runtime benches
_ "$cargo" nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
_ cargo +$rust_nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run core benches
_ "$cargo" nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
_ cargo +$rust_nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run bpf benches
_ "$cargo" nightly bench --manifest-path programs/bpf/Cargo.toml ${V:+--verbose} --features=bpf_c \
_ 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"
# Run banking/accounts bench. Doesn't require nightly, but use since it is already built.
_ "$cargo" nightly run --release --manifest-path banking-bench/Cargo.toml ${V:+--verbose} | tee -a "$BENCH_FILE"
_ "$cargo" nightly run --release --manifest-path accounts-bench/Cargo.toml ${V:+--verbose} -- --num_accounts 10000 --num_slots 4 | tee -a "$BENCH_FILE"
_ cargo +$rust_nightly run --release --manifest-path banking-bench/Cargo.toml ${V:+--verbose} | tee -a "$BENCH_FILE"
_ cargo +$rust_nightly run --release --manifest-path accounts-bench/Cargo.toml ${V:+--verbose} -- --num_accounts 10000 --num_slots 4 | tee -a "$BENCH_FILE"
# `solana-upload-perf` disabled as it can take over 30 minutes to complete for some
# reason
exit 0
_ "$cargo" nightly run --release --package solana-upload-perf \
_ cargo +$rust_nightly run --release --package solana-upload-perf \
-- "$BENCH_FILE" "$TARGET_BRANCH" "$UPLOAD_METRICS" | tee "$BENCH_ARTIFACT"
upload-ci-artifact "$BENCH_FILE"

View File

@@ -8,9 +8,6 @@ source ci/_
source ci/rust-version.sh stable
source ci/rust-version.sh nightly
eval "$(ci/channel-info.sh)"
cargo="$(readlink -f "./cargo")"
scripts/increment-cargo-version.sh check
echo --- build environment
(
@@ -19,14 +16,14 @@ echo --- build environment
rustup run "$rust_stable" rustc --version --verbose
rustup run "$rust_nightly" rustc --version --verbose
"$cargo" stable --version --verbose
"$cargo" nightly --version --verbose
cargo +"$rust_stable" --version --verbose
cargo +"$rust_nightly" --version --verbose
"$cargo" stable clippy --version --verbose
"$cargo" nightly clippy --version --verbose
cargo +"$rust_stable" clippy --version --verbose
cargo +"$rust_nightly" clippy --version --verbose
# audit is done only with stable
"$cargo" stable audit --version
cargo +"$rust_stable" audit --version
)
export RUST_BACKTRACE=1
@@ -47,56 +44,30 @@ if [[ $CI_BASE_BRANCH = "$EDGE_CHANNEL" ]]; then
# Ensure nightly and --benches
_ scripts/cargo-for-all-lock-files.sh +"$rust_nightly" check --locked --all-targets
else
echo "Note: cargo-for-all-lock-files.sh skipped because $CI_BASE_BRANCH != $EDGE_CHANNEL"
fi
_ ci/order-crates-for-publishing.py
_ "$cargo" stable fmt --all -- --check
_ cargo +"$rust_stable" fmt --all -- --check
# -Z... is needed because of clippy bug: https://github.com/rust-lang/rust-clippy/issues/4612
# run nightly clippy for `sdk/` as there's a moderate amount of nightly-only code there
_ "$cargo" nightly clippy -Zunstable-options --workspace --all-targets -- --deny=warnings
_ cargo +"$rust_nightly" clippy -Zunstable-options --workspace --all-targets -- --deny=warnings
cargo_audit_ignores=(
# failure is officially deprecated/unmaintained
#
# Blocked on multiple upstream crates removing their `failure` dependency.
--ignore RUSTSEC-2020-0036
# `net2` crate has been deprecated; use `socket2` instead
#
# Blocked on https://github.com/paritytech/jsonrpc/issues/575
--ignore RUSTSEC-2020-0016
# stdweb is unmaintained
#
# Blocked on multiple upstream crates removing their `stdweb` dependency.
--ignore RUSTSEC-2020-0056
# Potential segfault in the time crate
#
# Blocked on multiple crates updating `time` to >= 0.2.23
--ignore RUSTSEC-2020-0071
# difference is unmaintained
#
# Blocked on predicates v1.0.6 removing its dependency on `difference`
--ignore RUSTSEC-2020-0095
)
_ scripts/cargo-for-all-lock-files.sh +"$rust_stable" audit "${cargo_audit_ignores[@]}"
_ scripts/cargo-for-all-lock-files.sh +"$rust_stable" audit --ignore RUSTSEC-2020-0002 --ignore RUSTSEC-2020-0008
{
cd programs/bpf
_ "$cargo" stable audit
_ cargo +"$rust_stable" audit
for project in rust/*/ ; do
echo "+++ do_bpf_checks $project"
(
cd "$project"
_ "$cargo" stable fmt -- --check
_ "$cargo" nightly test
_ "$cargo" nightly clippy -- --deny=warnings --allow=clippy::missing_safety_doc
_ cargo +"$rust_stable" fmt -- --check
_ cargo +"$rust_nightly" test
_ cargo +"$rust_nightly" clippy -- --deny=warnings --allow=clippy::missing_safety_doc
)
done
}

View File

@@ -8,16 +8,10 @@ source ci/_
(
echo --- git diff --check
set -x
if [[ -n $CI_BASE_BRANCH ]]
then branch="$CI_BASE_BRANCH"
else branch="master"
fi
# Look for failed mergify.io backports by searching leftover conflict markers
# Also check for any trailing whitespaces!
git fetch origin "$branch"
git diff "$(git merge-base HEAD "origin/$branch")" --check --oneline
git fetch origin "$CI_BASE_BRANCH"
git diff "$(git merge-base HEAD "origin/$CI_BASE_BRANCH")..HEAD" --check --oneline
)
echo

View File

@@ -2,8 +2,6 @@
set -e
cd "$(dirname "$0")/.."
cargo="$(readlink -f "./cargo")"
source ci/_
annotate() {
@@ -21,6 +19,9 @@ export RUST_BACKTRACE=1
export RUSTFLAGS="-D warnings"
source scripts/ulimit-n.sh
# Clear cached json keypair files
rm -rf "$HOME/.config/solana"
# Clear the C dependency files, if dependency moves these files are not regenerated
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
@@ -36,15 +37,12 @@ NPROC=$((NPROC>14 ? 14 : NPROC))
echo "Executing $testName"
case $testName in
test-stable)
_ "$cargo" stable test --jobs "$NPROC" --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
_ cargo +"$rust_stable" test --jobs "$NPROC" --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
;;
test-stable-perf)
# BPF solana-sdk legacy compile test
./cargo-build-bpf --manifest-path sdk/Cargo.toml
# BPF program tests
_ make -C programs/bpf/c tests
_ "$cargo" stable test \
_ cargo +"$rust_stable" test \
--manifest-path programs/bpf/Cargo.toml \
--no-default-features --features=bpf_c,bpf_rust -- --nocapture
@@ -64,13 +62,13 @@ test-stable-perf)
export SOLANA_CUDA=1
fi
_ "$cargo" stable build --bins ${V:+--verbose}
_ "$cargo" stable test --package solana-perf --package solana-ledger --package solana-core --lib ${V:+--verbose} -- --nocapture
_ "$cargo" stable run --manifest-path poh-bench/Cargo.toml ${V:+--verbose} -- --hashes-per-tick 10
_ cargo +"$rust_stable" build --bins ${V:+--verbose}
_ cargo +"$rust_stable" test --package solana-perf --package solana-ledger --package solana-core --lib ${V:+--verbose} -- --nocapture
_ cargo +"$rust_stable" run --manifest-path poh-bench/Cargo.toml ${V:+--verbose} -- --hashes-per-tick 10
;;
test-local-cluster)
_ "$cargo" stable build --release --bins ${V:+--verbose}
_ "$cargo" stable test --release --package solana-local-cluster ${V:+--verbose} -- --nocapture --test-threads=1
_ cargo +"$rust_stable" build --release --bins ${V:+--verbose}
_ cargo +"$rust_stable" test --release --package solana-local-cluster ${V:+--verbose} -- --nocapture --test-threads=1
exit 0
;;
*)

View File

@@ -16,16 +16,3 @@ upload-ci-artifact() {
fi
}
upload-s3-artifact() {
echo "--- artifact: $1 to $2"
(
set -x
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 "$1" "$2"
)
}

View File

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

View File

@@ -15,7 +15,7 @@ pub fn commitment_arg_with_default<'a, 'b>(default_value: &'static str) -> Arg<'
Arg::with_name(COMMITMENT_ARG.name)
.long(COMMITMENT_ARG.long)
.takes_value(true)
.possible_values(&["recent", "single", "singleGossip", "root", "max"])
.possible_values(&["recent", "single", "root", "max"])
.default_value(default_value)
.value_name("COMMITMENT_LEVEL")
.help(COMMITMENT_ARG.help)

View File

@@ -189,7 +189,6 @@ pub fn commitment_of(matches: &ArgMatches<'_>, name: &str) -> Option<CommitmentC
"recent" => CommitmentConfig::recent(),
"root" => CommitmentConfig::root(),
"single" => CommitmentConfig::single(),
"singleGossip" => CommitmentConfig::single_gossip(),
_ => CommitmentConfig::default(),
})
}
@@ -229,8 +228,8 @@ mod tests {
assert_eq!(values_of(&matches, "multiple"), Some(vec![50, 39]));
assert_eq!(values_of::<u64>(&matches, "single"), None);
let pubkey0 = solana_sdk::pubkey::new_rand();
let pubkey1 = solana_sdk::pubkey::new_rand();
let pubkey0 = Pubkey::new_rand();
let pubkey1 = Pubkey::new_rand();
let matches = app().clone().get_matches_from(vec![
"test",
"--multiple",
@@ -252,7 +251,7 @@ mod tests {
assert_eq!(value_of(&matches, "single"), Some(50));
assert_eq!(value_of::<u64>(&matches, "multiple"), None);
let pubkey = solana_sdk::pubkey::new_rand();
let pubkey = Pubkey::new_rand();
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", &pubkey.to_string()]);
@@ -332,8 +331,8 @@ mod tests {
#[test]
fn test_pubkeys_sigs_of() {
let key1 = solana_sdk::pubkey::new_rand();
let key2 = solana_sdk::pubkey::new_rand();
let key1 = Pubkey::new_rand();
let key2 = Pubkey::new_rand();
let sig1 = Keypair::new().sign_message(&[0u8]);
let sig2 = Keypair::new().sign_message(&[1u8]);
let signer1 = format!("{}={}", key1, sig1);

View File

@@ -1,7 +1,7 @@
use crate::keypair::{parse_keypair_path, KeypairUrl, ASK_KEYWORD};
use chrono::DateTime;
use solana_sdk::{
clock::{Epoch, Slot},
clock::Slot,
hash::Hash,
pubkey::Pubkey,
signature::{read_keypair_file, Signature},
@@ -148,40 +148,6 @@ where
}
}
pub fn is_url_or_moniker<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
match url::Url::parse(&normalize_to_url_if_moniker(string.as_ref())) {
Ok(url) => {
if url.has_host() {
Ok(())
} else {
Err("no host provided".to_string())
}
}
Err(err) => Err(format!("{}", err)),
}
}
pub fn normalize_to_url_if_moniker(url_or_moniker: &str) -> String {
match url_or_moniker {
"m" | "mainnet-beta" => "https://api.mainnet-beta.solana.com",
"t" | "testnet" => "https://testnet.solana.com",
"d" | "devnet" => "https://devnet.solana.com",
"l" | "localhost" => "http://localhost:8899",
url => url,
}
.to_string()
}
pub fn is_epoch<T>(epoch: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
is_parsable_generic::<Epoch, _>(epoch)
}
pub fn is_slot<T>(slot: T) -> Result<(), String>
where
T: AsRef<str> + Display,

View File

@@ -58,15 +58,6 @@ impl CliSignerInfo {
Some(0)
}
}
pub fn index_of_or_none(&self, pubkey: Option<Pubkey>) -> Option<usize> {
if let Some(pubkey) = pubkey {
self.signers
.iter()
.position(|signer| signer.pubkey() == pubkey)
} else {
None
}
}
}
pub struct DefaultSigner {
@@ -307,24 +298,7 @@ pub fn keypair_from_seed_phrase(
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)?
} else {
let sanitized = sanitize_seed_phrase(seed_phrase);
let parse_language_fn = || {
for language in &[
Language::English,
Language::ChineseSimplified,
Language::ChineseTraditional,
Language::Japanese,
Language::Spanish,
Language::Korean,
Language::French,
Language::Italian,
] {
if let Ok(mnemonic) = Mnemonic::from_phrase(&sanitized, *language) {
return Ok(mnemonic);
}
}
Err("Can't get mnemonic from seed phrases")
};
let mnemonic = parse_language_fn()?;
let mnemonic = Mnemonic::from_phrase(&sanitized, Language::English)?;
let passphrase = prompt_passphrase(&passphrase_prompt)?;
let seed = Seed::new(&mnemonic, &passphrase);
keypair_from_seed(seed.as_bytes())?

View File

@@ -36,15 +36,12 @@ pub fn nonce_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
}
pub trait NonceArgs {
fn nonce_args(self, global: bool) -> Self;
fn nonce_args(self) -> Self;
}
impl NonceArgs for App<'_, '_> {
fn nonce_args(self, global: bool) -> Self {
self.arg(nonce_arg().global(global)).arg(
nonce_authority_arg()
.requires(NONCE_ARG.name)
.global(global),
)
fn nonce_args(self) -> Self {
self.arg(nonce_arg())
.arg(nonce_authority_arg().requires(NONCE_ARG.name))
}
}

View File

@@ -47,32 +47,14 @@ fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
.help(SIGNER_ARG.help)
}
pub trait ArgsConfig {
fn blockhash_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
arg
}
fn sign_only_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
arg
}
fn signer_arg<'a, 'b>(&self, arg: Arg<'a, 'b>) -> Arg<'a, 'b> {
arg
}
}
pub trait OfflineArgs {
fn offline_args(self) -> Self;
fn offline_args_config(self, config: &dyn ArgsConfig) -> Self;
}
impl OfflineArgs for App<'_, '_> {
fn offline_args_config(self, config: &dyn ArgsConfig) -> Self {
self.arg(config.blockhash_arg(blockhash_arg()))
.arg(config.sign_only_arg(sign_only_arg()))
.arg(config.signer_arg(signer_arg()))
}
fn offline_args(self) -> Self {
struct NullArgsConfig {}
impl ArgsConfig for NullArgsConfig {}
self.offline_args_config(&NullArgsConfig {})
self.arg(blockhash_arg())
.arg(sign_only_arg())
.arg(signer_arg())
}
}

View File

@@ -3,13 +3,13 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli-config"
description = "Blockchain, Rebuilt for Scale"
version = "1.5.3"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
dirs-next = "2.0.0"
dirs = "2.0.2"
lazy_static = "1.4.0"
serde = "1.0.112"
serde_derive = "1.0.103"

View File

@@ -5,7 +5,7 @@ use url::Url;
lazy_static! {
pub static ref CONFIG_FILE: Option<String> = {
dirs_next::home_dir().map(|mut path| {
dirs::home_dir().map(|mut path| {
path.extend(&[".config", "solana", "cli", "config.yml"]);
path.to_str().unwrap().to_string()
})
@@ -25,7 +25,7 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
let keypair_path = {
let mut keypair_path = dirs_next::home_dir().expect("home directory");
let mut keypair_path = dirs::home_dir().expect("home directory");
keypair_path.extend(&[".config", "solana", "id.json"]);
keypair_path.to_str().unwrap().to_string()
};
@@ -76,6 +76,17 @@ impl Config {
ws_url.to_string()
}
pub fn compute_rpc_banks_url(json_rpc_url: &str) -> String {
let json_rpc_url: Option<Url> = json_rpc_url.parse().ok();
if json_rpc_url.is_none() {
return "".to_string();
}
let mut url = json_rpc_url.unwrap();
let port = url.port_or_known_default().unwrap_or(80);
url.set_port(Some(port + 3)).expect("unable to set port");
url.to_string()
}
pub fn import_address_labels<P>(&mut self, filename: P) -> Result<(), io::Error>
where
P: AsRef<Path>,
@@ -122,4 +133,28 @@ mod test {
assert_eq!(Config::compute_websocket_url(&"garbage"), String::new());
}
#[test]
fn compute_rpc_banks_url() {
assert_eq!(
Config::compute_rpc_banks_url(&"http://devnet.solana.com"),
"http://devnet.solana.com:83/".to_string()
);
assert_eq!(
Config::compute_rpc_banks_url(&"https://devnet.solana.com"),
"https://devnet.solana.com:446/".to_string()
);
assert_eq!(
Config::compute_rpc_banks_url(&"http://example.com:8899"),
"http://example.com:8902/".to_string()
);
assert_eq!(
Config::compute_rpc_banks_url(&"https://example.com:1234"),
"https://example.com:1237/".to_string()
);
assert_eq!(Config::compute_rpc_banks_url(&"garbage"), String::new());
}
}

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli-output"
description = "Blockchain, Rebuilt for Scale"
version = "1.5.3"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -17,13 +17,12 @@ indicatif = "0.15.0"
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "1.5.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.3" }
solana-client = { path = "../client", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-stake-program = { path = "../programs/stake", version = "1.5.3" }
solana-transaction-status = { path = "../transaction-status", version = "1.5.3" }
solana-vote-program = { path = "../programs/vote", version = "1.5.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-stake-program = { path = "../programs/stake", version = "1.3.13" }
solana-transaction-status = { path = "../transaction-status", version = "1.3.13" }
solana-vote-program = { path = "../programs/vote", version = "1.3.13" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,17 +1,12 @@
use crate::{
display::{build_balance_message, format_labeled_address, writeln_name_value},
QuietDisplay, VerboseDisplay,
};
use crate::display::{build_balance_message, format_labeled_address, writeln_name_value};
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
use console::{style, Emoji};
use inflector::cases::titlecase::to_title_case;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use solana_account_decoder::parse_token::UiTokenAccount;
use solana_clap_utils::keypair::SignOnly;
use solana_client::rpc_response::{
RpcAccountBalance, RpcInflationGovernor, RpcInflationRate, RpcKeyedAccount, RpcSupply,
RpcVoteAccountInfo,
RpcAccountBalance, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
};
use solana_sdk::{
clock::{self, Epoch, Slot, UnixTimestamp},
@@ -42,27 +37,15 @@ pub enum OutputFormat {
Display,
Json,
JsonCompact,
DisplayQuiet,
DisplayVerbose,
}
impl OutputFormat {
pub fn formatted_string<T>(&self, item: &T) -> String
where
T: Serialize + fmt::Display + QuietDisplay + VerboseDisplay,
T: Serialize + fmt::Display,
{
match self {
OutputFormat::Display => format!("{}", item),
OutputFormat::DisplayQuiet => {
let mut s = String::new();
QuietDisplay::write_str(item, &mut s).unwrap();
s
}
OutputFormat::DisplayVerbose => {
let mut s = String::new();
VerboseDisplay::write_str(item, &mut s).unwrap();
s
}
OutputFormat::Json => serde_json::to_string_pretty(item).unwrap(),
OutputFormat::JsonCompact => serde_json::to_value(item).unwrap().to_string(),
}
@@ -77,9 +60,6 @@ pub struct CliAccount {
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliAccount {}
impl VerboseDisplay for CliAccount {}
impl fmt::Display for CliAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
@@ -122,9 +102,6 @@ pub struct CliBlockProduction {
pub verbose: bool,
}
impl QuietDisplay for CliBlockProduction {}
impl VerboseDisplay for CliBlockProduction {}
impl fmt::Display for CliBlockProduction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
@@ -133,7 +110,7 @@ impl fmt::Display for CliBlockProduction {
"{}",
style(format!(
" {:<44} {:>15} {:>15} {:>15} {:>23}",
"Identity",
"Identity Pubkey",
"Leader Slots",
"Blocks Produced",
"Skipped Slots",
@@ -229,9 +206,6 @@ impl From<EpochInfo> for CliEpochInfo {
}
}
impl QuietDisplay for CliEpochInfo {}
impl VerboseDisplay for CliEpochInfo {}
impl fmt::Display for CliEpochInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
@@ -242,9 +216,6 @@ impl fmt::Display for CliEpochInfo {
)?;
writeln_name_value(f, "Slot:", &self.epoch_info.absolute_slot.to_string())?;
writeln_name_value(f, "Epoch:", &self.epoch_info.epoch.to_string())?;
if let Some(transaction_count) = &self.epoch_info.transaction_count {
writeln_name_value(f, "Transaction Count:", &transaction_count.to_string())?;
}
let start_slot = self.epoch_info.absolute_slot - self.epoch_info.slot_index;
let end_slot = start_slot + self.epoch_info.slots_in_epoch;
writeln_name_value(
@@ -305,7 +276,7 @@ pub struct CliValidatorsStakeByVersion {
pub struct CliValidators {
pub total_active_stake: u64,
pub total_current_stake: u64,
pub total_delinquent_stake: u64,
pub total_deliquent_stake: u64,
pub current_validators: Vec<CliValidator>,
pub delinquent_validators: Vec<CliValidator>,
pub stake_by_version: BTreeMap<String, CliValidatorsStakeByVersion>,
@@ -313,9 +284,6 @@ pub struct CliValidators {
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliValidators {}
impl VerboseDisplay for CliValidators {}
impl fmt::Display for CliValidators {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn write_vote_account(
@@ -364,7 +332,7 @@ impl fmt::Display for CliValidators {
"Active Stake:",
&build_balance_message(self.total_active_stake, self.use_lamports_unit, true),
)?;
if self.total_delinquent_stake > 0 {
if self.total_deliquent_stake > 0 {
writeln_name_value(
f,
"Current Stake:",
@@ -380,11 +348,11 @@ impl fmt::Display for CliValidators {
&format!(
"{} ({:0.2}%)",
&build_balance_message(
self.total_delinquent_stake,
self.total_deliquent_stake,
self.use_lamports_unit,
true
),
100. * self.total_delinquent_stake as f64 / self.total_active_stake as f64
100. * self.total_deliquent_stake as f64 / self.total_active_stake as f64
),
)?;
}
@@ -416,8 +384,8 @@ impl fmt::Display for CliValidators {
"{}",
style(format!(
" {:<44} {:<38} {} {} {} {:>10} {:^8} {}",
"Identity",
"Vote Account",
"Identity Pubkey",
"Vote Account Pubkey",
"Commission",
"Last Vote",
"Root Block",
@@ -504,9 +472,6 @@ pub struct CliNonceAccount {
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliNonceAccount {}
impl VerboseDisplay for CliNonceAccount {}
impl fmt::Display for CliNonceAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
@@ -524,7 +489,7 @@ impl fmt::Display for CliNonceAccount {
)
)?;
let nonce = self.nonce.as_deref().unwrap_or("uninitialized");
writeln!(f, "Nonce blockhash: {}", nonce)?;
writeln!(f, "Nonce: {}", nonce)?;
if let Some(fees) = self.lamports_per_signature {
writeln!(f, "Fee: {} lamports per signature", fees)?;
} else {
@@ -544,17 +509,6 @@ impl CliStakeVec {
}
}
impl QuietDisplay for CliStakeVec {}
impl VerboseDisplay for CliStakeVec {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
for state in &self.0 {
writeln!(w)?;
VerboseDisplay::write_str(state, w)?;
}
Ok(())
}
}
impl fmt::Display for CliStakeVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for state in &self.0 {
@@ -573,14 +527,6 @@ pub struct CliKeyedStakeState {
pub stake_state: CliStakeState,
}
impl QuietDisplay for CliKeyedStakeState {}
impl VerboseDisplay for CliKeyedStakeState {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
writeln!(w, "Stake Pubkey: {}", self.stake_pubkey)?;
VerboseDisplay::write_str(&self.stake_state, w)
}
}
impl fmt::Display for CliKeyedStakeState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Stake Pubkey: {}", self.stake_pubkey)?;
@@ -588,98 +534,12 @@ impl fmt::Display for CliKeyedStakeState {
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliEpochReward {
pub epoch: Epoch,
pub effective_slot: Slot,
pub amount: u64, // lamports
pub post_balance: u64, // lamports
pub percent_change: f64,
pub apr: Option<f64>,
}
fn show_votes_and_credits(
f: &mut fmt::Formatter,
votes: &[CliLockout],
epoch_voting_history: &[CliEpochVotingHistory],
) -> fmt::Result {
if votes.is_empty() {
return Ok(());
}
writeln!(f, "Recent Votes:")?;
for vote in votes {
writeln!(f, "- slot: {}", vote.slot)?;
writeln!(f, " confirmation count: {}", vote.confirmation_count)?;
}
writeln!(f, "Epoch Voting History:")?;
writeln!(
f,
"* missed credits include slots unavailable to vote on due to delinquent leaders",
)?;
for entry in epoch_voting_history {
writeln!(
f, // tame fmt so that this will be folded like following
"- epoch: {}",
entry.epoch
)?;
writeln!(
f,
" credits range: [{}..{})",
entry.prev_credits, entry.credits
)?;
writeln!(
f,
" credits/slots: {}/{}",
entry.credits_earned, entry.slots_in_epoch
)?;
}
Ok(())
}
fn show_epoch_rewards(
f: &mut fmt::Formatter,
epoch_rewards: &Option<Vec<CliEpochReward>>,
) -> fmt::Result {
if let Some(epoch_rewards) = epoch_rewards {
if epoch_rewards.is_empty() {
return Ok(());
}
writeln!(f, "Epoch Rewards:")?;
writeln!(
f,
" {:<6} {:<11} {:<16} {:<16} {:>14} {:>14}",
"Epoch", "Reward Slot", "Amount", "New Balance", "Percent Change", "APR"
)?;
for reward in epoch_rewards {
writeln!(
f,
" {:<6} {:<11} ◎{:<16.9} ◎{:<14.9} {:>13.2}% {}",
reward.epoch,
reward.effective_slot,
lamports_to_sol(reward.amount),
lamports_to_sol(reward.post_balance),
reward.percent_change,
reward
.apr
.map(|apr| format!("{:>13.2}%", apr))
.unwrap_or_default(),
)?;
}
}
Ok(())
}
#[derive(Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliStakeState {
pub stake_type: CliStakeType,
pub account_balance: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub credits_observed: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delegated_stake: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delegated_vote_account_address: Option<String>,
@@ -703,19 +563,6 @@ pub struct CliStakeState {
pub activating_stake: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deactivating_stake: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub epoch_rewards: Option<Vec<CliEpochReward>>,
}
impl QuietDisplay for CliStakeState {}
impl VerboseDisplay for CliStakeState {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
write!(w, "{}", self)?;
if let Some(credits) = self.credits_observed {
writeln!(w, "Credits Observed: {}", credits)?;
}
Ok(())
}
}
impl fmt::Display for CliStakeState {
@@ -730,8 +577,13 @@ impl fmt::Display for CliStakeState {
if lockup.unix_timestamp != UnixTimestamp::default() {
writeln!(
f,
"Lockup Timestamp: {}",
unix_timestamp_to_string(lockup.unix_timestamp)
"Lockup Timestamp: {} (UnixTimestamp: {})",
DateTime::<Utc>::from_utc(
NaiveDateTime::from_timestamp(lockup.unix_timestamp, 0),
Utc
)
.to_rfc3339_opts(SecondsFormat::Secs, true),
lockup.unix_timestamp
)?;
}
if lockup.epoch != Epoch::default() {
@@ -861,14 +713,13 @@ impl fmt::Display for CliStakeState {
}
show_authorized(f, self.authorized.as_ref().unwrap())?;
show_lockup(f, self.lockup.as_ref())?;
show_epoch_rewards(f, &self.epoch_rewards)?
}
}
Ok(())
}
}
#[derive(Serialize, Deserialize, PartialEq)]
#[derive(Serialize, Deserialize)]
pub enum CliStakeType {
Stake,
RewardsPool,
@@ -890,9 +741,6 @@ pub struct CliStakeHistory {
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliStakeHistory {}
impl VerboseDisplay for CliStakeHistory {}
impl fmt::Display for CliStakeHistory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
@@ -987,9 +835,6 @@ impl CliValidatorInfoVec {
}
}
impl QuietDisplay for CliValidatorInfoVec {}
impl VerboseDisplay for CliValidatorInfoVec {}
impl fmt::Display for CliValidatorInfoVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.0.is_empty() {
@@ -1011,13 +856,10 @@ pub struct CliValidatorInfo {
pub info: Map<String, Value>,
}
impl QuietDisplay for CliValidatorInfo {}
impl VerboseDisplay for CliValidatorInfo {}
impl fmt::Display for CliValidatorInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Validator Identity:", &self.identity_pubkey)?;
writeln_name_value(f, " Info Address:", &self.info_pubkey)?;
writeln_name_value(f, "Validator Identity Pubkey:", &self.identity_pubkey)?;
writeln_name_value(f, " Info Pubkey:", &self.info_pubkey)?;
for (key, value) in self.info.iter() {
writeln_name_value(
f,
@@ -1045,13 +887,8 @@ pub struct CliVoteAccount {
pub epoch_voting_history: Vec<CliEpochVotingHistory>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub epoch_rewards: Option<Vec<CliEpochReward>>,
}
impl QuietDisplay for CliVoteAccount {}
impl VerboseDisplay for CliVoteAccount {}
impl fmt::Display for CliVoteAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
@@ -1072,14 +909,25 @@ impl fmt::Display for CliVoteAccount {
None => "~".to_string(),
}
)?;
writeln!(
f,
"Recent Timestamp: {} from slot {}",
unix_timestamp_to_string(self.recent_timestamp.timestamp),
self.recent_timestamp.slot
)?;
show_votes_and_credits(f, &self.votes, &self.epoch_voting_history)?;
show_epoch_rewards(f, &self.epoch_rewards)?;
writeln!(f, "Recent Timestamp: {:?}", self.recent_timestamp)?;
if !self.votes.is_empty() {
writeln!(f, "Recent Votes:")?;
for vote in &self.votes {
writeln!(
f,
"- slot: {}\n confirmation count: {}",
vote.slot, vote.confirmation_count
)?;
}
writeln!(f, "Epoch Voting History:")?;
for epoch_info in &self.epoch_voting_history {
writeln!(
f,
"- epoch: {}\n slots in epoch: {}\n credits earned: {}",
epoch_info.epoch, epoch_info.slots_in_epoch, epoch_info.credits_earned,
)?;
}
}
Ok(())
}
}
@@ -1090,9 +938,6 @@ pub struct CliAuthorizedVoters {
authorized_voters: BTreeMap<Epoch, String>,
}
impl QuietDisplay for CliAuthorizedVoters {}
impl VerboseDisplay for CliAuthorizedVoters {}
impl fmt::Display for CliAuthorizedVoters {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.authorized_voters)
@@ -1117,8 +962,6 @@ pub struct CliEpochVotingHistory {
pub epoch: Epoch,
pub slots_in_epoch: u64,
pub credits_earned: u64,
pub credits: u64,
pub prev_credits: u64,
}
#[derive(Serialize, Deserialize)]
@@ -1144,122 +987,18 @@ pub struct CliBlockTime {
pub timestamp: UnixTimestamp,
}
impl QuietDisplay for CliBlockTime {}
impl VerboseDisplay for CliBlockTime {}
fn unix_timestamp_to_string(unix_timestamp: UnixTimestamp) -> String {
format!(
"{} (UnixTimestamp: {})",
match NaiveDateTime::from_timestamp_opt(unix_timestamp, 0) {
Some(ndt) =>
DateTime::<Utc>::from_utc(ndt, Utc).to_rfc3339_opts(SecondsFormat::Secs, true),
None => "unknown".to_string(),
},
unix_timestamp,
)
}
impl fmt::Display for CliBlockTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Block:", &self.slot.to_string())?;
writeln_name_value(f, "Date:", &unix_timestamp_to_string(self.timestamp))
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliLeaderSchedule {
pub epoch: Epoch,
pub leader_schedule_entries: Vec<CliLeaderScheduleEntry>,
}
impl QuietDisplay for CliLeaderSchedule {}
impl VerboseDisplay for CliLeaderSchedule {}
impl fmt::Display for CliLeaderSchedule {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for entry in &self.leader_schedule_entries {
writeln!(f, " {:<15} {:<44}", entry.slot, entry.leader)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliLeaderScheduleEntry {
pub slot: Slot,
pub leader: String,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliInflation {
pub governor: RpcInflationGovernor,
pub current_rate: RpcInflationRate,
}
impl QuietDisplay for CliInflation {}
impl VerboseDisplay for CliInflation {}
impl fmt::Display for CliInflation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{}", style("Inflation Governor:").bold())?;
if (self.governor.initial - self.governor.terminal).abs() < f64::EPSILON {
writeln!(
f,
"Fixed APR: {:>5.2}%",
self.governor.terminal * 100.
)?;
} else {
writeln!(
f,
"Initial APR: {:>5.2}%",
self.governor.initial * 100.
)?;
writeln!(
f,
"Terminal APR: {:>5.2}%",
self.governor.terminal * 100.
)?;
writeln!(
f,
"Rate reduction per year: {:>5.2}%",
self.governor.taper * 100.
)?;
}
if self.governor.foundation_term > 0. {
writeln!(
f,
"Foundation percentage: {:>5.2}%",
self.governor.foundation
)?;
writeln!(
f,
"Foundation term: {:.1} years",
self.governor.foundation_term
)?;
}
writeln!(
writeln_name_value(
f,
"\n{}",
style(format!("Inflation for Epoch {}:", self.current_rate.epoch)).bold()
)?;
writeln!(
f,
"Total APR: {:>5.2}%",
self.current_rate.total * 100.
)?;
writeln!(
f,
"Staking APR: {:>5.2}%",
self.current_rate.validator * 100.
)?;
writeln!(
f,
"Foundation APR: {:>5.2}%",
self.current_rate.foundation * 100.
"Date:",
&format!(
"{} (UnixTimestamp: {})",
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(self.timestamp, 0), Utc)
.to_rfc3339_opts(SecondsFormat::Secs, true),
self.timestamp
),
)
}
}
@@ -1276,9 +1015,6 @@ pub struct CliSignOnlyData {
pub bad_sig: Vec<String>,
}
impl QuietDisplay for CliSignOnlyData {}
impl VerboseDisplay for CliSignOnlyData {}
impl fmt::Display for CliSignOnlyData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
@@ -1311,9 +1047,6 @@ pub struct CliSignature {
pub signature: String,
}
impl QuietDisplay for CliSignature {}
impl VerboseDisplay for CliSignature {}
impl fmt::Display for CliSignature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
@@ -1328,9 +1061,6 @@ pub struct CliAccountBalances {
pub accounts: Vec<RpcAccountBalance>,
}
impl QuietDisplay for CliAccountBalances {}
impl VerboseDisplay for CliAccountBalances {}
impl fmt::Display for CliAccountBalances {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
@@ -1373,9 +1103,6 @@ impl From<RpcSupply> for CliSupply {
}
}
impl QuietDisplay for CliSupply {}
impl VerboseDisplay for CliSupply {}
impl fmt::Display for CliSupply {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Total:", &format!("{} SOL", lamports_to_sol(self.total)))?;
@@ -1409,9 +1136,6 @@ pub struct CliFees {
pub last_valid_slot: Slot,
}
impl QuietDisplay for CliFees {}
impl VerboseDisplay for CliFees {}
impl fmt::Display for CliFees {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Blockhash:", &self.blockhash)?;
@@ -1425,50 +1149,6 @@ impl fmt::Display for CliFees {
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliTokenAccount {
pub address: String,
#[serde(flatten)]
pub token_account: UiTokenAccount,
}
impl QuietDisplay for CliTokenAccount {}
impl VerboseDisplay for CliTokenAccount {}
impl fmt::Display for CliTokenAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Address:", &self.address)?;
let account = &self.token_account;
writeln_name_value(
f,
"Balance:",
&account.token_amount.real_number_string_trimmed(),
)?;
let mint = format!(
"{}{}",
account.mint,
if account.is_native { " (native)" } else { "" }
);
writeln_name_value(f, "Mint:", &mint)?;
writeln_name_value(f, "Owner:", &account.owner)?;
writeln_name_value(f, "State:", &format!("{:?}", account.state))?;
if let Some(delegate) = &account.delegate {
writeln!(f, "Delegation:")?;
writeln_name_value(f, " Delegate:", delegate)?;
let allowance = account.delegated_amount.as_ref().unwrap();
writeln_name_value(f, " Allowance:", &allowance.real_number_string_trimmed())?;
}
writeln_name_value(
f,
"Close authority:",
&account.close_authority.as_ref().unwrap_or(&String::new()),
)?;
Ok(())
}
}
pub fn return_signers(
tx: &Transaction,
output_format: &OutputFormat,
@@ -1613,51 +1293,4 @@ mod tests {
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
}
#[test]
fn test_verbose_quiet_output_formats() {
#[derive(Deserialize, Serialize)]
struct FallbackToDisplay {}
impl std::fmt::Display for FallbackToDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "display")
}
}
impl QuietDisplay for FallbackToDisplay {}
impl VerboseDisplay for FallbackToDisplay {}
let f = FallbackToDisplay {};
assert_eq!(&OutputFormat::Display.formatted_string(&f), "display");
assert_eq!(&OutputFormat::DisplayQuiet.formatted_string(&f), "display");
assert_eq!(
&OutputFormat::DisplayVerbose.formatted_string(&f),
"display"
);
#[derive(Deserialize, Serialize)]
struct DiscreteVerbosityDisplay {}
impl std::fmt::Display for DiscreteVerbosityDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "display")
}
}
impl QuietDisplay for DiscreteVerbosityDisplay {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
write!(w, "quiet")
}
}
impl VerboseDisplay for DiscreteVerbosityDisplay {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
write!(w, "verbose")
}
}
let f = DiscreteVerbosityDisplay {};
assert_eq!(&OutputFormat::Display.formatted_string(&f), "display");
assert_eq!(&OutputFormat::DisplayQuiet.formatted_string(&f), "quiet");
assert_eq!(
&OutputFormat::DisplayVerbose.formatted_string(&f),
"verbose"
);
}
}

View File

@@ -27,7 +27,7 @@ pub fn build_balance_message(lamports: u64, use_lamports_unit: bool, show_unit:
// Pretty print a "name value"
pub fn println_name_value(name: &str, value: &str) {
let styled_value = if value.is_empty() {
let styled_value = if value == "" {
style("(not set)").italic()
} else {
style(value)
@@ -36,7 +36,7 @@ pub fn println_name_value(name: &str, value: &str) {
}
pub fn writeln_name_value(f: &mut fmt::Formatter, name: &str, value: &str) -> fmt::Result {
let styled_value = if value.is_empty() {
let styled_value = if value == "" {
style("(not set)").italic()
} else {
style(value)
@@ -197,15 +197,6 @@ pub fn write_transaction<W: io::Write>(
)?;
}
}
if let Some(log_messages) = &transaction_status.log_messages {
if !log_messages.is_empty() {
writeln!(w, "{}Log Messages:", prefix,)?;
for log_message in log_messages {
writeln!(w, "{} {}", prefix, log_message,)?;
}
}
}
} else {
writeln!(w, "{}Status: Unavailable", prefix)?;
}

View File

@@ -1,15 +1,3 @@
mod cli_output;
pub mod display;
pub use cli_output::*;
pub trait QuietDisplay: std::fmt::Display {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
write!(w, "{}", self)
}
}
pub trait VerboseDisplay: std::fmt::Display {
fn write_str(&self, w: &mut dyn std::fmt::Write) -> std::fmt::Result {
write!(w, "{}", self)
}
}

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "1.5.3"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -16,40 +16,40 @@ clap = "2.33.1"
criterion-stats = "0.3.0"
ctrlc = { version = "3.1.5", features = ["termination"] }
console = "0.11.3"
dirs-next = "2.0.0"
log = "0.4.11"
dirs = "2.0.2"
log = "0.4.8"
Inflector = "0.11.4"
indicatif = "0.15.0"
humantime = "2.0.1"
num-traits = "0.2"
pretty-hex = "0.2.1"
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
pretty-hex = "0.1.1"
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "1.5.3" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.5.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.3" }
solana-cli-config = { path = "../cli-config", version = "1.5.3" }
solana-cli-output = { path = "../cli-output", version = "1.5.3" }
solana-client = { path = "../client", version = "1.5.3" }
solana-config-program = { path = "../programs/config", version = "1.5.3" }
solana-faucet = { path = "../faucet", version = "1.5.3" }
solana-logger = { path = "../logger", version = "1.5.3" }
solana-net-utils = { path = "../net-utils", version = "1.5.3" }
solana_rbpf = "=0.2.3"
solana-remote-wallet = { path = "../remote-wallet", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-stake-program = { path = "../programs/stake", version = "1.5.3" }
solana-transaction-status = { path = "../transaction-status", version = "1.5.3" }
solana-version = { path = "../version", version = "1.5.3" }
solana-vote-program = { path = "../programs/vote", version = "1.5.3" }
thiserror = "1.0.21"
tiny-bip39 = "0.7.0"
solana-account-decoder = { path = "../account-decoder", version = "1.3.13" }
solana-budget-program = { path = "../programs/budget", version = "1.3.13" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-cli-config = { path = "../cli-config", version = "1.3.13" }
solana-cli-output = { path = "../cli-output", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-config-program = { path = "../programs/config", version = "1.3.13" }
solana-faucet = { path = "../faucet", version = "1.3.13" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-net-utils = { path = "../net-utils", version = "1.3.13" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-stake-program = { path = "../programs/stake", version = "1.3.13" }
solana-transaction-status = { path = "../transaction-status", version = "1.3.13" }
solana-version = { path = "../version", version = "1.3.13" }
solana-vote-program = { path = "../programs/vote", version = "1.3.13" }
solana-vote-signer = { path = "../vote-signer", version = "1.3.13" }
thiserror = "1.0.20"
url = "2.1.1"
[dev-dependencies]
solana-core = { path = "../core", version = "1.5.3" }
solana-core = { path = "../core", version = "1.3.13" }
solana-budget-program = { path = "../programs/budget", version = "1.3.13" }
tempfile = "3.1.0"
[[bin]]

View File

@@ -54,42 +54,12 @@ pub fn check_account_for_multiple_fees_with_commitment(
fee_calculator: &FeeCalculator,
messages: &[&Message],
commitment: CommitmentConfig,
) -> Result<(), CliError> {
check_account_for_spend_multiple_fees_with_commitment(
rpc_client,
account_pubkey,
0,
fee_calculator,
messages,
commitment,
)
}
pub fn check_account_for_spend_multiple_fees_with_commitment(
rpc_client: &RpcClient,
account_pubkey: &Pubkey,
balance: u64,
fee_calculator: &FeeCalculator,
messages: &[&Message],
commitment: CommitmentConfig,
) -> Result<(), CliError> {
let fee = calculate_fee(fee_calculator, messages);
if !check_account_for_balance_with_commitment(
rpc_client,
account_pubkey,
balance + fee,
commitment,
)
.map_err(Into::<ClientError>::into)?
if !check_account_for_balance_with_commitment(rpc_client, account_pubkey, fee, commitment)
.map_err(Into::<ClientError>::into)?
{
if balance > 0 {
return Err(CliError::InsufficientFundsForSpendAndFee(
lamports_to_sol(balance),
lamports_to_sol(fee),
));
} else {
return Err(CliError::InsufficientFundsForFee(lamports_to_sol(fee)));
}
return Err(CliError::InsufficientFundsForFee(lamports_to_sol(fee)));
}
Ok(())
}
@@ -97,7 +67,7 @@ pub fn check_account_for_spend_multiple_fees_with_commitment(
pub fn calculate_fee(fee_calculator: &FeeCalculator, messages: &[&Message]) -> u64 {
messages
.iter()
.map(|message| fee_calculator.calculate_fee(message))
.map(|message| fee_calculator.calculate_fee(message, None))
.sum()
}
@@ -161,7 +131,7 @@ mod tests {
context: RpcResponseContext { slot: 1 },
value: json!(account_balance),
});
let pubkey = solana_sdk::pubkey::new_rand();
let pubkey = Pubkey::new_rand();
let fee_calculator = FeeCalculator::new(1);
let pubkey0 = Pubkey::new(&[0; 32]);
@@ -221,7 +191,7 @@ mod tests {
context: RpcResponseContext { slot: 1 },
value: json!(account_balance),
});
let pubkey = solana_sdk::pubkey::new_rand();
let pubkey = Pubkey::new_rand();
let mut mocks = HashMap::new();
mocks.insert(RpcRequest::GetBalance, account_balance_response);
@@ -267,9 +237,9 @@ mod tests {
#[test]
fn test_check_unique_pubkeys() {
let pubkey0 = solana_sdk::pubkey::new_rand();
let pubkey0 = Pubkey::new_rand();
let pubkey_clone = pubkey0;
let pubkey1 = solana_sdk::pubkey::new_rand();
let pubkey1 = Pubkey::new_rand();
check_unique_pubkeys((&pubkey0, "foo".to_string()), (&pubkey1, "bar".to_string()))
.expect("unexpected result");

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,11 @@
use crate::{
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
stake::is_stake_program_v2_enabled,
};
use chrono::{Local, TimeZone};
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
use console::{style, Emoji};
use solana_clap_utils::{
commitment::{commitment_arg, commitment_arg_with_default},
input_parsers::*,
input_validators::*,
keypair::DefaultSigner,
offline::{blockhash_arg, BLOCKHASH_ARG},
commitment::commitment_arg, input_parsers::*, input_validators::*, keypair::DefaultSigner,
};
use solana_cli_output::{
display::{
@@ -20,33 +14,26 @@ use solana_cli_output::{
*,
};
use solana_client::{
client_error::ClientErrorKind,
pubsub_client::PubsubClient,
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
rpc_config::{
RpcAccountInfoConfig, RpcLargestAccountsConfig, RpcLargestAccountsFilter,
RpcProgramAccountsConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter,
},
rpc_filter,
rpc_response::SlotInfo,
rpc_config::{RpcLargestAccountsConfig, RpcLargestAccountsFilter},
rpc_response::{RpcVersionInfo, SlotInfo},
};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account::from_account,
account_utils::StateMut,
clock::{self, Clock, Slot},
commitment_config::CommitmentConfig,
epoch_schedule::Epoch,
hash::Hash,
message::Message,
native_token::lamports_to_sol,
pubkey::{self, Pubkey},
rpc_port::DEFAULT_RPC_PORT_STR,
signature::Signature,
system_instruction, system_program,
sysvar::{
self,
stake_history::{self},
stake_history::{self, StakeHistory},
Sysvar,
},
transaction::Transaction,
};
@@ -59,7 +46,7 @@ use std::{
Arc,
},
thread::sleep,
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
time::{Duration, Instant},
};
static CHECK_MARK: Emoji = Emoji("", "");
@@ -80,7 +67,8 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.validator(is_slot)
.value_name("SLOT")
.takes_value(true)
.index(1),
.index(1)
.required(true),
),
)
.subcommand(
@@ -89,14 +77,14 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.arg(
pubkey!(Arg::with_name("node_pubkey")
.index(1)
.value_name("OUR_VALIDATOR_PUBKEY")
.required(false),
.value_name("VALIDATOR_PUBKEY")
.required(true),
"Identity pubkey of the validator"),
)
.arg(
Arg::with_name("node_json_rpc_url")
.index(2)
.value_name("OUR_URL")
.value_name("URL")
.takes_value(true)
.validator(is_url)
.help("JSON RPC URL for validator, which is useful for validators with a private RPC service")
@@ -107,21 +95,6 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.takes_value(false)
.help("Continue reporting progress even after the validator has caught up"),
)
.arg(
Arg::with_name("our_localhost")
.long("our-localhost")
.takes_value(false)
.value_name("PORT")
.default_value(&DEFAULT_RPC_PORT_STR)
.validator(is_port)
.help("Guess Identity pubkey and validator rpc node assuming local (possibly private) validator"),
)
.arg(
Arg::with_name("log")
.long("log")
.takes_value(false)
.help("Don't update the progress inplace; instead show updates with its own new lines"),
)
.arg(commitment_arg()),
)
.subcommand(
@@ -148,17 +121,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.help("Slot number of the block to query")
)
)
.subcommand(SubCommand::with_name("leader-schedule")
.about("Display leader schedule")
.arg(
Arg::with_name("epoch")
.long("epoch")
.takes_value(true)
.value_name("EPOCH")
.validator(is_epoch)
.help("Epoch to show leader schedule for. (default: current)")
)
)
.subcommand(SubCommand::with_name("leader-schedule").about("Display leader schedule"))
.subcommand(
SubCommand::with_name("epoch-info")
.about("Get information about the current epoch")
@@ -240,13 +203,6 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.takes_value(true)
.help("Stop after submitting count transactions"),
)
.arg(
Arg::with_name("print_timestamp")
.short("D")
.long("print-timestamp")
.takes_value(false)
.help("Print timestamp (unix time + microseconds as in gettimeofday) before each line"),
)
.arg(
Arg::with_name("lamports")
.long("lamports")
@@ -265,33 +221,12 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.default_value("15")
.help("Wait up to timeout seconds for transaction confirmation"),
)
.arg(blockhash_arg())
.arg(commitment_arg()),
)
.subcommand(
SubCommand::with_name("live-slots")
.about("Show information about the current slot progression"),
)
.subcommand(
SubCommand::with_name("logs")
.about("Stream transaction logs")
.arg(
pubkey!(Arg::with_name("address")
.index(1)
.value_name("ADDRESS"),
"Account address to monitor \
[default: monitor all transactions except for votes] \
")
)
.arg(
Arg::with_name("include_votes")
.long("include-votes")
.takes_value(false)
.conflicts_with("address")
.help("Include vote transactions when monitoring all transactions")
)
.arg(commitment_arg_with_default("singleGossip")),
)
.subcommand(
SubCommand::with_name("block-production")
.about("Show information about block production")
@@ -377,17 +312,6 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.help("Display the full transactions"),
)
)
.subcommand(
SubCommand::with_name("wait-for-max-stake")
.about("Wait for the max stake of any one node to drop below a percentage of total.")
.arg(
Arg::with_name("max_percent")
.long("max-percent")
.value_name("PERCENT")
.takes_value(true)
.index(1),
),
)
}
}
@@ -395,31 +319,14 @@ pub fn parse_catchup(
matches: &ArgMatches<'_>,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let node_pubkey = pubkey_of_signer(matches, "node_pubkey", wallet_manager)?;
let mut our_localhost_port = value_t!(matches, "our_localhost", u16).ok();
// if there is no explicitly specified --our-localhost,
// disable the guess mode (= our_localhost_port)
if matches.occurrences_of("our_localhost") == 0 {
our_localhost_port = None
}
let node_pubkey = pubkey_of_signer(matches, "node_pubkey", wallet_manager)?.unwrap();
let node_json_rpc_url = value_t!(matches, "node_json_rpc_url", String).ok();
// requirement of node_pubkey is relaxed only if our_localhost_port
if our_localhost_port.is_none() && node_pubkey.is_none() {
return Err(CliError::BadParameter(
"OUR_VALIDATOR_PUBKEY (and possibly OUR_URL) must be specified \
unless --our-localhost is given"
.into(),
));
}
let follow = matches.is_present("follow");
let log = matches.is_present("log");
Ok(CliCommandInfo {
command: CliCommand::Catchup {
node_pubkey,
node_json_rpc_url,
follow,
our_localhost_port,
log,
},
signers: vec![],
})
@@ -438,23 +345,19 @@ pub fn parse_cluster_ping(
None
};
let timeout = Duration::from_secs(value_t_or_exit!(matches, "timeout", u64));
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
let print_timestamp = matches.is_present("print_timestamp");
Ok(CliCommandInfo {
command: CliCommand::Ping {
lamports,
interval,
count,
timeout,
blockhash,
print_timestamp,
},
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
})
}
pub fn parse_get_block(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let slot = value_of(matches, "slot");
let slot = value_t_or_exit!(matches, "slot", Slot);
Ok(CliCommandInfo {
command: CliCommand::GetBlock { slot },
signers: vec![],
@@ -599,93 +502,42 @@ pub fn parse_transaction_history(
pub fn process_catchup(
rpc_client: &RpcClient,
config: &CliConfig,
node_pubkey: Option<Pubkey>,
mut node_json_rpc_url: Option<String>,
node_pubkey: &Pubkey,
node_json_rpc_url: &Option<String>,
follow: bool,
our_localhost_port: Option<u16>,
log: bool,
) -> ProcessResult {
let sleep_interval = 5;
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message("Connecting...");
if let Some(our_localhost_port) = our_localhost_port {
let gussed_default = Some(format!("http://localhost:{}", our_localhost_port));
if node_json_rpc_url.is_some() && node_json_rpc_url != gussed_default {
// go to new line to leave this message on console
println!(
"Prefering explicitly given rpc ({}) as us, \
although --our-localhost is given\n",
node_json_rpc_url.as_ref().unwrap()
);
} else {
node_json_rpc_url = gussed_default;
}
}
let (node_client, node_pubkey) = if our_localhost_port.is_some() {
let client = RpcClient::new(node_json_rpc_url.unwrap());
let guessed_default = Some(client.get_identity()?);
(
client,
(if node_pubkey.is_some() && node_pubkey != guessed_default {
// go to new line to leave this message on console
println!(
"Prefering explicitly given node pubkey ({}) as us, \
although --our-localhost is given\n",
node_pubkey.unwrap()
);
node_pubkey
} else {
guessed_default
})
.unwrap(),
)
} else if let Some(node_pubkey) = node_pubkey {
if let Some(node_json_rpc_url) = node_json_rpc_url {
(RpcClient::new(node_json_rpc_url), node_pubkey)
} else {
let rpc_addr = loop {
let cluster_nodes = rpc_client.get_cluster_nodes()?;
if let Some(contact_info) = cluster_nodes
.iter()
.find(|contact_info| contact_info.pubkey == node_pubkey.to_string())
{
if let Some(rpc_addr) = contact_info.rpc {
break rpc_addr;
}
progress_bar.set_message(&format!("RPC service not found for {}", node_pubkey));
} else {
progress_bar.set_message(&format!(
"Contact information not found for {}",
node_pubkey
));
}
sleep(Duration::from_secs(sleep_interval as u64));
};
(RpcClient::new_socket(rpc_addr), node_pubkey)
}
let node_client = if let Some(node_json_rpc_url) = node_json_rpc_url {
RpcClient::new(node_json_rpc_url.to_string())
} else {
unreachable!()
};
let reported_node_pubkey = loop {
match node_client.get_identity() {
Ok(reported_node_pubkey) => break reported_node_pubkey,
Err(err) => {
if let ClientErrorKind::Reqwest(err) = err.kind() {
progress_bar.set_message(&format!("Connection failed: {}", err));
sleep(Duration::from_secs(sleep_interval as u64));
continue;
let rpc_addr = loop {
let cluster_nodes = rpc_client.get_cluster_nodes()?;
if let Some(contact_info) = cluster_nodes
.iter()
.find(|contact_info| contact_info.pubkey == node_pubkey.to_string())
{
if let Some(rpc_addr) = contact_info.rpc {
break rpc_addr;
}
return Err(Box::new(err));
progress_bar.set_message(&format!("RPC service not found for {}", node_pubkey));
} else {
progress_bar.set_message(&format!(
"Contact information not found for {}",
node_pubkey
));
}
}
sleep(Duration::from_secs(sleep_interval as u64));
};
RpcClient::new_socket(rpc_addr)
};
if reported_node_pubkey != node_pubkey {
let reported_node_pubkey = node_client.get_identity()?;
if reported_node_pubkey != *node_pubkey {
return Err(format!(
"The identity reported by node RPC URL does not match. Expected: {:?}. Reported: {:?}",
node_pubkey, reported_node_pubkey
@@ -693,41 +545,15 @@ pub fn process_catchup(
.into());
}
if rpc_client.get_identity()? == node_pubkey {
if rpc_client.get_identity()? == *node_pubkey {
return Err("Both RPC URLs reference the same node, unable to monitor for catchup. Try a different --url".into());
}
let mut previous_rpc_slot = std::u64::MAX;
let mut previous_slot_distance = 0;
let mut retry_count = 0;
let max_retry_count = 5;
let mut get_slot_while_retrying = |client: &RpcClient| {
loop {
match client.get_slot_with_commitment(config.commitment) {
Ok(r) => {
retry_count = 0;
return Ok(r);
}
Err(e) => {
if retry_count >= max_retry_count {
return Err(e);
}
retry_count += 1;
if log {
// go to new line to leave this message on console
println!("Retrying({}/{}): {}\n", retry_count, max_retry_count, e);
}
sleep(Duration::from_secs(1));
}
};
}
};
loop {
// humbly retry; the reference node (rpc_client) could be spotty,
// especially if pointing to api.meinnet-beta.solana.com at times
let rpc_slot = get_slot_while_retrying(rpc_client)?;
let node_slot = get_slot_while_retrying(&node_client)?;
let rpc_slot = rpc_client.get_slot_with_commitment(config.commitment)?;
let node_slot = node_client.get_slot_with_commitment(config.commitment)?;
if !follow && node_slot > std::cmp::min(previous_rpc_slot, rpc_slot) {
progress_bar.finish_and_clear();
return Ok(format!(
@@ -750,21 +576,15 @@ pub fn process_catchup(
};
progress_bar.set_message(&format!(
"{} slot(s) {} (us:{} them:{}){}",
slot_distance.abs(),
if slot_distance >= 0 {
"behind"
} else {
"ahead"
},
"{} slots behind (us:{} them:{}){}",
slot_distance,
node_slot,
rpc_slot,
if slot_distance == 0 || previous_rpc_slot == std::u64::MAX {
"".to_string()
} else {
format!(
", {} node is {} at {:.1} slots/second{}",
if slot_distance >= 0 { "our" } else { "their" },
", {} at {:.1} slots/second{}",
if slots_per_second < 0.0 {
"falling behind"
} else {
@@ -773,11 +593,8 @@ pub fn process_catchup(
slots_per_second,
time_remaining
)
},
}
));
if log {
println!();
}
sleep(Duration::from_secs(sleep_interval as u64));
previous_rpc_slot = rpc_slot;
@@ -789,7 +606,7 @@ pub fn process_cluster_date(rpc_client: &RpcClient, config: &CliConfig) -> Proce
let result = rpc_client
.get_account_with_commitment(&sysvar::clock::id(), CommitmentConfig::default())?;
if let Some(clock_account) = result.value {
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
let clock: Clock = Sysvar::from_account(&clock_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string())
})?;
let block_time = CliBlockTime {
@@ -829,27 +646,9 @@ pub fn process_first_available_block(rpc_client: &RpcClient) -> ProcessResult {
Ok(format!("{}", first_available_block))
}
pub fn parse_leader_schedule(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let epoch = value_of(matches, "epoch");
Ok(CliCommandInfo {
command: CliCommand::LeaderSchedule { epoch },
signers: vec![],
})
}
pub fn process_leader_schedule(
rpc_client: &RpcClient,
config: &CliConfig,
epoch: Option<Epoch>,
) -> ProcessResult {
pub fn process_leader_schedule(rpc_client: &RpcClient) -> ProcessResult {
let epoch_info = rpc_client.get_epoch_info()?;
let epoch = epoch.unwrap_or(epoch_info.epoch);
if epoch > epoch_info.epoch {
return Err(format!("Epoch {} is in the future", epoch).into());
}
let epoch_schedule = rpc_client.get_epoch_schedule()?;
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
let first_slot_in_epoch = epoch_info.absolute_slot - epoch_info.slot_index;
let leader_schedule = rpc_client.get_leader_schedule(Some(first_slot_in_epoch))?;
if leader_schedule.is_none() {
@@ -871,86 +670,41 @@ pub fn process_leader_schedule(
}
}
let mut leader_schedule_entries = vec![];
for (slot_index, leader) in leader_per_slot_index.iter().enumerate() {
leader_schedule_entries.push(CliLeaderScheduleEntry {
slot: first_slot_in_epoch + slot_index as u64,
leader: leader.to_string(),
});
println!(
" {:<15} {:<44}",
first_slot_in_epoch + slot_index as u64,
leader
);
}
Ok(config.output_format.formatted_string(&CliLeaderSchedule {
epoch,
leader_schedule_entries,
}))
Ok("".to_string())
}
pub fn process_get_block(
rpc_client: &RpcClient,
_config: &CliConfig,
slot: Option<Slot>,
) -> ProcessResult {
let slot = if let Some(slot) = slot {
slot
} else {
rpc_client.get_slot()?
};
let mut block =
pub fn process_get_block(rpc_client: &RpcClient, _config: &CliConfig, slot: Slot) -> ProcessResult {
let block =
rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Base64)?;
println!("Slot: {}", slot);
println!("Parent Slot: {}", block.parent_slot);
println!("Blockhash: {}", block.blockhash);
println!("Previous Blockhash: {}", block.previous_blockhash);
if let Some(block_time) = block.block_time {
println!("Block Time: {:?}", Local.timestamp(block_time, 0));
if block.block_time.is_some() {
println!("Block Time: {:?}", block.block_time);
}
if !block.rewards.is_empty() {
block.rewards.sort_by(|a, b| a.pubkey.cmp(&b.pubkey));
let mut total_rewards = 0;
println!("Rewards:",);
println!(
" {:<44} {:^15} {:<15} {:<20} {:>14}",
"Address", "Type", "Amount", "New Balance", "Percent Change"
);
for reward in block.rewards {
let sign = if reward.lamports < 0 { "-" } else { "" };
total_rewards += reward.lamports;
println!(
" {:<44} {:^15} {:>15} {}",
" {:<44}: {}",
reward.pubkey,
if let Some(reward_type) = reward.reward_type {
format!("{}", reward_type)
if reward.lamports > 0 {
format!("{}", lamports_to_sol(reward.lamports as u64))
} else {
"-".to_string()
},
format!(
"{}{:<14.9}",
sign,
lamports_to_sol(reward.lamports.abs() as u64)
),
if reward.post_balance == 0 {
" - -".to_string()
} else {
format!(
"{:<19.9} {:>13.9}%",
lamports_to_sol(reward.post_balance),
(reward.lamports.abs() as f64
/ (reward.post_balance as f64 - reward.lamports as f64))
* 100.0
)
format!("-{}", lamports_to_sol(reward.lamports.abs() as u64))
}
);
}
let sign = if total_rewards < 0 { "-" } else { "" };
println!(
"Total Rewards: {}{:<12.9}",
sign,
lamports_to_sol(total_rewards.abs() as u64)
);
}
for (index, transaction_with_meta) in block.transactions.iter().enumerate() {
println!("Transaction {}:", index);
@@ -1024,7 +778,7 @@ pub fn process_show_block_production(
slot_limit: Option<u64>,
) -> ProcessResult {
let epoch_schedule = rpc_client.get_epoch_schedule()?;
let epoch_info = rpc_client.get_epoch_info_with_commitment(CommitmentConfig::max())?;
let epoch_info = rpc_client.get_epoch_info_with_commitment(CommitmentConfig::root())?;
let epoch = epoch.unwrap_or(epoch_info.epoch);
if epoch > epoch_info.epoch {
@@ -1212,8 +966,6 @@ pub fn process_ping(
interval: &Duration,
count: &Option<u64>,
timeout: &Duration,
fixed_blockhash: &Option<Hash>,
print_timestamp: bool,
) -> ProcessResult {
println_name_value("Source Account:", &config.signers[0].pubkey().to_string());
println!();
@@ -1231,21 +983,9 @@ pub fn process_ping(
let (mut blockhash, mut fee_calculator) = rpc_client.get_recent_blockhash()?;
let mut blockhash_transaction_count = 0;
let mut blockhash_acquired = Instant::now();
if let Some(fixed_blockhash) = fixed_blockhash {
let blockhash_origin = if *fixed_blockhash != Hash::default() {
blockhash = *fixed_blockhash;
"supplied from cli arguments"
} else {
"fetched from cluster"
};
println!(
"Fixed blockhash is used: {} ({})",
blockhash, blockhash_origin
);
}
'mainloop: for seq in 0..count.unwrap_or(std::u64::MAX) {
let now = Instant::now();
if fixed_blockhash.is_none() && now.duration_since(blockhash_acquired).as_secs() > 60 {
if now.duration_since(blockhash_acquired).as_secs() > 60 {
// Fetch a new blockhash every minute
let (new_blockhash, new_fee_calculator) = rpc_client.get_new_blockhash(&blockhash)?;
blockhash = new_blockhash;
@@ -1276,18 +1016,6 @@ pub fn process_ping(
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, blockhash)?;
let timestamp = || {
let micros = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_micros();
if print_timestamp {
format!("[{}.{:06}] ", micros / 1_000_000, micros % 1_000_000)
} else {
format!("")
}
};
match rpc_client.send_transaction(&tx) {
Ok(signature) => {
let transaction_sent = Instant::now();
@@ -1301,20 +1029,15 @@ pub fn process_ping(
let elapsed_time_millis = elapsed_time.as_millis() as u64;
confirmation_time.push_back(elapsed_time_millis);
println!(
"{}{}{} lamport(s) transferred: seq={:<3} time={:>4}ms signature={}",
timestamp(),
"{}{} lamport(s) transferred: seq={:<3} time={:>4}ms signature={}",
CHECK_MARK, lamports, seq, elapsed_time_millis, signature
);
confirmed_count += 1;
}
Err(err) => {
println!(
"{}{}Transaction failed: seq={:<3} error={:?} signature={}",
timestamp(),
CROSS_MARK,
seq,
err,
signature
"{}Transaction failed: seq={:<3} error={:?} signature={}",
CROSS_MARK, seq, err, signature
);
}
}
@@ -1323,11 +1046,8 @@ pub fn process_ping(
if elapsed_time >= *timeout {
println!(
"{}{}Confirmation timeout: seq={:<3} signature={}",
timestamp(),
CROSS_MARK,
seq,
signature
"{}Confirmation timeout: seq={:<3} signature={}",
CROSS_MARK, seq, signature
);
break;
}
@@ -1345,11 +1065,8 @@ pub fn process_ping(
}
Err(err) => {
println!(
"{}{}Submit failed: seq={:<3} error={:?}",
timestamp(),
CROSS_MARK,
seq,
err
"{}Submit failed: seq={:<3} error={:?}",
CROSS_MARK, seq, err
);
}
}
@@ -1384,83 +1101,24 @@ pub fn process_ping(
Ok("".to_string())
}
pub fn parse_logs(
matches: &ArgMatches<'_>,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let address = pubkey_of_signer(matches, "address", wallet_manager)?;
let include_votes = matches.is_present("include_votes");
let filter = match address {
None => {
if include_votes {
RpcTransactionLogsFilter::AllWithVotes
} else {
RpcTransactionLogsFilter::All
}
}
Some(address) => RpcTransactionLogsFilter::Mentions(vec![address.to_string()]),
};
Ok(CliCommandInfo {
command: CliCommand::Logs { filter },
signers: vec![],
})
}
pub fn process_logs(config: &CliConfig, filter: &RpcTransactionLogsFilter) -> ProcessResult {
println!(
"Streaming transaction logs{}. {:?} commitment",
match filter {
RpcTransactionLogsFilter::All => "".into(),
RpcTransactionLogsFilter::AllWithVotes => " (including votes)".into(),
RpcTransactionLogsFilter::Mentions(addresses) =>
format!(" mentioning {}", addresses.join(",")),
},
config.commitment.commitment
);
let (_client, receiver) = PubsubClient::logs_subscribe(
&config.websocket_url,
filter.clone(),
RpcTransactionLogsConfig {
commitment: Some(config.commitment),
},
)?;
loop {
match receiver.recv() {
Ok(logs) => {
println!("Transaction executed in slot {}:", logs.context.slot);
println!(" Signature: {}", logs.value.signature);
println!(
" Status: {}",
logs.value
.err
.map(|err| err.to_string())
.unwrap_or_else(|| "Ok".to_string())
);
println!(" Log Messages:");
for log in logs.value.logs {
println!(" {}", log);
}
}
Err(err) => {
return Ok(format!("Disconnected: {}", err));
}
}
}
}
pub fn process_live_slots(config: &CliConfig) -> ProcessResult {
pub fn process_live_slots(url: &str) -> ProcessResult {
let exit = Arc::new(AtomicBool::new(false));
// Disable Ctrl+C handler as sometimes the PubsubClient shutdown can stall. Also it doesn't
// really matter that the shutdown is clean because the process is terminating.
/*
let exit_clone = exit.clone();
ctrlc::set_handler(move || {
exit_clone.store(true, Ordering::Relaxed);
})?;
*/
let mut current: Option<SlotInfo> = None;
let mut message = "".to_string();
let slot_progress = new_spinner_progress_bar();
slot_progress.set_message("Connecting...");
let (mut client, receiver) = PubsubClient::slot_subscribe(&config.websocket_url)?;
let (mut client, receiver) = PubsubClient::slot_subscribe(url)?;
slot_progress.set_message("Connected.");
let spacer = "|";
@@ -1550,16 +1208,14 @@ pub fn process_show_gossip(rpc_client: &RpcClient, config: &CliConfig) -> Proces
.into_iter()
.map(|node| {
format!(
"{:15} | {:44} | {:6} | {:5} | {:21} | {}",
"{:15} | {:44} | {:6} | {:5} | {:5} | {}",
node.gossip
.map(|addr| addr.ip().to_string())
.unwrap_or_else(|| "none".to_string()),
format_labeled_address(&node.pubkey, &config.address_labels),
format_port(node.gossip),
format_port(node.tpu),
node.rpc
.map(|addr| addr.to_string())
.unwrap_or_else(|| "none".to_string()),
format_port(node.rpc),
node.version.unwrap_or_else(|| "unknown".to_string()),
)
})
@@ -1567,9 +1223,9 @@ pub fn process_show_gossip(rpc_client: &RpcClient, config: &CliConfig) -> Proces
Ok(format!(
"IP Address | Node identifier \
| Gossip | TPU | RPC Address | Version\n\
| Gossip | TPU | RPC | Version\n\
----------------+----------------------------------------------+\
--------+-------+-----------------------+----------------\n\
--------+-------+-------+----------------\n\
{}\n\
Nodes: {}",
s.join("\n"),
@@ -1588,52 +1244,17 @@ pub fn process_show_stakes(
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message("Fetching stake accounts...");
let mut program_accounts_config = RpcProgramAccountsConfig {
filters: None,
account_config: RpcAccountInfoConfig {
encoding: Some(solana_account_decoder::UiAccountEncoding::Base64),
..RpcAccountInfoConfig::default()
},
};
if let Some(vote_account_pubkeys) = vote_account_pubkeys {
// Use server-side filtering if only one vote account is provided
if vote_account_pubkeys.len() == 1 {
program_accounts_config.filters = Some(vec![
// Filter by `StakeState::Stake(_, _)`
rpc_filter::RpcFilterType::Memcmp(rpc_filter::Memcmp {
offset: 0,
bytes: rpc_filter::MemcmpEncodedBytes::Binary(
bs58::encode([2, 0, 0, 0]).into_string(),
),
encoding: Some(rpc_filter::MemcmpEncoding::Binary),
}),
// Filter by `Delegation::voter_pubkey`, which begins at byte offset 124
rpc_filter::RpcFilterType::Memcmp(rpc_filter::Memcmp {
offset: 124,
bytes: rpc_filter::MemcmpEncodedBytes::Binary(
vote_account_pubkeys[0].to_string(),
),
encoding: Some(rpc_filter::MemcmpEncoding::Binary),
}),
]);
}
}
let all_stake_accounts = rpc_client
.get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?;
let all_stake_accounts = rpc_client.get_program_accounts(&solana_stake_program::id())?;
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string())
})?;
progress_bar.finish_and_clear();
let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
let stake_history = from_account(&stake_history_account).ok_or_else(|| {
let stake_history = StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
})?;
// At v1.6, this check can be removed and simply passed as `true`
let stake_program_v2_enabled = is_stake_program_v2_enabled(rpc_client);
let clock: Clock = Sysvar::from_account(&clock_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string())
})?;
let mut stake_accounts: Vec<CliKeyedStakeState> = vec![];
for (stake_pubkey, stake_account) in all_stake_accounts {
@@ -1649,7 +1270,6 @@ pub fn process_show_stakes(
use_lamports_unit,
&stake_history,
&clock,
stake_program_v2_enabled,
),
});
}
@@ -1668,7 +1288,6 @@ pub fn process_show_stakes(
use_lamports_unit,
&stake_history,
&clock,
stake_program_v2_enabled,
),
});
}
@@ -1682,16 +1301,6 @@ pub fn process_show_stakes(
.formatted_string(&CliStakeVec::new(stake_accounts)))
}
pub fn process_wait_for_max_stake(
rpc_client: &RpcClient,
config: &CliConfig,
max_stake_percent: f32,
) -> ProcessResult {
let now = std::time::Instant::now();
rpc_client.wait_for_max_stake(config.commitment, max_stake_percent)?;
Ok(format!("Done waiting, took: {}s", now.elapsed().as_secs()))
}
pub fn process_show_validators(
rpc_client: &RpcClient,
config: &CliConfig,
@@ -1705,9 +1314,12 @@ pub fn process_show_validators(
for contact_info in rpc_client.get_cluster_nodes()? {
node_version.insert(
contact_info.pubkey,
contact_info
.version
.unwrap_or_else(|| unknown_version.clone()),
RpcVersionInfo {
solana_core: contact_info
.version
.unwrap_or_else(|| unknown_version.clone()),
}
.to_string(),
);
}
@@ -1718,12 +1330,12 @@ pub fn process_show_validators(
.map(|vote_account| vote_account.activated_stake)
.sum();
let total_delinquent_stake = vote_accounts
let total_deliquent_stake = vote_accounts
.delinquent
.iter()
.map(|vote_account| vote_account.activated_stake)
.sum();
let total_current_stake = total_active_stake - total_delinquent_stake;
let total_current_stake = total_active_stake - total_deliquent_stake;
let mut current = vote_accounts.current;
current.sort_by(|a, b| b.activated_stake.cmp(&a.activated_stake));
@@ -1777,7 +1389,7 @@ pub fn process_show_validators(
let cli_validators = CliValidators {
total_active_stake,
total_current_stake,
total_delinquent_stake,
total_deliquent_stake,
current_validators,
delinquent_validators,
stake_by_version,
@@ -1852,7 +1464,6 @@ mod tests {
use super::*;
use crate::cli::{app, parse_command};
use solana_sdk::signature::{write_keypair, Keypair};
use std::str::FromStr;
use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) {
@@ -1988,11 +1599,8 @@ mod tests {
"2",
"-t",
"3",
"-D",
"--commitment",
"max",
"--blockhash",
"4CCNp28j6AhGq7PkjPDP4wbQWBS8LLbQin2xV5n8frKX",
]);
assert_eq!(
parse_command(&test_ping, &default_signer, &mut None).unwrap(),
@@ -2002,10 +1610,6 @@ mod tests {
interval: Duration::from_secs(1),
count: Some(2),
timeout: Duration::from_secs(3),
blockhash: Some(
Hash::from_str("4CCNp28j6AhGq7PkjPDP4wbQWBS8LLbQin2xV5n8frKX").unwrap()
),
print_timestamp: true,
},
signers: vec![default_keypair.into()],
}

View File

@@ -1,379 +0,0 @@
use crate::{
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use console::style;
use serde::{Deserialize, Serialize};
use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*};
use solana_cli_output::{QuietDisplay, VerboseDisplay};
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
clock::Slot,
feature::{self, Feature},
feature_set::FEATURE_NAMES,
message::Message,
pubkey::Pubkey,
transaction::Transaction,
};
use std::{collections::HashMap, fmt, sync::Arc};
#[derive(Debug, PartialEq)]
pub enum FeatureCliCommand {
Status { features: Vec<Pubkey> },
Activate { feature: Pubkey },
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "status", content = "sinceSlot")]
pub enum CliFeatureStatus {
Inactive,
Pending,
Active(Slot),
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliFeature {
pub id: String,
pub description: String,
#[serde(flatten)]
pub status: CliFeatureStatus,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliFeatures {
pub features: Vec<CliFeature>,
pub feature_activation_allowed: bool,
#[serde(skip)]
pub inactive: bool,
}
impl fmt::Display for CliFeatures {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.features.len() > 1 {
writeln!(
f,
"{}",
style(format!(
"{:<44} {:<40} {}",
"Feature", "Description", "Status"
))
.bold()
)?;
}
for feature in &self.features {
writeln!(
f,
"{:<44} {:<40} {}",
feature.id,
feature.description,
match feature.status {
CliFeatureStatus::Inactive => style("inactive".to_string()).red(),
CliFeatureStatus::Pending => style("activation pending".to_string()).yellow(),
CliFeatureStatus::Active(activation_slot) =>
style(format!("active since slot {}", activation_slot)).green(),
}
)?;
}
if self.inactive && !self.feature_activation_allowed {
writeln!(
f,
"{}",
style("\nFeature activation is not allowed at this time")
.bold()
.red()
)?;
}
Ok(())
}
}
impl QuietDisplay for CliFeatures {}
impl VerboseDisplay for CliFeatures {}
pub trait FeatureSubCommands {
fn feature_subcommands(self) -> Self;
}
impl FeatureSubCommands for App<'_, '_> {
fn feature_subcommands(self) -> Self {
self.subcommand(
SubCommand::with_name("feature")
.about("Runtime feature management")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
SubCommand::with_name("status")
.about("Query runtime feature status")
.arg(
Arg::with_name("features")
.value_name("ADDRESS")
.validator(is_valid_pubkey)
.index(1)
.multiple(true)
.help("Feature status to query [default: all known features]"),
),
)
.subcommand(
SubCommand::with_name("activate")
.about("Activate a runtime feature")
.arg(
Arg::with_name("feature")
.value_name("FEATURE_KEYPAIR")
.validator(is_valid_signer)
.index(1)
.required(true)
.help("The signer for the feature to activate"),
),
),
)
}
}
fn known_feature(feature: &Pubkey) -> Result<(), CliError> {
if FEATURE_NAMES.contains_key(feature) {
Ok(())
} else {
Err(CliError::BadParameter(format!(
"Unknown feature: {}",
feature
)))
}
}
pub fn parse_feature_subcommand(
matches: &ArgMatches<'_>,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let response = match matches.subcommand() {
("activate", Some(matches)) => {
let (feature_signer, feature) = signer_of(matches, "feature", wallet_manager)?;
let mut signers = vec![default_signer.signer_from_path(matches, wallet_manager)?];
signers.push(feature_signer.unwrap());
let feature = feature.unwrap();
known_feature(&feature)?;
CliCommandInfo {
command: CliCommand::Feature(FeatureCliCommand::Activate { feature }),
signers,
}
}
("status", Some(matches)) => {
let mut features = if let Some(features) = pubkeys_of(matches, "features") {
for feature in &features {
known_feature(feature)?;
}
features
} else {
FEATURE_NAMES.keys().cloned().collect()
};
features.sort();
CliCommandInfo {
command: CliCommand::Feature(FeatureCliCommand::Status { features }),
signers: vec![],
}
}
_ => unreachable!(),
};
Ok(response)
}
pub fn process_feature_subcommand(
rpc_client: &RpcClient,
config: &CliConfig,
feature_subcommand: &FeatureCliCommand,
) -> ProcessResult {
match feature_subcommand {
FeatureCliCommand::Status { features } => process_status(rpc_client, config, features),
FeatureCliCommand::Activate { feature } => process_activate(rpc_client, config, *feature),
}
}
fn active_stake_by_feature_set(rpc_client: &RpcClient) -> Result<HashMap<u32, u64>, ClientError> {
// Validator identity -> feature set
let feature_set_map = rpc_client
.get_cluster_nodes()?
.into_iter()
.map(|contact_info| (contact_info.pubkey, contact_info.feature_set))
.collect::<HashMap<_, _>>();
let vote_accounts = rpc_client.get_vote_accounts()?;
let total_active_stake: u64 = vote_accounts
.current
.iter()
.chain(vote_accounts.delinquent.iter())
.map(|vote_account| vote_account.activated_stake)
.sum();
// Sum all active stake by feature set
let mut active_stake_by_feature_set = HashMap::new();
for vote_account in vote_accounts.current {
if let Some(Some(feature_set)) = feature_set_map.get(&vote_account.node_pubkey) {
*active_stake_by_feature_set.entry(*feature_set).or_default() +=
vote_account.activated_stake;
} else {
*active_stake_by_feature_set
.entry(0 /* "unknown" */)
.or_default() += vote_account.activated_stake;
}
}
// Convert active stake to a percentage so the caller doesn't need `total_active_stake`
for (_, val) in active_stake_by_feature_set.iter_mut() {
*val = *val * 100 / total_active_stake;
}
Ok(active_stake_by_feature_set)
}
// Feature activation is only allowed when 95% of the active stake is on the current feature set
fn feature_activation_allowed(rpc_client: &RpcClient, quiet: bool) -> Result<bool, ClientError> {
let my_feature_set = solana_version::Version::default().feature_set;
let active_stake_by_feature_set = active_stake_by_feature_set(rpc_client)?;
let feature_activation_allowed = active_stake_by_feature_set
.get(&my_feature_set)
.map(|percentage| *percentage >= 95)
.unwrap_or(false);
if !feature_activation_allowed && !quiet {
if active_stake_by_feature_set.get(&my_feature_set).is_none() {
println!(
"{}",
style("To activate features the tool and cluster feature sets must match, select a tool version that matches the cluster")
.bold());
} else {
println!(
"{}",
style("To activate features the stake must be >= 95%").bold()
);
}
println!(
"{}",
style(format!("Tool Feture Set: {}", my_feature_set)).bold()
);
println!("{}", style("Cluster Feature Sets and Stakes:").bold());
for (feature_set, percentage) in active_stake_by_feature_set.iter() {
if *feature_set == 0 {
println!("unknown - {}%", percentage);
} else {
println!(
"{} - {}% {}",
feature_set,
percentage,
if *feature_set == my_feature_set {
" <-- me"
} else {
""
}
);
}
}
println!();
}
Ok(feature_activation_allowed)
}
fn process_status(
rpc_client: &RpcClient,
config: &CliConfig,
feature_ids: &[Pubkey],
) -> ProcessResult {
let mut features: Vec<CliFeature> = vec![];
let mut inactive = false;
for (i, account) in rpc_client
.get_multiple_accounts(feature_ids)?
.into_iter()
.enumerate()
{
let feature_id = &feature_ids[i];
let feature_name = FEATURE_NAMES.get(feature_id).unwrap();
if let Some(account) = account {
if let Some(feature) = feature::from_account(&account) {
let feature_status = match feature.activated_at {
None => CliFeatureStatus::Pending,
Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
};
features.push(CliFeature {
id: feature_id.to_string(),
description: feature_name.to_string(),
status: feature_status,
});
continue;
}
}
inactive = true;
features.push(CliFeature {
id: feature_id.to_string(),
description: feature_name.to_string(),
status: CliFeatureStatus::Inactive,
});
}
let feature_activation_allowed = feature_activation_allowed(rpc_client, features.len() <= 1)?;
let feature_set = CliFeatures {
features,
feature_activation_allowed,
inactive,
};
Ok(config.output_format.formatted_string(&feature_set))
}
fn process_activate(
rpc_client: &RpcClient,
config: &CliConfig,
feature_id: Pubkey,
) -> ProcessResult {
let account = rpc_client
.get_multiple_accounts(&[feature_id])?
.into_iter()
.next()
.unwrap();
if let Some(account) = account {
if feature::from_account(&account).is_some() {
return Err(format!("{} has already been activated", feature_id).into());
}
}
if !feature_activation_allowed(rpc_client, false)? {
return Err("Feature activation is not allowed at this time".into());
}
let rent = rpc_client.get_minimum_balance_for_rent_exemption(Feature::size_of())?;
let (blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let (message, _) = resolve_spend_tx_and_check_account_balance(
rpc_client,
false,
SpendAmount::Some(rent),
&fee_calculator,
&config.signers[0].pubkey(),
|lamports| {
Message::new(
&feature::activate_with_lamports(
&feature_id,
&config.signers[0].pubkey(),
lamports,
),
Some(&config.signers[0].pubkey()),
)
},
config.commitment,
)?;
let mut transaction = Transaction::new_unsigned(message);
transaction.try_sign(&config.signers, blockhash)?;
println!(
"Activating {} ({})",
FEATURE_NAMES.get(&feature_id).unwrap(),
feature_id
);
rpc_client.send_and_confirm_transaction_with_spinner(&transaction)?;
Ok("".to_string())
}

View File

@@ -1,51 +0,0 @@
use crate::cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult};
use clap::{App, ArgMatches, SubCommand};
use solana_clap_utils::keypair::*;
use solana_cli_output::CliInflation;
use solana_client::rpc_client::RpcClient;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use std::sync::Arc;
#[derive(Debug, PartialEq)]
pub enum InflationCliCommand {
Show,
}
pub trait InflationSubCommands {
fn inflation_subcommands(self) -> Self;
}
impl InflationSubCommands for App<'_, '_> {
fn inflation_subcommands(self) -> Self {
self.subcommand(SubCommand::with_name("inflation").about("Show inflation information"))
}
}
pub fn parse_inflation_subcommand(
_matches: &ArgMatches<'_>,
_default_signer: &DefaultSigner,
_wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
Ok(CliCommandInfo {
command: CliCommand::Inflation(InflationCliCommand::Show),
signers: vec![],
})
}
pub fn process_inflation_subcommand(
rpc_client: &RpcClient,
config: &CliConfig,
inflation_subcommand: &InflationCliCommand,
) -> ProcessResult {
assert_eq!(*inflation_subcommand, InflationCliCommand::Show);
let governor = rpc_client.get_inflation_governor()?;
let current_rate = rpc_client.get_inflation_rate()?;
let inflation = CliInflation {
governor,
current_rate,
};
Ok(config.output_format.formatted_string(&inflation))
}

View File

@@ -23,11 +23,7 @@ extern crate serde_derive;
pub mod checks;
pub mod cli;
pub mod cluster_query;
pub mod feature;
pub mod inflation;
pub mod nonce;
pub mod program;
pub mod send_tpu;
pub mod spend_utils;
pub mod stake;
pub mod test_utils;

View File

@@ -7,7 +7,7 @@ use console::style;
use solana_clap_utils::{
commitment::COMMITMENT_ARG,
input_parsers::commitment_of,
input_validators::{is_url, is_url_or_moniker},
input_validators::is_url,
keypair::{CliSigners, DefaultSigner, SKIP_SEED_PHRASE_VALIDATION_ARG},
DisplayError,
};
@@ -168,7 +168,6 @@ pub fn parse_args<'a>(
let CliCommandInfo { command, signers } =
parse_command(&matches, &default_signer, &mut wallet_manager)?;
let verbose = matches.is_present("verbose");
let output_format = matches
.value_of("output_format")
.map(|value| match value {
@@ -176,22 +175,13 @@ pub fn parse_args<'a>(
"json-compact" => OutputFormat::JsonCompact,
_ => unreachable!(),
})
.unwrap_or(if verbose {
OutputFormat::DisplayVerbose
} else {
OutputFormat::Display
});
.unwrap_or(OutputFormat::Display);
let commitment = {
let mut sub_matches = matches;
while let Some(subcommand_name) = sub_matches.subcommand_name() {
sub_matches = sub_matches
.subcommand_matches(subcommand_name)
.expect("subcommand_matches");
}
commitment_of(sub_matches, COMMITMENT_ARG.long)
}
.unwrap_or_default();
let commitment = matches
.subcommand_name()
.and_then(|name| matches.subcommand_matches(name))
.and_then(|sub_matches| commitment_of(sub_matches, COMMITMENT_ARG.long))
.unwrap_or_default();
let address_labels = if matches.is_present("no_address_labels") {
HashMap::new()
@@ -208,13 +198,10 @@ pub fn parse_args<'a>(
keypair_path: default_signer_path,
rpc_client: None,
rpc_timeout,
verbose,
verbose: matches.is_present("verbose"),
output_format,
commitment,
send_transaction_config: RpcSendTransactionConfig {
preflight_commitment: Some(commitment.commitment),
..RpcSendTransactionConfig::default()
},
send_transaction_config: RpcSendTransactionConfig::default(),
address_labels,
},
signers,
@@ -246,14 +233,11 @@ fn main() -> Result<(), Box<dyn error::Error>> {
Arg::with_name("json_rpc_url")
.short("u")
.long("url")
.value_name("URL_OR_MONIKER")
.value_name("URL")
.takes_value(true)
.global(true)
.validator(is_url_or_moniker)
.help(
"URL for Solana's JSON RPC or moniker (or their first letter): \
[mainnet-beta, testnet, devnet, localhost]",
),
.validator(is_url)
.help("JSON RPC URL for the solana cluster"),
)
.arg(
Arg::with_name("websocket_url")

View File

@@ -580,7 +580,6 @@ mod tests {
fee_calculator::FeeCalculator,
hash::hash,
nonce::{self, state::Versions, State},
nonce_account,
signature::{read_keypair_file, write_keypair, Keypair, Signer},
system_program,
};
@@ -834,7 +833,7 @@ mod tests {
#[test]
fn test_check_nonce_account() {
let blockhash = Hash::default();
let nonce_pubkey = solana_sdk::pubkey::new_rand();
let nonce_pubkey = Pubkey::new_rand();
let data = Versions::new_current(State::Initialized(nonce::state::Data {
authority: nonce_pubkey,
blockhash,
@@ -870,7 +869,7 @@ mod tests {
}
let data = Versions::new_current(State::Initialized(nonce::state::Data {
authority: solana_sdk::pubkey::new_rand(),
authority: Pubkey::new_rand(),
blockhash,
fee_calculator: FeeCalculator::default(),
}));
@@ -892,7 +891,7 @@ mod tests {
#[test]
fn test_account_identity_ok() {
let nonce_account = nonce_account::create_account(1).into_inner();
let nonce_account = nonce::create_account(1).into_inner();
assert_eq!(account_identity_ok(&nonce_account), Ok(()));
let system_account = Account::new(1, 0, &system_program::id());
@@ -911,7 +910,7 @@ mod tests {
#[test]
fn test_state_from_account() {
let mut nonce_account = nonce_account::create_account(1).into_inner();
let mut nonce_account = nonce::create_account(1).into_inner();
assert_eq!(state_from_account(&nonce_account), Ok(State::Uninitialized));
let data = nonce::state::Data {
@@ -936,7 +935,7 @@ mod tests {
#[test]
fn test_data_from_helpers() {
let mut nonce_account = nonce_account::create_account(1).into_inner();
let mut nonce_account = nonce::create_account(1).into_inner();
let state = state_from_account(&nonce_account).unwrap();
assert_eq!(
data_from_state(&state),

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +0,0 @@
use log::*;
use solana_client::rpc_response::{RpcContactInfo, RpcLeaderSchedule};
use std::net::{SocketAddr, UdpSocket};
pub fn get_leader_tpu(
slot_index: u64,
leader_schedule: Option<&RpcLeaderSchedule>,
cluster_nodes: Option<&Vec<RpcContactInfo>>,
) -> Option<SocketAddr> {
leader_schedule?
.iter()
.find(|(_pubkey, slots)| slots.iter().any(|slot| *slot as u64 == slot_index))
.and_then(|(pubkey, _)| {
cluster_nodes?
.iter()
.find(|contact_info| contact_info.pubkey == *pubkey)
.and_then(|contact_info| contact_info.tpu)
})
}
pub fn send_transaction_tpu(
send_socket: &UdpSocket,
tpu_address: &SocketAddr,
wire_transaction: &[u8],
) {
if let Err(err) = send_socket.send_to(wire_transaction, tpu_address) {
warn!("Failed to send transaction to {}: {:?}", tpu_address, err);
}
}

View File

@@ -7,7 +7,6 @@ use crate::{
nonce::check_nonce_account,
spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount},
};
use chrono::{Local, TimeZone};
use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand};
use solana_clap_utils::{
fee_payer::{fee_payer_arg, FEE_PAYER_ARG},
@@ -19,29 +18,23 @@ use solana_clap_utils::{
ArgConstant,
};
use solana_cli_output::{
return_signers, CliEpochReward, CliStakeHistory, CliStakeHistoryEntry, CliStakeState,
CliStakeType,
return_signers, CliStakeHistory, CliStakeHistoryEntry, CliStakeState, CliStakeType,
};
use solana_client::{
blockhash_query::BlockhashQuery,
client_error::{ClientError, ClientErrorKind},
nonce_utils,
rpc_client::RpcClient,
rpc_custom_error,
rpc_request::{self, DELINQUENT_VALIDATOR_SLOT_DISTANCE},
blockhash_query::BlockhashQuery, nonce_utils, rpc_client::RpcClient,
rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE,
};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account::from_account,
account_utils::StateMut,
clock::{Clock, Epoch, Slot, UnixTimestamp, SECONDS_PER_DAY},
feature, feature_set,
clock::Clock,
message::Message,
pubkey::Pubkey,
system_instruction::SystemError,
sysvar::{
clock,
stake_history::{self, StakeHistory},
Sysvar,
},
transaction::Transaction,
};
@@ -50,7 +43,7 @@ use solana_stake_program::{
stake_state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState},
};
use solana_vote_program::vote_state::VoteState;
use std::{convert::TryInto, ops::Deref, sync::Arc};
use std::{ops::Deref, sync::Arc};
pub const STAKE_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant {
name: "stake_authority",
@@ -162,7 +155,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("Source account of funds [default: cli config keypair]"),
)
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@@ -191,7 +184,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@@ -221,7 +214,7 @@ impl StakeSubCommands for App<'_, '_> {
.arg(stake_authority_arg())
.arg(withdraw_authority_arg())
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@@ -236,7 +229,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@@ -276,7 +269,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@@ -298,7 +291,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@@ -329,7 +322,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(withdraw_authority_arg())
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
.arg(
Arg::with_name("custodian")
@@ -384,7 +377,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("Keypair of the existing custodian [default: cli config pubkey]")
)
.offline_args()
.nonce_args(false)
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@@ -1502,7 +1495,6 @@ pub fn build_stake_state(
use_lamports_unit: bool,
stake_history: &StakeHistory,
clock: &Clock,
stake_program_v2_enabled: bool,
) -> CliStakeState {
match stake_state {
StakeState::Stake(
@@ -1514,12 +1506,9 @@ pub fn build_stake_state(
stake,
) => {
let current_epoch = clock.epoch;
let (active_stake, activating_stake, deactivating_stake) =
stake.delegation.stake_activating_and_deactivating(
current_epoch,
Some(stake_history),
stake_program_v2_enabled,
);
let (active_stake, activating_stake, deactivating_stake) = stake
.delegation
.stake_activating_and_deactivating(current_epoch, Some(stake_history));
let lockup = if lockup.is_in_force(clock, None) {
Some(lockup.into())
} else {
@@ -1528,7 +1517,6 @@ pub fn build_stake_state(
CliStakeState {
stake_type: CliStakeType::Stake,
account_balance,
credits_observed: Some(stake.credits_observed),
delegated_stake: Some(stake.delegation.stake),
delegated_vote_account_address: if stake.delegation.voter_pubkey
!= Pubkey::default()
@@ -1555,7 +1543,6 @@ pub fn build_stake_state(
active_stake: u64_some_if_not_zero(active_stake),
activating_stake: u64_some_if_not_zero(activating_stake),
deactivating_stake: u64_some_if_not_zero(deactivating_stake),
..CliStakeState::default()
}
}
StakeState::RewardsPool => CliStakeState {
@@ -1580,7 +1567,6 @@ pub fn build_stake_state(
CliStakeState {
stake_type: CliStakeType::Initialized,
account_balance,
credits_observed: Some(0),
authorized: Some(authorized.into()),
lockup,
use_lamports_unit,
@@ -1591,153 +1577,39 @@ pub fn build_stake_state(
}
}
pub(crate) fn fetch_epoch_rewards(
rpc_client: &RpcClient,
address: &Pubkey,
lowest_epoch: Epoch,
) -> Result<Vec<CliEpochReward>, Box<dyn std::error::Error>> {
let mut all_epoch_rewards = vec![];
let epoch_schedule = rpc_client.get_epoch_schedule()?;
let slot = rpc_client.get_slot()?;
let first_available_block = rpc_client.get_first_available_block()?;
let mut epoch = epoch_schedule.get_epoch_and_slot_index(slot).0;
let mut epoch_info: Option<(Slot, UnixTimestamp, solana_transaction_status::Rewards)> = None;
while epoch > lowest_epoch {
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
if first_slot_in_epoch < first_available_block {
// RPC node is out of history data
break;
}
let first_confirmed_block_in_epoch = *rpc_client
.get_confirmed_blocks_with_limit(first_slot_in_epoch, 1)?
.get(0)
.ok_or_else(|| format!("Unable to fetch first confirmed block for epoch {}", epoch))?;
let first_confirmed_block = match rpc_client.get_confirmed_block_with_encoding(
first_confirmed_block_in_epoch,
solana_transaction_status::UiTransactionEncoding::Base64,
) {
Ok(first_confirmed_block) => first_confirmed_block,
Err(ClientError {
kind:
ClientErrorKind::RpcError(rpc_request::RpcError::RpcResponseError {
code: rpc_custom_error::JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE,
..
}),
..
}) => {
// RPC node doesn't have this block
break;
}
Err(err) => {
return Err(err.into());
}
};
let epoch_start_time = if let Some(block_time) = first_confirmed_block.block_time {
block_time
} else {
break;
};
// Rewards for the previous epoch are found in the first confirmed block of the current epoch
let previous_epoch_rewards = first_confirmed_block.rewards;
if let Some((effective_slot, epoch_end_time, epoch_rewards)) = epoch_info {
let wallclock_epoch_duration = if epoch_end_time > epoch_start_time {
Some(
{ Local.timestamp(epoch_end_time, 0) - Local.timestamp(epoch_start_time, 0) }
.to_std()?
.as_secs_f64(),
)
} else {
None
};
if let Some(reward) = epoch_rewards
.into_iter()
.find(|reward| reward.pubkey == address.to_string())
{
if reward.post_balance > reward.lamports.try_into().unwrap_or(0) {
let rate_change = reward.lamports.abs() as f64
/ (reward.post_balance as f64 - reward.lamports as f64);
let apr = wallclock_epoch_duration.map(|wallclock_epoch_duration| {
let wallclock_epochs_per_year =
(SECONDS_PER_DAY * 356) as f64 / wallclock_epoch_duration;
rate_change * wallclock_epochs_per_year
});
all_epoch_rewards.push(CliEpochReward {
epoch,
effective_slot,
amount: reward.lamports.abs() as u64,
post_balance: reward.post_balance,
percent_change: rate_change * 100.0,
apr: apr.map(|r| r * 100.0),
});
}
}
}
epoch -= 1;
epoch_info = Some((
first_confirmed_block_in_epoch,
epoch_start_time,
previous_epoch_rewards,
));
}
Ok(all_epoch_rewards)
}
pub fn process_show_stake_account(
rpc_client: &RpcClient,
config: &CliConfig,
stake_account_address: &Pubkey,
stake_account_pubkey: &Pubkey,
use_lamports_unit: bool,
) -> ProcessResult {
let stake_account = rpc_client.get_account(stake_account_address)?;
let stake_account = rpc_client.get_account(stake_account_pubkey)?;
if stake_account.owner != solana_stake_program::id() {
return Err(CliError::RpcRequestError(format!(
"{:?} is not a stake account",
stake_account_address,
stake_account_pubkey,
))
.into());
}
match stake_account.state() {
Ok(stake_state) => {
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
let stake_history = from_account(&stake_history_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
})?;
let stake_history =
StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
})?;
let clock_account = rpc_client.get_account(&clock::id())?;
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
let clock: Clock = Sysvar::from_account(&clock_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string())
})?;
let mut state = build_stake_state(
let state = build_stake_state(
stake_account.lamports,
&stake_state,
use_lamports_unit,
&stake_history,
&clock,
is_stake_program_v2_enabled(rpc_client), // At v1.6, this check can be removed and simply passed as `true`
);
if state.stake_type == CliStakeType::Stake {
if let Some(activation_epoch) = state.activation_epoch {
let rewards =
fetch_epoch_rewards(rpc_client, stake_account_address, activation_epoch);
match rewards {
Ok(rewards) => state.epoch_rewards = Some(rewards),
Err(error) => eprintln!("Failed to fetch epoch rewards: {:?}", error),
};
}
}
Ok(config.output_format.formatted_string(&state))
}
Err(err) => Err(CliError::RpcRequestError(format!(
@@ -1754,7 +1626,7 @@ pub fn process_show_stake_history(
use_lamports_unit: bool,
) -> ProcessResult {
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
let stake_history = from_account::<StakeHistory>(&stake_history_account).ok_or_else(|| {
let stake_history = StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
})?;
@@ -1897,15 +1769,6 @@ pub fn process_delegate_stake(
}
}
pub fn is_stake_program_v2_enabled(rpc_client: &RpcClient) -> bool {
rpc_client
.get_account(&feature_set::stake_program_v2::id())
.ok()
.and_then(|account| feature::from_account(&account))
.and_then(|feature| feature.activated_at)
.is_some()
}
#[cfg(test)]
mod tests {
use super::*;
@@ -2451,9 +2314,9 @@ mod tests {
);
// Test CreateStakeAccount SubCommand
let custodian = solana_sdk::pubkey::new_rand();
let custodian = Pubkey::new_rand();
let custodian_string = format!("{}", custodian);
let authorized = solana_sdk::pubkey::new_rand();
let authorized = Pubkey::new_rand();
let authorized_string = format!("{}", authorized);
let test_create_stake_account = test_commands.clone().get_matches_from(vec![
"test",
@@ -2591,7 +2454,7 @@ mod tests {
);
// Test DelegateStake Subcommand
let vote_account_pubkey = solana_sdk::pubkey::new_rand();
let vote_account_pubkey = Pubkey::new_rand();
let vote_account_string = vote_account_pubkey.to_string();
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
"test",
@@ -2618,7 +2481,7 @@ mod tests {
);
// Test DelegateStake Subcommand w/ authority
let vote_account_pubkey = solana_sdk::pubkey::new_rand();
let vote_account_pubkey = Pubkey::new_rand();
let vote_account_string = vote_account_pubkey.to_string();
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
"test",
@@ -2737,7 +2600,7 @@ mod tests {
);
// Test Delegate Subcommand w/ absent fee payer
let key1 = solana_sdk::pubkey::new_rand();
let key1 = Pubkey::new_rand();
let sig1 = Keypair::new().sign_message(&[0u8]);
let signer1 = format!("{}={}", key1, sig1);
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
@@ -2777,7 +2640,7 @@ mod tests {
);
// Test Delegate Subcommand w/ absent fee payer and absent nonce authority
let key2 = solana_sdk::pubkey::new_rand();
let key2 = Pubkey::new_rand();
let sig2 = Keypair::new().sign_message(&[0u8]);
let signer2 = format!("{}={}", key2, sig2);
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
@@ -3105,7 +2968,7 @@ mod tests {
);
// Test Deactivate Subcommand w/ absent fee payer
let key1 = solana_sdk::pubkey::new_rand();
let key1 = Pubkey::new_rand();
let sig1 = Keypair::new().sign_message(&[0u8]);
let signer1 = format!("{}={}", key1, sig1);
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
@@ -3142,7 +3005,7 @@ mod tests {
);
// Test Deactivate Subcommand w/ absent fee payer and nonce authority
let key2 = solana_sdk::pubkey::new_rand();
let key2 = Pubkey::new_rand();
let sig2 = Keypair::new().sign_message(&[0u8]);
let signer2 = format!("{}={}", key2, sig2);
let test_deactivate_stake = test_commands.clone().get_matches_from(vec![
@@ -3321,7 +3184,7 @@ mod tests {
let stake_account_keypair = Keypair::new();
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
let source_stake_account_pubkey = solana_sdk::pubkey::new_rand();
let source_stake_account_pubkey = Pubkey::new_rand();
let test_merge_stake_account = test_commands.clone().get_matches_from(vec![
"test",
"merge-stake",

View File

@@ -486,7 +486,7 @@ mod tests {
#[test]
fn test_parse_validator_info() {
let pubkey = solana_sdk::pubkey::new_rand();
let pubkey = Pubkey::new_rand();
let keys = vec![(validator_info::id(), false), (pubkey, true)];
let config = ConfigKeys { keys };

View File

@@ -671,11 +671,11 @@ fn get_vote_account(
pub fn process_show_vote_account(
rpc_client: &RpcClient,
config: &CliConfig,
vote_account_address: &Pubkey,
vote_account_pubkey: &Pubkey,
use_lamports_unit: bool,
) -> ProcessResult {
let (vote_account, vote_state) =
get_vote_account(rpc_client, vote_account_address, config.commitment)?;
get_vote_account(rpc_client, vote_account_pubkey, config.commitment)?;
let epoch_schedule = rpc_client.get_epoch_schedule()?;
@@ -685,28 +685,17 @@ pub fn process_show_vote_account(
for vote in &vote_state.votes {
votes.push(vote.into());
}
for (epoch, credits, prev_credits) in vote_state.epoch_credits().iter().copied() {
for (epoch, credits, prev_credits) in vote_state.epoch_credits() {
let credits_earned = credits - prev_credits;
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(epoch);
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
epoch_voting_history.push(CliEpochVotingHistory {
epoch,
epoch: *epoch,
slots_in_epoch,
credits_earned,
credits,
prev_credits,
});
}
}
let epoch_rewards = match crate::stake::fetch_epoch_rewards(rpc_client, vote_account_address, 1)
{
Ok(rewards) => Some(rewards),
Err(error) => {
eprintln!("Failed to fetch epoch rewards: {:?}", error);
None
}
};
let vote_account_data = CliVoteAccount {
account_balance: vote_account.lamports,
validator_identity: vote_state.node_pubkey.to_string(),
@@ -719,7 +708,6 @@ pub fn process_show_vote_account(
votes,
epoch_voting_history,
use_lamports_unit,
epoch_rewards,
};
Ok(config.output_format.formatted_string(&vote_account_data))
@@ -920,7 +908,7 @@ mod tests {
);
// test init with an authed voter
let authed = solana_sdk::pubkey::new_rand();
let authed = Pubkey::new_rand();
let (keypair_file, mut tmp_file) = make_tmp_file();
let keypair = Keypair::new();
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();

118
cli/tests/deploy.rs Normal file
View File

@@ -0,0 +1,118 @@
use serde_json::Value;
use solana_cli::cli::{process_command, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient;
use solana_core::test_validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
bpf_loader,
commitment_config::CommitmentConfig,
pubkey::Pubkey,
signature::{Keypair, Signer},
};
use std::{
fs::{remove_dir_all, File},
io::Read,
path::PathBuf,
str::FromStr,
sync::mpsc::channel,
};
#[test]
fn test_cli_deploy_program() {
solana_logger::setup();
let mut pathbuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
pathbuf.push("tests");
pathbuf.push("fixtures");
pathbuf.push("noop");
pathbuf.set_extension("so");
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let minimum_balance_for_rent_exemption = rpc_client
.get_minimum_balance_for_rent_exemption(program_data.len())
.unwrap();
let mut config = CliConfig::recent_for_tests();
let keypair = Keypair::new();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 3 * minimum_balance_for_rent_exemption, // min balance for rent exemption for two programs + leftover for tx processing
};
config.signers = vec![&keypair];
process_command(&config).unwrap();
config.command = CliCommand::Deploy {
program_location: pathbuf.to_str().unwrap().to_string(),
address: None,
use_deprecated_loader: false,
};
let response = process_command(&config);
let json: Value = serde_json::from_str(&response.unwrap()).unwrap();
let program_id_str = json
.as_object()
.unwrap()
.get("programId")
.unwrap()
.as_str()
.unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap();
let account0 = rpc_client
.get_account_with_commitment(&program_id, CommitmentConfig::recent())
.unwrap()
.value
.unwrap();
assert_eq!(account0.lamports, minimum_balance_for_rent_exemption);
assert_eq!(account0.owner, bpf_loader::id());
assert_eq!(account0.executable, true);
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
assert_eq!(account0.data, elf);
// Test custom address
let custom_address_keypair = Keypair::new();
config.signers = vec![&keypair, &custom_address_keypair];
config.command = CliCommand::Deploy {
program_location: pathbuf.to_str().unwrap().to_string(),
address: Some(1),
use_deprecated_loader: false,
};
process_command(&config).unwrap();
let account1 = rpc_client
.get_account_with_commitment(&custom_address_keypair.pubkey(), CommitmentConfig::recent())
.unwrap()
.value
.unwrap();
assert_eq!(account1.lamports, minimum_balance_for_rent_exemption);
assert_eq!(account1.owner, bpf_loader::id());
assert_eq!(account1.executable, true);
assert_eq!(account0.data, account1.data);
// Attempt to redeploy to the same address
process_command(&config).unwrap_err();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@@ -9,7 +9,8 @@ use solana_client::{
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::test_validator::TestValidator;
use solana_core::contact_info::ContactInfo;
use solana_core::test_validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
commitment_config::CommitmentConfig,
@@ -18,53 +19,69 @@ use solana_sdk::{
signature::{keypair_from_seed, Keypair, Signer},
system_program,
};
use std::sync::mpsc::channel;
use std::{fs::remove_dir_all, sync::mpsc::channel};
#[test]
fn test_nonce() {
let mint_keypair = Keypair::new();
full_battery_tests(
TestValidator::with_no_fees(mint_keypair.pubkey()),
mint_keypair,
None,
false,
);
solana_logger::setup();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
full_battery_tests(leader_data, alice, None, false);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_nonce_with_seed() {
let mint_keypair = Keypair::new();
full_battery_tests(
TestValidator::with_no_fees(mint_keypair.pubkey()),
mint_keypair,
Some(String::from("seed")),
false,
);
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
full_battery_tests(leader_data, alice, Some(String::from("seed")), false);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_nonce_with_authority() {
let mint_keypair = Keypair::new();
full_battery_tests(
TestValidator::with_no_fees(mint_keypair.pubkey()),
mint_keypair,
None,
true,
);
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
full_battery_tests(leader_data, alice, None, true);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
fn full_battery_tests(
test_validator: TestValidator,
mint_keypair: Keypair,
leader_data: ContactInfo,
alice: Keypair,
seed: Option<String>,
use_nonce_authority: bool,
) {
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let json_rpc_url = test_validator.rpc_url();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let mut config_payer = CliConfig::recent_for_tests();
config_payer.json_rpc_url = json_rpc_url.clone();
@@ -155,7 +172,7 @@ fn full_battery_tests(
assert_ne!(first_nonce, third_nonce);
// Withdraw from nonce account
let payee_pubkey = solana_sdk::pubkey::new_rand();
let payee_pubkey = Pubkey::new_rand();
config_payer.signers = authorized_signers;
config_payer.command = CliCommand::WithdrawFromNonceAccount {
nonce_account,
@@ -214,9 +231,17 @@ fn full_battery_tests(
#[test]
fn test_create_account_with_seed() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let TestValidator {
server,
leader_data,
alice: mint_keypair,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
@@ -228,7 +253,7 @@ fn test_create_account_with_seed() {
let config = CliConfig::recent_for_tests();
// Setup accounts
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
@@ -260,7 +285,8 @@ fn test_create_account_with_seed() {
check_recent_balance(0, &rpc_client, &nonce_address);
let mut creator_config = CliConfig::recent_for_tests();
creator_config.json_rpc_url = test_validator.rpc_url();
creator_config.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
creator_config.signers = vec![&online_nonce_creator_signer];
creator_config.command = CliCommand::CreateNonceAccount {
nonce_account: 0,
@@ -310,7 +336,8 @@ fn test_create_account_with_seed() {
// And submit it
let mut submit_config = CliConfig::recent_for_tests();
submit_config.json_rpc_url = test_validator.rpc_url();
submit_config.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
submit_config.signers = vec![&authority_presigner];
submit_config.command = CliCommand::Transfer {
amount: SpendAmount::Some(10),
@@ -331,4 +358,7 @@ fn test_create_account_with_seed() {
check_recent_balance(31, &rpc_client, &offline_nonce_authority_signer.pubkey());
check_recent_balance(4000, &rpc_client, &online_nonce_creator_signer.pubkey());
check_recent_balance(10, &rpc_client, &to_address);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

452
cli/tests/pay.rs Normal file
View File

@@ -0,0 +1,452 @@
use chrono::prelude::*;
use serde_json::Value;
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand},
spend_utils::SpendAmount,
test_utils::check_recent_balance,
};
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
use solana_client::{
blockhash_query::{self, BlockhashQuery},
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::test_validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
commitment_config::CommitmentConfig,
nonce::State as NonceState,
pubkey::Pubkey,
signature::{Keypair, Signer},
};
use std::{fs::remove_dir_all, sync::mpsc::channel};
#[test]
fn test_cli_timestamp_tx() {
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer0 = Keypair::new();
let default_signer1 = Keypair::new();
let mut config_payer = CliConfig::recent_for_tests();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_payer.signers = vec![&default_signer0];
let mut config_witness = CliConfig::recent_for_tests();
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
config_witness.signers = vec![&default_signer1];
assert_ne!(
config_payer.signers[0].pubkey(),
config_witness.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_payer.signers[0].pubkey(),
50,
&config_witness,
)
.unwrap();
check_recent_balance(50, &rpc_client, &config_payer.signers[0].pubkey());
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_witness.signers[0].pubkey(),
1,
&config_witness,
)
.unwrap();
// Make transaction (from config_payer to bob_pubkey) requiring timestamp from config_witness
let date_string = "\"2018-09-19T17:30:59Z\"";
let dt: DateTime<Utc> = serde_json::from_str(&date_string).unwrap();
config_payer.command = CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(10),
to: bob_pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(config_witness.signers[0].pubkey()),
..PayCommand::default()
});
let sig_response = process_command(&config_payer);
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
let process_id_vec = bs58::decode(process_id_str)
.into_vec()
.expect("base58-encoded public key");
let process_id = Pubkey::new(&process_id_vec);
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_recent_balance(10, &rpc_client, &process_id); // contract balance
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
// Sign transaction by config_witness
config_witness.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt);
process_command(&config_witness).unwrap();
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_recent_balance(0, &rpc_client, &process_id); // contract balance
check_recent_balance(10, &rpc_client, &bob_pubkey); // recipient balance
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_cli_witness_tx() {
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer0 = Keypair::new();
let default_signer1 = Keypair::new();
let mut config_payer = CliConfig::recent_for_tests();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_payer.signers = vec![&default_signer0];
let mut config_witness = CliConfig::recent_for_tests();
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
config_witness.signers = vec![&default_signer1];
assert_ne!(
config_payer.signers[0].pubkey(),
config_witness.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_payer.signers[0].pubkey(),
50,
&config_witness,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_witness.signers[0].pubkey(),
1,
&config_witness,
)
.unwrap();
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
config_payer.command = CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(10),
to: bob_pubkey,
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
..PayCommand::default()
});
let sig_response = process_command(&config_payer);
let object: Value = serde_json::from_str(&sig_response.unwrap()).unwrap();
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
let process_id_vec = bs58::decode(process_id_str)
.into_vec()
.expect("base58-encoded public key");
let process_id = Pubkey::new(&process_id_vec);
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_recent_balance(10, &rpc_client, &process_id); // contract balance
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
// Sign transaction by config_witness
config_witness.command = CliCommand::Witness(bob_pubkey, process_id);
process_command(&config_witness).unwrap();
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_recent_balance(0, &rpc_client, &process_id); // contract balance
check_recent_balance(10, &rpc_client, &bob_pubkey); // recipient balance
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_cli_cancel_tx() {
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer0 = Keypair::new();
let default_signer1 = Keypair::new();
let mut config_payer = CliConfig::recent_for_tests();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_payer.signers = vec![&default_signer0];
let mut config_witness = CliConfig::recent_for_tests();
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
config_witness.signers = vec![&default_signer1];
assert_ne!(
config_payer.signers[0].pubkey(),
config_witness.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_payer.signers[0].pubkey(),
50,
&config_witness,
)
.unwrap();
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
config_payer.command = CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(10),
to: bob_pubkey,
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
cancelable: true,
..PayCommand::default()
});
let sig_response = process_command(&config_payer).unwrap();
let object: Value = serde_json::from_str(&sig_response).unwrap();
let process_id_str = object.get("processId").unwrap().as_str().unwrap();
let process_id_vec = bs58::decode(process_id_str)
.into_vec()
.expect("base58-encoded public key");
let process_id = Pubkey::new(&process_id_vec);
check_recent_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_recent_balance(10, &rpc_client, &process_id); // contract balance
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
// Sign transaction by config_witness
config_payer.command = CliCommand::Cancel(process_id);
process_command(&config_payer).unwrap();
check_recent_balance(50, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_recent_balance(0, &rpc_client, &process_id); // contract balance
check_recent_balance(0, &rpc_client, &bob_pubkey); // recipient balance
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_offline_pay_tx() {
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let default_offline_signer = Keypair::new();
let mut config_offline = CliConfig::recent_for_tests();
config_offline.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_offline.signers = vec![&default_offline_signer];
let mut config_online = CliConfig::recent_for_tests();
config_online.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_online.signers = vec![&default_signer];
assert_ne!(
config_offline.signers[0].pubkey(),
config_online.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_offline.signers[0].pubkey(),
50,
&config_offline,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_online.signers[0].pubkey(),
50,
&config_offline,
)
.unwrap();
check_recent_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
check_recent_balance(50, &rpc_client, &config_online.signers[0].pubkey());
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_offline.command = CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(10),
to: bob_pubkey,
blockhash_query: BlockhashQuery::None(blockhash),
sign_only: true,
..PayCommand::default()
});
config_offline.output_format = OutputFormat::JsonCompact;
let sig_response = process_command(&config_offline).unwrap();
check_recent_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
check_recent_balance(50, &rpc_client, &config_online.signers[0].pubkey());
check_recent_balance(0, &rpc_client, &bob_pubkey);
let sign_only = parse_sign_only_reply_string(&sig_response);
assert!(sign_only.has_all_signers());
let offline_presigner = sign_only
.presigner_of(&config_offline.signers[0].pubkey())
.unwrap();
let online_pubkey = config_online.signers[0].pubkey();
config_online.signers = vec![&offline_presigner];
config_online.command = CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(10),
to: bob_pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
..PayCommand::default()
});
process_command(&config_online).unwrap();
check_recent_balance(40, &rpc_client, &config_offline.signers[0].pubkey());
check_recent_balance(50, &rpc_client, &online_pubkey);
check_recent_balance(10, &rpc_client, &bob_pubkey);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_nonced_pay_tx() {
solana_logger::setup();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let minimum_nonce_balance = rpc_client
.get_minimum_balance_for_rent_exemption(NonceState::size())
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config.signers[0].pubkey(),
50 + minimum_nonce_balance,
&config,
)
.unwrap();
check_recent_balance(
50 + minimum_nonce_balance,
&rpc_client,
&config.signers[0].pubkey(),
);
// Create nonce account
let nonce_account = Keypair::new();
config.command = CliCommand::CreateNonceAccount {
nonce_account: 1,
seed: None,
nonce_authority: Some(config.signers[0].pubkey()),
amount: SpendAmount::Some(minimum_nonce_balance),
};
config.signers.push(&nonce_account);
process_command(&config).unwrap();
check_recent_balance(50, &rpc_client, &config.signers[0].pubkey());
check_recent_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
// Fetch nonce hash
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
let bob_pubkey = Pubkey::new_rand();
config.signers = vec![&default_signer];
config.command = CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(10),
to: bob_pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
nonce_hash,
),
nonce_account: Some(nonce_account.pubkey()),
..PayCommand::default()
});
process_command(&config).expect("failed to process pay command");
check_recent_balance(40, &rpc_client, &config.signers[0].pubkey());
check_recent_balance(10, &rpc_client, &bob_pubkey);
// Verify that nonce has been used
let nonce_hash2 = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
assert_ne!(nonce_hash, nonce_hash2);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,23 +2,24 @@ use solana_cli::cli::{process_command, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient;
use solana_core::test_validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
};
use std::sync::mpsc::channel;
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
use std::{fs::remove_dir_all, sync::mpsc::channel};
#[test]
fn test_cli_request_airdrop() {
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let mut bob_config = CliConfig::recent_for_tests();
bob_config.json_rpc_url = test_validator.rpc_url();
bob_config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
bob_config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
@@ -31,11 +32,14 @@ fn test_cli_request_airdrop() {
let sig_response = process_command(&bob_config);
sig_response.unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let balance = rpc_client
.get_balance_with_commitment(&bob_config.signers[0].pubkey(), CommitmentConfig::recent())
.unwrap()
.value;
assert_eq!(balance, 50);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@@ -9,7 +9,7 @@ use solana_client::{
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::test_validator::TestValidator;
use solana_core::test_validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
account_utils::StateMut,
@@ -22,21 +22,26 @@ use solana_stake_program::{
stake_instruction::LockupArgs,
stake_state::{Lockup, StakeAuthorize, StakeState},
};
use std::sync::mpsc::channel;
use std::{fs::remove_dir_all, sync::mpsc::channel};
#[test]
fn test_stake_delegation_force() {
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
request_and_confirm_airdrop(
@@ -108,23 +113,33 @@ fn test_stake_delegation_force() {
fee_payer: 0,
};
process_command(&config).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_seed_stake_delegation_and_deactivation() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
vote_pubkey,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let validator_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let mut config_validator = CliConfig::recent_for_tests();
config_validator.json_rpc_url = test_validator.rpc_url();
config_validator.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_validator.signers = vec![&validator_keypair];
request_and_confirm_airdrop(
@@ -165,7 +180,7 @@ fn test_seed_stake_delegation_and_deactivation() {
// Delegate stake
config_validator.command = CliCommand::DelegateStake {
stake_account_pubkey: stake_address,
vote_account_pubkey: test_validator.vote_account_address(),
vote_account_pubkey: vote_pubkey,
stake_authority: 0,
force: true,
sign_only: false,
@@ -187,23 +202,33 @@ fn test_seed_stake_delegation_and_deactivation() {
fee_payer: 0,
};
process_command(&config_validator).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_stake_delegation_and_deactivation() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
vote_pubkey,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let validator_keypair = Keypair::new();
let mut config_validator = CliConfig::recent_for_tests();
config_validator.json_rpc_url = test_validator.rpc_url();
config_validator.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_validator.signers = vec![&validator_keypair];
let stake_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
@@ -240,7 +265,7 @@ fn test_stake_delegation_and_deactivation() {
config_validator.signers.pop();
config_validator.command = CliCommand::DelegateStake {
stake_account_pubkey: stake_keypair.pubkey(),
vote_account_pubkey: test_validator.vote_account_address(),
vote_account_pubkey: vote_pubkey,
stake_authority: 0,
force: true,
sign_only: false,
@@ -262,27 +287,38 @@ fn test_stake_delegation_and_deactivation() {
fee_payer: 0,
};
process_command(&config_validator).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_offline_stake_delegation_and_deactivation() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
vote_pubkey,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let mut config_validator = CliConfig::recent_for_tests();
config_validator.json_rpc_url = test_validator.rpc_url();
config_validator.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let validator_keypair = Keypair::new();
config_validator.signers = vec![&validator_keypair];
let mut config_payer = CliConfig::recent_for_tests();
config_payer.json_rpc_url = test_validator.rpc_url();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let stake_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
@@ -336,7 +372,7 @@ fn test_offline_stake_delegation_and_deactivation() {
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_offline.command = CliCommand::DelegateStake {
stake_account_pubkey: stake_keypair.pubkey(),
vote_account_pubkey: test_validator.vote_account_address(),
vote_account_pubkey: vote_pubkey,
stake_authority: 0,
force: true,
sign_only: true,
@@ -355,7 +391,7 @@ fn test_offline_stake_delegation_and_deactivation() {
config_payer.signers = vec![&offline_presigner];
config_payer.command = CliCommand::DelegateStake {
stake_account_pubkey: stake_keypair.pubkey(),
vote_account_pubkey: test_validator.vote_account_address(),
vote_account_pubkey: vote_pubkey,
stake_authority: 0,
force: true,
sign_only: false,
@@ -394,24 +430,33 @@ fn test_offline_stake_delegation_and_deactivation() {
fee_payer: 0,
};
process_command(&config_payer).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_nonced_stake_delegation_and_deactivation() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
vote_pubkey,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let config_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let mut config = CliConfig::recent_for_tests();
config.signers = vec![&config_keypair];
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let minimum_nonce_balance = rpc_client
.get_minimum_balance_for_rent_exemption(NonceState::size())
@@ -470,7 +515,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
config.signers = vec![&config_keypair];
config.command = CliCommand::DelegateStake {
stake_account_pubkey: stake_keypair.pubkey(),
vote_account_pubkey: test_validator.vote_account_address(),
vote_account_pubkey: vote_pubkey,
stake_authority: 0,
force: true,
sign_only: false,
@@ -508,23 +553,31 @@ fn test_nonced_stake_delegation_and_deactivation() {
fee_payer: 0,
};
process_command(&config).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_stake_authorize() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
request_and_confirm_airdrop(
@@ -779,6 +832,9 @@ fn test_stake_authorize() {
.unwrap()
.blockhash;
assert_ne!(nonce_hash, new_nonce_hash);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
@@ -786,24 +842,34 @@ fn test_stake_authorize_with_fee_payer() {
solana_logger::setup();
const SIG_FEE: u64 = 42;
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), SIG_FEE);
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: SIG_FEE,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let default_pubkey = default_signer.pubkey();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let payer_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let mut config_payer = CliConfig::recent_for_tests();
config_payer.signers = vec![&payer_keypair];
config_payer.json_rpc_url = test_validator.rpc_url();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let payer_pubkey = config_payer.signers[0].pubkey();
let mut config_offline = CliConfig::recent_for_tests();
@@ -904,24 +970,36 @@ fn test_stake_authorize_with_fee_payer() {
// `config_offline` however has paid 1 sig due to being both authority
// and fee payer
check_recent_balance(100_000 - SIG_FEE, &rpc_client, &offline_pubkey);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_stake_split() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let offline_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let mut config_offline = CliConfig::recent_for_tests();
@@ -1047,24 +1125,36 @@ fn test_stake_split() {
&rpc_client,
&split_account.pubkey(),
);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_stake_set_lockup() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let offline_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let mut config_offline = CliConfig::recent_for_tests();
@@ -1097,10 +1187,8 @@ fn test_stake_set_lockup() {
let stake_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let stake_account_pubkey = stake_keypair.pubkey();
let lockup = Lockup {
custodian: config.signers[0].pubkey(),
..Lockup::default()
};
let mut lockup = Lockup::default();
lockup.custodian = config.signers[0].pubkey();
config.signers.push(&stake_keypair);
config.command = CliCommand::CreateStakeAccount {
@@ -1310,23 +1398,32 @@ fn test_stake_set_lockup() {
);
assert_eq!(current_lockup.epoch, lockup.epoch.unwrap());
assert_eq!(current_lockup.custodian, offline_pubkey);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_offline_nonced_create_stake_account_and_withdraw() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let mut config = CliConfig::recent_for_tests();
let default_signer = keypair_from_seed(&[1u8; 32]).unwrap();
config.signers = vec![&default_signer];
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let mut config_offline = CliConfig::recent_for_tests();
let offline_signer = keypair_from_seed(&[2u8; 32]).unwrap();
@@ -1522,4 +1619,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
let seed_address =
Pubkey::create_with_seed(&stake_pubkey, seed, &solana_stake_program::id()).unwrap();
check_recent_balance(50_000, &rpc_client, &seed_address);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@@ -9,7 +9,7 @@ use solana_client::{
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::test_validator::TestValidator;
use solana_core::test_validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
commitment_config::CommitmentConfig,
@@ -17,25 +17,33 @@ use solana_sdk::{
pubkey::Pubkey,
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
};
use std::sync::mpsc::channel;
use std::{fs::remove_dir_all, sync::mpsc::channel};
#[test]
fn test_transfer() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let TestValidator {
server,
leader_data,
alice: mint_keypair,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let default_offline_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let sender_pubkey = config.signers[0].pubkey();
@@ -237,13 +245,24 @@ fn test_transfer() {
process_command(&config).unwrap();
check_recent_balance(28, &rpc_client, &offline_pubkey);
check_recent_balance(40, &rpc_client, &recipient_pubkey);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_transfer_multisession_signing() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let TestValidator {
server,
leader_data,
alice: mint_keypair,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
@@ -256,7 +275,7 @@ fn test_transfer_multisession_signing() {
let config = CliConfig::recent_for_tests();
// Setup accounts
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
@@ -338,7 +357,7 @@ fn test_transfer_multisession_signing() {
// Finally submit to the cluster
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&fee_payer_presigner, &from_presigner];
config.command = CliCommand::Transfer {
amount: SpendAmount::Some(42),
@@ -356,24 +375,35 @@ fn test_transfer_multisession_signing() {
check_recent_balance(1, &rpc_client, &offline_from_signer.pubkey());
check_recent_balance(1, &rpc_client, &offline_fee_payer_signer.pubkey());
check_recent_balance(42, &rpc_client, &to_pubkey);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_transfer_all() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let TestValidator {
server,
leader_data,
alice: mint_keypair,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let sender_pubkey = config.signers[0].pubkey();
@@ -401,4 +431,7 @@ fn test_transfer_all() {
process_command(&config).unwrap();
check_recent_balance(0, &rpc_client, &sender_pubkey);
check_recent_balance(49_999, &rpc_client, &recipient_pubkey);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@@ -12,24 +12,30 @@ use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
account_utils::StateMut,
commitment_config::CommitmentConfig,
pubkey::Pubkey,
signature::{Keypair, Signer},
};
use solana_vote_program::vote_state::{VoteAuthorize, VoteState, VoteStateVersions};
use std::sync::mpsc::channel;
use std::{fs::remove_dir_all, sync::mpsc::channel};
#[test]
fn test_vote_authorize_and_withdraw() {
let mint_keypair = Keypair::new();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new(test_validator.rpc_url());
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
request_and_confirm_airdrop(
@@ -104,7 +110,7 @@ fn test_vote_authorize_and_withdraw() {
assert_eq!(authorized_withdrawer, withdraw_authority.pubkey());
// Withdraw from vote account
let destination_account = solana_sdk::pubkey::new_rand(); // Send withdrawal to new account to make balance check easy
let destination_account = Pubkey::new_rand(); // Send withdrawal to new account to make balance check easy
config.signers = vec![&default_signer, &withdraw_authority];
config.command = CliCommand::WithdrawFromVoteAccount {
vote_account_pubkey,
@@ -125,4 +131,7 @@ fn test_vote_authorize_and_withdraw() {
withdraw_authority: 1,
};
process_command(&config).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "1.5.3"
version = "1.3.13"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -9,36 +9,32 @@ license = "Apache-2.0"
edition = "2018"
[dependencies]
base64 = "0.13.0"
bincode = "1.3.1"
bs58 = "0.3.1"
clap = "2.33.0"
indicatif = "0.15.0"
jsonrpc-core = "15.0.0"
log = "0.4.11"
net2 = "0.2.37"
jsonrpc-core = "14.2.0"
log = "0.4.8"
rayon = "1.4.0"
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
semver = "0.11.0"
reqwest = { version = "0.10.6", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "1.5.3" }
solana-clap-utils = { path = "../clap-utils", version = "1.5.3" }
solana-net-utils = { path = "../net-utils", version = "1.5.3" }
solana-sdk = { path = "../sdk", version = "1.5.3" }
solana-transaction-status = { path = "../transaction-status", version = "1.5.3" }
solana-version = { path = "../version", version = "1.5.3" }
solana-vote-program = { path = "../programs/vote", version = "1.5.3" }
solana-account-decoder = { path = "../account-decoder", version = "1.3.13" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-net-utils = { path = "../net-utils", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-transaction-status = { path = "../transaction-status", version = "1.3.13" }
solana-vote-program = { path = "../programs/vote", version = "1.3.13" }
thiserror = "1.0"
tungstenite = "0.10.1"
url = "2.1.1"
[dev-dependencies]
assert_matches = "1.3.0"
jsonrpc-core = "15.0.0"
jsonrpc-http-server = "15.0.0"
solana-logger = { path = "../logger", version = "1.5.3" }
jsonrpc-core = "14.2.0"
jsonrpc-http-server = "14.2.0"
solana-logger = { path = "../logger", version = "1.3.13" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -177,9 +177,7 @@ mod tests {
#[test]
fn test_blockhash_query_new_from_matches_ok() {
let test_commands = App::new("blockhash_query_test")
.nonce_args(false)
.offline_args();
let test_commands = App::new("blockhash_query_test").nonce_args().offline_args();
let blockhash = hash(&[1u8]);
let blockhash_string = blockhash.to_string();

View File

@@ -5,8 +5,6 @@ use solana_sdk::{
use std::io;
use thiserror::Error;
pub use reqwest; // export `reqwest` for clients
#[derive(Error, Debug)]
pub enum ClientErrorKind {
#[error(transparent)]
@@ -52,10 +50,10 @@ impl Into<TransportError> for ClientErrorKind {
#[derive(Error, Debug)]
#[error("{kind}")]
pub struct ClientError {
pub request: Option<rpc_request::RpcRequest>,
request: Option<rpc_request::RpcRequest>,
#[source]
pub kind: ClientErrorKind,
kind: ClientErrorKind,
}
impl ClientError {

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