Compare commits

...

590 Commits

Author SHA1 Message Date
de94c4e867 Add set_root bank drop logging (#21144) (#21194)
(cherry picked from commit 706b60b5c8)

Co-authored-by: carllin <carl@solana.com>
2021-11-10 11:58:28 -07:00
74684a107c Revert "Bump version to 1.8.4 (#21232)"
This reverts commit 19b3ba0442.
2021-11-10 11:19:39 -07:00
19b3ba0442 Bump version to 1.8.4 (#21232) 2021-11-10 16:38:44 +01:00
784c745efa Disable JIT compiler on unsupported platforms (#21215) (#21218)
(cherry picked from commit b4d09388aa)

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
2021-11-09 13:29:49 +00:00
a7b3436b1e report pubsub stats every 2s (backport #21192) (#21196)
* report pubsub stats every 2s (#21192)

(cherry picked from commit 7659a2edc2)

* remove use of Duration::MAX

Co-authored-by: Jeff Biseda <jbiseda@gmail.com>
2021-11-06 15:22:07 +00:00
89b2a3d0ae Refactor RentDebits to use hashmap instead of vec (v1.8 backport) (#21176)
* Refactor `RentDebits` to use hashmap instead of vec (v1.8 backport)

* Fix rent debits test (#21177)
2021-11-05 08:52:14 +00:00
56fc58a2b5 Simplify replay vote tracking by using packet metadata (backport #21112) (#21149)
* Simplify replay vote tracking by using packet metadata (#21112)

(cherry picked from commit 140a5f633d)

# Conflicts:
#	core/src/banking_stage.rs
#	ledger-tool/src/main.rs
#	rpc/src/rpc.rs
#	runtime/src/bank.rs
#	runtime/src/bank_utils.rs
#	runtime/src/stakes.rs
#	sdk/src/transaction/sanitized.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-11-05 00:16:34 +00:00
53e0c9710e Fix typo in bankless-leader.md (#21152) (#21160)
Reseting -> Resetting

(cherry picked from commit ae207b7dbb)

Co-authored-by: Ikko Ashimine <eltociear@gmail.com>
2021-11-03 23:16:43 +00:00
c14864a608 Add accounts stats for space amplification (#21151) 2021-11-03 16:41:29 +01:00
780302af56 Add set_root timing metrics (#21119) (#21135)
(cherry picked from commit 1e5212e60d)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-11-02 20:17:04 +00:00
90557564c3 Accountsdb plugin postgres improvement (#21034) (#21096)
Summary of Changes

Added the reference postgresql.conf
Prepare slot update statement to reduce overhead in updating slot
Support custom connection string
Allow the plugin to panic on replication issues to ensure consistency
2021-11-02 01:07:21 -07:00
6d2fd078be Update deprecated variant in RpcClient doctests (#21121) (#21131)
(cherry picked from commit 96e5342292)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-11-01 23:48:30 -06:00
4a874e9ba1 Fixup filter deprecated since (#21123) (#21128)
(cherry picked from commit 1b47f7f2cd)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-11-02 04:23:32 +00:00
22510678b4 docs: Update language around immutable programs (#21116) (#21118)
(cherry picked from commit ec86ff8fb3)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-11-01 21:01:27 +00:00
69b973a3a6 Parallel notifications in RPC PubSub (backport #20543) (#21092)
* Parallel notifications in RPC PubSub (#20543)

* generate rpc notifications in parallel

* Use multithreaded runtime for pubsub

* add metric for time since creation of rpc notification to queue

* measure notification entry processing

* fix: add n_threads config argument

* configure rayon thread pool for rpc notifications

* add config option for pubsub notification threads

* rename metric to created_to_queue_time_us

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* rename metric to notification_entry_processing_time_us

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* use value_of for rpc_pubsub_notification_threads parsing

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* rename threads to sol-sub-notif-N

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* fix rpc tests for TimestampedNotificationEntry

* rustfmt

* use rayon thread limit for rpc

Co-authored-by: Pavel Strakhov <p.strakhov@iconic.vc>
Co-authored-by: Alexander Polakov <a.polakov@zubr.io>
Co-authored-by: Nikita Podoliako <bananaelecitrus@gmail.com>
Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit 9fabff5129)

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

* Fix conflicts

Co-authored-by: Pavel Strakhov <ri@idzaaus.org>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-11-01 20:19:51 +00:00
cc7ed71cb7 Fix serum-dex downstream build (#21115) 2021-11-01 17:54:22 +00:00
b6fe051d24 Document next_account_info(s) (#21076) (#21080)
(cherry picked from commit 62c8fb4792)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-10-29 22:22:09 +00:00
506d39ea82 Add missing websocket methods to rust RPC PubSub client (backport #21065) (#21073)
* Add missing websocket methods to rust RPC PubSub client (#21065)

- Added accountSubscribe,  programSubscribe, slotSubscribe and rootSubscribe to rust RpcClient
 - Removed duplication on cleanup threads
 - Moved RPCVote from rpc/ to client/rpc_response

(cherry picked from commit a0f9e0e8ee)

# Conflicts:
#	Cargo.lock
#	client-test/Cargo.toml
#	core/tests/client.rs

* Fix conflicts

* Make test result not depend on TestValidator setup

Co-authored-by: Manuel Gil <manugildev@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-10-29 21:46:59 +00:00
a595e06b48 Check whether vote-authorize-voter-checked new vote authority is_interactive (#21051) (#21057)
* Check interactive signer for vote-authorize-voter-checked

* Recommend checked vote reauthorization

(cherry picked from commit 0b8fcf0808)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-10-28 23:10:25 +00:00
da08f3dc2b seeds rng for test_build_crds_filter test (#21031) (#21048)
(cherry picked from commit eea3fb327f)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-28 22:06:13 +00:00
8dd3c1ece1 Bump version to v1.8.3 (#21040) 2021-10-28 11:17:11 -06:00
42a2c29234 Different error if block status is not yet available (#20407) (#21029)
* Different error if block is not available

* Add slot to error message

* Make and use helper function

* Check finalized path as well

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

Co-authored-by: sakridge <sakridge@gmail.com>
2021-10-27 20:58:15 +00:00
a1f1264962 Swap banking stage vote channels (#20987) (#21000)
(cherry picked from commit 261dd96ae3)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-10-27 20:17:38 +00:00
66caead016 Add compute budget noops (backport #20992) (#21014)
* Add compute budget program as a noop (#20992)

(cherry picked from commit 1e2bef76e3)

# Conflicts:
#	sdk/src/feature_set.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-10-27 12:47:35 -07:00
de1f60fb2d Refactor cost tracker metrics reporting (backport #20802) (#20933)
* - cost_tracker is data member of a bank, it can report metrics when bank is frozen (#20802)

- removed cost_tracker_stats and histogram
- move stats reporting outside of bank freeze

(cherry picked from commit c2bfce90b3)

# Conflicts:
#	Cargo.lock
#	core/src/banking_stage.rs
#	core/src/replay_stage.rs
#	core/src/tvu.rs
#	ledger-tool/src/main.rs
#	programs/bpf/Cargo.lock
#	runtime/Cargo.toml
#	runtime/src/cost_tracker.rs

* manual fix merge conflicts

Co-authored-by: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com>
Co-authored-by: Tao Zhu <tao@solana.com>
2021-10-27 16:48:20 +00:00
7528016e2d Add counter for dropped duplicated packets, fix dropped_packets_count (#20834) (#21023)
(cherry picked from commit 71d0bd4605)
2021-10-27 11:36:37 -05:00
adc57899fe tpu-client: Add send_messages_with_spinner from program / stake-o-matic (backport #20960) (#21002)
* tpu-client: Move `send_messages_with_spinner` from program (#20960)

We have too many ways of sending transactions, and too many
reimplementations of the same logic all over the place.

The program deploy logic and stake-o-matic currently make the
most use of the TPU client, so this merges their implementations into
one place to be reused by both.  Yay for consolidation!

(cherry picked from commit 5f7b60576f)

# Conflicts:
#	cli/src/program.rs
#	client/src/mock_sender.rs

* Fix merge issues, use older APIs

* Update mock sender fee to match block height

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-10-27 12:22:17 +00:00
afe229a89e Document entrypoint!, custom_heap_default!, and custom_panic_default! (#21003) (#21015)
(cherry picked from commit ced1505b75)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-10-27 07:49:14 +00:00
5dd00e9230 Force a recent version of the openssl crate to allow this to build on M1 macs (backport #21008) (#21012)
* Force a recent version of the openssl crate to allow this to build on M1 macs

(cherry picked from commit 920159fc63)

# Conflicts:
#	Cargo.lock
#	programs/bpf_loader/Cargo.toml

* Run cargo check

(cherry picked from commit 8efc577374)

# Conflicts:
#	programs/bpf/Cargo.lock

* Resolve merge conflicts

Co-authored-by: Matt Wilde <matthewcwilde@gmail.com>
Co-authored-by: Michael Vines <mvines@gmail.com>
2021-10-27 02:55:49 +00:00
0a698fc48f Instruction sysvar fixes, additions (backport #20958) (#21001)
* Instruction sysvar fixes, additions (#20958)

(cherry picked from commit 4fe3354c8f)

# Conflicts:
#	programs/bpf/rust/sysvar/src/lib.rs
#	programs/bpf/tests/programs.rs
#	sdk/program/src/sysvar/instructions.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-10-27 01:00:01 +00:00
1666fc5483 Restore getProgramAccounts spl-token secondary-index functionality (backport #20993) (#21005)
* Restore getProgramAccounts spl-token secondary-index functionality (#20993)

* Allow get_spl_token_X_filters to match on any encoding, and optimize earlier

* Remove redundant optimize calls

* Compress match statements

* Add method docs, including note to use optimize_filters before spl-token checks

* Add logs

(cherry picked from commit b2f6cfb9ff)

# Conflicts:
#	rpc/src/rpc.rs

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-10-26 23:43:45 +00:00
467abd1f5b feat: update getClusterNodes
(cherry picked from commit dec104c580)
2021-10-26 13:18:19 -07:00
19432f2e5f Add CrdsData::IncrementalSnapshotHashes (backport #20374) (#20994)
* Add CrdsData::IncrementalSnapshotHashes (#20374)

(cherry picked from commit 4e3818e5c1)

# Conflicts:
#	gossip/src/cluster_info.rs

* removes backport merge conflicts

Co-authored-by: Brooks Prumo <brooks@solana.com>
Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-26 20:07:09 +00:00
7e7f8ef5f0 Report timing info for stakes cache updates from txs (backport #20856) (#20884)
* Report timing info for stakes cache updates from txs (#20856)

(cherry picked from commit 735016661b)

# Conflicts:
#	runtime/src/bank.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-10-26 20:04:32 +00:00
9e81798d6d fix(docs): missing import (#20788) (#20996)
add missing import of `Connection`

(cherry picked from commit 521b7b79cc)

Co-authored-by: Colin Ogoo <ogoo.colin@gmail.com>
2021-10-26 19:10:27 +00:00
8986bd301c adds metrics tracking gossip crds writes and votes (backport #20953) (#20982)
* adds metrics tracking crds writes and votes (#20953)

(cherry picked from commit 1297a13586)

# Conflicts:
#	core/src/cluster_nodes.rs
#	gossip/benches/crds_shards.rs
#	gossip/src/cluster_info.rs
#	gossip/src/cluster_info_metrics.rs
#	gossip/src/crds_entry.rs
#	gossip/src/crds_gossip.rs
#	gossip/src/crds_gossip_pull.rs
#	gossip/src/crds_gossip_push.rs
#	gossip/src/crds_shards.rs
#	gossip/tests/crds_gossip.rs
#	rpc/src/rpc_service.rs

* updates itertools version in gossip

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-26 17:41:45 +00:00
6baad8e239 doubles crds unique pubkey capacity (#20947) (#20981)
(cherry picked from commit 43168e6365)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-26 15:14:29 +00:00
782d143489 Accountsdb plugin write ordering (#20948) (#20964)
Use the write_version in the Accounts's meta data so that account write with lower write_version would not overwrite the higher ones.
2021-10-26 00:05:40 -07:00
b15e87631c [solana-test-validator] add support for keypair file parsing for --bpf-program address argument (#20962)
(cherry picked from commit 58aa2b964b)

Co-authored-by: Paul Schaaf <paulsimonschaaf@gmail.com>
2021-10-26 01:09:56 +00:00
d18f553e2d Extend TestBroadcastReceiver::recv timeout (#20957) (#20961)
* Extend TestBroadcastReceiver timeout

* Add elapsed log

(cherry picked from commit 337b94b3bc)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-10-26 00:51:29 +00:00
e84c57b659 Hide deploy from cli subcommands (#20901) (#20951)
(cherry picked from commit af405f0ed7)

Co-authored-by: Jack May <jack@solana.com>
2021-10-25 20:03:44 +00:00
66630804de Accountsdb plugin postgres -- bulk insertion at startup (#20763) (#20931)
* Accountsdb plugin postgres -- bulk insertion at startup (#20763)

Use bulk insertion to Postgres at startup to reduce time taken for initial snapshot restore for postgres plugin. Avoid duplicate writes of accounts at startup. Doing account plugin notification and indexing in parallel.

Improved error handling for postgres plugin to show the real db issues for debug purpose
Added more metrics for postgres plugin.
Refactored plugin centric code out to a sub module from accounts_db and added unit tests

* Fixed the unit test failures
2021-10-25 09:18:32 -07:00
72158e3bf9 CLI: Add SW versions to feature status output (backport #20878) (#20905)
* cli: struct the tuples

(cherry picked from commit b9eb6242f5)

* cli: add software version(s) to feature status

(cherry picked from commit 152da44b62)

# Conflicts:
#	cli/Cargo.toml

* cli: sort feature status output

(cherry picked from commit 30d277b9fd)

* cli: improve feature status arithmatic readability

(cherry picked from commit d98c8b861c)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-10-25 05:04:08 +00:00
df6063a622 removes backport merge conflicts 2021-10-24 21:29:29 -07:00
55a1f03eee adds metrics for number of outgoing shreds in retransmit stage (#20882)
(cherry picked from commit 5e1cf39c74)

# Conflicts:
#	core/src/retransmit_stage.rs
2021-10-24 21:29:29 -07:00
d20cccc26b Add check for shred data header size (#20668)
(cherry picked from commit 588168b99d)
2021-10-24 20:16:41 -07:00
6c4a8b2d72 feat(docs): add transactionCount to getEpochInfo response
(cherry picked from commit aa13c90dd7)
2021-10-24 20:15:12 -07:00
307cda52ac Fixed bug in AccountInfo::serialize() (#20923)
Closes #20917

(cherry picked from commit edf5bc242c)

Co-authored-by: Eugene Lomov <eugene.v.lomov@gmail.com>
2021-10-25 02:26:18 +00:00
026385effd ci: Increase timeout duration for coverage step (#20888)
(cherry picked from commit 4fbf44dc75)
2021-10-24 17:44:36 -07:00
0363d8d373 Use config limit instead of default (#20900) (#20907)
(cherry picked from commit 9dd87bcdb5)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-10-23 21:05:07 +00:00
5c3f15e9c5 Support port number in postgres connection (#20662) (#20704)
* Support port number in postgres connection

* Addressed a few comments from Trent

(cherry picked from commit ad0a88f1f2)

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2021-10-23 18:35:30 +00:00
47e80be023 Fix response examples for getTokenAccountsByOwner and getTokenAccountsByDelegate (#20919)
(cherry picked from commit 63f94a4db3)

Co-authored-by: Slavomir <gagliardetto@users.noreply.github.com>
2021-10-23 16:43:13 +00:00
460dcad578 solana-test-validator --log now includes version/argument information
(cherry picked from commit 86bf071d77)
2021-10-22 13:46:29 -07:00
257d19ca48 Update 'Developing with Rust' GitHub links (#20860) (#20875)
* Update old GitHub links in 'Developing with Rust' docs

* exclude_entrypoint -> no-entrypoint in 'Developing with Rust'

(cherry picked from commit f729dec321)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-10-22 08:13:38 +00:00
de2aa898a7 Add counter for new transactions in SendTransactionService (#20852) (#20859)
* Add counter for inserted transactions

* Add counter for tx recv

(cherry picked from commit 8959d5e21c)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-10-22 05:03:26 +00:00
23b6ce7980 Bump version to 1.8.2 2021-10-21 00:43:40 -06:00
8cba6cca76 rpc-send-tx-svc server-side retry knobs (backport #20818) (#20830)
* rpc-send-tx-svc: add with_config constructor

(cherry picked from commit fe098b5ddc)

# Conflicts:
#	Cargo.lock
#	core/Cargo.toml
#	replica-node/Cargo.toml
#	rpc/src/rpc_service.rs
#	rpc/src/send_transaction_service.rs
#	validator/Cargo.toml

* rpc-send-tx-svc: server-side retry knobs

(cherry picked from commit 2744a2128c)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-10-21 02:15:03 +00:00
85048c667c cli: account for rpc nodes when considering feature set adoption (#20774)
(cherry picked from commit 5794bba65c)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-10-20 17:41:47 -06:00
440ccd189e Add program heap bump instruction (backport #20607) (#20815)
* Add program heap bump instruction (#20607)

(cherry picked from commit 58164517e4)

* nudge

Co-authored-by: Jack May <jack@solana.com>
2021-10-20 23:05:57 +00:00
d5fc81e12a Reduce budget request instruction length (#20636) (#20644)
(cherry picked from commit c231cfe235)

Co-authored-by: Jack May <jack@solana.com>
2021-10-20 12:17:29 -07:00
53f4bde471 add checked instructions sysvar api (backport #20790) (#20816)
* add checked instructions sysvar api (#20790)

(cherry picked from commit a8098f37d0)

# Conflicts:
#	programs/bpf/rust/sysvar/src/lib.rs
#	runtime/src/accounts.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-10-20 18:11:51 +00:00
232731e869 adds more metrics to blockstore insert shreds stats (backport #20701) (#20751)
* adds more metrics to blockstore insert shreds stats (#20701)

(cherry picked from commit 231b58b5f1)

# Conflicts:
#	ledger/src/blockstore.rs

* removes backport merge conflicts

* removes error logs

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-20 08:12:32 +00:00
63835ec214 prior to panicing with cap mismatch, try other calculation (#20292) (#20804)
(cherry picked from commit fa5b091b4c)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-10-20 02:26:23 +00:00
6de9ef62e8 docs: Amend RPC Transaction History proposal (#20794) (#20812)
# Problem

The initial proposal ruled out implementing BigTable queries for
the `getBlockTime` RPC, but then it was implemented a couple months
later. Indicating that the functionality was never implemented in
the "implemented-proposals" document is a little confusing, so let's
bring the document in line with what actually happened. 🦾

# Summary of Changes

Remove the blurb about how `getBlockTime` was going to be deprecated
and add it to the list of calls that didn't yet support BigTable
queries at the time the proposal was written.

(cherry picked from commit 0c7bade0b2)

Co-authored-by: Arthur Burkart <arthur@presynce.com>
2021-10-20 02:07:17 +00:00
0759b666ce Expand Rust API docs entry point (#20770) (#20801)
(cherry picked from commit cc4bb5a451)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-10-20 01:53:55 +00:00
c7e3d4cf79 Add docs to solana_clap_utils::keypair (backport #20665) (#20789)
* Add docs to solana_clap_utils::keypair (#20665)

* Add docs to solana_clap_utils::keypair

* Apply suggestions from code review

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Move imports to module level in solana_clap_utils::keypair::tests

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit 96c6ba6eb2)

# Conflicts:
#	clap-utils/src/keypair.rs

* Fix conflicts

Co-authored-by: Brian Anderson <andersrb@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-10-20 01:45:14 +00:00
63e37b2b20 Remove @brief annotations from Rust API docs (backport #20769) (#20807)
* Remove @brief annotations from Rust API docs (#20769)

(cherry picked from commit d9b0fc0e3e)

# Conflicts:
#	programs/bpf/rust/invoke/src/instructions.rs
#	programs/bpf/rust/invoke/src/processor.rs
#	programs/bpf/rust/realloc/src/instructions.rs
#	programs/bpf/rust/realloc/src/lib.rs
#	programs/bpf/rust/realloc/src/processor.rs
#	programs/bpf/rust/realloc_invoke/src/instructions.rs
#	programs/bpf/rust/realloc_invoke/src/lib.rs
#	programs/bpf/rust/realloc_invoke/src/processor.rs
#	sdk/cargo-build-bpf/tests/crates/fail/src/lib.rs
#	sdk/src/precompiles.rs

* Fix conflicts

Co-authored-by: Brian Anderson <andersrb@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-10-19 19:17:33 -06:00
436ec212f4 report udp stats from validator (backport #20587) (#20799)
* report udp stats from validator (#20587)

(cherry picked from commit 4cac66244d)

# Conflicts:
#	core/src/validator.rs

* resolve merge conflicts

Co-authored-by: Jeff Biseda <jbiseda@gmail.com>
2021-10-20 00:57:38 +00:00
564cc95b00 runtime: Add foundation stake pool withdraw authority (#20797)
(cherry picked from commit cb2bd65858)
2021-10-19 17:56:09 -07:00
28eb6ff796 Invoke cost tracker from its bank (backport #20627) (#20800)
* - make cost_tracker a member of bank, remove shared instance from TPU; (#20627)

- decouple cost_model from cost_tracker; allowing one cost_model
  instance being shared within a validator;
- update cost_model api to calculate_cost(&self...)->transaction_cost

(cherry picked from commit 7496b5784b)

# Conflicts:
#	core/src/banking_stage.rs
#	ledger-tool/src/main.rs
#	runtime/src/bank.rs
#	runtime/src/cost_model.rs
#	runtime/src/cost_tracker.rs

* manual fix merge conflicts

Co-authored-by: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com>
Co-authored-by: Tao Zhu <tao@solana.com>
2021-10-20 00:22:38 +00:00
de32ab4d57 Separate out interrupted slots broadcast metrics (#20537) (#20798)
(cherry picked from commit 838ff3b871)

Co-authored-by: carllin <carl@solana.com>
2021-10-19 22:26:49 +00:00
cabe2d5d04 Use node LTS (#20803) (#20806)
(cherry picked from commit 2c2bcd20e6)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-10-19 15:51:59 -06:00
ece4ecb792 stake: Add BorshSerialize trait to structs (#20784) (#20792)
(cherry picked from commit dc1b8ddea1)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-10-19 20:23:24 +00:00
ba366f49ad Ignore RUSTSEC-2020-0159
(cherry picked from commit 7baeb04f26)
2021-10-18 13:50:31 -07:00
8e666f47e0 optimistic-confirmation-and-slashing - fix typos (#20741) (#20765)
(cherry picked from commit 84660bbf3d)

Co-authored-by: Elliot Lee <github.public@intelliot.com>
2021-10-18 17:49:45 +00:00
0619705ce5 Simplify ed25519 instruction index
Allow u16::MAX to be specified for the instruction index. This makes it
possible to specify the current instruction, so it is not necessary to
know the instruction number.
2021-10-18 15:41:24 +01:00
188089389f feat: support for builtin ed25519 program
Conflicts:
	web3.js/src/index.ts
2021-10-18 15:41:24 +01:00
0a6bb84aec feat: add ed25519 signature verify program
Solang requires a method for verify ed25519 signatures. Add a new
builtin program at address Ed25519SigVerify111111111111111111111111111
which takes any number of ed25519 signature, public key, and message.
If any of the signatures fails to verify, an error is returned.

The changes for the web3.js package will go into another commit, since
the tests test against a released solana node. Adding web3.js ed25519
testing will break CI.

(cherry picked from commit b491354e51)

Conflicts:
	Cargo.lock
	Cargo.toml
	programs/bpf/Cargo.lock
	runtime/Cargo.toml
	sdk/src/feature_set.rs
	sdk/src/transaction.rs
	sdk/src/transaction/sanitized.rs
2021-10-18 15:41:24 +01:00
c8f6a0817b verify_precompiles needs FeatureSet
Rather than pass in individual features, pass in the entire feature set
so that we can add the ed25519 program feature in a later commit.

(cherry picked from commit 0f62771f42)

 Conflicts:
	banks-server/src/banks_server.rs
	core/src/banking_stage.rs
	programs/secp256k1/src/lib.rs
	rpc/src/rpc.rs
	runtime/src/bank.rs
	sdk/src/transaction.rs
	sdk/src/transaction/sanitized.rs
2021-10-18 15:41:24 +01:00
5350250a06 Improve program-test process_transaction() speed by reducing sleep duration in banks-server (backport #20508) (#20733)
* Improve program-test process_transaction() speed by reducing sleep duration in banks-server (#20508)

* banks_server: Reduce sleep duration for local server

This speeds up process_transaction_with_commitment_and_context()
and thus most program tests by a lot.

* Plumb tick duration through poh config and signature polling

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
(cherry picked from commit bea181eba9)

# Conflicts:
#	banks-server/src/banks_server.rs
#	program-test/src/lib.rs

* Fix merge issues

Co-authored-by: Christian Kamm <ckamm@delightful-solutions.de>
Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-10-15 21:36:59 +00:00
f8fccc7e91 docs: prefer solana gossip to solana-gossip spy (#20734)
(cherry picked from commit 9543fd9cdd)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-10-15 19:42:20 +00:00
eaa6d1a4b5 adds counters for errors in window-service run_insert (#20670) (#20724)
(cherry picked from commit 0f03971c3c)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-15 18:09:11 +00:00
b66c9539c2 program-test: Fix getting new blockhash post-warp (#20710) (#20723)
(cherry picked from commit 0419e6c22e)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-10-15 16:13:09 +00:00
bdea60cc19 Rpc: filters performance improvement (#20185) (#20703)
* Add Base58,Base64,Bytes to MemcmpEncodedBytes

* Rpc: decode memcmp before filtering accounts

* Add deprecated attribute

* Add Memcmp::bytes

* Fix clippy for deprecated

* Another clippy fix

* merge RpcFilterError::DataTooLarge

* add deprecation for Base58DataTooLarge

* change filter data size limit

* strict data size len for base58

* add magic numbers

* fix tests

(cherry picked from commit e9a427b9c8)

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
2021-10-14 21:48:13 +00:00
63ac5e4561 clap-utils: trim single-quotes from signer uris on windows (#20695)
(cherry picked from commit 6649dfa899)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-10-14 20:23:15 +00:00
88e6f41bec Include token owners in TransactionTokenBalances (backport #20642) (#20677)
* Include token owners in TransactionTokenBalances (#20642)

* Cache owners in TransactionTokenBalances

* Light cleanup

* Use return struct, and remove pub

* Single-use statements

* Why not, just do the whole crate

* Add metrics

* Make datapoint_debug to prevent spam unless troubleshooting

(cherry picked from commit e806fa6904)

# Conflicts:
#	ledger/src/blockstore.rs
#	transaction-status/Cargo.toml
#	transaction-status/src/token_balances.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-10-14 07:09:13 +00:00
e0280a68ba Accountsdb plugin metrics (#20606) (#20664)
Added metrics for accountsdb plugin
Handle and log postgres db errors
Print account pubkeys nicely in logging
2021-10-13 14:35:46 -07:00
aa8d04d44b uses nanos precision for timestamp when submitting metrics to influxdb (#20623) (#20659)
Current datapoint_info! is apparently overwriting itself when run inside
a loop. For example in
https://github.com/solana-labs/solana/blob/005d6863f/core/src/window_service.rs#L101-L107
only one of the slots will show up in influxdb.

This is apparently because of metrics code using milliseconds as the
timestamp, as mentioned here:
https://github.com/solana-labs/solana/issues/19789#issuecomment-922482013

(cherry picked from commit cd87525f54)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-13 20:47:01 +00:00
778f37b12d fix unstable test (#20645) (#20663)
(cherry picked from commit 220fd41bbc)

Co-authored-by: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com>
2021-10-13 20:02:42 +00:00
ebe77a0985 Proposal: log binary data for Solidity
Rename "Program return data: " to "Program return: " since "data" is
redundant.

(cherry picked from commit b89177c8de)

Conflicts:
	programs/bpf_loader/src/syscalls.rs
	sdk/bpf/c/inc/sol/log.h
	sdk/program/Cargo.toml
	sdk/src/feature_set.rs
	sdk/src/process_instruction.rs
2021-10-13 14:34:36 +01:00
400a88786a aggregate cost_tracker to bank (backport #20527) (#20622)
* - move cost tracker into bank, so each bank has its own cost tracker; (#20527)

- move related modules to runtime

(cherry picked from commit 005d6863fd)

# Conflicts:
#	Cargo.lock
#	core/benches/banking_stage.rs
#	core/src/banking_stage.rs
#	core/src/lib.rs
#	core/src/tvu.rs
#	ledger-tool/src/main.rs
#	ledger/src/blockstore_processor.rs
#	programs/bpf/Cargo.lock
#	runtime/Cargo.toml
#	runtime/src/cost_model.rs

* manual fix merge conflicts

Co-authored-by: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com>
Co-authored-by: Tao Zhu <tao@solana.com>
2021-10-13 05:07:09 +00:00
29eae21057 Ignore delinquent stake on exit (backport #20367) (#20612)
* Ignore delinquent stake on exit (#20367)

* add --ignore-delinquency flag to validator exit and wait-for-restart-window sub commands

* Fix a merge issue

* Add missing variable declaration

* Remove empty line to help CI checks pass

* run rustfmt

* Change argument wording for clarity and verbosity

* Change --ignore-delinquent-stake to --max-delinquent-stake

* cargo fmtgit add validator/src/main.rsgit add validator/src/main.rs

* Adjust per mvines

* Formatting

* Improve input validation

* Please automate cargo fmt somehow

(cherry picked from commit fc5dd7f3bc)

# Conflicts:
#	validator/src/main.rs

* Fixes cherry-pick conflict

Co-authored-by: Michael <68944931+michaelh-laine@users.noreply.github.com>
Co-authored-by: Steven Czabaniuk <steven@solana.com>
2021-10-12 20:30:47 +00:00
0d1dbb6160 Fix return data too large test
(cherry picked from commit d09687c30e)
2021-10-12 18:31:42 +01:00
927d3b5e0d Add return data implementation
This consists of:
 - syscalls
 - passing return data from invoked to invoker
 - printing to stable log
 - rust and C SDK changes

(cherry picked from commit 53b47b87b2)
2021-10-12 18:31:42 +01:00
df929bda38 Do not shell out for tar (#19043)
When making a snapshot archive, we used to shell out and call `tar -S`
for sparse file support.  The tar crate supports sparse files, so no
need to do this anymore.

Fixes #10860

(cherry picked from commit 68cc71409e)

# Conflicts:
#	runtime/src/snapshot_utils.rs
2021-10-12 15:36:51 +00:00
200c5c9fd6 solana-validator wait-for-restart-window command now accepts an optional --identity argument (backport #18684) (#20610)
* wait-for-restart-window command now accepts an optional --identity argument

(cherry picked from commit c418e8f370)

# Conflicts:
#	validator/src/main.rs

* Fixed cherry-pick conflicts

Co-authored-by: Michael Vines <mvines@gmail.com>
Co-authored-by: Steven Czabaniuk <steven@solana.com>
2021-10-12 07:07:40 +00:00
9acf708344 Remove support for dynamically loaded native programs (backport #20444) (#20560)
* Remove support for dynamically loaded native programs (#20444)

(cherry picked from commit 785fcb63f5)

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	program-runtime/src/instruction_processor.rs
#	programs/failure/Cargo.toml
#	programs/failure/tests/failure.rs
#	programs/noop/Cargo.toml
#	programs/ownable/Cargo.toml
#	programs/ownable/src/ownable_processor.rs
#	runtime/src/bank.rs
#	runtime/tests/noop.rs
#	sdk/src/feature_set.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-10-11 23:55:39 +00:00
af4c1785b6 Reorder RpcClient method defs for more logical docs. (backport #20549) (#20597)
* Reorder RpcClient method defs for more logical docs. (#20549)

Methods follow this order:

- Constructors
- send_and_confirm variations
- send variations
- confirm variations
- simulate variations
- queries

(cherry picked from commit 1417c1456d)

# Conflicts:
#	client/src/rpc_client.rs

* Fix conflicts

Co-authored-by: Brian Anderson <andersrb@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-10-11 21:33:10 +00:00
b8f68860a4 docs: Remove outdated instructions for managing stake accounts (#20555) (#20600)
(cherry picked from commit 03d3e0098e)

Co-authored-by: Justin Starry <justin@solana.com>
2021-10-11 20:17:02 +00:00
547f33d1d1 Adjust solana validators output to account for the 1k+ validators on mainnet (#20576)
(cherry picked from commit bdf8b1da6b)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-10-11 16:51:18 +00:00
67738a229c fix(docs): getInflationRate epoch type from f64 => u64 (#20589) (#20590)
(cherry picked from commit 185c9f9e8f)

Co-authored-by: Yihau Chen <a122092487@gmail.com>
2021-10-11 16:03:41 +00:00
50803c3f58 Rework AVX/AVX2 detection again
(cherry picked from commit c16510152e)
2021-10-10 15:28:14 -07:00
50cb612ae1 Accountsdb stream plugin improvement (#20419) (#20573)
* Accountsdb stream plugin improvement (#20419)

Support using connection pooling and use multiple threads to do Postgres db operations. The performance is improved from 1500 RPS to 40,000 RPS measured during validator start.

Support multiple plugins at the same time.

* Fixed a fmt issue
2021-10-10 15:24:12 -07:00
e5dc8d731b Web3 docs updated with quickstart guide (#19457) (#20571) 2021-10-09 16:01:35 -06:00
f9dcb8228f Added web3 reference guide (#19970) (#20568)
Co-authored-by: cryptogosu <82475023+cryptogosu@users.noreply.github.com>
2021-10-09 15:24:50 -06:00
68e8a05848 Fix solana docker image (#20551)
The docker image fails with:

/usr/bin/solana-run.sh: line 66: ./fetch-spl.sh: No such file or directory

In the solana docker image, scripts/run.sh is copied to
/usr/bin/solana-run.sh and fetch-spl.sh to /usr/bin/fetch-spl.sh. This
means that the line:

cd "$(dirname "$0")/.."

means we're doing a "cd /usr", which means we can't find fetch-spl.sh or
spl-genesis-args.sh (i.e., the error above).

(cherry picked from commit 2762f6f96f)

Co-authored-by: Sean Young <sean@mess.org>
2021-10-09 04:05:10 +00:00
bfc5f9fb6c v1.8: Bump crates to resolve audit failures (#20552)
* Bump nix

* Bump sha2 to resolve warning
2021-10-09 00:27:30 +00:00
c3cc7d52fe Revert "docs: Explain what solana-stake-accounts new does (#20401)" (#20554) (#20556)
This reverts commit 00c6536528.

(cherry picked from commit 17314f4a95)

Co-authored-by: Justin Starry <justin@solana.com>
2021-10-08 19:46:48 +00:00
4268cf1d8b docs: Explain what solana-stake-accounts new does (#20401) (#20547)
(cherry picked from commit 00c6536528)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-10-08 15:54:03 +00:00
c693ecc4c8 fixes backports code changes (#20541) 2021-10-08 15:30:27 +00:00
afe866ad02 Enable easy full-rpc services on testnet nodes (#20530) 2021-10-07 19:36:23 -06:00
6a73bf767b adds metrics for number of nodes vs number of pubkeys (backport #20512) (#20524)
* adds metrics for number of nodes vs number of pubkeys (#20512)

(cherry picked from commit 0da661de62)

# Conflicts:
#	gossip/src/cluster_info_metrics.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-10-07 22:27:48 +00:00
7d0494fcaa Merge AccountsDb plugin framework to v1.8 (#20518)
Merge AccountsDb plugin framework to v1.8 (#20518)
Summary of Changes

Create a plugin mechanism in the accounts update path so that accounts data can be streamed out to external data stores (be it Kafka or Postgres). The plugin mechanism allows

Data stores of connection strings/credentials to be configured,
Accounts with patterns to be streamed
PostgreSQL implementation of the streaming for different destination stores to be plugged in.

The code comprises 4 major parts:

accountsdb-plugin-intf: defines the plugin interface which concrete plugin should implement.
accountsdb-plugin-manager: manages the load/unload of plugins and provide interfaces which the validator can notify of accounts update to plugins.
accountsdb-plugin-postgres: the concrete plugin implementation for PostgreSQL
The validator integrations: updated streamed right after snapshot restore and after account update from transaction processing or other real updates.
The plugin is optionally loaded on demand by new validator CLI argument -- there is no impact if the plugin is not loaded.
2021-10-07 14:15:05 -07:00
33d8e242c5 Fixup docs on deprecated JSON-RPC methods (backport #20515) (#20521)
* Update expected removal version to match backward-compatibility policy (#20515)

(cherry picked from commit d56ad8ff4f)

# Conflicts:
#	docs/src/developing/clients/jsonrpc-api.md

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-10-07 20:37:01 +00:00
ef55045724 rebase 2021-10-07 07:44:12 -07:00
81d2c3261c Derive Pod/Zeroable for Pubkey
(cherry picked from commit f966859829)

# Conflicts:
#	Cargo.lock
#	programs/bpf/Cargo.lock
#	sdk/program/Cargo.toml
2021-10-07 07:44:12 -07:00
348ba57b12 Bump version to 1.8.1 2021-10-06 17:57:06 -07:00
4a8ff62ad3 Add RecentItems metrics (#20484) (#20490) 2021-10-06 17:07:33 -06:00
db85d659b9 Cost model 1.7 (#20188)
* Cost Model to limit transactions which are not parallelizeable (#16694)

* * Add following to banking_stage:
  1. CostModel as immutable ref shared between threads, to provide estimated cost for transactions.
  2. CostTracker which is shared between threads, tracks transaction costs for each block.

* replace hard coded program ID with id() calls

* Add Account Access Cost as part of TransactionCost. Account Access cost are weighted differently between read and write, signed and non-signed.

* Establish instruction_execution_cost_table, add function to update or insert instruction cost, unit tested. It is read-only for now; it allows Replay to insert realtime instruction execution costs to the table.

* add test for cost_tracker atomically try_add operation, serves as safety guard for future changes

* check cost against local copy of cost_tracker, return transactions that would exceed limit as unprocessed transaction to be buffered; only apply bank processed transactions cost to tracker;

* bencher to new banking_stage with max cost limit to allow cost model being hit consistently during bench iterations

* replay stage feed back program cost (#17731)

* replay stage feeds back realtime per-program execution cost to cost model;

* program cost execution table is initialized into empty table, no longer populated with hardcoded numbers;

* changed cost unit to microsecond, using value collected from mainnet;

* add ExecuteCostTable with fixed capacity for security concern, when its limit is reached, programs with old age AND less occurrence will be pushed out to make room for new programs.

* investigate system performance test degradation  (#17919)

* Add stats and counter around cost model ops, mainly:
- calculate transaction cost
- check transaction can fit in a block
- update block cost tracker after transactions are added to block
- replay_stage to update/insert execution cost to table

* Change mutex on cost_tracker to RwLock

* removed cloning cost_tracker for local use, as the metrics show clone is very expensive.

* acquire and hold locks for block of TXs, instead of acquire and release per transaction;

* remove redundant would_fit check from cost_tracker update execution path

* refactor cost checking with less frequent lock acquiring

* avoid many Transaction_cost heap allocation when calculate cost, which
is in the hot path - executed per transaction.

* create hashmap with new_capacity to reduce runtime heap realloc.

* code review changes: categorize stats, replace explicit drop calls, concisely initiate to default

* address potential deadlock by acquiring locks one at time

* Persist cost table to blockstore (#18123)

* Add `ProgramCosts` Column Family to blockstore, implement LedgerColumn; add `delete_cf` to Rocks
* Add ProgramCosts to compaction excluding list alone side with TransactionStatusIndex in one place: `excludes_from_compaction()`

* Write cost table to blockstore after `replay_stage` replayed active banks; add stats to measure persist time
* Deletes program from `ProgramCosts` in blockstore when they are removed from cost_table in memory
* Only try to persist to blockstore when cost_table is changed.
* Restore cost table during validator startup

* Offload `cost_model` related operations from replay main thread to dedicated service thread, add channel to send execute_timings between these threads;
* Move `cost_update_service` to its own module; replay_stage is now decoupled from cost_model.

* log warning when channel send fails (#18391)

* Aggregate cost_model into cost_tracker (#18374)

* * aggregate cost_model into cost_tracker, decouple it from banking_stage to prevent accidental deadlock. * Simplified code, removed unused functions

* review fixes

* update ledger tool to restore cost table from blockstore (#18489)

* update ledger tool to restore cost model from blockstore when compute-slot-cost

* Move initialize_cost_table into cost_model, so the function can be tested and shared between validator and ledger-tool

* refactor and simplify a test

* manually fix merge conflicts

* Per-program id timings (#17554)

* more manual fixing

* solve a merge conflict

* featurize cost model

* more merge fix

* cost model uses compute_unit to replace microsecond as cost unit
(#18934)

* Reject blocks for costs above the max block cost (#18994)

* Update block max cost limit to fix performance regession (#19276)

* replace function with const var for better readability (#19285)

* Add few more metrics data points (#19624)

* periodically report sigverify_stage stats (#19674)

* manual merge

* cost model nits (#18528)

* Accumulate consumed units (#18714)

* tx wide compute budget (#18631)

* more manual merge

* ignore zerorize drop security

* - update const cost values with data collected by #19627
- update cost calculation to closely proposed fee schedule #16984

* add transaction cost histogram metrics (#20350)

* rebase to 1.7.15

* add tx count and thread id to stats (#20451)
each stat reports and resets when slot changes

* remove cost_model feature_set

* ignore vote transactions from cost model

Co-authored-by: sakridge <sakridge@gmail.com>
Co-authored-by: Jeff Biseda <jbiseda@gmail.com>
Co-authored-by: Jack May <jack@solana.com>
2021-10-06 15:55:29 -06:00
a4df784e82 Bump version to 1.8.0 2021-10-06 15:48:23 -06:00
414674eba1 Fix dos data-type for non-gossip mode (#20465) (#20478)
(cherry picked from commit b178f3f2d3)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-10-06 19:00:34 +00:00
d922971ec6 Optimize stakes cache and rewards at epoch boundaries (backport #20432) (#20472)
* Optimize stakes cache and rewards at epoch boundaries (backport #20432)

* fix conflicts
2021-10-06 16:15:27 +00:00
95ac00d30a Make rewards tracer async friendly (backport #20452) (#20456)
* Make rewards tracer async friendly (#20452)

(cherry picked from commit 250a8503fe)

# Conflicts:
#	Cargo.lock
#	ledger-tool/Cargo.toml
#	runtime/src/bank.rs

* fix conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-10-06 11:20:50 +00:00
1ca4f7d110 Install openssl for travisci windows builds (#20420) (#20458)
(cherry picked from commit df73d8e8a1)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-10-05 22:30:23 -06:00
8999f07ed2 Remove nodejs (#20399) (#20433)
(cherry picked from commit 6df0ce5457)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-10-05 08:56:57 +00:00
9f4f8fc9e9 Add struct and convenience methods to track stake activation status (backport #20392) (#20425)
* Add struct and convenience methods to track stake activation status (#20392)

* Add struct and convenience methods to track stake activation status

* fix nits

* rename

(cherry picked from commit 0ddb34a0b4)

# Conflicts:
#	runtime/src/stakes.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-10-05 04:33:30 +00:00
00b03897e1 Default --rpc-bind-address to 127.0.0.1 when --private-rpc is provided and --bind-address is not
(cherry picked from commit 221343e849)
2021-10-04 16:58:46 -07:00
6181df68cf Staking docs: link to overview (#20426)
(cherry picked from commit 2d5b471c09)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-10-04 23:22:21 +00:00
1588b00f2c fix syntax error in bash_profile (#20386)
if there is no newline at the end of the file, this export is glued to the rest of the code and generates a syntax error like this

```bash
if [ -f ~/.git-completion.bash ]; then
  . ~/.git-completion.bash
fiexport PATH="/Users/user/.local/share/solana/install/active_release/bin:$PATH"
```

(cherry picked from commit 87c0d8d9e7)

Co-authored-by: OleG <emptystamp@gmail.com>
2021-10-02 04:50:39 +00:00
ef306aa7cb Deploy error is buffer is too small (#20358) (#20362)
* Deploy error is buffer is too small

* missing file

(cherry picked from commit de8331eeaf)

# Conflicts:
#	cli/tests/fixtures/noop.so

Co-authored-by: Jack May <jack@solana.com>
2021-10-01 05:25:11 +00:00
e718f4b04a terminology.md: remove CBC block and unneeded filename (#20269) (#20349)
(cherry picked from commit a7f2d9f55f)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-30 23:19:12 +00:00
51593a882b Properly enable unprefixed_malloc_on_supported_platforms in tikv-jemallocator (#20351) (#20354)
Trivial typo fix.

Fixes: 4bf6d0c4d7 ("adds unprefixed_malloc_on_supported_platforms to jemalloc (#20317)")
(cherry picked from commit 8ae88632cb)

Co-authored-by: Ivan Mironov <mironov.ivan@gmail.com>
2021-09-30 20:26:11 +00:00
1c15cc6e9a add unchecked invokes (#20313) (#20337)
(cherry picked from commit 8188c1dd59)

Co-authored-by: Jack May <jack@solana.com>
2021-09-30 17:05:51 +00:00
734b380cdb Bump version to v1.7.15 (#20338) 2021-09-30 10:51:34 -06:00
9cc26b3b00 cli: Stop topping up buffer balance (#20181) (#20312)
(cherry picked from commit 53a810dbad)

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-30 12:31:12 -04:00
ef5a0e842c stake-accounts.md: fix grammar, link Solana Explorer (#20270) (#20274)
(cherry picked from commit f24fff8495)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-29 22:57:00 -06:00
5bdb824267 Remove original feature gating (#20334) 2021-09-29 22:36:51 -06:00
474f2bcdf4 Prune sigverify queue (#20315) 2021-09-30 05:40:48 +02:00
2302211963 Remove files (#20332) 2021-09-30 02:25:24 +00:00
8178db52a5 Add transaction mode to dos (#20191) (#20329)
(cherry picked from commit 94a1a57106)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-09-29 23:53:15 +00:00
5d8429d953 adds unprefixed_malloc_on_supported_platforms to jemalloc (#20317) (#20325)
Without this feature jemalloc is used only for Rust code but not for
bundled C/C++ libraries (like rocksdb).
https://github.com/solana-labs/solana/issues/14366#issuecomment-930404992

(cherry picked from commit 4bf6d0c4d7)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-29 22:49:47 +00:00
fec15f69f4 Increment 1.7 version (#20316) 2021-09-29 15:37:45 -04:00
257ddbeee1 Tpu vote 1.7 (#20187)
* Add separate vote processing tpu port

* Add feature to send to tpu vote port

* Add vote rejecting sigverify mode

* use packet.meta.is_simple_vote_tx in place of deserialization

* consolidate code that identifies vote tx atcommon path for cpu and gpu

* new key for feature set

* banking forward tpu vote

* add tpu vote port to dockerfile and other review changes

* Simplify thread id compare

* fix a test; updated cluster_info ABI change

Co-authored-by: Tao Zhu <tao@solana.com>
2021-09-29 18:12:58 +02:00
47c1730808 uses rayon thread-pool for retransmit-stage parallelization (#19486) (#20293)
(cherry picked from commit 01a7ec8198)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-29 14:11:46 +00:00
a005a6b816 Restore ability for programs to upgrade themselves (backport #20265) (#20295)
* Restore ability for programs to upgrade themselves (#20265)

* Make helper associated fn

* Add feature definition

* Add handling to preserve program-id write lock when upgradeable loader is present; restore bpf upgrade-self test

* Use single feature

(cherry picked from commit 2cd9dc99b6)

# Conflicts:
#	runtime/src/accounts.rs
#	sdk/program/src/message.rs
#	sdk/program/src/message/mapped.rs
#	sdk/program/src/message/sanitized.rs
#	sdk/src/feature_set.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-29 01:34:33 +00:00
2f2948f998 Extricate RpcCompletedSlotsService from RetransmitStage (backport #18017) (#20294)
* Extricate RpcCompletedSlotsService from RetransmitStage

(cherry picked from commit fa04531c7a)

# Conflicts:
#	core/src/replay_stage.rs
#	core/src/retransmit_stage.rs
#	core/src/tvu.rs
#	core/src/validator.rs

* removes backport merge conflicts

Co-authored-by: Michael Vines <mvines@gmail.com>
Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-28 18:25:51 +00:00
55ccff7604 skips retransmit for shreds with unknown slot leader (backport #19472) (#20291)
* skips retransmit for shreds with unknown slot leader (#19472)

Shreds' signatures should be verified before they reach retransmit
stage, and if the leader is unknown they should fail signature check.
Therefore retransmit-stage can as well expect to know who the slot
leader is and otherwise just skip the shred.

Blockstore checking signature of recovered shreds before sending them to
retransmit stage:
https://github.com/solana-labs/solana/blob/4305d4b7b/ledger/src/blockstore.rs#L884-L930

Shred signature verifier:
https://github.com/solana-labs/solana/blob/4305d4b7b/core/src/sigverify_shreds.rs#L41-L57
https://github.com/solana-labs/solana/blob/4305d4b7b/ledger/src/sigverify_shreds.rs#L105

(cherry picked from commit 6d9818b8e4)

# Conflicts:
#	core/src/broadcast_stage/broadcast_duplicates_run.rs
#	ledger/src/shred.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-28 15:26:30 +00:00
1bf88556ee removes Slot from TransmitShreds (backport #19327) (#20260)
* removes Slot from TransmitShreds (#19327)

An earlier version of the code was funneling through stakes along with
shreds to broadcast:
https://github.com/solana-labs/solana/blob/b67ffab37/core/src/broadcast_stage.rs#L127

This was changed to only slots as stakes computation was pushed further
down the pipeline in:
https://github.com/solana-labs/solana/pull/18971

However shreds themselves embody which slot they belong to. So pairing
them with slot is redundant and adds rooms for bugs should they become
inconsistent.

(cherry picked from commit 1deb4add81)

# Conflicts:
#	core/benches/cluster_info.rs
#	core/src/broadcast_stage.rs
#	core/src/broadcast_stage/broadcast_duplicates_run.rs
#	core/src/broadcast_stage/fail_entry_verification_broadcast_run.rs
#	core/src/broadcast_stage/standard_broadcast_run.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-28 12:55:01 +00:00
4c4f183515 reverts #17542 (#20259) (#20273)
https://github.com/solana-labs/solana/pull/17542
excludes caller's crds values from pull responses.

Reverting that commit so that when a (staked) node restarts, it can
obtain its crds values before restart from other nodes.

(cherry picked from commit 43ed727ba7)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-28 12:54:31 +00:00
282322cbe8 Add more docs for RpcClient (backport #19771) (#20266)
* Add more docs for RpcClient (#19771)

* Add more docs for RpcClient

* Use custom mocks in rpc_client examples

* Move create_rpc_client_mocks into rpc_client module

Signed-off-by: Brian Anderson <andersrb@gmail.com>

* Update client/src/rpc_client.rs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Update RpcClient docs per review feedback

* Consistently link 'commitment level' in RpcClient docs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit 082d5dc5b2)

# Conflicts:
#	client/src/mock_sender.rs
#	client/src/rpc_client.rs

* Fix conflicts

Co-authored-by: Brian Anderson <andersrb@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-28 07:27:23 +00:00
2dc00d0e13 Paper wallet: fix URI scheme (#20233) (#20278)
(cherry picked from commit 38844a7010)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-28 01:29:42 +00:00
a90c338982 Rpc: use rust convenient methods
(cherry picked from commit ac79ae6848)
2021-09-27 13:46:27 -07:00
36c283026f fix Borsh typo
changes `BORSH_IO_ERROR` from `unkown` to `unknown` error

(cherry picked from commit e94b7984a1)
2021-09-27 12:30:41 -07:00
a1a0c63862 retransmits shreds recovered from erasure codes (backport #19233) (#20249)
* removes packet-count metrics from retransmit stage

Working towards sending shreds (instead of packets) to retransmit stage
so that shreds recovered from erasure codes are as well retransmitted.

Following commit will add these metrics back to window-service, earlier
in the pipeline.

(cherry picked from commit bf437b0336)

# Conflicts:
#	core/src/retransmit_stage.rs

* adds packet/shred count stats to window-service

Adding back these metrics from the earlier commit which removed them
from retransmit stage.

(cherry picked from commit 8198a7eae1)

* removes erroneous uses of Arc<...> from retransmit stage

(cherry picked from commit 6e413331b5)

# Conflicts:
#	core/src/retransmit_stage.rs
#	core/src/tvu.rs

* sends shreds (instead of packets) to retransmit stage

Working towards channelling through shreds recovered from erasure codes
to retransmit stage.

(cherry picked from commit 3efccbffab)

# Conflicts:
#	core/src/retransmit_stage.rs

* returns completed-data-set-info from insert_data_shred

instead of opaque (u32, u32) which are then converted to
CompletedDataSetInfo at the call-site.

(cherry picked from commit 3c71670bd9)

# Conflicts:
#	ledger/src/blockstore.rs

* retransmits shreds recovered from erasure codes

Shreds recovered from erasure codes have not been received from turbine
and have not been retransmitted to other nodes downstream. This results
in more repairs across the cluster which is slower.

This commit channels through recovered shreds to retransmit stage in
order to further broadcast the shreds to downstream nodes in the tree.

(cherry picked from commit 7a8807b8bb)

# Conflicts:
#	core/src/retransmit_stage.rs
#	core/src/window_service.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-27 18:11:37 +00:00
e20fdde0a4 Wallet guide: fix grammar (#20228) (#20254)
(cherry picked from commit f107aa296b)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-27 16:56:14 +00:00
5b52ac8990 Fix grammar in conventions.md (#20236) (#20252)
(cherry picked from commit af57bd3d48)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-27 16:39:39 +00:00
502ae8b319 removes repeated bank-forks locking in window-service (backport #19210) (#20239)
* removes repeated bank-forks locking in window-service

Window service is repeatedly locking bank-forks to look-up working-bank
for every single shred:
https://github.com/solana-labs/solana/blob/5fde4ee3a/core/src/window_service.rs#L597-L606

This commit updates shred_filter signature in recv_window so that where
we already obtain the lock on bank-forks, we can also look-up
working-bank once for all packets:
https://github.com/solana-labs/solana/blob/5fde4ee3a/core/src/window_service.rs#L256-L277

(cherry picked from commit d57398a959)

# Conflicts:
#	core/src/window_service.rs

* removes erroneous uses of &Arc<...> from window-service

(cherry picked from commit b64eeb7729)

# Conflicts:
#	core/src/window_service.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-27 13:48:58 +00:00
30f0b3cf53 removes raw indexing from streamer (backport #19183) (#20237)
* removes raw indexing from streamer (#19183)

Raw indexing is verbose and error-prone. This same code had an indexing
bug causing validator nodes panic just a few months ago:
https://github.com/solana-labs/solana/commit/482b8c6be

(cherry picked from commit 8229a4fbf6)

# Conflicts:
#	streamer/Cargo.toml

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-27 13:48:13 +00:00
2975dc5c1a removes use of public ip addresses from perf tests (backport #19184) (#20238)
* removes use of public ip addresses from system tests

Using global IPs causes outbound traffic which costs money:
https://github.com/solana-labs/solana/pull/18728#issuecomment-884290209

(cherry picked from commit bd8f793809)

* removes redundant allow-private-addr from system tests

Following https://github.com/solana-labs/solana/pull/19130
if gce.sh creat is invoked without -P then --allow-private-addr is
implied:
https://github.com/solana-labs/solana/blob/4cc1b1504/net/common.sh#L68-L73

Therefore tests only need to specify:
  USE_PUBLIC_IP_ADDRESSES: "false"

(cherry picked from commit 18463aa846)

# Conflicts:
#	system-test/partition-testcases/gce-5-node-3-partition.yml
#	system-test/partition-testcases/gce-partition-once-then-stabilize.yml
#	system-test/partition-testcases/gce-partition-with-offline.yml

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-27 01:23:02 +00:00
d68377e927 unifies cluster-nodes computation & caching across turbine stages (backport #18971) (#20231)
* sends slots (instead of stakes) through broadcast flow

Current broadcast code is computing stakes for each slot before sending
them down the channel:
https://github.com/solana-labs/solana/blob/049fb0417/core/src/broadcast_stage/standard_broadcast_run.rs#L208-L228
https://github.com/solana-labs/solana/blob/0cf52e206/core/src/broadcast_stage.rs#L342-L349

Since the stakes are a function of epoch the slot belongs to (and so
does not necessarily change from one slot to another), forwarding the
slot itself would allow better caching downstream.

In addition we need to invalidate the cache if the epoch changes (which
the current code does not do), and that requires to know which slot (and
so epoch) current broadcasted shreds belong to:
https://github.com/solana-labs/solana/blob/19bd30262/core/src/broadcast_stage/standard_broadcast_run.rs#L332-L344

(cherry picked from commit 44b11154ca)

# Conflicts:
#	core/src/broadcast_stage/broadcast_duplicates_run.rs
#	core/src/broadcast_stage/standard_broadcast_run.rs

* implements cluster-nodes cache

Cluster nodes are cached keyed by the respective epoch from which stakes
are obtained, and so if epoch changes cluster-nodes will be recomputed.

A time-to-live eviction policy is enforced to refresh entries in case
gossip contact-infos are updated.

(cherry picked from commit ecc1c7957f)

* uses cluster-nodes cache in retransmit stage

The new cluster-nodes cache will:
  * ensure cluster-nodes are recalculated if the epoch (and so the epoch
    staked nodes) changes.
  * encapsulate time-to-live eviction policy.

(cherry picked from commit 30bec3921e)

* uses cluster-nodes cache in broadcast-stage

* Current caching mechanism does not update cluster-nodes when the epoch
  (and so epoch staked nodes) changes:
  https://github.com/solana-labs/solana/blob/19bd30262/core/src/broadcast_stage/standard_broadcast_run.rs#L332-L344

* Additionally, the cache update has a concurrency bug in which the
  thread which does compare_and_swap may be blocked when it tries to
  obtain the write-lock on cache, while other threads will keep running
  ahead with the outdated cache (since the atomic timestamp is already
  updated).

In the new ClusterNodesCache, entries are keyed by epoch, and so if
epoch changes cluster-nodes will be recalculated. The time-to-live
eviction policy is also encapsulated and rigidly enforced.

(cherry picked from commit aa32738dd5)

# Conflicts:
#	core/src/broadcast_stage/broadcast_duplicates_run.rs
#	core/src/broadcast_stage/fail_entry_verification_broadcast_run.rs
#	core/src/broadcast_stage/standard_broadcast_run.rs

* unifies cluster-nodes computation & caching across turbine stages

Broadcast-stage is using epoch_staked_nodes based on the same slot that
shreds belong to:
https://github.com/solana-labs/solana/blob/049fb0417/core/src/broadcast_stage/standard_broadcast_run.rs#L208-L228
https://github.com/solana-labs/solana/blob/0cf52e206/core/src/broadcast_stage.rs#L342-L349

But retransmit-stage is using bank-epoch of the working-bank:
https://github.com/solana-labs/solana/blob/19bd30262/core/src/retransmit_stage.rs#L272-L289

So the two are not consistent at epoch boundaries where some nodes may
have a working bank (or similarly a root bank) lagging other nodes. As a
result the node which obtains a packet may construct turbine broadcast
tree inconsistently with its parent node in the tree and so some packets
may fail to reach all nodes in the tree.

(cherry picked from commit 50d0e830c9)

* adds fallback & metric for when epoch staked-nodes are none

(cherry picked from commit fb69f45f14)

* allows only one thread to update cluster-nodes cache entry for an epoch

If two threads simultaneously call into ClusterNodesCache::get for the
same epoch, and the cache entry is outdated, then both threads recompute
cluster-nodes for the epoch and redundantly overwrite each other.

This commit wraps ClusterNodesCache entries in Arc<Mutex<...>>, so that
when needed only one thread does the computations to update the entry.

(cherry picked from commit eaf927cf49)

* falls back on working-bank if root-bank::epoch-staked-nodes is none

bank.get_leader_schedule_epoch(shred_slot)
is one epoch after epoch_schedule.get_epoch(shred_slot).

At epoch boundaries, shred is already one epoch after the root-slot. So
we need epoch-stakes 2 epochs ahead of the root. But the root bank only
has epoch-stakes for one epoch ahead, and as a result looking up epoch
staked-nodes from the root-bank fails.

To be backward compatible with the current master code, this commit
implements a fallback on working-bank if epoch staked-nodes obtained
from the root-bank is none.

(cherry picked from commit e4be00fece)

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-26 23:45:42 +00:00
cc1a3d6645 recvmmsg IPv6 awareness (#18957) (#20232)
(cherry picked from commit 0b7ed18cfa)

Co-authored-by: Jeff Biseda <jbiseda@gmail.com>
2021-09-26 23:09:21 +00:00
e9a993fb59 allows sendmmsg api taking owned values (as well as references) (#18999) (#20226)
Current signature of api in sendmmsg requires a slice of inner
references:
https://github.com/solana-labs/solana/blob/fe1ee4980/streamer/src/sendmmsg.rs#L130-L152

That forces the call-site to convert owned values to references even
though doing so is redundant and adds an extra level of indirection:
https://github.com/solana-labs/solana/blob/fe1ee4980/core/src/repair_service.rs#L291

This commit expands the api using AsRef and Borrow traits to allow
calling the method with owned values (as well as references like
before).

(cherry picked from commit 049fb0417f)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-26 20:35:13 +00:00
88177d33fd Rpc: remove not required clone
(cherry picked from commit 9542bae56e)
2021-09-26 12:50:53 -07:00
0ec301f1c3 improves parallelism in window-service recv_window (backport #18446) (#20142)
* sends packets in batches from sigverify-stage (#18446)

sigverify-stage is breaking batches to single-item vectors before
sending them down the channel:
https://github.com/solana-labs/solana/blob/d451363dc/core/src/sigverify_stage.rs#L88-L92

Also simplifying window-service code, reducing number of nested branches.

(cherry picked from commit 7d56fa8363)

# Conflicts:
#	core/src/window_service.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-26 18:54:07 +00:00
34665571fa drop outstanding_requests lock before sending repair requests (backport #18893) (#20227)
* drop outstanding_requests lock before sending repair requests (#18893)

(cherry picked from commit 9255ae334d)

# Conflicts:
#	core/src/repair_service.rs

* removes backport merge conflicts

Co-authored-by: Jeff Biseda <jbiseda@gmail.com>
Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-26 18:39:28 +00:00
5dd1c2191e shares cluster-nodes between retransmit threads (backport #18947) (#20221)
* shares cluster-nodes between retransmit threads (#18947)

cluster_nodes and last_peer_update are not shared between retransmit
threads, as each thread have its own value:
https://github.com/solana-labs/solana/blob/65ccfed86/core/src/retransmit_stage.rs#L476-L477

Additionally, with shared references, this code:
https://github.com/solana-labs/solana/blob/0167daa11/core/src/retransmit_stage.rs#L315-L328
has a concurrency bug where the thread which does compare_and_swap,
updates cluster_nodes much later after other threads have run with
outdated cluster_nodes for a while. In particular, the write-lock there
may block.

(cherry picked from commit d06dc6c8a6)

# Conflicts:
#	core/benches/retransmit_stage.rs
#	core/src/retransmit_stage.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-26 16:29:34 +00:00
aacb5e58ad sendmmsg cleanup #18589 (#20175)
Rationalize usage of sendmmsg(2). Skip packets which failed to send and track failures.

(cherry picked from commit ae5ad5cf9b)

Co-authored-by: Jeff Biseda <jbiseda@gmail.com>
2021-09-25 23:00:00 +00:00
8d2dce6f6b allows private addresses if not public network (#20178)
(cherry picked from commit c4f2e5f88c)

# Conflicts:
#	net/net.sh

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-25 21:34:24 +00:00
e50a26a493 passes through --allow-private-addr to validators in system perf tests (backport #18876) (#20180)
* passes through --allow-private-addr to validators in system perf tests (#18876)

(cherry picked from commit 81026f9ea5)

# Conflicts:
#	multinode-demo/bootstrap-validator.sh
#	multinode-demo/validator.sh
#	net/net.sh

* removes backport merge conflicts

* ignores RUSTSEC-2021-0115

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-25 20:08:32 +00:00
302887da67 Add new logos to README files and docs (#20049) (#20093)
* Add new logos to README files and docs

* Add explorer logos

(cherry picked from commit 8dbed193c2)

Co-authored-by: Ryan M. Shea <8948187+rmshea@users.noreply.github.com>
2021-09-25 15:15:29 -04:00
597c504c27 generate deterministic seeds for shreds (backport #17950) (#20172)
* generate deterministic seeds for shreds (#17950)

* generate shred seed from leader pubkey

* clippy

* clippy

* review

* review 2

* fmt

* review

* check

* review

* cleanup

* fmt

(cherry picked from commit a86ced0bac)

# Conflicts:
#	core/benches/cluster_info.rs
#	core/src/broadcast_stage.rs
#	core/src/broadcast_stage/fail_entry_verification_broadcast_run.rs
#	core/src/broadcast_stage/standard_broadcast_run.rs
#	ledger/src/shred.rs
#	sdk/src/feature_set.rs

* removes backport merge conflicts

Co-authored-by: jbiseda <jbiseda@gmail.com>
Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-25 19:09:49 +00:00
b7af118091 Fix typo (#20218) (#20219)
(cherry picked from commit b95653331c)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-25 18:54:59 +00:00
9e392687eb chore: bump tiny-bip39 from 0.8.0 to 0.8.1 (backport #20136) (#20207)
* chore: bump tiny-bip39 from 0.8.0 to 0.8.1 (#20136)

* chore: bump tiny-bip39 from 0.8.0 to 0.8.1

Bumps [tiny-bip39](https://github.com/maciejhirsz/tiny-bip39) from 0.8.0 to 0.8.1.
- [Release notes](https://github.com/maciejhirsz/tiny-bip39/releases)
- [Changelog](https://github.com/maciejhirsz/tiny-bip39/blob/master/CHANGELOG.md)
- [Commits](https://github.com/maciejhirsz/tiny-bip39/compare/v0.8.0...v0.8.1)

---
updated-dependencies:
- dependency-name: tiny-bip39
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* [auto-commit] Update all Cargo lock files

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot-buildkite <anatoly+githubjenkins@solana.io>
(cherry picked from commit 038d77347a)

# Conflicts:
#	Cargo.lock
#	clap-utils/Cargo.toml
#	cli/Cargo.toml
#	keygen/Cargo.toml
#	sdk/Cargo.toml

* resolve conflicts

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Justin Starry <justin@solana.com>
2021-09-25 16:48:42 +00:00
bee923ca6c gossip.md: simplify Markdown (#20201) (#20205)
No need for \-escaping

(cherry picked from commit e9c839a9e7)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-25 14:01:47 +00:00
879df38059 Terminology: link BPF (#20199) (#20204)
(cherry picked from commit cb4121da19)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-25 13:50:12 +00:00
3e776267b5 Resolve zeroize_derive audit warning by bumping version (#20182) (#20190)
* Revert "temporarily disable new audit"

This reverts commit 3dfbd95ddc.

* Bump version of zeroize_derive from v1.0.0 to v1.2.0

(cherry picked from commit 0c62a6fe3f)

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-25 09:48:07 -04:00
0bfb466184 Fix blatant md formatting at the very top (#20198) (#20203)
(cherry picked from commit c137c50d15)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-25 13:43:43 +00:00
71bb3bf6aa Improve grammar in terminology/ledger (#20197) (#20202)
(cherry picked from commit 20fbf09072)

Co-authored-by: Ted Robertson <10043369+tredondo@users.noreply.github.com>
2021-09-25 13:30:39 +00:00
99c74c8902 Limit transaction forwarding from banking_stage (#19940) (#20081)
(cherry picked from commit 013e1d9d49)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-09-24 18:04:22 +00:00
085f5f945d uses tikv_jemallocator::Jemalloc as the global allocator (backport #20149) (#20166)
* uses tikv_jemallocator::Jemalloc as the global allocator (#20149)

https://github.com/solana-labs/solana/pull/16346
switched default allocator from jemalloc to system allocator, but that
has shown regressions in form of higher ram usage causing nodes go OOM:
https://discord.com/channels/428295358100013066/439194979856809985/890413193858539580

This commit sets jemalloc as the default allocator.

(cherry picked from commit 2cf081d863)

# Conflicts:
#	Cargo.lock

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-09-24 17:37:57 +00:00
e757e51ddc Port sigverify to identify and mark simple vote transaction to v1.7 (#20147)
* sigverify to identify and mark simple vote transaction (#20021)

* check vote tx at get_packet_offsets to cover both cpu and gpu paths

* add pubkey_len to PacketOffsets to reduce the redundant bytes counting

* allow vote to have 1 or 2 sigs (#20082)
2021-09-24 11:35:50 -05:00
458ccecb5d Bump bpf-tools version to 1.12
(cherry picked from commit e98a7504f2)
2021-09-24 18:05:13 +02:00
7f21a55a32 Fix public key md links (#20162) (#20167)
(cherry picked from commit 9653f6b28d)

Co-authored-by: Israel Ferrer Camacho <rallat@gmail.com>
2021-09-24 15:28:46 +00:00
b112e4a8aa windows: Make solana-test-validator work (backport #20099) (#20123)
* windows: Make solana-test-validator work (#20099)

* windows: Make solana-test-validator work

The important changes to get this going on Windows:

* ledger lock needs to be done on a file instead of the directory
* IPC service needs to use the Windows pipe naming scheme
* always disable the JIT
* file logging not possible yet because we can't redirect stderr,
but this will change once env_logger fixes the pipe output target!

* Integrate review feedback

(cherry picked from commit 567f30aa1a)

# Conflicts:
#	validator/src/bin/solana-test-validator.rs
#	validator/src/lib.rs
#	validator/src/main.rs

* Fix merge conflicts

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-09-24 12:59:12 +00:00
63b24d9577 Update TransactionError link to docs.rs (#20145) (#20146)
(cherry picked from commit a70fd8e606)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-09-23 21:15:36 +00:00
49a6acffca Add metric for duplicate retransmit (#20129) 2021-09-22 22:51:44 -07:00
7b4638aa0b runtime: remove inactive delegation from stakes cache 2021-09-22 20:43:34 -06:00
f51ee23837 Fix typo in docs/cli/deploy-a-program (#20097) (#20098)
(cherry picked from commit 3d0db28d12)

Co-authored-by: Christoph Michel <MrToph@users.noreply.github.com>
2021-09-22 01:46:58 +00:00
55f27d5c26 Fix memo handling and "blocks" key formatting (#20044) (#20080)
* Fix memo handling and "blocks" key formatting

* Skip memo equality check

* Define slot_to_tx_by_addr_key

Co-authored-by: Justin Starry <justin@solana.com>
(cherry picked from commit 795dde109c)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-09-21 22:22:55 +00:00
f33c651114 Minor ProgramTest improvements (backport #20051) (#20054)
* Add stable_log output when a program is loaded as native code instead of BPF

(cherry picked from commit 34f5020457)

* Add ProgramTest::add_builtin_program()

This permits the unit testing of builtin programs in the ProgramTest environment

(cherry picked from commit 830ca369f1)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-09-21 17:04:16 +00:00
a71ebcc9f3 demote ./run.sh (backport #19679) (#20052)
* move `./run.sh` into `./scripts`

(cherry picked from commit 92e343da26)

* add some guidance in place of `./run.sh`

(cherry picked from commit 33de7b856f)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-09-21 15:59:48 +00:00
cd575945b6 Make bigtable delete-slots actually usable (#20037) (#20042)
(cherry picked from commit 22f45dca80)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-09-21 13:40:21 +00:00
6b24dd1c6a client: Add retry logic on Pubsub 429 error during connect (backport #19990) (#20002)
* client: Add retry logic on Pubsub 429s (#19990)

(cherry picked from commit e9b066d497)

* Use exponential backoff for older version of tungstenite

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-09-20 12:13:06 +00:00
03da3eaa81 Optimize RPC pubsub for multiple clients with the same subscription (backport #18943) (#19987)
* Optimize RPC pubsub for multiple clients with the same subscription (#18943)

* reimplement rpc pubsub with a broadcast queue

* update tests for new pubsub implementation

* fix: fix review suggestions

* chore(rpc): add additional pubsub metrics

* integrate max subscriptions check into SubscriptionTracker to reduce locking

* separate subscription control from tracker

* limit memory usage of items in pubsub broadcast queue, improve error handling

* add more pubsub metrics

* add final count metrics to pubsub

* add metric for total number of subscriptions

* fix small review suggestions

* remove by_params from SubscriptionTracker and add node_progress_watchers map instead

* add subscription tracker tests

* add metrics for number of pubsub notifications as a counter

* ignore clippy lint in TokenCounter

* fix underflow in token counter

* reduce queue capacity in pubsub tests

* fix(rpc): fix test timeouts

* fix race in account subscription test

* Add RpcSubscriptions::new_for_tests

Co-authored-by: Pavel Strakhov <p.strakhov@iconic.vc>
Co-authored-by: Nikita Podoliako <n.podoliako@zubr.io>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
(cherry picked from commit 65227f44dc)

# Conflicts:
#	Cargo.lock
#	core/Cargo.toml
#	core/src/replay_stage.rs
#	core/src/validator.rs
#	replica-node/src/replica_node.rs
#	rpc/Cargo.toml

* Fix conflicts (and standardize naming to make future subscription backports easier

Co-authored-by: Pavel Strakhov <ri@idzaaus.org>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-20 06:00:08 +00:00
07b71329a7 Update feature switch for reduced required deploy balance (backport #19999) (#20012)
* Update feature switch for reduced required deploy balance (#19999)

(cherry picked from commit ea34eb8a4b)

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

* fix conflict

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-19 23:17:59 +00:00
53b387f113 Report consumed_buffered_packets_count stat to metrics (backport #19900) (#19915)
* Report consumed_buffered_packets_count stat to metrics (#19900)

(cherry picked from commit 34c1a9ac85)

# Conflicts:
#	core/src/banking_stage.rs

* fix conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-18 20:57:28 +00:00
d0143dad8f Reduce payer balance needed to deploy programs (backport #19645) (#19998)
* Reduce payer balance needed to deploy programs (#19645)

* Reduce payer balance needed to deploy programs

* Fix test and unbalanced ix error

* fix test

* fix up tests

(cherry picked from commit efd024510a)

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

* fix conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-18 04:46:42 +00:00
3e870a40f2 Fix broken links in terminology.md (#19978) (#19992)
(cherry picked from commit 073c5359b0)

Co-authored-by: visortelle <visortelle@gmail.com>
2021-09-18 00:16:32 +00:00
707302d9f2 Add delete subcommand to ledger-tool bigtable (#19931) (#19963)
* Add `delete` subcommand to `ledger-tool bigtable` command

* feedback

(cherry picked from commit c71fab6cb3)

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-17 16:26:57 -05:00
b8ab6a46a8 Fix typos in terminology.md (#19977) (#19979)
(cherry picked from commit 1ec22572f2)

Co-authored-by: visortelle <visortelle@gmail.com>
2021-09-17 16:48:55 +00:00
9ad801a52c stake: Add BorshDeserialize trait to structs (#19958) (#19976)
(cherry picked from commit 9eb98adf97)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-09-17 11:33:18 +00:00
c85816c44e rpc: performance fix for getProgramAccounts (#19941) (#19950)
* rpc: performance fix for getProgramAccounts

The accounts were gradually pushed into a vector, which produced
significant slowdowns for very large responses.

* rpc: rewrite loops using iterators

Co-authored-by: Christian Kamm <ckamm@delightful-solutions.de>
(cherry picked from commit f1bbf1d8b0)

Co-authored-by: Christian Kamm <mail@ckamm.de>
2021-09-16 23:26:21 +00:00
70d556782b Bump 1.7 version (#19943) 2021-09-16 13:16:09 -06:00
ca83167cfc Only allow votes when root distance gets too high (#19933) 2021-09-16 16:48:51 +02:00
54ad080bf2 Fix native invoke writable privileges (backport #19750) (#19860)
* Fix native invoke writable privileges (#19750)

* Fix native invoke writable privileges

* build downstream spl bpf programs for tests

(cherry picked from commit 00d7981f64)

# Conflicts:
#	program-runtime/src/instruction_processor.rs
#	runtime/src/message_processor.rs
#	sdk/src/feature_set.rs

* resolve conflictds

Co-authored-by: Jack May <jack@solana.com>
2021-09-16 01:42:26 +00:00
80e239550b Add banking metrics for buffered and dropped packets (#19902) (#19927)
(cherry picked from commit ca3f147670)

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-16 00:59:27 +00:00
992b313941 Cli: check current authorities before attempting to change them (backport #19853) (#19923)
* Cli: check current authorities before attempting to change them (#19853)

* Stake-authorize: check account current authority

* Stake-set-lockup: check account current custodian

* Make helper fn pub(crate)

* Vote-authorize: check account current authority

(cherry picked from commit 15144fc923)

# Conflicts:
#	cli/src/vote.rs

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-15 22:53:44 +00:00
97bd521725 Add logging after taking a bank snapshot (backport #19891) (#19920)
* Add logging after taking a bank snapshot (#19891)

(cherry picked from commit 8e3c420414)

* Fix conflict

Co-authored-by: Brooks Prumo <brooks@solana.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-15 14:29:33 -06:00
3ae2917603 build downstream spl bpf programs for tests (backport #19851) (#19887)
Co-authored-by: Justin Starry <justin@solana.com>
2021-09-15 12:20:00 -06:00
e51c2d1a84 Add an info log to indicate the node has reached supermajority and print the active stake percentage (#19893)
(cherry picked from commit 4ff50519ff)
2021-09-15 01:59:01 -07:00
a24b0dc81c Use f64 for stake math in get_stake_percent_in_gossip (#19895)
(cherry picked from commit c91519961c)
2021-09-15 01:58:52 -07:00
6e856cd468 Silence vercel github comments (#19827) (#19833)
(cherry picked from commit 8ac12c29ed)

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-13 17:30:05 +00:00
0dde54b95b Add --destake-vote-account <VOTE_ADDRESS>... argument to create-snapshot command (#19749) (#19796)
(cherry picked from commit 0f76077969)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-09-11 23:34:34 +00:00
1fa863e4b2 docs: be less specific about zen3 skus (#19791)
(cherry picked from commit 999ba9e026)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-09-11 05:30:30 +00:00
73e97aab5b Recover from interrupted bpf sdk installs (#19651) 2021-09-10 20:02:52 -07:00
8f082a239a Revert "fixup! test-validator: start logging asap (#19655)" (#19740) (#19745)
This reverts commit 64a2d7081b.

(cherry picked from commit 46fc92f392)

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-10 21:57:57 +00:00
7e5026bde2 removes backport merge conflicts 2021-09-09 23:33:29 -07:00
7ac0ea0885 filters for recent contact-infos when checking for live stake (#19204)
Contact-infos are saved to disk:
https://github.com/solana-labs/solana/blob/9dfeee299/gossip/src/cluster_info.rs#L1678-L1683

and restored on validator start-up:
https://github.com/solana-labs/solana/blob/9dfeee299/core/src/validator.rs#L450

Staked nodes entries will not expire until an epoch after. So when the
validator checks for online stake it is erroneously picking up
contact-infos restored from disk, which breaks the entire
wait-for-supermajority logic:
https://github.com/solana-labs/solana/blob/9dfeee299/core/src/validator.rs#L1515-L1561

This commit adds an extra check for the age of contact-info entries and
filters out old ones.

(cherry picked from commit 7a789e0763)

# Conflicts:
#	core/src/validator.rs
2021-09-09 23:33:29 -07:00
dc06d3dee5 Reduce wait for supermajority threshold back to 80%
(cherry picked from commit 4386e09710)
2021-09-09 21:45:00 -07:00
0b1aadf446 Add RpcClient::get_transport_stats()
(cherry picked from commit 21f4606212)
2021-09-09 21:17:56 -07:00
b9a0156a93 Return error if Transaction contains writable executable or ProgramData accounts (backport #19629) (#19730)
* Return error if Transaction contains writable executable or ProgramData accounts (#19629)

* Return error if Transaction locks an executable as writable

* Return error if a ProgramData account is writable but the upgradable loader isn't present

* Remove unreachable clause

* Fixup bpf tests

* Review comments

* Add new TransactionError

* Disallow writes to any upgradeable-loader account when loader not present; remove is_upgradeable_loader_present exception for all other executables

(cherry picked from commit 38bbb77989)

# Conflicts:
#	programs/bpf/tests/programs.rs
#	runtime/src/accounts.rs
#	runtime/src/bank.rs
#	sdk/src/transaction.rs
#	storage-proto/proto/transaction_by_addr.proto
#	storage-proto/src/convert.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-09 14:02:07 +00:00
f786d1d0f3 cargo-build-bpf: allow sdk path to be set by environment variables (#19509)
In many Linux distros such as NixOS, the directory in which packages are
installed is assumed to be read-only. To work around this, it is
expected that the filepaths which packaged CLI tools take in are able to
be freely configured through either 1) command-line flags, 2)
environment variables, or 3) a configuration file.

In this commit, environment variables 'BPF_SDK_PATH' and 'BPF_OUT_PATH',
which map respectively to command-line flags '--bpf-sdk-path' and
'--bpf-out-dir', are now handled in cargo-build-bpf.

Additionally, given that arbitrary filepaths may now be set in which the
BPF SDK is located, the requirement in which
'$BPF_SDK_PATH/dependencies/bpf-tools' must strictly be a symbolic link
to the directory '$HOME/.cache/solana/${bpf-tools.version}/bpf-tools has
been relaxed.

Ideally, the directory in which bpf-tools is expected to be downloaded
to and stored should be configurable. Though, this commit serves as a
temporary fix which enables NixOS users to now start being able to build
applications with the Solana SDK.

Co-authored-by: Kenta Iwasaki <kenta@lithdew.net>
2021-09-09 12:29:33 +00:00
b360c90d21 Add cargo-build-bpf integration tests (backport #18255) (#19720)
* Add cargo-build-bpf integration tests

(cherry picked from commit cf25729eaa)

* reduce version number

Co-authored-by: Dmitri Makarov <dmakarov@alumni.stanford.edu>
Co-authored-by: Justin Starry <justin@solana.com>
2021-09-08 23:31:13 +00:00
da801b753b Speed up program deploys by writing larger chunks (backport #19654) (#19680)
* Speed up program deploys by writing larger chunks (#19654)

(cherry picked from commit 24fd47a32d)

# Conflicts:
#	cli/src/program.rs

* resolve conflict

Co-authored-by: Justin Starry <justin@solana.com>
2021-09-08 21:45:30 +00:00
8f168a610e Updating Phantom description, removing invite code (#19004) (#19725)
* Updating Phantom description, removing invite code

* Updated copy

* Update web-wallets.md

(cherry picked from commit 9d2f0e237b)

Co-authored-by: Chris Kalani <chriskalani@gmail.com>
2021-09-08 21:23:37 +00:00
d7e6ab58c4 TpuClient now uses the processed slot to seed its leader schedule cache 2021-09-08 19:15:35 +00:00
a0e6a7c73b fixup! test-validator: start logging asap (backport #19655) (#19711)
* fixup! test-validator: start logging asap (#19655)

(cherry picked from commit 64a2d7081b)

# Conflicts:
#	validator/src/bin/solana-test-validator.rs

* Resolves conflicts

Co-authored-by: steviez <steven@solana.com>
2021-09-08 10:58:07 +00:00
ed4e7c0c87 Check seed length before trying to cal program address (backport #19699) (#19708)
* Check seed length before trying to cal program address (#19699)

(cherry picked from commit 778b2adbea)

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-09-08 08:26:07 +00:00
584f8deae3 cli: show upgradeable program accounts (backport #19431) (#19435)
* cli: show upgradeable program accounts (#19431)

(cherry picked from commit 57bbbb83a4)

* resolve conflicts

* nudge

Co-authored-by: Jack May <jack@solana.com>
2021-09-08 07:48:31 +00:00
e9c3f11d24 Remove native id check in pda creation (backport #19595) (#19689)
* Remove native id check in pda creation (#19595)

(cherry picked from commit 529fefc7cc)

# Conflicts:
#	programs/bpf/rust/invoke/src/lib.rs
#	programs/bpf_loader/src/syscalls.rs
#	sdk/src/feature_set.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-09-07 23:26:08 -07:00
57e87a09c0 Grammar nits (#19703) (#19706)
* Grammar nits

* add Phantom to staking docs

(cherry picked from commit 590e113f16)

Co-authored-by: Ryan M. Shea <8948187+rmshea@users.noreply.github.com>
2021-09-08 04:53:24 +00:00
a2b435916d Fix handling of stale links to bpf-tools in cargo-build-bpf (#17772) (#19667)
(cherry picked from commit 910ac94a8c)

Co-authored-by: Dmitri Makarov <dmakarov@users.noreply.github.com>
2021-09-06 22:23:40 +00:00
ad66189463 Update web-wallets.md (#19648) (#19650)
(cherry picked from commit f0be3e4ea9)

Co-authored-by: bitkeepwallet <85662627+bitkeepwallet@users.noreply.github.com>
2021-09-05 16:21:32 +00:00
9a280426da docs: fix typo (#19646) (#19647)
(cherry picked from commit f68ca3895b)

Co-authored-by: Zahin Mohammad <zahin.dev@gmail.com>
2021-09-04 18:48:36 +00:00
864006a78a docs: fix typo (#19641) (#19644)
(cherry picked from commit 497b6c152f)

Co-authored-by: Zahin Mohammad <zahin.dev@gmail.com>
2021-09-04 17:21:20 +00:00
e37e46cfc2 update Telegram link at docs (#19638) (#19639)
(cherry picked from commit 8352bc48db)

Co-authored-by: Pierre/Long <pierreneter@gmail.com>
2021-09-04 08:30:27 +00:00
376b21c6e7 Tiny dedupe 2021-09-04 01:43:23 -06:00
fcda5d4a7d Demote write locks on transaction program ids (backport #19593) (#19633)
* Demote write locks on transaction program ids (#19593)

* Add feature

* Demote write lock on program ids

* Fixup bpf tests

* Update MappedMessage::is_writable

* Comma nit

* Review comments

(cherry picked from commit decec3cd8b)

# Conflicts:
#	core/src/banking_stage.rs
#	core/src/cost_model.rs
#	core/src/cost_tracker.rs
#	ledger-tool/src/main.rs
#	program-runtime/src/instruction_processor.rs
#	programs/bpf/tests/programs.rs
#	programs/bpf_loader/src/syscalls.rs
#	rpc/src/transaction_status_service.rs
#	runtime/src/accounts.rs
#	runtime/src/bank.rs
#	runtime/src/message_processor.rs
#	sdk/benches/serialize_instructions.rs
#	sdk/program/src/message/mapped.rs
#	sdk/program/src/message/sanitized.rs
#	sdk/src/transaction/sanitized.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-04 06:46:09 +00:00
2e4a2c15be s/authorized_withdrawer_pubkey/authorized_withdrawer/
(cherry picked from commit f1ba759940)
2021-09-03 22:07:58 -07:00
a8ec380c56 Rework authorized_withdrawer usage
(cherry picked from commit fa61b90796)
2021-09-03 22:07:58 -07:00
afb87a386a Removed the --authorized-withdrawer argument from create-vote-account
The parameter is now a required third argument.  This is because authorized
withdrawer should never be the same as vote account keypair or validator
identity keypair for security reasons.

Added a --allow-unsafe-authorized-withdrawer to override this restriction if
necessary.

(cherry picked from commit e288459cf2)
2021-09-03 22:07:58 -07:00
2d060fd2d9 Add RpcClient::get_multiple_accounts_with_config()
(cherry picked from commit ae43ca3bfb)
2021-09-03 20:24:50 -07:00
c180f4c84e stake: Advance credits_observed on activation epoch (backport #19309) (#19626)
* stake: Advance `credits_observed` on activation epoch (#19309)

* stake: Advance `credits_observed` on activation epoch

* Add test for merging stakes just after activation

(cherry picked from commit 2c3bdedea3)

# Conflicts:
#	runtime/src/bank.rs

* Fix merge issues

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-09-04 01:29:00 +00:00
105a89175c Populate memo in blockstore signatures-for-address (backport #19515) (#19605)
* Populate memo in blockstore signatures-for-address (#19515)

* Add TransactionMemos column family

* Traitify extract_memos

* Write TransactionMemos in TransactionStatusService

* Populate memos from column

* Dedupe and add unit test

(cherry picked from commit 5fa3e5744c)

# Conflicts:
#	ledger/src/blockstore.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-09-03 08:51:02 +00:00
959334d2e3 docs: update spl token exchange integration (#19573) (#19578)
* docs: update spl token exchange integration

* Apply suggestions from code review

Co-authored-by: Michael Vines <mvines@gmail.com>

Co-authored-by: Michael Vines <mvines@gmail.com>
(cherry picked from commit f4f14c42bb)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-09-02 18:36:04 +00:00
aa2098d115 Write helper for multithread update (#18808) (#19282)
Co-authored-by: sakridge <sakridge@gmail.com>
2021-09-02 11:05:15 +00:00
37ee47c3e6 Add executor using the program's id during deploy (#19555) (#19572)
(cherry picked from commit 622a6fba7f)

Co-authored-by: Jack May <jack@solana.com>
2021-09-02 03:04:13 +00:00
4fb43bbd90 Fix tests that make assumptions about tx fee rate (#19538) 2021-08-31 22:02:20 -06:00
5fbcb10e6f adds logs when push-vote panics with invalid vote-index (#19485) (#19521)
In order to debug this panic on the clusters:

  panicked at 'assertion failed: (vote_index as usize) <
  MAX_LOCKOUT_HISTORY', core/src/cluster_info.rs:1012:9

(cherry picked from commit d7051b0d21)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-08-31 15:35:33 +00:00
6f86abf551 Populate memo in bigtable transaction structs (#19512) (#19514)
* Populate memo in bigtable transaction structs

* Preface memos with len

(cherry picked from commit f4ae450f34)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-08-31 05:14:25 +00:00
744a69f818 Fix shreds-to-hours/days estimations (#19477) (#19503)
(cherry picked from commit a3bef2e537)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-08-30 22:34:13 +00:00
1c6cac2054 fix typo in calling-between-programs developing documentation (#19502) (#19504)
(cherry picked from commit d11b0abf11)

Co-authored-by: Matthew Callens <callensmatt@gmail.com>
2021-08-30 20:04:39 +00:00
0c64bd0938 Improve terminology page (backport #18441) (#19165)
* Improve terminology page (#18441)

Co-authored-by: Gregg Dourgarian <greggd@aidacreative.com>
Co-authored-by: Haskell FTW <HaskellFTW@protonmail.com>
(cherry picked from commit e7190cc727)

# Conflicts:
#	docs/src/terminology.md

* Fix conflict

Co-authored-by: Haik Dulgarian <greggd@tempworks.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-30 16:48:22 +00:00
f73a61d2ec Bump version to 1.7.12 2021-08-27 16:24:24 +00:00
bdb77b0c98 Add missing owner check to bpf loader close ix (#19460) (#19470)
(cherry picked from commit 4305d4b7b1)

Co-authored-by: Justin Starry <justin@solana.com>
2021-08-27 10:19:14 -06:00
58bef3a94b Allow closing upgradeable program accounts (backport #19319) (#19411)
* Allow closing upgradeable program accounts (#19319)

(cherry picked from commit a89f180145)

# Conflicts:
#	programs/bpf_loader/src/lib.rs
#	programs/bpf_loader/src/syscalls.rs
#	sdk/src/feature_set.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
Co-authored-by: Justin Starry <justin@solana.com>
2021-08-27 08:56:51 +00:00
52dfb4a09c Bump jsonrpc crates and remove old tokio (backport #18779) (#19453)
* Bump jsonrpc crates and remove old tokio (#18779)

* Bump jsonrpc crates and replace old tokio

* Bump tokio

* getBlockTime

* getBlocks

* getBlocksWithLimit, getInflationReward

* getBlock

* getFirstAvailableBlock

* getTransaction

* getSignaturesForAddress

* getSignatureStatuses

* Remove superfluous runtime

(cherry picked from commit 8596db8f53)

# Conflicts:
#	Cargo.lock
#	client/Cargo.toml
#	core/Cargo.toml
#	programs/bpf/Cargo.lock
#	rpc/Cargo.toml
#	rpc/src/rpc.rs
#	validator/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-27 00:55:02 +00:00
c734db59cb hash calculation adds really old slots to dirty_stores (backport #19434) (#19451)
* hash calculation adds really old slots to dirty_stores (#19434)

(cherry picked from commit 98bc694606)

* fix test compile error

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-08-26 22:44:25 +00:00
3b36e8e285 Add missing description for feature switch (#19428) 2021-08-25 18:24:28 +00:00
cdbc77bf97 Add parameter to allow setting max-retries for SendTransaction rpc (backport #19387) (#19416)
* Add parameter to allow setting max-retries for SendTransaction rpc (#19387)

* Add parameter to cap rpc send retries for a tx

* Add parameter to docs

(cherry picked from commit 7482861f4b)

# Conflicts:
#	banks-server/src/banks_server.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-25 07:23:03 +00:00
8ab358ce78 Preserve pre-existing vote/stake keypairs for bootstrap validator (#19405) (#19410)
(cherry picked from commit d559426373)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-08-24 23:44:06 +00:00
5193ba2062 Document more RpcClient methods (backport #19236) (#19390)
* Document more RpcClient methods (#19236)

* Document more RpcClient methods

* Update client/src/rpc_client.rs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Update RpcClient docs per feedback

* Address review feedback

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit 628ad58912)

# Conflicts:
#	client/src/mock_sender.rs

* Fix conflicts

* Restore previous methods for docs

Co-authored-by: Brian Anderson <andersrb@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-24 15:46:56 +00:00
7e5767f926 Bump crossbeam-epoch (backport #19378) (#19389)
* Bump to get off yanked crate (#19378)

(cherry picked from commit 82ea4891fd)

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

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-24 03:10:55 +00:00
e5e6829d20 Update crossbeam-deque to 0.8.1 (#19361) (#19382)
(cherry picked from commit 2ccbe471ae)
2021-08-24 00:21:25 +00:00
3976816b79 Correct JSON-RPC docs for getSlot (#19355) (#19356)
* Correct JSON-RPC docs for getSlot

* Update docs/src/developing/clients/jsonrpc-api.md

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit 9483866e0b)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-08-21 00:55:11 +00:00
9732157f0c Only encode data with <128 bytes in base58 (#19317) (#19351)
* Only encode data with <128 bytes in bs58

* Use same MAX_BS58_BYTES const in rpc

* Fix test

* Spell out base

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

Co-authored-by: sakridge <sakridge@gmail.com>
2021-08-21 00:32:30 +00:00
ed18d6d38d Remove tar-rs audit ignore (#19344) (#19352)
(cherry picked from commit 17978c2ff4)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-08-20 22:21:04 +00:00
ef336a44a1 change untar to use unpack instead of unpack_in (backport #19216) (#19340)
* change untar to use unpack instead of unpack_in (#19216)

* change untar to use unpack instead of unpack_in

* hacky, but maybe passes tests

* chore: bump tar from 0.4.35 to 0.4.37

Bumps [tar](https://github.com/alexcrichton/tar-rs) from 0.4.35 to 0.4.37.
- [Release notes](https://github.com/alexcrichton/tar-rs/releases)
- [Commits](https://github.com/alexcrichton/tar-rs/compare/0.4.35...0.4.37)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* [auto-commit] Update all Cargo lock files

* cleanup

* cleanup, add validate_inside_dst

* collapse use

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* delete comment line

* add comments

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot-buildkite <dependabot-buildkite@noreply.solana.com>
Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit 89a31ff473)

# Conflicts:
#	Cargo.lock
#	download-utils/Cargo.toml
#	install/Cargo.toml
#	programs/bpf/Cargo.lock
#	runtime/Cargo.toml
#	sdk/cargo-build-bpf/Cargo.toml

* Fix conflicts

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-20 17:13:35 +00:00
de5f503a76 Add note about ASK keyword to paper wallet doc (#19330) (#19343)
* Add note about ASK keyword to paper wallet doc

Per https://github.com/solana-labs/solana/issues/17325#issuecomment-844434585, this change adds a note to the paper wallet docs mentioning the use of the `ASK` keyword.

Also specifes that the `solana-keygen pubkey prompt://` command returns a derived bip44 base address.

(I'm new to Solana development and this was a point of confusion for me, only resolved by finding this issue)

* Update docs/src/wallet-guide/paper-wallet.md

Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>

Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>
(cherry picked from commit 3be5715f45)

Co-authored-by: Brent Fitzgerald <burnto@gmail.com>
2021-08-20 15:20:09 +00:00
b5b1ed2a55 stake: Remove v2 program references (backport #19308) (#19336)
* stake: Remove v2 program references (#19308)

* stake: Remove v2 program references

* Remove stake v2 feature, along with stake rewrite

(cherry picked from commit 73aa004c59)

# Conflicts:
#	runtime/src/bank.rs

* Fix merge conflict

* Fix uses of old `stake` function

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-08-20 07:32:24 +00:00
caea9c99cd Minimize trust (backport #19279) (#19335)
* docs: Mainnet Beta inflation has been enabled for quite some time

(cherry picked from commit 169ded9a70)

* validator: Trusted validators are now called known validators

(cherry picked from commit e0bc5fa690)

* docs: trust minimize

(cherry picked from commit 40613161a0)

* docs: correct known validator operator

(cherry picked from commit eced50d103)

* docs: Remove decommissioned testnet archetype validator

(cherry picked from commit a587eec20b)

* docs: update devnet start args with new validators

(cherry picked from commit 2a877ae06e)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-08-20 06:24:43 +00:00
1495b94f7a discards epoch-slots epochs ahead of the current root (#19256) (#19328)
Cross cluster gossip contamination is causing cluster-slots hash map to
contain a lot of bogus values and consume too much memory:
https://github.com/solana-labs/solana/issues/17789

If a node is using the same identity key across clusters, then these
erroneous values might not be filtered out by shred-versions check,
because one of the variants of the contact-info will have matching
shred-version:
https://github.com/solana-labs/solana/issues/17789#issuecomment-896304969

The cluster-slots hash-map is bounded and trimmed at the lower end by
the current root. This commit also discards slots epochs ahead of the
root.

(cherry picked from commit 563aec0b4d)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-08-19 23:35:34 +00:00
f55bb78307 updates cluster-slots with root-bank instead of root-slot + bank-forks (backport #19058) (#19324)
* removes unused code from cluster-slots

(cherry picked from commit 2fc112edcf)

# Conflicts:
#	core/src/cluster_slots.rs

* updates cluster-slots with root-bank instead of root-slot + bank-forks

ClusterSlots::update is taking both root-slot and bank-forks only to
later lookup root-bank from bank-forks, which is redundant. Also
potentially by the time bank-forks is locked to obtain root-bank,
root-slot may have already changed and so be inconsistent with the
root-slot passed in as the argument.
https://github.com/solana-labs/solana/blob/6d95d679c/core/src/cluster_slots.rs#L32-L39
https://github.com/solana-labs/solana/blob/6d95d679c/core/src/cluster_slots.rs#L122

(cherry picked from commit 40914de811)

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-08-19 20:52:41 +00:00
fa5a71dbf0 ci: pin patched solana crates version for downstream project builds (#19322)
(cherry picked from commit b59b557163)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-08-19 15:58:24 +00:00
80a6479c47 Enable booting testnet validators without tower required (backport #19298) (#19306)
* Enable booting testnet validators without tower required (#19298)

(cherry picked from commit 7d135f185c)

# Conflicts:
#	net/net.sh

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-19 06:37:17 +00:00
a492de1bea Plumb accounts-db-skip-shrink through testnet scripts (backport #19290) (#19303)
* Plumb accounts-db-skip-shrink through testnet scripts (#19290)

(cherry picked from commit 1d375ff2da)

# Conflicts:
#	multinode-demo/bootstrap-validator.sh
#	multinode-demo/validator.sh
#	net/net.sh

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-19 01:14:06 +00:00
43b414b0df RPC: add option to exclude accounts from get_supply (backport #19270) (#19283)
* RPC: add option to exclude accounts from get_supply (#19270)

(cherry picked from commit c053df143f)

# Conflicts:
#	rpc/src/rpc.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
2021-08-18 20:22:06 +00:00
6f31882260 Fix memoverlap check (backport #19232) (#19259)
* Fix memoverlap check (#19232)

(cherry picked from commit 9be988db41)

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

* Resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-08-18 18:07:36 +00:00
5042808ecf Expose genesis block time via rpc (backport #19267) (#19277)
* Expose genesis block time via rpc (#19267)

* Expose genesis_creation_time from Bank

* Backfill genesis_creation_time for block/block-time requests of slot 0

(cherry picked from commit c167211611)

# Conflicts:
#	rpc/src/rpc.rs

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-18 00:19:59 +00:00
1c9d0521ca Revert TestValidatorGenesis::start() to v1.7.8 signature; add TestValidatorGenesis::start_with_socket_addr_space() (#19241)
(cherry picked from commit 3e5ba594e0)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-08-16 08:21:48 +00:00
ddda94e486 Add AsRef<AccountInfo> for AccountInfo (backport #19235) (#19238)
* Add AsRef<AccountInfo> for AccountInfo

(cherry picked from commit 930465e67c)

* add test for AsRef

(cherry picked from commit d10e37a829)

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
2021-08-15 16:21:04 +00:00
73ed9f56d7 Fixing missing pubsub notification for programSubscribe and logsSubscribe (backport #19092) (#19207)
* Fixing missing pubsub notification for programSubscribe and logsSubscribe (#19092)

#18587: programSubscribe is missing notifications randomly. The issue is because of two reasons

Not all rooted slots get OptimisticallyConfirmed notifications
The OptimisticallyConfirmed notifications can be out of order for slots: slot A and B with A < B can see notification for B first before A.
Summary of Changes

Changed OptimisticallyConfirmedBankTracker to send notifications for parent banks if they have not been notified yet. We use a new variable last_notified_slot to track that.

Tests:
With my validator running against testnet, before the fix, it was failing 75% of time, with the fix, it is passing consistently. Using the program mentioned in #18587.

(cherry picked from commit 1a372a792e)

* Use v1.7 api

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-12 19:17:36 +00:00
ab5d032634 Bump version to v1.7.11 2021-08-12 06:55:18 +00:00
03b930515b Handle 0-lamport account in index generation (#19041) (#19160)
* Handle 0-lamport account in index generation

* rename duplicate to dirty keys

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

Co-authored-by: sakridge <sakridge@gmail.com>
2021-08-11 09:49:19 +00:00
c9f763ea6e Use last_valid_block_height in services and client apps (backport #19163) (#19171)
* Use last_valid_block_height in services and client apps (#19163)

* Add deprecated tag to Bank::get_blockhash_last_valid_slot

* Update SendTransactionService to use last_valid_block_height

* Update solana-tokens to use last_valid_block_height

* Remove dangling file

* Update solana program to use last_valid_block_height

* Update Banks crates to use last_valid_block_height

(cherry picked from commit 5970083b4d)

# Conflicts:
#	cli/src/program.rs

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-11 09:07:53 +00:00
422044f375 Updated transaction fee burn description. (#19161) (#19164)
(cherry picked from commit 83f0915e15)

Co-authored-by: bji <bryan@ischo.com>
2021-08-10 23:17:51 +00:00
7584262f47 add validator option --accounts-db-skip-shrink (backport #19028) (#19128)
* add validator option --accounts-db-skip-shrink (#19028)

* add validator option --accounts-db-skip-shrink

* typo

(cherry picked from commit 3280ae3e9f)

# Conflicts:
#	core/tests/snapshots.rs
#	ledger/src/bank_forks_utils.rs
#	ledger/src/blockstore_processor.rs
#	replica-node/src/replica_node.rs
#	runtime/src/snapshot_utils.rs

* Fix conflicts

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-10 10:07:27 -06:00
894f121d0e Fix deserialization of RPC errors in HttpSender (#19110) (#19127)
Fixes #15576

(cherry picked from commit e4b66a5913)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-08-09 22:36:16 -07:00
4b133509d9 v1.7: Handle new security advisories (#19131)
* Update hyper 0.14

* Add audit ignores

* Bump assert_cmd and remove audit ignore

* Remove pin-project-lite warning
2021-08-09 18:22:28 -06:00
e8040a828d Clean within shrink_all_slots (#19042) (#19109)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 592013eaf4)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-08-07 06:16:43 +00:00
78086329be Add more API documentation for Rust RpcClient (#19021) (#19091)
* Add doc links to Transaction API docs

* Add more RpcClient API docs

* Reflow some rpc_client docs

* Update client/src/rpc_client.rs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Update client/src/rpc_client.rs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Update client/src/rpc_client.rs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Update sdk/src/transaction.rs

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Update RpcClient docs per review

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit b67ffab370)

Co-authored-by: Brian Anderson <andersrb@gmail.com>
2021-08-05 23:42:56 +00:00
6deeedd886 bump recommended maps/nofiles (#19059)
(cherry picked from commit d60ccf64e1)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-08-04 20:28:34 +00:00
1a0146f21d stake: Allow stakes with unmatched credits observed to merge (backport #18985) (#19055)
* stake: Allow stakes with unmatched credits observed to merge (#18985)

* stake: Allow stakes with unmatched credits observed to merge

* Address feedback

* Remove branch by doing a ceiling in one calc

(cherry picked from commit 2b33c0c165)

# Conflicts:
#	Cargo.lock
#	programs/stake/Cargo.toml
#	sdk/src/feature_set.rs

* Fix merge conflicts

* Fix clippy lint

* Add back whitespace

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-08-04 17:43:20 +00:00
7d0a9e0381 Add some docs for RpcClient and friends (backport #18748) (#19036)
* Add some docs for RpcClient and friends (#18748)

* Add some docs for RpcSender, HttpSender, MockSender

* Support SimulateTransaction in MockSender

* Add docs for RpcClient constructors

* Add some more RpcClient examples

* rustfmt

* Reflow docs in rpc_client and friends

(cherry picked from commit 5dcfd7ce74)

# Conflicts:
#	client/src/mock_sender.rs

* Fix conflicts

Co-authored-by: Brian Anderson <andersrb@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-08-03 22:18:48 +00:00
0f7b84197f Exit stable-bpf CI runs before localnet-sanity (#19016) (#19018)
(cherry picked from commit 95c2873b3c)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-08-02 19:28:55 +00:00
bb06502d24 v1.7: Fix broken test validator
Removes duplicated locking logic
2021-08-02 08:08:28 -06:00
b7f1f19d8e Bump version to v1.7.10 2021-07-31 01:19:33 -06:00
0707290bbf Fix serialization of parameters in RpcClient::get_block_production_with_config (backport #18998) (#19000)
* Fix serialization of parameters in RpcClient::get_block_production_with_config (#18998)

Params must be an array or null.

(cherry picked from commit 58f395257b)

# Conflicts:
#	client/src/mock_sender.rs

* Fix conflict

Co-authored-by: Brian Anderson <andersrb@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-31 02:00:32 +00:00
8934a3961f Add get_clock to BanksClient (#18591)
(cherry picked from commit d30a36641e)

Co-authored-by: Kirill Fomichev <fanatid@ya.ru>
2021-07-30 18:29:42 +00:00
b142ef5f8b Improve target CPU feature checks (backport #18940) (#18958)
* Improve check for Apple M1 silicon under Rosetta

(cherry picked from commit 59641623d1)

# Conflicts:
#	core/src/validator.rs

* test-validator: start logging asap

(cherry picked from commit ee65ffb3c8)

* test-validator: move feature check earlier in startup

(cherry picked from commit e641f257ef)

* validator: add avx2 runtime check

(cherry picked from commit c435f7b3e3)

* validator: start logging asap

(cherry picked from commit ed8285c096)

* validator: check target CPU features earlier

(cherry picked from commit 8ed0cd0fff)

* validator: remove disused cuda config argument

(cherry picked from commit 71f6d839f9)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-30 06:47:22 +00:00
f2dc9dd96e Fix unstable retransmit-num_nodes (#18970) (#18974)
(cherry picked from commit da480bdb5f)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-07-30 10:52:37 +09:00
20ad3005b5 allows private addresses by default in test-validator (backport #18976) (#18980)
* allows private addresses by default in test-validator (#18976)

(cherry picked from commit 1cef6fd4b4)

# Conflicts:
#	validator/src/bin/solana-test-validator.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-30 00:05:19 +00:00
eacc69efba adds validator flag to allow private ip addresses (backport #18850) (#18975)
* adds validator flag to allow private ip addresses (#18850)

(cherry picked from commit d2d5f36a3c)

# Conflicts:
#	accounts-cluster-bench/Cargo.toml
#	bench-tps/Cargo.toml
#	cli/Cargo.toml
#	core/benches/cluster_info.rs
#	core/src/banking_stage.rs
#	core/src/broadcast_stage.rs
#	core/src/broadcast_stage/broadcast_duplicates_run.rs
#	core/src/broadcast_stage/fail_entry_verification_broadcast_run.rs
#	core/src/broadcast_stage/standard_broadcast_run.rs
#	core/src/cluster_slots_service.rs
#	core/src/repair_service.rs
#	core/src/tvu.rs
#	core/src/validator.rs
#	dos/Cargo.toml
#	gossip/src/cluster_info.rs
#	gossip/src/crds_gossip_pull.rs
#	gossip/src/crds_gossip_push.rs
#	gossip/src/gossip_service.rs
#	local-cluster/Cargo.toml
#	local-cluster/src/cluster_tests.rs
#	local-cluster/tests/local_cluster.rs
#	rpc/Cargo.toml
#	rpc/src/rpc.rs
#	tokens/Cargo.toml
#	validator/Cargo.toml
#	validator/src/main.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-29 21:43:24 +00:00
3c200ae45a Tiny typo fix (#18978) (#18979)
(cherry picked from commit 46fdf8a4d2)

Co-authored-by: NearlyAlwaysThere <87867628+NearlyAlwaysThere@users.noreply.github.com>
2021-07-29 14:22:10 -06:00
74e7c7cbd0 Cli: app and wallet command reorg (backport #18955) (#18959)
* Cli: app and wallet command reorg (#18955)

* Clean up wallet commands

* Move global args

(cherry picked from commit 662ccfa558)

# Conflicts:
#	cli/src/cli.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-29 09:46:48 -06:00
6bd6d6212c Fix erroneous default start_slot (#18948) (#18952)
(cherry picked from commit 578f2aa22b)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-29 00:11:35 +00:00
4d2e66cf9c Added missing method to index and updated token account methods docs. (#18906) (#18954)
(cherry picked from commit 4d0cd9b283)

Co-authored-by: hugo <murlux@protonmail.com>
2021-07-28 22:35:55 +00:00
65fe00b7ad Auto-generate shell completions for solana-cli (issue #8879 and #14005) (#18931) (#18945)
* Auto-generate shell completions for solana-cli (issue #8879 and #14005)

Implement `completion` SubCommand for solana-cli, which outputs
completion script to stdout and exits the process. The script generation
handled completely by clap.

In order to implement the generation, one minor design change was
necessary regarding the creation of clap `App`.

Previously: One part of App initialization was in the `app` function,
and some other arguments and subcommands were added later directly in
the `main` function.

Now: The whole construction of App was moved to `get_clap_app` function.

P.S. I wasn't sure if constructing App separately had visual importance,
so both constructing parts are still separate in `base_clap_app` and
`final_clap_app` functions. But they sure could be in one single
function.

* Dereplicode match expr, fix clippy warning.

* Move clap App construction into separate module

Also join two parts of the construction into a single function

* Fix tests

* Apply rustfmt lints

(cherry picked from commit 9d0a937a05)

Co-authored-by: theonekeyg <34949189+theonekeyg@users.noreply.github.com>
2021-07-28 17:26:19 +00:00
02c509390a Add cli-output helpers (backport #18933) (#18935)
* Add cli-output helpers (#18933)

* Add OutputFormat helper to reduce copy-pasta

* Add CliSignOnlyData constructor

(cherry picked from commit 467c18e0d1)

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

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-28 15:25:56 +00:00
49b0d1792b filters crds values in parallel when responding to gossip pull-requests (backport #18877) (#18901)
* filters crds values in parallel when responding to gossip pull-requests (#18877)

When responding to gossip pull-requests, filter_crds_values takes a lot of time
while holding onto read-lock:
https://github.com/solana-labs/solana/blob/f51d64868/gossip/src/crds_gossip_pull.rs#L509-L566

This commit will filter-crds-values in parallel using rayon thread-pools.

(cherry picked from commit f1198fc6d5)

# Conflicts:
#	gossip/src/cluster_info.rs
#	gossip/src/crds_gossip_pull.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-26 21:30:24 +00:00
9511031490 v1.7: backport new column families from master (#18897)
* backport new column families from master to 1.6 (#18743)

* backporting bank_hash and program_costs column families from master to 1.6 for rocksdb backward compatibility

* missed a line to allow dead code

* include code for purge

* Exclude stubbed ProgramCosts column from compaction (#18840)

Co-authored-by: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com>
2021-07-26 13:38:47 -06:00
04ee86e93c rebase 2021-07-24 19:48:12 -07:00
82f25f982e Put is_x86_feature_detected behind a target_arch check
This change adds a target arch check so that cargo build can be run from an
Apple M1 mac.

(cherry picked from commit 7ee5b02bc5)
2021-07-24 19:48:12 -07:00
1cc32c9cda Disable reed-solomon-erasure/simd-accel feature on aarch64 (Apple M1)
This feature requires clang to support -march=native on M1. Before this change,
cargo build would output a build error when building for aarch64.

(cherry picked from commit 8a9b7f5ef2)

# Conflicts:
#	ledger/Cargo.toml
2021-07-24 19:48:12 -07:00
aedcab846c RpcClient::send<T> now supports client-defined RPC methods via RpcRequest::Custom (#18882)
(cherry picked from commit f264511585)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-07-24 19:15:51 +00:00
548ddff7ed Bump version to v1.7.9 2021-07-24 11:23:44 -06:00
7aced9e772 Sigverify refactor (#18872) 2021-07-23 22:23:57 +02:00
1cc8de0fed Bump version to v1.7.8 (#18866) 2021-07-24 01:14:03 +09:00
f08c7b2294 Rpc: getProgramAccounts, restruct base58 account data size (#18852) (#18855)
* Refactor account encoding to povide helper w/out querying Bank

* Use new method in get_program_accounts to properly return length err

(cherry picked from commit 3eecb6f4ae)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-23 05:52:53 +00:00
cc58d36de6 Really start caching by fixing swapped CAS... (#18842) (#18853)
(cherry picked from commit 611af87fdb)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-07-23 03:51:12 +00:00
128393da54 Clarify entities in docs (#18821) (#18845)
* Update docs

* Change History

(cherry picked from commit e7a687d7ee)

Co-authored-by: Ryan M. Shea <8948187+rmshea@users.noreply.github.com>
2021-07-22 20:25:38 +00:00
e7964a0b89 token: Swap new token program id for consistency on all networks (#18823) (#18837)
(cherry picked from commit d6f5945653)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-07-22 11:03:41 +00:00
77dc3746a3 docs: fix link to Native Programs page in transactions.md (#18830) (#18832)
(cherry picked from commit 71bd434297)

Co-authored-by: Stephen Peterkins <stephen@peterkins.ca>
2021-07-22 03:59:45 +00:00
e88f4d689c Fixed broken links and added more context to getTokenAccountBalance docs (#18811)
(cherry picked from commit d751d5b6e8)

Co-authored-by: murlux <murlux@protonmail.com>
2021-07-21 18:32:58 +00:00
f1858c74a4 Disambiguate archive_snapshot_package IO error sources (#18798)
(cherry picked from commit a4c3db51fc)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-21 17:17:57 +00:00
7427dafc36 feature: add new token program feature (backport #18780) (#18803)
* feature: add new token program feature (#18780)

* feature: add new token program feature

* Fixup test

* Update to spl-token v3.2.0

* Update Cargo.lock + fmt

* Update token program version in fetch-spl.sh

* Bump associated token program to 1.0.3

* Add aToken so

(cherry picked from commit 51f3b9aa7c)

# Conflicts:
#	Cargo.lock
#	account-decoder/Cargo.toml
#	accounts-cluster-bench/Cargo.toml
#	programs/bpf/Cargo.lock
#	rpc/Cargo.toml
#	sdk/src/feature_set.rs
#	tokens/Cargo.toml
#	transaction-status/Cargo.toml

* Fix merge issues

* Re-generate lock files

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-07-21 15:05:45 +00:00
1cdcabf7cf Bump BPF tools to v1.9 (#18766)
(cherry picked from commit 47861fc373)

Co-authored-by: Dmitri Makarov <dmakarov@alumni.stanford.edu>
2021-07-19 20:46:59 +00:00
ea192b3c83 prevent excess allocation with AccountsIndexIterator (#18605) (#18642)
(cherry picked from commit 0bd8710d34)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-07-19 20:15:40 +00:00
927057df26 correct typo (backport #18750) (#18751)
* correct typo

(cherry picked from commit 1507477306)

* fix another typo

(cherry picked from commit 269028360c)

Co-authored-by: Yang Li <yangli1990@live.com.au>
2021-07-18 13:52:57 +00:00
19049ca91b Bump version to v1.7.7 2021-07-17 08:42:22 +00:00
3542348c1e CI Tweaks (backport #18738) (#18742)
* ci: fix typo

(cherry picked from commit 96a7cedaca)

* ci: suppress cargo tree output

(cherry picked from commit 59cd0556ef)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-17 06:07:45 +00:00
df9061b933 excludes private ip addresses (#18740)
(cherry picked from commit e316586516)

# Conflicts:
#	core/src/broadcast_stage.rs
#	gossip/src/cluster_info.rs

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-17 04:10:43 +00:00
98658ebed5 Use rustup default profile (#18727) (#18731)
(cherry picked from commit 2ec81f627d)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-16 15:21:34 -06:00
2a93147b1b Add voting service (#18552) (#18722)
Co-authored-by: sakridge <sakridge@gmail.com>
2021-07-16 22:12:04 +02:00
4145c629c0 removes id from push_lowest_slot args (backport #18645) (#18649)
* removes id from push_lowest_slot args (#18645)

push_lowest_slot cannot sign the new crds-value unless the id (pubkey)
argument passed-in is the same pubkey as in ClusterInfo::keypair(), in
which case the id argument is redundant:
https://github.com/solana-labs/solana/blob/bb41cf346/gossip/src/cluster_info.rs#L824-L845

Additionally, the lookup is done with self.id(), but insert is done with
the id argument, which is logically a bug.

(cherry picked from commit c90af3cd63)

# Conflicts:
#	gossip/src/cluster_info.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-16 18:31:54 +00:00
551dc0a74c Bump 1.7 version (#18723) 2021-07-16 09:43:18 -06:00
85bbcdad9a Cli: Support checked stake and vote operations (#18449) (#18705)
* Refactor VoteAuthorize to use SignerIndex and support vote-authorize-*-checked

* Add checked bool const and use in command parsing

* Add create-stake-account-checked handling

* Add stake-set-lockup-checked handling

* Remove unnecessary mut

* Add stake-authorized-checked handling

(cherry picked from commit aeb30fa873)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-16 09:42:29 -06:00
336c1c1d37 nonce: Unify NonceError with SystemError 2021-07-16 04:41:51 -06:00
1570afe493 Cli configurable validators (backport #18630) (#18666)
* rpc: more params for `GetVoteAccountsConfig`

(cherry picked from commit bf90ea282a)

* cli: allow returning more `solana validators`

(cherry picked from commit a4a24b6531)

# Conflicts:
#	Cargo.lock

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-16 09:49:13 +00:00
c7c650fccc Gate libsecp256k1 update (backport #18656) (#18701)
* hijack secp256k1 enablement feature plumbing for libsecp256k1 upgrade

* bump libsecp256k1 to v0.5.0

* gate libsecp256k1 upgrade to v0.5.0

* ci: allow clippy::inconsistent_struct_constructor

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-16 07:38:45 +00:00
9b7fba69f4 Remove tour-de-sol.md link 2021-07-15 21:55:04 -07:00
0bd355c166 Remove zh tds pages 2021-07-15 21:08:35 -07:00
0d8c8d013d Remove Tour de SOL more
(cherry picked from commit c03490b24a)
2021-07-15 21:07:11 -07:00
7a57f7b8cc Remove tour-de-sol/
(cherry picked from commit 5fe0350c2e)
2021-07-15 20:17:54 -07:00
940c4731c4 Align vote-account output with stake-account output 2021-07-15 08:16:17 -07:00
4332f0ca05 Replace get_clock by get_sysvar in BanksClient 2021-07-14 18:06:27 -07:00
e0e6e20e02 Add method id to SysbarId trait (#18604)
(cherry picked from commit 5cea25ac3e)
2021-07-14 17:51:54 -07:00
0fdaa1438e Drop default_on_eof attribute from Reward struct
(cherry picked from commit 33718e5fb4)
2021-07-14 12:37:38 -07:00
8a111229f7 Cleanup secp256k1 deps (backport #18618) (#18625)
* Cleanup secp256k1 deps (#18618)

(cherry picked from commit 0d3e8ada94)

# Conflicts:
#	Cargo.lock
#	programs/bpf/Cargo.lock
#	programs/secp256k1/Cargo.toml
#	runtime/Cargo.toml

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-07-13 08:35:50 +00:00
e3eb9c195a Cli: expose last valid block height (#18620) (#18627)
* Add Fees struct to client

* Add complete RpcClient::get_fees methods

* Switch cli to last_valid_block_height

(cherry picked from commit 8ad4ffdee5)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-13 06:34:31 +00:00
8dd5ec6fbd refactor(rpc_client): const number of retries for send and confirm transaction (#18390) (#18427)
* refactor(rpc_client): simplfy send and confirm transaction flow

* chore: configurable num of retries for send and confirm

(cherry picked from commit 70234dfdf4)

Co-authored-by: hrls <viktor.kharitonovich@gmail.com>
2021-07-13 06:28:11 +00:00
e5d60bc56d Record vote account commission with voting/staking rewards and surface in RPC
(cherry picked from commit 4098af3b5b)
2021-07-12 17:07:07 -07:00
cba97d576a serial insertion of bins into accounts index (#18469) (#18617)
(cherry picked from commit f5ff4b2058)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-07-12 22:26:29 +00:00
0670213365 Unignore spl downstream build (#18218) (#18611)
(cherry picked from commit 072a7761e1)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-12 20:12:39 +00:00
ed5c11b3aa Update neon program id (backport #18607) (#18608)
* Update neon program id (#18607)

(cherry picked from commit 00f7e514b8)

* fix test

Co-authored-by: Jack May <jack@solana.com>
2021-07-12 11:18:29 -07:00
4b8c4704b0 Fix typo (#18595) (#18596)
(cherry picked from commit ab45532b52)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-12 08:02:06 +00:00
c5374095e6 storage-proto: Rework source generation (#18584)
(cherry picked from commit 899b09872b)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-11 03:33:56 +00:00
6abd5fbc3e removes redundant (mutable) self receivers (backport #18574) (#18580)
* removes redundant (mutable) self receivers (#18574)

(cherry picked from commit 918b5c28b2)

# Conflicts:
#	gossip/src/cluster_info.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-11 01:02:20 +00:00
a6a302f41f chore: bump ouroboros from 0.5.1 to 0.9.3 (#18189) (#18573)
* chore: bump ouroboros from 0.5.1 to 0.9.3

Bumps [ouroboros](https://github.com/joshua-maros/ouroboros) from 0.5.1 to 0.9.3.
- [Release notes](https://github.com/joshua-maros/ouroboros/releases)
- [Commits](https://github.com/joshua-maros/ouroboros/commits)

---
updated-dependencies:
- dependency-name: ouroboros
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* [auto-commit] Update all Cargo lock files

* Api changes

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot-buildkite <dependabot-buildkite@noreply.solana.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot-buildkite <dependabot-buildkite@noreply.solana.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-10 20:44:54 +00:00
4c764829da CI: Make BPF test suite a first-class citizen (backport #18535) (#18571)
* CI: Extricate BPF tests from stable-perf

(cherry picked from commit 1eab0773af)

* CI: Dump BPF assembly listings and upload as artifact

(cherry picked from commit f1996ca0f3)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-10 19:24:23 +00:00
9900c1ad8a adds a generic implementation of Gossip{Read,Write}Lock (#18559) (#18569)
(cherry picked from commit fd9c10c2e2)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-10 15:51:29 +00:00
3fabbab417 Add storage-proto build.rs and readme (backport #18353) (#18562)
* Add storage-proto build.rs and readme (#18353)

* Use build.rs for storage-proto generation

* Add readme

* Single use statements

(cherry picked from commit c2e7d39154)

# Conflicts:
#	Cargo.lock
#	storage-proto/build-proto/Cargo.lock
#	storage-proto/build-proto/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-09 22:21:08 +00:00
6c99c1ae13 Bump prost, prost-types, and tonic (backport #18537) (#18558)
* Bump prost, prost-types, and tonic (#18537)

* Bump prost+tonic and accommodate generated service changes

* Unignore advisory

* Fixup .proto error list

(cherry picked from commit 761de8b1a3)

# Conflicts:
#	Cargo.lock
#	storage-bigtable/Cargo.toml
#	storage-proto/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-09 19:54:29 +00:00
c2320fceab Remove sysvar special cases for rent and assign 2021-07-10 01:24:44 +09:00
8b87d86358 Bump compute budget for neon evm (#17700) (#18522)
(cherry picked from commit 2867584985)

Co-authored-by: Jack May <jack@solana.com>
2021-07-09 09:12:31 -07:00
5d0e1d62d5 removes id and shred_version from CrdsGossip (backport #18505) (#18554)
* removes id and shred_version from CrdsGossip (#18505)

ClusterInfo is the gateway to CrdsGossip function calls, and it already
has node's pubkey and shred version (full ContactInfo and Keypair in
fact).
Duplicating these data in CrdsGossip adds redundancy and possibility for
bugs should they not be consistent with ClusterInfo.

(cherry picked from commit 4e1333fbe6)

# Conflicts:
#	gossip/src/cluster_info.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-09 15:37:05 +00:00
7e613c7a78 skips process_push_message for local messages (backport #18493) (#18532)
* skips process_push_message for local messages (#18493)

received_cache is not relevant for local messages, and does not need to
be updated:
https://github.com/solana-labs/solana/blob/92c5cdab6/gossip/src/crds_gossip_push.rs#L166-L189

(cherry picked from commit 27cc7577a1)

# Conflicts:
#	gossip/src/cluster_info.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-09 13:33:40 +00:00
2a30436e45 Show grcov version as well (#18549) (#18551)
(cherry picked from commit a5b91ef4c3)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-07-09 12:41:44 +00:00
5315a89e7d Remove dead solana airdrop parameters (#18520) (#18524)
(cherry picked from commit f39ffa69f6)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-08 21:56:25 +00:00
8c328316ae Add ecrecover syscall (backport #17720) (#18500)
* Add ecrecover syscall (#17720)

Co-authored-by: Anton Lisanin <lisanin.anton@gmail.com>
(cherry picked from commit 1f288ce527)

# Conflicts:
#	Cargo.lock
#	programs/bpf/Cargo.lock
#	programs/bpf/tests/programs.rs
#	programs/bpf_loader/Cargo.toml
#	programs/bpf_loader/src/syscalls.rs
#	sdk/program/Cargo.toml

* resolve conflicts

Co-authored-by: s-medvedev <40623263+s-medvedev@users.noreply.github.com>
Co-authored-by: Jack May <jack@solana.com>
2021-07-08 21:56:19 +00:00
030a97d098 Temporarily ignore prost-types advisory (backport #18525) (#18527)
* Temporarily ignore prost-types audit (#18525)

(cherry picked from commit 6188283ba6)

* Bump tokio

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-08 13:49:33 -06:00
c40e71dc03 featurize_policy_update (#18492) (#18502)
(cherry picked from commit ccdf93e2b8)

Co-authored-by: Jack May <jack@solana.com>
2021-07-07 22:31:05 +00:00
2f633cdfb7 Refactor verify_and_update write privileges check (#18468) (#18484)
Co-authored-by: Justin Starry <justin@solana.com>
2021-07-07 21:46:07 +00:00
edd6ae588a Update verify policy (backport #18459) (#18491)
* Update verify policy (#18459)

(cherry picked from commit 44289e6728)

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-07-07 19:02:52 +00:00
2a73ba2fbb Fix cargo check (#18497) 2021-07-07 14:01:19 -05:00
5eadb86500 Fix example in docs for getInflationReward (#18494) (#18496)
(cherry picked from commit ebc7df62f3)

Co-authored-by: Max Ogden <maxogden@users.noreply.github.com>
2021-07-07 18:43:24 +00:00
c98ab6c6dc Record parent slot to reconstruct fork tree from influxdb (#18482) (#18488)
(cherry picked from commit d69f469b83)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-07-07 17:42:03 +00:00
5321463892 Refactoring: Unify account_deps and accounts (backport #17898) (#18486)
* Refactoring: Unify account_deps and accounts (#17898)

* Changes ThisInvokeContext::get_account() to use accounts instead of pre_accounts.

* Adds explicit keys to accounts to make them symmetric to account_deps.

* Appends account_deps to accounts in transaction loading and removes account_deps everywhere else.

(cherry picked from commit 7462c27d07)

# Conflicts:
#	program-test/src/lib.rs
#	runtime/src/bank.rs
#	runtime/src/message_processor.rs

* fix conflicts

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
Co-authored-by: Justin Starry <justin@solana.com>
2021-07-07 17:14:39 +00:00
d668a7694f implements an unbiased weighted shuffle using binary indexed tree (#18343) (#18485)
Current implementation of weighted_shuffle:
https://github.com/solana-labs/solana/blob/b08f8bd1b/gossip/src/weighted_shuffle.rs#L11-L37
uses a heuristic which results in biased samples.

For example, if the weights are [1, 10, 100], then the 3rd index should
come first 100 times more often than the 1st index. However,
weighted_shuffle is picking the 3rd index 200+ times more often than the
1st index, showing a disproportional bias in favor of higher weights.

This commit implements weighted shuffle using binary indexed tree to
maintain cumulative sum of weights while sampling. The resulting samples
are demonstrably unbiased and precisely proportional to the weights.

Additionally the iterator interface allows to skip computations when
not all indices are processed.

Of the use cases of weighted_shuffle, changing turbine code requires
feature-gating to keep the cluster in sync. That is not updated in
this commit, but can be done together with future updates to turbine.

(cherry picked from commit dba42c57b4)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-07 16:07:41 +00:00
9bb482e46f persists repair-peers cache across repair service loops (#18400) (#18483)
The repair-peers cache is reset each time repair service loop runs,
and so computed repeatedly for the same slots:
https://github.com/solana-labs/solana/blob/d2b07dca9/core/src/repair_service.rs#L275

This commit uses an LRU cache to persists repair-peers for each slot.
In addition to LRU eviction rules, in order to avoid re-using outdated
data, each entry also has 10 seconds TTL.

(cherry picked from commit a0551b4054)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-07 15:43:15 +00:00
c534c928a7 encapsulates turbine peers computations of broadcast & retransmit stages (#18238) (#18464)
Broadcast stage and retransmit stage should arrange nodes on turbine
broadcast tree in exactly same order. Additionally any changes to this
ordering (e.g. updating how unstaked nodes are handled) requires feature
gating to keep the cluster in sync.

Current implementation is scattered out over several public methods and
exposes too much of implementation details (e.g. usize indices into
peers vector) which makes code changes and checking for feature
activations more difficult.

This commit encapsulates turbine peer computations into a new struct,
and only exposes two public methods, get_broadcast_peer and
get_retransmit_peers, for call-sites.

(cherry picked from commit 04787be8b1)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-07-07 14:30:55 +00:00
0d0478c4a4 Add vote/stake checked instructions (backport #18345) (#18457)
* Add vote/stake checked instructions

(cherry picked from commit ee219ffa47)

* Fix set-lockup custodian index

(cherry picked from commit 544f62c92f)

* Add parsing for new stake instructions; clean up confusing test args

(cherry picked from commit 9b302ac0b5)

* Add parsing for new vote instructions

(cherry picked from commit 39bac256ab)

* Add VoteInstruction::AuthorizeChecked test

(cherry picked from commit b8ca2250fd)

* Add Stake checked tests

(cherry picked from commit 74e89a3e3e)

Co-authored-by: Michael Vines <mvines@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-07 03:17:21 +00:00
cda681a2f0 Remove obsolete stake-monitor command (backport #18020) (#18462)
* Remove obsolete stake-monitor command

(cherry picked from commit f859a39b86)

# Conflicts:
#	Cargo.lock
#	stake-monitor/Cargo.toml

* Fix conflict

Co-authored-by: Michael Vines <mvines@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-07-07 00:55:13 +00:00
72ed4f28b1 Remove feature switch for demoting sysvar write locks (#18373) (#18454)
Co-authored-by: Justin Starry <justin@solana.com>
2021-07-06 23:25:28 +00:00
6afeaac7a5 Fix transaction logs and inner ixs for leader nodes (backport #18395) (#18448)
* Fix transaction logs and inner ixs for leader nodes (#18395)

* Fix transaction logs and inner ixs for leader nodes

* Fix cpi log storage flag

(cherry picked from commit 5dd399dafa)

# Conflicts:
#	runtime/src/bank.rs

* resolve conflict

Co-authored-by: Justin Starry <justin@solana.com>
2021-07-06 23:04:19 +00:00
75a2b66206 docs: Correct integration validator cli reference (#18458)
(cherry picked from commit 77f61a5e2e)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-06 22:26:38 +00:00
5966053a6d Improve account unlock performance (#18442) (#18447)
* Improve account unlock performance

* fix clippy

(cherry picked from commit 6319e8811a)

Co-authored-by: Justin Starry <justin@solana.com>
2021-07-06 21:40:04 +00:00
e500b79858 Update terminology.md (#18430) (#18431)
* Update terminology.md

Fix duplicate "holders"

* Update docs/src/inflation/terminology.md

Co-authored-by: Michael Vines <mvines@gmail.com>
(cherry picked from commit b887e89972)

Co-authored-by: Sean Michael <seankmichael@gmail.com>
2021-07-06 03:13:50 +00:00
428c20c79f borsh: add bool type (#18429)
(cherry picked from commit e7b36c8484)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-07-05 21:48:10 +00:00
bf84bc17ea Cli: expose --with-memo to nonce and stake commands (#18404) (#18410)
* Fmt memo_arg

* Add --with-memo to nonce and stake cli commands

(cherry picked from commit 1dd730d685)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-05 01:19:17 +00:00
30fa9cbee7 sdk: add is_interactive() method Signer trait (#18407)
(cherry picked from commit 2af5ec4f57)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-03 09:09:39 +00:00
eefca613ad Rename Tower::lockouts to Tower::vote_state
(cherry picked from commit d5c2c72360)
2021-07-02 20:35:02 -07:00
f6d943aec7 SDK: Add test for illegal Pubkey::create_with_seed owners (#18402)
(cherry picked from commit 216983c50e)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-03 01:27:53 +00:00
88462e67b5 Allow a solana-validator to join a cluster established by solana-test-validator (backport #18394) (#18399)
* Report 404 instead of 502 when a snapshot file is not found

This provides the client with more useful information about why their
request failed

(cherry picked from commit 40d696fcbc)

* As a last resort try to download an uncompressed snapshot

`solana-test-validator` creates uncompressed snapshots and it can be
useful to attach another validator to a `solana-test-validator` cluster
from time to time

(cherry picked from commit e36247d187)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-07-03 00:27:42 +00:00
eb683dd402 Document order of recent blockhashes sysvar (#18379)
I wanted to use this sysvar to get a recent block hash, but I didn't
know whether the first or the last entry contains the most recent block
hash.

By calling it for mainnet, printing the results, and comparing that to
the recent blocks on solanabeach.io/blocks, I discovered that the
entries are ordered from most recent to least recent. Document this to
save future readers the trouble.

(cherry picked from commit 94ab0eb49f)

Co-authored-by: Ruud van Asseldonk <ruud@chorus.one>
2021-07-02 07:03:04 +00:00
c7d0aea5f4 Make set roots an iterator (#18357) (#18377)
(cherry picked from commit 0eca92de18)

Co-authored-by: carllin <carl@solana.com>
2021-07-02 04:44:38 +00:00
8f08953100 Added formats to notifications in WebSocket RPC client. (#18231)
(cherry picked from commit 8e7d393b70)
2021-07-01 21:14:49 -07:00
09b009abd9 Removed unused purged_slots in purge_older_root_entries (#18102)
Removed unused purged_slots in purge_older_root_entries

(cherry picked from commit ccf6b21bf8)
2021-07-01 21:13:02 -07:00
c37e481a43 test (#18159) (#18289)
(cherry picked from commit 47cafb70da)

Co-authored-by: carllin <carl@solana.com>
2021-07-02 04:12:53 +00:00
72cf55b8c3 More detailed voting timings in replay stage (#18229)
(cherry picked from commit 5d08bf9aa3)
2021-07-01 21:12:11 -07:00
6cb24ae7b6 Docs expose Transaction v2 proposal (backport #18283) (#18286)
* docs: expose TX v2 proposal

(cherry picked from commit 0972d12c1c)

* docs: A-Z sort accepted proposals

(cherry picked from commit 70d75ce4e8)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-07-02 03:07:26 +00:00
eeaf0234f0 Add proposal for transactions v2 and address map program (#17103) (#18376)
* Add proposal for supporting big transactions

* account index program

* fix formatting

* review feedback

* Add cost changes section

* Add cost section and more attack details

* fix lint

* document metadata changes

* nit

* rpc details

* add index meta struct

* add additional proposal and chagne title

* rename proposal file

* rename to address map and rewrite tx format

* no more appends, limit mapping size to 256

* update dos section

* add note about readonly

* restructure message to use enum

* cleanup

(cherry picked from commit 191519188d)

Co-authored-by: Justin Starry <justin@solana.com>
2021-07-02 02:39:44 +00:00
0200740d70 Add sdk and program READMEs (#18154)
(cherry picked from commit 94905dae52)
2021-07-01 18:25:04 -07:00
1268eef3b2 Revert "Clean up build warning"
This reverts commit 17a173ebb5.

(cherry picked from commit d269975784)
2021-07-01 18:23:23 -07:00
b433048003 report on min/max bin stats for accounts index (#18338) (#18347)
(cherry picked from commit 531f1bce78)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-07-01 23:55:43 +00:00
daf2c3c155 Consider all peers as potential candidates during pull-request in case of offline nodes (#18333) (#18372)
* Try all peers during pull-request in case of offline nodes

* fix clippy err

(cherry picked from commit f4fb5de545)

Co-authored-by: Ashwin Sekar <ashwin@solana.com>
2021-07-01 22:56:20 +00:00
03d213d764 Reject transactions with extra signatures (#18306) (#18370)
* Reject transactions with extra signatures

* fix tests

* fix check

* fix check

* tx method

* fix checks

(cherry picked from commit d5961e9d9f)

Co-authored-by: Justin Starry <justin@solana.com>
2021-07-01 20:07:43 +00:00
99f9481b5d Remove hackathon banner 2021-07-01 13:01:48 -07:00
10bd14bca6 Remove feature switch for using message hash for already processed check (#18340) (#18367)
(cherry picked from commit 5ca975383c)

Co-authored-by: Justin Starry <justin@solana.com>
2021-07-01 17:39:22 +00:00
d26533e370 Cleanup ReplayStage tests (#18241) (#18292)
(cherry picked from commit 68c87469c3)

Co-authored-by: carllin <carl@solana.com>
2021-07-01 07:47:02 +00:00
820abacf49 Update notification format info to be consistent (#18354) (#18356)
(cherry picked from commit cc80197349)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-01 06:14:03 +00:00
4466aa39c4 Bump version to v1.7.5 2021-06-30 22:55:01 -06:00
f4e43731ef solana validators output now includes average skip rate
(cherry picked from commit 52290dbd35)
2021-06-30 17:47:49 -07:00
884ef211f7 Document slotsUpdates (#18335) (#18339)
* Add slotsUpdates to jsonrpc docs

* Re-add unstable section

(cherry picked from commit dfb6296499)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-07-01 00:25:24 +00:00
896ef5a15f Fixed an issue doing the set_roots repeatedly for the same set. Instead doing the per chunks. (#18314) (#18337)
(cherry picked from commit a67d26a1e8)

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
2021-07-01 00:12:33 +00:00
4ff482cd47 Fail simulation if transaction contains duplicate accounts (#18304) (#18334)
(cherry picked from commit b08f8bd1b0)

Co-authored-by: Justin Starry <justin@solana.com>
2021-06-30 21:35:56 +00:00
6e27360fbc Add repair number per slot (#18082) (#18329)
(cherry picked from commit 8d9a6deda4)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-06-30 20:39:05 +00:00
a10a0824eb refactor untar_snapshot_in to push parallelism deeper for further refactoring (#18310) (#18312)
(cherry picked from commit ce53b84cdc)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-30 17:59:57 +00:00
2fdda2ec1b test-validator: hold rent constant with --slots-per-epoch (#18318)
(cherry picked from commit 02b14caa5f)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-06-30 08:37:54 +00:00
57f76a2111 Use timeout to allow RpcClient to retry initial transaction confirmation (#18311) (#18316)
* Tidying: relocate function

* Use proper helper method for RpcClient commitment

* Add RpcClientConfig

* Add configurable confirm_transaction_initial_timeout

* Use default 5s timeout for initial tx confirmation

(cherry picked from commit 9d4428d3d8)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-30 03:09:47 +00:00
287daa9248 debug logs when crds table trim failed (#18307) (#18309)
reports of this error being possibly spammy:
https://discord.com/channels/428295358100013066/689412830075551748/859441080054710293

The commit changes the log level to debug.
Additionally adding a new metric to understand the frequency of this error.

(cherry picked from commit 9d983a34a0)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-29 22:43:33 +00:00
7e40a051a4 bin accounts index (#18111) (#18280)
Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-29 09:14:10 -05:00
bd0a7730b6 tx-status: Don't assume a memo instruction succeeded (#18288)
(cherry picked from commit 7babf28ef7)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-06-29 03:37:44 +00:00
0d1c87e650 Cli epoch-info: generate epoch-completed time from block times (#18258) (#18285)
* Generate epoch-completed time from block times

* Add annotation when block times not available

(cherry picked from commit f2b0d562b0)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-28 17:54:20 -06:00
56cd963fd7 Ignore flaky tests (#18278) (#18282)
(cherry picked from commit 639a61d639)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-28 23:13:25 +00:00
d1b26cb267 reduce pubkey copies on insert path (#18240) (#18276)
(cherry picked from commit 1f1e54b9d8)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-28 16:31:48 -05:00
6a0a03415c Don't update if already an executable
(cherry picked from commit 2fbedd834f)
2021-06-27 12:24:00 -06:00
41d50adbf3 Only print Foundation inflation rate if it is greater than 0
(cherry picked from commit b44af11511)
2021-06-26 14:57:03 -07:00
328b52c4d6 Zelcore wallet support for SOL/SPLs info added (#17580) (#18249)
* Zelcore wallet support for SOL/SPLs info added

I have added a quick infodump about Zelcore wallet supporting various features of the Solana ecosystem. I looked at previous commits and it seemed adding to the top of the file was the norm, but please feel free to move around if needed.

* Zelcore wallet info moved to bottom of file.

(cherry picked from commit 8fc4c2f375)

Co-authored-by: trial123Zel <38964930+trial123Zel@users.noreply.github.com>
2021-06-26 17:22:55 +00:00
b7d04cf7b9 replace account index bulk insert with iterator (#18198) (#18235)
(cherry picked from commit e06376664b)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-25 17:55:42 -05:00
7ed2cf30a5 Bump borsh from 0.8.1 to 0.9.0 (#18230) 2021-06-25 14:43:04 -06:00
78fe5576a9 Added notes to running validator documentation to ensure that 'exec' is used from scripts when starting the validator to prevent logrotate signals from killing the validator. (#18234) (#18236)
(cherry picked from commit c045f1dfb5)

Co-authored-by: bji <bryan@ischo.com>
2021-06-25 20:36:41 +00:00
41179b1282 metric for accounts index insertion time (#18202) (#18226)
(cherry picked from commit f2a2581259)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-25 13:36:29 -05:00
f82d99b4c2 ci: add wrapper script for running ci locally
Linux only for now

(cherry picked from commit 0bc38153ca)
2021-06-25 10:17:17 -06:00
967f0d07f2 ci: add downstream build wrapper
(cherry picked from commit 761e324982)
2021-06-25 10:17:17 -06:00
940dbe99e9 ci: give localnet nodes a more time to startup
(cherry picked from commit 278a241db3)
2021-06-25 10:17:17 -06:00
98e1c68a70 sdk: ensure ld can find criterion when running BPF tests
(cherry picked from commit 7ee39fcb0f)
2021-06-25 10:17:17 -06:00
d8e250e9b0 ci: nvidia persistence mode isn't a hard requirement
(cherry picked from commit f213e48067)
2021-06-25 10:17:17 -06:00
c8be8510ba ci: use versioned cargo wrapper for crate ordering
(cherry picked from commit 554002b73c)
2021-06-25 10:17:17 -06:00
c99460ba15 remove unnecessary copies from accounts index code paths (#18196) (#18212)
(cherry picked from commit f9fccdee85)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-25 02:23:23 +00:00
769fcb7f50 untar in parallel (#18184) (#18210)
* untar in parallel

* make enum for 'ignore' return value

(cherry picked from commit 31ec986ea1)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-24 19:35:21 -05:00
60812790e1 rework dirty_pubkeys from insert_new_if_missing_into_primary_index (#18200) (#18208)
(cherry picked from commit 4b314be5bd)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-24 17:55:45 -05:00
a01e44f3b9 Update README.md (#18191) (#18195)
(cherry picked from commit 3362ac06b5)

Co-authored-by: Hao-Cher Hong <rax333j@gmail.com>
2021-06-24 15:47:12 +00:00
0917370bd5 Update leader-rotation.md (#18192) (#18193)
Confusing wording regarding epoch length

(cherry picked from commit 6b62ba045d)

Co-authored-by: Marcel Jackisch <jackisch@protonmail.com>
2021-06-24 14:49:22 +00:00
09b612b130 add min/max bin size metrics to hash calculation (#18155) (#18181)
(cherry picked from commit 77c3ffe4cf)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-23 20:04:15 +00:00
26fdf3fb07 Add batch stats (#18096) (#18142)
(cherry picked from commit e808f34b0b)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-06-23 12:43:37 -05:00
f41f3f6b51 apply 'debug_do_not_add_builtins' to feature activations (#18110) (#18150)
(cherry picked from commit fbc94d84c8)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-23 17:34:19 +00:00
677664e71d filters crds values obtained through gossip by their shred version (backport #18072) (#18175)
* filters crds values obtained through gossip by their shred version (#18072)

filter_by_shred_version does not check the shred-version of the owner of
the crds-value. It only checks the shred-version of the node which is
relaying the value:
https://github.com/solana-labs/solana/blob/5cc073420/gossip/src/cluster_info.rs#L2274-L2289

So crds-values with different shred versions can still pass through this
function as long as they are relayed by a node with matching shred
version; and so, a single node can bridge different shred values
through-out the cluster.

(cherry picked from commit 69a5f0e6cd)

# Conflicts:
#	gossip/src/cluster_info.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-23 17:16:33 +00:00
a8071f1039 chore(pubkey): remove dead code (#18162)
(cherry picked from commit 755b7c7aee)

Co-authored-by: hrls <viktor.kharitonovich@gmail.com>
2021-06-23 17:07:21 +00:00
bc08351a0a capture sort time in hash calculation (#18118) (#18153)
(cherry picked from commit d3ee73e151)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-23 15:49:28 +00:00
088b3893c3 Keep track of dirty stores on remove accounts to clean (#17601) (#18173)
* Keep track of dirty stores on remove accounts to clean

and not zero_lamport key set

* Only dirty when count==0?

* Add another clean

(cherry picked from commit 3b1738c000)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-06-23 10:23:44 +00:00
d9d6dd9ba6 Add metrics for rpc send-tx failures (#18156) (#18164)
(cherry picked from commit 64cff8c5a1)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-22 22:28:22 -06:00
aca66674d3 correctly calculate hash_total for hash/lamport calculation (#18144) (#18146)
(cherry picked from commit d5f9f3b7ce)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-22 21:21:10 +00:00
597429ab3e Bump version to v1.7.4 2021-06-22 19:57:34 +00:00
715360c1e7 ci: fix release build agent targeting 2021-06-22 13:36:34 -06:00
fcabaa7eff sdk: refactor pda generation 2021-06-22 11:36:05 -06:00
b14af989b8 Update sysvar docs (#18125) (#18147)
(cherry picked from commit 8a136736ad)

Co-authored-by: Jack May <jack@solana.com>
2021-06-22 17:28:15 +00:00
1a919e0c3e ci: isolate release builds (#18133)
(cherry picked from commit d43c6eafaf)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-06-22 06:14:59 +00:00
9c1a6bed7b Fix flaky optimistic violation detection cluster test (#18027) (#18126)
* Fix flaky optimistic violation detection cluster test

* Add small sleep to avoid tight loop

(cherry picked from commit 423e0d90ee)

Co-authored-by: Ashwin Sekar <ashwin@solana.com>
2021-06-22 05:07:33 +00:00
c48ec02f42 Docs val net reqs (backport #18122) (#18130)
* docs: don't suggest cloud instances for validators

(cherry picked from commit cf187dcb0b)

* docs: flesh out validator network requirements

(cherry picked from commit 93dd965947)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-06-22 02:12:49 +00:00
6f376489a5 Handle removing slots during account scans (#17471) (#17953)
(cherry picked from commit ccc013e134)

Co-authored-by: carllin <carl@solana.com>
2021-06-22 00:59:12 +00:00
0cbf7bef1e Move stake_weighted_timestamp module (#18114) (#18120)
* Move timestamp module into runtime

* Less public

* Remove unused enum

(cherry picked from commit 19fe1dd463)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-22 00:11:12 +00:00
0f87e598f6 refactor generate_index_for_slot (#17984) (#18116)
(cherry picked from commit 2087f5da94)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-21 18:25:56 -05:00
363b75619f adds shred-version to ip-echo-server response (backport #18066) (#18113)
* adds shred-version to ip-echo-server response

When starting a validator, the node initially joins gossip with
shred_verison = 0, until it adopts the entrypoint's shred-version:
https://github.com/solana-labs/solana/blob/9b182f408/validator/src/main.rs#L417

Depending on the load on the entrypoint, this adopting entrypoint
shred-version through gossip sometimes becomes very slow, and causes
several problems in gossip because we have to partially support
shred_version == 0 which is a source of leaking crds values from one
cluster to another. e.g. see
https://github.com/solana-labs/solana/pull/17899
and the other linked issues there.

In order to remove shred_version == 0 from gossip, this commit adds
shred-version to ip-echo-server response. Once the entrypoints are
updated, on validator start-up, if --expected_shred_version is not
specified we will obtain shred-version from the entrypoint using
ip-echo-server.

(cherry picked from commit 598093b5db)

# Conflicts:
#	Cargo.lock
#	net-utils/Cargo.toml
#	programs/bpf/Cargo.lock

* removes backport merge conflicts

* obtains shred-version from entrypoint's ip-echo-server in validator-main

(cherry picked from commit 58e115275a)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-21 23:04:08 +00:00
090c801cc6 eliminate flatten and sort in hash calculation (#17802) (#18115)
* eliminate flatten and sort in hash calculation

* reduce critical section time

* remove now no-longer necessary test code

* conflict with reset bins to 0 pr

(cherry picked from commit bf97627021)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-21 17:47:47 -05:00
b711778d4a More nightly clippy fixes (#18081)
(cherry picked from commit 1b7f6d2bc0)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-06-21 21:55:42 +00:00
d52569d66f user process.accounts_db_test_hash_calculation for debug_verify hash (#18053) (#18109)
(cherry picked from commit ec2f930475)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-21 16:15:13 -05:00
c676b7a473 refactor reconstruct_accountsdb_from_fields (#17987) (#18100)
(cherry picked from commit ae82e4e25b)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-21 15:14:45 -05:00
71c49bc8cd Add logging when RpcHealthStatus::Unknown (#18098) (#18107)
(cherry picked from commit faecc41603)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-21 13:53:25 -06:00
97a7f747fb remove unused code (#17981) (#18048)
(cherry picked from commit 20e714b3d0)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-21 10:12:50 -05:00
cef9e0de0c generate_index timings (#17983) (#18049)
(cherry picked from commit 1feaaf009d)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-21 10:12:27 -05:00
5637acb799 Add additional subscription metrics (#18071) (#18076)
(cherry picked from commit 83a6c669a5)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-19 04:51:40 +00:00
3d3bdcb966 Drop Error suffix from enum values to avoid the enum_variant_names clippy lint
(cherry picked from commit 4a12c715a3)
2021-06-18 19:59:20 -07:00
c9f02ae020 fix loader instruction checker (#18047) (#18074)
(cherry picked from commit d18e02ef44)

Co-authored-by: Jack May <jack@solana.com>
2021-06-18 21:28:29 +00:00
0e7512a225 Fix Nightly Clippy Warnings (backport #18065) (#18070)
* chore: cargo +nightly clippy --fix -Z unstable-options

(cherry picked from commit 6514096a67)

# Conflicts:
#	core/src/banking_stage.rs
#	core/src/cost_model.rs
#	core/src/cost_tracker.rs
#	core/src/execute_cost_table.rs
#	core/src/replay_stage.rs
#	core/src/tvu.rs
#	ledger-tool/src/main.rs
#	programs/bpf_loader/build.rs
#	rbpf-cli/src/main.rs
#	sdk/cargo-build-bpf/src/main.rs
#	sdk/cargo-test-bpf/src/main.rs
#	sdk/src/secp256k1_instruction.rs

* chore: cargo fmt

(cherry picked from commit 789f33e8db)

* Updates BPF program assert_instruction_count tests.

(cherry picked from commit c1e03f3410)

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

* Resolve conflicts

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
Co-authored-by: Michael Vines <mvines@gmail.com>
2021-06-18 20:02:48 +00:00
c330016109 adds mapping from nodes pubkeys to their shred-version (#17940) (#18067)
Crds values of nodes with different shred versions are creeping into
gossip table resulting in runtime issues as the one addressed in:
https://github.com/solana-labs/solana/pull/17899

This commit works towards enforcing more checks and filtering based on
shred version by adding necessary mapping and api to gossip table.
Once populated, pubkey->shred-version mapping persists as long as there
are any values associated with the pubkey.

(cherry picked from commit 5a99fa3790)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-18 18:02:23 +00:00
cb13cdec85 Fix build issues downstream due to stake state shuffle
(cherry picked from commit 810fce1f3d)
2021-06-18 07:13:40 -07:00
c65c580b20 introduce LockMapType for accounts_index (#18021) (#18051)
(cherry picked from commit 0a81c37fce)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-18 01:39:27 +00:00
d159ae9342 Bump version to v1.7.3 2021-06-17 15:34:50 -06:00
a540af1ca7 refactor rebuild_bank_from_snapshots (backport #17988) (#18006)
* refactor rebuild_bank_from_snapshots (#17988)

(cherry picked from commit bb7413c9f9)

# Conflicts:
#	runtime/src/snapshot_utils.rs

* merge errors

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-17 19:26:10 +00:00
e9c234d89f Make account shrink configurable #17544 (backport #17778) (#18013)
* Make account shrink configurable #17544 (#17778)

1. Added both options for measuring space usage using total accounts usage and for individual store shrink ratio using an enum. Validator CLI options: --accounts-shrink-optimize-total-space and --accounts-shrink-ratio
2. Added code for selecting candidates based on total usage in a separate function select_candidates_by_total_usage
3. Added unit tests for the new functions added
4. The default implementations is kept at 0.8 shrink ratio with --accounts-shrink-optimize-total-space set to true

Fixes #17544

(cherry picked from commit 269d995832)

# Conflicts:
#	core/tests/snapshots.rs
#	ledger/src/bank_forks_utils.rs
#	runtime/src/accounts_db.rs
#	runtime/src/snapshot_utils.rs

* fix some merge errors

Co-authored-by: Lijun Wang <83639177+lijunwangs@users.noreply.github.com>
Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-17 17:32:03 +00:00
b472dac6b3 validator: expose max active pubsub subscriptions to CLI (#18036)
(cherry picked from commit 5efc48fc69)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-06-17 08:02:20 +00:00
523dac1be3 metrics: Don't unwrap client instantiation errors (#18019)
(cherry picked from commit 5cc073420a)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-06-17 07:08:36 +00:00
962a2126b5 Log more info on runtime account verification errors (#17861) (#17879)
(cherry picked from commit a1fab0c5ca)

Co-authored-by: Jack May <jack@solana.com>
2021-06-17 01:55:37 +00:00
5c495ad1b0 ledger tool limit_load_slot_count_from_snapshot avoids assert failures (backport #17974) (#18008)
* ledger tool limit_load_slot_count_from_snapshot avoids assert failures (#17974)

(cherry picked from commit dbd4dc04b0)

# Conflicts:
#	core/tests/snapshots.rs
#	ledger/src/blockstore_processor.rs
#	runtime/benches/accounts.rs
#	runtime/src/bank.rs

* fix merge errors

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-17 01:32:50 +00:00
f633f34e43 Clean up remove_all_authorized_voters() (#18029)
(cherry picked from commit f1ebbbab8f)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-06-17 00:28:41 +00:00
bacf1b9acc accounts-cluster-bench, close all accounts in a sliding window (#17993) (#18026)
(cherry picked from commit ed18add7d3)

Co-authored-by: carllin <carl@solana.com>
2021-06-16 23:53:31 +00:00
4df9da5c48 validator: run poh speed test earlier in start up (#18024)
(cherry picked from commit 5bc6c89adc)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-06-16 23:28:15 +00:00
30bbc1350d Startup optimization in shrink - don't shrink non-shrinkable slots (backport #17405) (#17792)
* Skip shrink when it doesn't save anything (#17405)

(cherry picked from commit 14c52ab018)

# Conflicts:
#	runtime/src/accounts_db.rs

* fix merge error

Co-authored-by: sakridge <sakridge@gmail.com>
Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-16 23:28:03 +00:00
2f0f1fd5f5 break out generate index reporting (#17980) (#18015)
(cherry picked from commit 71796f4951)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 22:02:19 +00:00
c28e6ebc4c do not use index for verify_bank_hash_and_lamports (#17812) (#18010)
(cherry picked from commit adc683956f)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 21:33:30 +00:00
6479c11e9a Don't store votes unless we are leader soon (#17803) (#17894)
(cherry picked from commit 0feac57cb0)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-06-16 21:28:06 +00:00
4ed0fcdde6 avoid unnecessary empty arrays when binning (#17944) (#18011)
(cherry picked from commit eee5414c64)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 20:48:18 +00:00
296a8ade63 set hash bins to 65k (#17912) (#18009)
(cherry picked from commit 55ee3b5f2f)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 20:31:26 +00:00
a84953ccfd Improve program deployment error message (#17717) (#17725)
(cherry picked from commit 39654d3fa5)

Co-authored-by: Jack May <jack@solana.com>
2021-06-16 20:16:00 +00:00
8492031fd0 refactor generate_index process_storage_slot (#17982) (#18007)
(cherry picked from commit 7ca04d6a86)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 20:14:49 +00:00
bff7259111 parallel storage -> accounts folder (#17955) (#18004)
(cherry picked from commit 7de79425ce)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 15:51:00 +00:00
67e1814581 nit: rename measure (#17946) (#17995)
(cherry picked from commit 5ecb30ff58)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 14:51:38 +00:00
12e92dd59d verify bank hash on startup with ledger tool option (backport #17939) (#17996)
* verify bank hash on startup with ledger tool option (#17939)

(cherry picked from commit f558b9b6bf)

# Conflicts:
#	core/tests/snapshots.rs
#	ledger/src/bank_forks_utils.rs
#	runtime/src/snapshot_utils.rs

* fix merge errors

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-16 14:46:34 +00:00
4ee366edfa Properly handle block_height in Bigtable bincode deserialization (#17990) (#17994)
* Default block_height on eof

* Add comment to prevent future errors

(cherry picked from commit c57d1b44ef)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-16 05:41:38 +00:00
61573756f8 add metrics for startup (#17913) (#17975)
* add metrics for startup

    * roll timings up higher

    * fix test

    * fix duplicate

    (cherry picked from commit 471b34132e)

    # Conflicts:
    #       ledger/src/bank_forks_utils.rs
    #       runtime/src/snapshot_utils.rs
conflicts because #17778 is not present.

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-16 01:40:56 +00:00
fe5fed1182 Refactor bank_forks_utils::load() and some snapshot logic (#17492) (#17979)
Refactor a few functions that are on the load-from-snapshot path, to facilitate
adding in incremental snapshots more easily.

Additionally, add some tests and doc comments.

(cherry picked from commit 1953543274)

Co-authored-by: Brooks Prumo <brooks@solana.com>
2021-06-15 22:03:49 +00:00
0c90307677 v1.7: Stake refactor (Manual backport of #17906) (#17978)
* Refactor stake program into solana_program (#17906)

* Move stake state / instructions into solana_program

* Update account-decoder

* Update cli and runtime

* Update all other parts

* Commit Cargo.lock changes in programs/bpf

* Update cli stake instruction import

* Allow integer arithmetic

* Update ABI digest

* Bump rust mem instruction count

* Remove useless structs

* Move stake::id() -> stake::program::id()

* Re-export from solana_sdk and mark deprecated

* Address feedback

* Run cargo fmt

* Run cargo fmt post cherry-pick
2021-06-15 23:43:22 +02:00
cdd2a51f1f remove unused parameters from CalculateHashIntermediate (#17949) (#17976)
(cherry picked from commit 4d8ffdcc11)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-15 19:15:07 +00:00
0dbe3434f0 refactor so hash verify can be done by more callers (#17941) (#17947)
Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-15 16:49:32 +00:00
ef205593c5 removes port-based forwarding logic from turbine retransmit (#17716) (#17973)
Turbine retransmit logic is based on which socket it received the packet
from (i.e `packet.meta.forward`):
https://github.com/solana-labs/solana/blob/708bbcb00/core/src/retransmit_stage.rs#L467-L470

This can leave the cluster vulnerable to spoofing and selective
propagation of packets; see
https://github.com/solana-labs/solana/issues/6672
https://github.com/solana-labs/solana/pull/7774

This commit identifies if the node is on the "critical path" based on
its index in the shuffled cluster. If so, it forwards the packet to both
neighbors and children; otherwise, the packet is only forwarded to the
children.

The metrics added in
https://github.com/solana-labs/solana/pull/17351
shows that the number of times the index does not match the port is very
rare, and therefore this change should be safe.

(cherry picked from commit 161838655c)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-15 15:16:20 +00:00
8b5ba771ad name arguments to help with confusion (#17942) (#17948)
(cherry picked from commit 7fde9b6ff0)

    # Conflicts:
    #       runtime/src/accounts_db.rs

Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-15 14:46:07 +00:00
991f99b239 Bump spl-token to v3.1.1 (backport #17951) (#17958)
* Bump spl-token to v3.1.1 (#17951)

(cherry picked from commit b7de369992)

# Conflicts:
#	Cargo.lock
#	account-decoder/Cargo.toml
#	accounts-cluster-bench/Cargo.toml
#	programs/bpf/Cargo.lock
#	rpc/Cargo.toml
#	tokens/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-06-15 08:29:54 +00:00
d6f17517cb calculate_capitalization uses hash calculation (#17443) (#17932)
* calculate_capitalization uses hash calculation

* feedback

* remove debugging code, clean up slot math

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-15 05:03:06 +00:00
15b2f280e3 use trait to simplify and consolidate cumulative code (#17852) (#17931)
(cherry picked from commit 2dc6969858)

    # Conflicts:
    #       runtime/src/accounts_hash.rs

Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-15 04:29:13 +00:00
60b43a1ddf Pass iterator for SortedStorages::new_with_slots (#17811) (#17847)
Co-authored-by: Carl Lin <carl@solana.com>
(cherry picked from commit 2a9b127029)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-15 00:01:53 +00:00
d6b83e3b0a add metrics to handle_snapshot_requests (#17937) (#17945)
(cherry picked from commit e6bbd4b3f0)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-14 22:56:14 +00:00
0446f89d22 binary search in slices for hashing (#17755) (#17804)
(cherry picked from commit 817d48be21)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-14 17:32:05 -05:00
54bc3e606e Fix typo in docs (#17920) (#17938)
(cherry picked from commit 3657469826)

Co-authored-by: Sarat Limawongpranee <innneang@users.noreply.github.com>
2021-06-14 12:04:02 -06:00
fed90cfbe8 Fix accounts index panic in purge_exact (#17757) (#17935)
(cherry picked from commit c2191d885d)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-06-14 17:41:59 +00:00
e2e41a29eb Don't use pinned memory when unnecessary (#17832) (#17934)
Reports of excessive GPU memory usage and errors
from cudaHostRegister. There are some cases where pinning is
not required.

(cherry picked from commit eeee75c5be)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-06-14 16:30:51 +00:00
3b813db42f minor fixes to punctuation and typos (#17881) (#17923)
* fix minor typos and punctuation

* fix minor typos and punctuation

* rewording for clarity and typo corrections

* rewording for clarity and typo corrections

* rewording for clarity and typo corrections

Co-authored-by: Gregg Dourgarian <greggd@aidacreative.com>
(cherry picked from commit 54155f875a)

Co-authored-by: Haik Dulgarian <greggd@tempworks.com>
2021-06-14 06:56:39 +00:00
16b1a4d003 short cuts expiration check if origin's contact-info is still valid (#17918) (#17921)
Crds::find_old_labels can skip checking values timestamps if the
origin's contact info hasn't expired yet:
https://github.com/solana-labs/solana/blob/985280ec0/gossip/src/crds.rs#L394-L408

(cherry picked from commit cca46308bc)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-13 21:12:24 +00:00
b51ea3ca0c excludes epoch-slots from nodes with unknown or different shred version (#17899) (#17916)
Inspecting TDS gossip table shows that crds values of nodes with
different shred-versions are creeping in. Their epoch-slots are
accumulated in ClusterSlots causing bogus slots very far from current
root which are not purged and so cause ClusterSlots keep consuming more
memory:
https://github.com/solana-labs/solana/issues/17789
https://github.com/solana-labs/solana/issues/14366#issuecomment-769896036
https://github.com/solana-labs/solana/issues/14366#issuecomment-832754654

This commit updates ClusterInfo::get_epoch_slots, and discards entries
from nodes with unknown or different shred-version.

Follow up commits will patch gossip not to waste bandwidth and memory
over crds values of nodes with different shred-version.

(cherry picked from commit 985280ec0b)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-13 15:56:05 +00:00
dc76675644 Don't require non-existent param for keygen new (#17896) (#17897)
(cherry picked from commit 22c356d24c)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-11 22:08:46 +00:00
274a238a00 Port unconfirmed duplicate tracking logic from ProgressMap to ForkChoice (#17779) (#17889)
(cherry picked from commit c8535be0e1)

Co-authored-by: carllin <carl@solana.com>
2021-06-11 11:41:59 +00:00
10507f0ade Account for duplicate before a bank is frozen or replayed (#17866) (#17883)
(cherry picked from commit afafa624a3)

Co-authored-by: carllin <carl@solana.com>
2021-06-11 07:06:42 +00:00
af2a6106da Check for undefined symbols in .so and warn about run-time errors (#17850) (#17880)
(cherry picked from commit c684e2bdc0)

Co-authored-by: Dmitri Makarov <dmakarov@users.noreply.github.com>
2021-06-11 00:03:17 +00:00
120a7e433f Warn about InstructionError meta (#17864) (#17878)
(cherry picked from commit fa6bdd2d12)

Co-authored-by: Jack May <jack@solana.com>
2021-06-10 23:49:03 +00:00
98e34f07df programs/config: Disallow duplicate signers 2021-06-10 06:54:18 +00:00
738df79394 Add local cluster tests that broadcast duplicate slots (#13995) (#17863)
* Add duplicate node local cluster test

* fix clippy

* remove dupe test

(cherry picked from commit 050bb5446d)

Co-authored-by: Justin Starry <justin@solana.com>
2021-06-10 03:17:44 +00:00
98e9b6e70b refactor: create type (#17818) (#17848)
(cherry picked from commit 576e3d95f7)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-09 08:38:04 +00:00
c9318f8dc2 Wrap long lines (#17842)
(cherry picked from commit e5e7390d44)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-06-09 08:10:34 +00:00
78f3606e30 test: simple CalculateHashIntermediate refactoring (#17813) (#17846)
(cherry picked from commit 01ef2a5c4a)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-08 21:47:40 +00:00
97f4d098e1 Add more info about how to safely change the identity of a staked validator (#17843)
(cherry picked from commit 193813d49a)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-06-08 19:25:41 +00:00
144a13b096 Update a dangling devnet endpoint doc (#17836) (#17839)
(cherry picked from commit 2dfb5b7579)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-08 16:20:43 +00:00
af0869c66c add min to roots_tracker (#17806) (#17835)
(cherry picked from commit 58fe1d0764)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-08 16:14:59 +00:00
48e565038a Bump version to v1.7.2 (#17831) 2021-06-08 10:29:39 +00:00
cd6e1d921c update dependence version for gag to latest support windows (#17801) (#17825)
* update dependence version for gag to leatest support windows

* fix compile on windows

* add Cargo.lock

(cherry picked from commit e0ab5ee4f8)

Co-authored-by: Govlzkoy <gotope@users.noreply.github.com>
2021-06-08 07:48:39 +00:00
fb767f4612 Remove budget program (backport #17816) (#17822)
* Remove budget program (#17816)

(cherry picked from commit a66566e75b)

# Conflicts:
#	Cargo.lock
#	genesis/Cargo.toml
#	ledger/Cargo.toml
#	perf/Cargo.toml
#	programs/budget/Cargo.toml

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-06-08 03:07:26 +00:00
9f35db28e5 Switch EpochSlots to be frozen slots, not completed slots (#17168) (#17776)
(cherry picked from commit 96ba2edfeb)

Co-authored-by: carllin <carl@solana.com>
2021-06-07 22:51:30 +00:00
ab19543dff break out hash time in metric (#17721) (#17753)
(cherry picked from commit 00ee84af37)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-07 22:19:52 +00:00
3d5f333a3b parallelizes gossip packets receiver with processing of requests (#17647) (#17807)
Gossip packet processing is composed of two stages:
  * The first is consuming packets from the socket, deserializing,
    sanitizing and verifying them:
    https://github.com/solana-labs/solana/blob/7f0349b29/gossip/src/cluster_info.rs#L2510-L2521
  * The second is actually processing the requests/messages:
    https://github.com/solana-labs/solana/blob/7f0349b29/gossip/src/cluster_info.rs#L2585-L2605

The former does not acquire any locks and so can be parallelized with
the later, allowing better pipelineing properties and smaller latency in
responding to gossip requests or propagating messages.

(cherry picked from commit cab30e2356)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-07 20:30:31 +00:00
d06ca605cf Bump jsonrpc crates (backport #17797) (#17805)
* Bump jsonrpc crates (#17797)

* Bump jsonrpc crates

* Update error text

* gitignore for rpc

(cherry picked from commit 2e998ed11d)

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

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-06-07 20:15:23 +00:00
334e11e4b9 rework hash calculation to not keep slot and write version (#17685) (#17794)
* rework hash calculation to not keep slot and write version

* refactor functions and add tests

* always use multiple slot code path

(cherry picked from commit b5bb91b50f)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-07 15:31:18 +00:00
fd68b4e7a8 Support out of band dumping of unrooted slots in AccountsDb (#17269) (#17777)
* Accounts dumping logic

* Add test for interaction between cache flush and remove_unrooted_slot()

* Update comments

* Rename

* renaming

* Add more comments

* Renaming

* Fixup test and bad check

(cherry picked from commit bbcdf073ba)

Co-authored-by: carllin <carl@solana.com>
2021-06-07 09:37:55 +00:00
e5ea16fad8 system-program: Remove zero lamport check on transfers (#17726) (#17764)
* system-program: Move lamports == 0 check on transfers

* Address feedback

* Update stake split to explicitly allocate + assign

* Update stake tests referring to split instruction

* Revert whitespace

* Update split instruction index in test

* Remove unnecessary `assign_with_seed` from `split_with_seed`

* Fix stake instruction parser

* Update test to allow splitting into account with lamports

(cherry picked from commit 8f5e773caf)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-06-06 18:27:29 +00:00
6d5a4b5cce Document ProgramTest::new and fix ProgramTest::add_program (#17754) (#17768)
* document ProgramTest::new

* simplify ProgramTest::new doc-string

* make ProgramTest::add_program noisier

`add_program` (and `new`, implicitly) now prints a warning when the user
supplies a bogus program name to a ProgramTest and invokes `test-bpf`.

Additionally, it is now impossible to ask for a regular `test` and for
the generated ProgramTest to load BPF code instead of native code.
Previously, this was caused by a precedence issue: BPF code would always
be preferred over native if the program name was valid, regardless of
user choice.

(cherry picked from commit 2aaf55795f)

Co-authored-by: xuoe <alex@psi.io>
2021-06-06 07:03:13 +00:00
ffb6b5a23b add data point for cap mismatch (#17746) (#17751)
(cherry picked from commit f6fb8906c7)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-04 20:39:46 +00:00
e247625025 Create solana-poh and move remaining rpc modules to solana-rpc (backport #17698) (#17745)
* Create solana-poh and move remaining rpc modules to solana-rpc (#17698)

* Create solana-poh crate

* Move BigTableUploadService to solana-ledger

* Add solana-rpc to workspace

* Move dependencies to solana-rpc

* Move remaining rpc modules to solana-rpc

* Single use statement solana-poh

* Single use statement solana-rpc

(cherry picked from commit 544b3c0d17)

# Conflicts:
#	Cargo.lock
#	banking-bench/Cargo.toml
#	core/Cargo.toml
#	core/benches/banking_stage.rs
#	local-cluster/Cargo.toml
#	rpc/Cargo.toml
#	stake-monitor/Cargo.toml
#	validator/Cargo.toml

* Fix conflicts & versions

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-06-04 18:19:08 +00:00
67c07aa5d3 increase bin count for hash scan (#17562) (#17747)
(cherry picked from commit 5197454fea)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-04 18:12:48 +00:00
0de1ce0c2c adds fallback logic if retransmit multicast fails (#17714) (#17742)
In retransmit-stage, based on the packet.meta.seed and resulting
children/neighbors, each packet is sent to a different set of peers:
https://github.com/solana-labs/solana/blob/708bbcb00/core/src/retransmit_stage.rs#L421-L457

However, current code errors out as soon as a multicast call fails,
which will skip all the remaining packets:
https://github.com/solana-labs/solana/blob/708bbcb00/core/src/retransmit_stage.rs#L467-L470

This can exacerbate packets loss in turbine.

This commit:
  * keeps iterating over retransmit packets for loop even if some
    intermediate sends fail.
  * adds a fallback to UdpSocket::send_to if multicast fails.

Recent discord chat:
https://discord.com/channels/428295358100013066/689412830075551748/849530845052403733

(cherry picked from commit be957f25c9)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-04 16:20:44 +00:00
59f4fba05c simplify test construction (#17686) (#17693)
(cherry picked from commit 83ceedc091)

# Conflicts:
#	runtime/src/accounts_db.rs

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-04 15:57:11 +00:00
c0c764377c excludes caller's crds values from pull responses (#17542) (#17744)
If the crds entry belongs to the caller itself, then the caller will
always have the more recent version of it, regardless of it being
filtered out by the bloom filter or not.

The exception is node-instance types which are meant to detect duplicate
running instances, and those are exempted.

(cherry picked from commit 7cf6e66ddd)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-04 15:54:00 +00:00
c9bc059637 writes epoch-slots to crds table synchronously (#17719) (#17743)
epoch-slots may be overwritten before they are written to crds table:
https://github.com/solana-labs/solana/issues/17711

This commit writes new epoch-slots to crds table synchronously with
push_epoch_slots. The functions is still not thread-safe as commented in
the code, however currently only one threads is invoking this code.

(cherry picked from commit 60b0a13444)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-06-04 15:34:39 +00:00
78147d48e4 use slots returned from get_snapshot_storages to sort (#17638) (#17695)
* use slots returned from get_snapshot_storages to sort

    * add tests

    (cherry picked from commit 9388aaca15)

    # Conflicts:
    #       runtime/src/accounts_db.rs
    #       runtime/src/sorted_storages.rs

Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-04 10:14:37 -05:00
5e7db52087 Avoid full-range compactions with periodic filtered b.g. ones (backport #16697) (#17741)
* Avoid full-range compactions with periodic filtered b.g. ones (#16697)

* Update rocksdb to v0.16.0

* Promote the infrequent and important log to info!

* Force background compaction by ttl without manual compaction

* Fix test

* Support no compaction mode in test_ledger_cleanup_compaction

* Fix comment

* Make compaction_interval customizable

* Avoid major compaction with periodic filtering...

* Adress lazy_static, special cfs and range check

* Clean up a bit and add comment

* Add comment

* More comments...

* Config code cleanup

* Add comment

* Use .conflicts_with()

* Nullify unneeded delete_range ops for special CFs

* Some clean ups

* Clarify the locking intention

* Ensure special CFs' consistency with PurgeType::CompactionFilter

* Fix comment

* Fix bad copy paste

* Fix various types...

* Don't use tuples

* Add a unit test for compaction_filter

* Fix typo...

* Remove flag and just use new behavior always

* Fix wrong condition negation...

* Doc. about no set_last_purged_slot in purge_slots

* Write a test and fix off-by-one bug....

* Apply suggestions from code review

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>

* Follow up to github review suggestions

* Fix line-wrapping

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
(cherry picked from commit 1f97b2365f)

# Conflicts:
#	ledger/src/blockstore_db.rs

* Fix conflict

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-06-04 14:38:02 +00:00
ae42413d57 support bin divisions up to 65536 (#17563) (#17692)
* support bin divisions up to 65536

* add tests

(cherry picked from commit db8811eacd)

# Conflicts:
#	runtime/src/accounts_db.rs

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-04 06:33:00 +00:00
d433bd3d84 remove slot lookup (#17691) (#17694)
(cherry picked from commit 4bd32d891f)

    # Conflicts:
    #       runtime/src/accounts_db.rs

Co-authored-by: Jeff Washington (jwash) <wash678@gmail.com>
2021-06-04 06:09:46 +00:00
58dd6dc227 add info for vm.max_map_count incorrectly set. (#17727) (#17730)
(cherry picked from commit 81bafd9daf)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-04 05:02:13 +00:00
893df9b277 Rename ValidatorExit and move to sdk (#17728) (#17729)
(cherry picked from commit 3a647c4bea)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-04 04:38:49 +00:00
17dc13760b sort storages by slot before scan (#17411) (#17724)
* sort storages by slot before scan

* fix return value

(cherry picked from commit ef5169ff24)

# Conflicts:
#	runtime/src/accounts_db.rs

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-04 03:21:20 +00:00
498bf911eb Add missing ProgramError to InstructionError mappings (#16231) (#17723)
* Add missing ProgramError to InstructionError mappings

* add note

* Clarify process of adding new program error

(cherry picked from commit 83b9a046d1)

Co-authored-by: Jack May <jack@solana.com>
2021-06-04 00:25:25 +00:00
96de58b3a4 reduce copy (#17672) (#17688)
(cherry picked from commit d802eb303c)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-03 22:26:31 +00:00
9b61fa24c7 rework test for flexibility (#17592) (#17681)
* rework test for flexibility

* respond to pr feedback

(cherry picked from commit 886898eabf)

# Conflicts:
#	runtime/src/accounts_db.rs

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-03 21:25:58 +00:00
e9be3cf6bc implement ancestors as rolling bit field (#17482) (#17673)
(cherry picked from commit eec996ba41)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-03 18:47:37 +00:00
ea44a71914 parallel get_snapshot_storages (#17589) (#17679)
(cherry picked from commit 738cc9549f)

# Conflicts:
#	runtime/src/accounts_db.rs
#	runtime/src/bank.rs
#	runtime/src/serde_snapshot/tests.rs

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-03 18:32:04 +00:00
a00fbbf5ca add metric for collecting storages (#17527) (#17675)
(cherry picked from commit 72bb271a94)

# Conflicts:
#	runtime/src/accounts_db.rs
#	runtime/src/snapshot_utils.rs

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-03 05:34:32 +00:00
eb1a04af65 refactor SnapshotStorage helpers to prepare for later changes (#17560) (#17678)
(cherry picked from commit 654918ab27)

# Conflicts:
#	runtime/src/accounts_db.rs

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-03 05:24:11 +00:00
d1fbf77f3f RollingBitField: bug fixes and add tests (#17525) (#17674)
* RollingBitField: bug fixes and add tests

* respond to feedback

(cherry picked from commit 8924fbf6a0)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-03 05:07:02 +00:00
04fbf73a29 remove antiquated assert (#17643) (#17689)
(cherry picked from commit 07bac27ac7)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-02 21:53:33 +00:00
db70eb3160 minor test code cleanup (#17645) (#17680)
(cherry picked from commit 107af52deb)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-02 20:14:23 +00:00
cd974c26b6 add check_hash to non-index hash calculation (#17558) (#17676)
(cherry picked from commit 55c22d3b76)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-02 20:00:50 +00:00
53e0f5d61c remove unnecessary clone (#17559) (#17677)
(cherry picked from commit 1d02dba06f)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-06-02 19:59:55 +00:00
e864bf4898 Fix CPI recursion depth (#17659) (#17670)
* Fix CPI recursion depth

(cherry picked from commit 80e5b24b38)

Co-authored-by: Jack May <jack@solana.com>
2021-06-02 11:06:50 +00:00
81d12b7644 Fix test instruction count (#17655) (#17660)
(cherry picked from commit 4e0db50e4e)

Co-authored-by: Jack May <jack@solana.com>
2021-06-02 09:20:11 +00:00
309fcd6270 Fix test instruction count (#17655) (#17660)
(cherry picked from commit 4e0db50e4e)

Co-authored-by: Jack May <jack@solana.com>
2021-06-02 08:51:45 +00:00
938112e449 fix getBlock API reference (#17661) (#17662)
(cherry picked from commit 10c6e771b5)

Co-authored-by: oncecsc <74547046+oncecsc@users.noreply.github.com>
2021-06-02 07:32:15 +00:00
3e012ea69e Cli: Decode known program custom errors returned from simulation (#17652) (#17658)
(cherry picked from commit b7f98ea18a)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-06-02 07:03:46 +00:00
975c942ea7 Bump version to v1.7.1 2021-06-02 05:21:14 +00:00
2798271da0 Add memory operation syscalls (backport #16447) (#17648)
* Add memory operation syscalls (#16447)

(cherry picked from commit 2b50529265)

# Conflicts:
#	programs/bpf/Cargo.lock

* Resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
2021-06-01 18:43:50 -07:00
dc258cebab Add create-stake command to solana-tokens CLI (#17550) (#17649)
* Add create-stake command to solana-tokens CLI

* Add --unlocked-sol arg

Thanks @CriesofCarrots!

(cherry picked from commit 1b7f8777d6)

Co-authored-by: Greg Fitzgerald <greg@solana.com>
2021-06-02 01:16:48 +00:00
4b8c5194c7 Purge expired BlockHeight data from blockstore (backport #17634) (#17641)
* Purge expired BlockHeight data from blockstore (#17634)

* Purge expired BlockHeight data from blockstore

* Also call compact_storage and add comment....

(cherry picked from commit 96cdbfdcc0)

# Conflicts:
#	ledger/src/blockstore_db.rs

* Fix conflict

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-06-02 01:04:11 +00:00
3c7c6dacfb Add BPF rustc option to reduce the optimizations to safer level (#17590) (#17594)
(cherry picked from commit 831e87c65d)

Co-authored-by: Dmitri Makarov <dmakarov@users.noreply.github.com>
2021-05-31 19:15:56 +00:00
e36337a764 Make the sys-tuner oneliner actually copy-pastable (#17615) (#17619)
* Make the sys-tuner oneliner actually copy-pastable

* Use `command -v`

(cherry picked from commit 41975016b9)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-05-31 18:13:47 +00:00
a49856b898 Rework #17486 (backport #17566) (#17597)
* Revert "Improve missing default signer error messaging (#17486)"

This reverts commit 6d40d0d141.

(cherry picked from commit ca8c1c6c42)

* Improve missing default filepath signer error messaging

(cherry picked from commit 06a926f2f4)

* CI: temporarily skip spl downstream build

(cherry picked from commit d01b4f80f9)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-05-31 17:28:06 +00:00
8ca2f52041 Make initialize public (#17605) (#17607)
(cherry picked from commit 2896fc3987)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-05-31 08:51:05 +00:00
2f7f243022 Always bail if program modifies a ro account (backport #17569) (#17584)
* Always bail if program modifies a ro account (#17569)

(cherry picked from commit a3240aebde)

* resolve conflicts

* nudge

Co-authored-by: Jack May <jack@solana.com>
2021-05-28 20:34:10 +00:00
7e443770d7 test-validator: add an arg to control faucet genesis balance (#17582)
(cherry picked from commit 974a96738a)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-05-28 17:50:44 +00:00
8ec09884b8 Revert bpf-tools to version 1.8 because of a codegen bug suspicion (#17568) (#17577)
(cherry picked from commit 2316ddb90a)

Co-authored-by: Dmitri Makarov <dmakarov@users.noreply.github.com>
2021-05-28 11:10:14 +00:00
88c7e636d6 Bump console from 0.11.3 to 0.14.1 (#16301) (#17552)
* Bump console from 0.11.3 to 0.14.1

Bumps [console](https://github.com/mitsuhiko/console) from 0.11.3 to 0.14.1.
- [Release notes](https://github.com/mitsuhiko/console/releases)
- [Changelog](https://github.com/mitsuhiko/console/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mitsuhiko/console/compare/0.11.3...0.14.1)

Signed-off-by: dependabot[bot] <support@github.com>

* Update all Cargo lock files

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
(cherry picked from commit ec1a307a7c)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-27 21:30:17 +00:00
add3fd479d chore: bump chrono-humanize from 0.1.1 to 0.2.1 (#16895) (#17549)
* chore: bump chrono-humanize from 0.1.1 to 0.2.1

Bumps [chrono-humanize](https://gitlab.com/imp/chrono-humanize-rs) from 0.1.1 to 0.2.1.
- [Release notes](https://gitlab.com/imp/chrono-humanize-rs/tags)
- [Commits](https://gitlab.com/imp/chrono-humanize-rs/compare/0.1.1...0.2.1)

Signed-off-by: dependabot[bot] <support@github.com>

* [auto-commit] Update all Cargo lock files

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot-buildkite <anatoly+githubjenkins@solana.io>
(cherry picked from commit 4f74c77146)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-27 20:37:42 +00:00
70410536b9 Bump serde_bytes from 0.11.4 to 0.11.5 (#16299) (#17546)
* Bump serde_bytes from 0.11.4 to 0.11.5

Bumps [serde_bytes](https://github.com/serde-rs/bytes) from 0.11.4 to 0.11.5.
- [Release notes](https://github.com/serde-rs/bytes/releases)
- [Commits](https://github.com/serde-rs/bytes/compare/0.11.4...0.11.5)

Signed-off-by: dependabot[bot] <support@github.com>

* [auto-commit] Update all Cargo lock files

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: dependabot-buildkite <dependabot-buildkite@noreply.solana.com>
(cherry picked from commit 6e2ae68643)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-27 20:04:59 +00:00
6f3f9b485c Allow configuring testnet slots-per-epoch (#17545) (#17551)
(cherry picked from commit cb1fb28247)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-05-27 19:46:49 +00:00
bd9ce3590d Remove redundant copy from RocksDB get_cf() wrapper (#17529) (#17543)
(cherry picked from commit 983828a2a9)

Co-authored-by: steviez <steven@solana.com>
2021-05-27 18:58:47 +00:00
774 changed files with 57207 additions and 25459 deletions

View File

@ -38,6 +38,7 @@ jobs:
- readlink -f .
script:
- source ci/env.sh
- rustup set profile default
- ci/publish-tarball.sh
deploy:
- provider: s3
@ -60,6 +61,12 @@ jobs:
- <<: *release-artifacts
name: "Windows release artifacts"
os: windows
install:
- choco install openssl
- export OPENSSL_DIR="C:\Program Files\OpenSSL-Win64"
- source ci/rust-version.sh
- PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"
- readlink -f .
# Linux release artifacts are still built by ci/buildkite-secondary.yml
#- <<: *release-artifacts
# name: "Linux release artifacts"
@ -116,7 +123,7 @@ jobs:
if: type IN (push, pull_request) OR tag IS present
language: node_js
node_js:
- "node"
- "lts/*"
services:
- docker

2548
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,8 @@
[workspace]
members = [
"accountsdb-plugin-interface",
"accountsdb-plugin-manager",
"accountsdb-plugin-postgres",
"accounts-cluster-bench",
"bench-exchange",
"bench-streamer",
@ -39,19 +42,19 @@ members = [
"metrics",
"net-shaper",
"notifier",
"poh",
"poh-bench",
"program-test",
"programs/secp256k1",
"programs/bpf_loader",
"programs/budget",
"programs/compute-budget",
"programs/config",
"programs/exchange",
"programs/failure",
"programs/noop",
"programs/ownable",
"programs/ed25519",
"programs/secp256k1",
"programs/stake",
"programs/vote",
"remote-wallet",
"rpc",
"runtime",
"runtime/store-tool",
"sdk",
@ -59,7 +62,6 @@ members = [
"sdk/cargo-test-bpf",
"scripts",
"stake-accounts",
"stake-monitor",
"sys-tuner",
"tokens",
"transaction-status",
@ -76,5 +78,10 @@ exclude = [
"programs/bpf",
]
# TODO: Remove once the "simd-accel" feature from the reed-solomon-erasure
# dependency is supported on Apple M1. v2 of the feature resolver is needed to
# specify arch-specific features.
resolver = "2"
[profile.dev]
split-debuginfo = "unpacked"

View File

@ -1,6 +1,6 @@
<p align="center">
<a href="https://solana.com">
<img alt="Solana" src="https://i.imgur.com/uBVzyX3.png" width="250" />
<img alt="Solana" src="https://i.imgur.com/IKyzQ6T.png" width="250" />
</a>
</p>
@ -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:
Please make sure you are always using the latest stable rust version by running:
```bash
$ rustup update
@ -51,11 +51,6 @@ $ cd solana
$ cargo build
```
## **4. Run a minimal local cluster.**
```bash
$ ./run.sh
```
# Testing
**Run the test suite:**

View File

@ -1,6 +1,6 @@
[package]
name = "solana-account-decoder"
version = "1.7.0"
version = "1.8.3"
description = "Solana account decoder"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@ -19,11 +19,10 @@ lazy_static = "1.4.0"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-config-program = { path = "../programs/config", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.0" }
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
solana-config-program = { path = "../programs/config", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.8.3" }
spl-token-v2-0 = { package = "spl-token", version = "=3.2.0", features = ["no-entrypoint"] }
thiserror = "1.0"
zstd = "0.5.1"

View File

@ -28,6 +28,7 @@ use {
pub type StringAmount = String;
pub type StringDecimals = String;
pub const MAX_BASE58_BYTES: usize = 128;
/// A duplicate representation of an Account for pretty JSON serialization
#[derive(Serialize, Deserialize, Clone, Debug)]
@ -48,7 +49,7 @@ pub enum UiAccountData {
Binary(String, UiAccountEncoding),
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[serde(rename_all = "camelCase")]
pub enum UiAccountEncoding {
Binary, // Legacy. Retained for RPC backwards compatibility
@ -60,6 +61,17 @@ pub enum UiAccountEncoding {
}
impl UiAccount {
fn encode_bs58<T: ReadableAccount>(
account: &T,
data_slice_config: Option<UiDataSliceConfig>,
) -> String {
if account.data().len() <= MAX_BASE58_BYTES {
bs58::encode(slice_data(account.data(), data_slice_config)).into_string()
} else {
"error: data too large for bs58 encoding".to_string()
}
}
pub fn encode<T: ReadableAccount>(
pubkey: &Pubkey,
account: &T,
@ -68,33 +80,34 @@ impl UiAccount {
data_slice_config: Option<UiDataSliceConfig>,
) -> Self {
let data = match encoding {
UiAccountEncoding::Binary => UiAccountData::LegacyBinary(
bs58::encode(slice_data(&account.data(), data_slice_config)).into_string(),
),
UiAccountEncoding::Base58 => UiAccountData::Binary(
bs58::encode(slice_data(&account.data(), data_slice_config)).into_string(),
encoding,
),
UiAccountEncoding::Binary => {
let data = Self::encode_bs58(account, data_slice_config);
UiAccountData::LegacyBinary(data)
}
UiAccountEncoding::Base58 => {
let data = Self::encode_bs58(account, data_slice_config);
UiAccountData::Binary(data, encoding)
}
UiAccountEncoding::Base64 => UiAccountData::Binary(
base64::encode(slice_data(&account.data(), data_slice_config)),
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))
.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)),
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)
parse_account_data(pubkey, account.owner(), account.data(), additional_data)
{
UiAccountData::Json(parsed_data)
} else {
@ -166,7 +179,7 @@ impl Default for UiFeeCalculator {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiDataSliceConfig {
pub offset: usize,

View File

@ -9,14 +9,14 @@ use crate::{
};
use inflector::Inflector;
use serde_json::Value;
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program, sysvar};
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, stake, system_program, sysvar};
use std::collections::HashMap;
use thiserror::Error;
lazy_static! {
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();

View File

@ -6,10 +6,10 @@ use bincode::deserialize;
use serde_json::Value;
use solana_config_program::{get_config_data, ConfigKeys};
use solana_sdk::pubkey::Pubkey;
use solana_stake_program::config::Config as StakeConfig;
use solana_sdk::stake::config::{self as stake_config, Config as StakeConfig};
pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
let parsed_account = if pubkey == &solana_stake_program::config::id() {
let parsed_account = if pubkey == &stake_config::id() {
get_config_data(data)
.ok()
.and_then(|data| deserialize::<StakeConfig>(data).ok())
@ -37,7 +37,7 @@ fn parse_config_data<T>(data: &[u8], keys: Vec<(Pubkey, bool)>) -> Option<UiConf
where
T: serde::de::DeserializeOwned,
{
let config_data: T = deserialize(&get_config_data(data).ok()?).ok()?;
let config_data: T = deserialize(get_config_data(data).ok()?).ok()?;
let keys = keys
.iter()
.map(|key| UiConfigKey {
@ -101,11 +101,7 @@ mod test {
};
let stake_config_account = create_config_account(vec![], &stake_config, 10);
assert_eq!(
parse_config(
&stake_config_account.data(),
&solana_stake_program::config::id()
)
.unwrap(),
parse_config(stake_config_account.data(), &stake_config::id()).unwrap(),
ConfigAccountType::StakeConfig(UiStakeConfig {
warmup_cooldown_rate: 0.25,
slash_penalty: 50,
@ -125,7 +121,7 @@ mod test {
10,
);
assert_eq!(
parse_config(&validator_info_config_account.data(), &info_pubkey).unwrap(),
parse_config(validator_info_config_account.data(), &info_pubkey).unwrap(),
ConfigAccountType::ValidatorInfo(UiConfig {
keys: vec![
UiConfigKey {

View File

@ -4,7 +4,7 @@ use crate::{
};
use bincode::deserialize;
use solana_sdk::clock::{Epoch, UnixTimestamp};
use solana_stake_program::stake_state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
use solana_sdk::stake::state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
let stake_state: StakeState = deserialize(data)

View File

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

View File

@ -6,6 +6,7 @@ use rayon::prelude::*;
use solana_measure::measure::Measure;
use solana_runtime::{
accounts::{create_test_accounts, update_accounts_bench, Accounts},
accounts_db::AccountShrinkThreshold,
accounts_index::AccountSecondaryIndexes,
ancestors::Ancestors,
};
@ -64,6 +65,8 @@ fn main() {
&ClusterType::Testnet,
AccountSecondaryIndexes::default(),
false,
AccountShrinkThreshold::default(),
None,
);
println!("Creating {} accounts", num_accounts);
let mut create_time = Measure::start("create accounts");
@ -119,6 +122,8 @@ fn main() {
solana_sdk::clock::Slot::default(),
&ancestors,
None,
false,
None,
);
time_store.stop();
if results != results_store {

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-accounts-cluster-bench"
version = "1.7.0"
version = "1.8.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -13,23 +13,24 @@ clap = "2.33.1"
log = "0.4.11"
rand = "0.7.0"
rayon = "1.4.1"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.0" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.0" }
solana-client = { path = "../client", version = "=1.7.0" }
solana-core = { path = "../core", version = "=1.7.0" }
solana-faucet = { path = "../faucet", version = "=1.7.0" }
solana-gossip = { path = "../gossip", version = "=1.7.0" }
solana-logger = { path = "../logger", version = "=1.7.0" }
solana-measure = { path = "../measure", version = "=1.7.0" }
solana-net-utils = { path = "../net-utils", version = "=1.7.0" }
solana-runtime = { path = "../runtime", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.0" }
solana-version = { path = "../version", version = "=1.7.0" }
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
solana-account-decoder = { path = "../account-decoder", version = "=1.8.3" }
solana-clap-utils = { path = "../clap-utils", version = "=1.8.3" }
solana-client = { path = "../client", version = "=1.8.3" }
solana-core = { path = "../core", version = "=1.8.3" }
solana-faucet = { path = "../faucet", version = "=1.8.3" }
solana-gossip = { path = "../gossip", version = "=1.8.3" }
solana-logger = { path = "../logger", version = "=1.8.3" }
solana-measure = { path = "../measure", version = "=1.8.3" }
solana-net-utils = { path = "../net-utils", version = "=1.8.3" }
solana-runtime = { path = "../runtime", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
solana-streamer = { path = "../streamer", version = "=1.8.3" }
solana-transaction-status = { path = "../transaction-status", version = "=1.8.3" }
solana-version = { path = "../version", version = "=1.8.3" }
spl-token-v2-0 = { package = "spl-token", version = "=3.2.0", features = ["no-entrypoint"] }
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "=1.7.0" }
solana-local-cluster = { path = "../local-cluster", version = "=1.8.3" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -20,6 +20,7 @@ use solana_sdk::{
timing::timestamp,
transaction::Transaction,
};
use solana_streamer::socket::SocketAddrSpace;
use solana_transaction_status::parse_token::spl_token_v2_0_instruction;
use std::{
net::SocketAddr,
@ -55,7 +56,7 @@ pub fn airdrop_lamports(
);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => {
let mut tries = 0;
loop {
@ -363,7 +364,7 @@ fn run_accounts_bench(
iterations: usize,
maybe_space: Option<u64>,
batch_size: usize,
close_nth: u64,
close_nth_batch: u64,
maybe_lamports: Option<u64>,
num_instructions: usize,
mint: Option<Pubkey>,
@ -431,7 +432,7 @@ fn run_accounts_bench(
if !airdrop_lamports(
&client,
&faucet_addr,
&payer_keypairs[i],
payer_keypairs[i],
lamports * 100_000,
) {
warn!("failed airdrop, exiting");
@ -441,6 +442,7 @@ fn run_accounts_bench(
}
}
// Create accounts
let sigs_len = executor.num_outstanding();
if sigs_len < batch_size {
let num_to_create = batch_size - sigs_len;
@ -475,21 +477,25 @@ fn run_accounts_bench(
}
}
if close_nth > 0 {
let expected_closed = total_accounts_created as u64 / close_nth;
if expected_closed > total_accounts_closed {
let txs: Vec<_> = (0..expected_closed - total_accounts_closed)
if close_nth_batch > 0 {
let num_batches_to_close =
total_accounts_created as u64 / (close_nth_batch * batch_size as u64);
let expected_closed = num_batches_to_close * batch_size as u64;
let max_closed_seed = seed_tracker.max_closed.load(Ordering::Relaxed);
// Close every account we've created with seed between max_closed_seed..expected_closed
if max_closed_seed < expected_closed {
let txs: Vec<_> = (0..expected_closed - max_closed_seed)
.into_par_iter()
.map(|_| {
let message = make_close_message(
&payer_keypairs[0],
payer_keypairs[0],
&base_keypair,
seed_tracker.max_closed.clone(),
1,
min_balance,
mint.is_some(),
);
let signers: Vec<&Keypair> = vec![&payer_keypairs[0], &base_keypair];
let signers: Vec<&Keypair> = vec![payer_keypairs[0], &base_keypair];
Transaction::new(&signers, message, recent_blockhash.0)
})
.collect();
@ -572,14 +578,14 @@ fn main() {
.help("Number of transactions to send per batch"),
)
.arg(
Arg::with_name("close_nth")
Arg::with_name("close_nth_batch")
.long("close-frequency")
.takes_value(true)
.value_name("BYTES")
.help(
"Send close transactions after this many accounts created. \
Note: a `close-frequency` value near or below `batch-size` \
may result in transaction-simulation errors, as the close \
"Every `n` batches, create a batch of close transactions for
the earliest remaining batch of accounts created.
Note: Should be > 1 to avoid situations where the close \
transactions will be submitted before the corresponding \
create transactions have been confirmed",
),
@ -632,7 +638,7 @@ fn main() {
let space = value_t!(matches, "space", u64).ok();
let lamports = value_t!(matches, "lamports", u64).ok();
let batch_size = value_t!(matches, "batch_size", usize).unwrap_or(4);
let close_nth = value_t!(matches, "close_nth", u64).unwrap_or(0);
let close_nth_batch = value_t!(matches, "close_nth_batch", u64).unwrap_or(0);
let iterations = value_t!(matches, "iterations", usize).unwrap_or(10);
let num_instructions = value_t!(matches, "num_instructions", usize).unwrap_or(1);
if num_instructions == 0 || num_instructions > 500 {
@ -665,6 +671,7 @@ fn main() {
Some(&entrypoint_addr), // find_node_by_gossip_addr
None, // my_gossip_addr
0, // my_shred_version
SocketAddrSpace::Unspecified,
)
.unwrap_or_else(|err| {
eprintln!("Failed to discover {} node: {:?}", entrypoint_addr, err);
@ -685,7 +692,7 @@ fn main() {
iterations,
space,
batch_size,
close_nth,
close_nth_batch,
lamports,
num_instructions,
mint,
@ -716,11 +723,11 @@ pub mod test {
};
let faucet_addr = SocketAddr::from(([127, 0, 0, 1], 9900));
let cluster = LocalCluster::new(&mut config);
let cluster = LocalCluster::new(&mut config, SocketAddrSpace::Unspecified);
let iterations = 10;
let maybe_space = None;
let batch_size = 100;
let close_nth = 100;
let close_nth_batch = 100;
let maybe_lamports = None;
let num_instructions = 2;
let mut start = Measure::start("total accounts run");
@ -731,7 +738,7 @@ pub mod test {
iterations,
maybe_space,
batch_size,
close_nth,
close_nth_batch,
maybe_lamports,
num_instructions,
None,

View File

@ -0,0 +1,17 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-accountsdb-plugin-interface"
description = "The Solana AccountsDb plugin interface."
version = "1.8.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-validator"
[dependencies]
log = "0.4.11"
thiserror = "1.0.29"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -0,0 +1,20 @@
<p align="center">
<a href="https://solana.com">
<img alt="Solana" src="https://i.imgur.com/IKyzQ6T.png" width="250" />
</a>
</p>
# Solana AccountsDb Plugin Interface
This crate enables an AccountsDb plugin to be plugged into the Solana Validator runtime to take actions
at the time of each account update; for example, saving the account state to an external database. The plugin must implement the `AccountsDbPlugin` trait. Please see the detail of the `accountsdb_plugin_interface.rs` for the interface definition.
The plugin should produce a `cdylib` dynamic library, which must expose a `C` function `_create_plugin()` that
instantiates the implementation of the interface.
The `solana-accountsdb-plugin-postgres` crate provides an example of how to create a plugin which saves the accounts data into an
external PostgreSQL databases.
More information about Solana is available in the [Solana documentation](https://docs.solana.com/).
Still have questions? Ask us on [Discord](https://discordapp.com/invite/pquxPsq)

View File

@ -0,0 +1,99 @@
/// The interface for AccountsDb plugins. A plugin must implement
/// the AccountsDbPlugin trait to work with the runtime.
/// In addition, the dynamic library must export a "C" function _create_plugin which
/// creates the implementation of the plugin.
use {
std::{any::Any, error, io},
thiserror::Error,
};
impl Eq for ReplicaAccountInfo<'_> {}
#[derive(Clone, PartialEq, Debug)]
pub struct ReplicaAccountInfo<'a> {
pub pubkey: &'a [u8],
pub lamports: u64,
pub owner: &'a [u8],
pub executable: bool,
pub rent_epoch: u64,
pub data: &'a [u8],
pub write_version: u64,
}
pub enum ReplicaAccountInfoVersions<'a> {
V0_0_1(&'a ReplicaAccountInfo<'a>),
}
#[derive(Error, Debug)]
pub enum AccountsDbPluginError {
#[error("Error opening config file. Error detail: ({0}).")]
ConfigFileOpenError(#[from] io::Error),
#[error("Error reading config file. Error message: ({msg})")]
ConfigFileReadError { msg: String },
#[error("Error updating account. Error message: ({msg})")]
AccountsUpdateError { msg: String },
#[error("Error updating slot status. Error message: ({msg})")]
SlotStatusUpdateError { msg: String },
#[error("Plugin-defined custom error. Error message: ({0})")]
Custom(Box<dyn error::Error + Send + Sync>),
}
#[derive(Debug, Clone)]
pub enum SlotStatus {
Processed,
Rooted,
Confirmed,
}
impl SlotStatus {
pub fn as_str(&self) -> &'static str {
match self {
SlotStatus::Confirmed => "confirmed",
SlotStatus::Processed => "processed",
SlotStatus::Rooted => "rooted",
}
}
}
pub type Result<T> = std::result::Result<T, AccountsDbPluginError>;
pub trait AccountsDbPlugin: Any + Send + Sync + std::fmt::Debug {
fn name(&self) -> &'static str;
/// The callback called when a plugin is loaded by the system,
/// used for doing whatever initialization is required by the plugin.
/// The _config_file contains the name of the
/// of the config file. The config must be in JSON format and
/// include a field "libpath" indicating the full path
/// name of the shared library implementing this interface.
fn on_load(&mut self, _config_file: &str) -> Result<()> {
Ok(())
}
/// The callback called right before a plugin is unloaded by the system
/// Used for doing cleanup before unload.
fn on_unload(&mut self) {}
/// Called when an account is updated at a slot.
fn update_account(
&mut self,
account: ReplicaAccountInfoVersions,
slot: u64,
is_startup: bool,
) -> Result<()>;
/// Called when all accounts are notified of during startup.
fn notify_end_of_startup(&mut self) -> Result<()>;
/// Called when a slot status is updated
fn update_slot_status(
&mut self,
slot: u64,
parent: Option<u64>,
status: SlotStatus,
) -> Result<()>;
}

View File

@ -0,0 +1 @@
pub mod accountsdb_plugin_interface;

View File

@ -0,0 +1,30 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-accountsdb-plugin-manager"
description = "The Solana AccountsDb plugin manager."
version = "1.8.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-validator"
[dependencies]
bs58 = "0.4.0"
crossbeam-channel = "0.4"
libloading = "0.7.0"
log = "0.4.11"
serde = "1.0.130"
serde_derive = "1.0.103"
serde_json = "1.0.67"
solana-accountsdb-plugin-interface = { path = "../accountsdb-plugin-interface", version = "=1.8.3" }
solana-logger = { path = "../logger", version = "=1.8.3" }
solana-measure = { path = "../measure", version = "=1.8.3" }
solana-metrics = { path = "../metrics", version = "=1.8.3" }
solana-rpc = { path = "../rpc", version = "=1.8.3" }
solana-runtime = { path = "../runtime", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
thiserror = "1.0.21"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -0,0 +1,227 @@
/// Module responsible for notifying plugins of account updates
use {
crate::accountsdb_plugin_manager::AccountsDbPluginManager,
log::*,
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
ReplicaAccountInfo, ReplicaAccountInfoVersions, SlotStatus,
},
solana_measure::measure::Measure,
solana_metrics::*,
solana_runtime::{
accounts_update_notifier_interface::AccountsUpdateNotifierInterface,
append_vec::{StoredAccountMeta, StoredMeta},
},
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
clock::Slot,
},
std::sync::{Arc, RwLock},
};
#[derive(Debug)]
pub(crate) struct AccountsUpdateNotifierImpl {
plugin_manager: Arc<RwLock<AccountsDbPluginManager>>,
}
impl AccountsUpdateNotifierInterface for AccountsUpdateNotifierImpl {
fn notify_account_update(&self, slot: Slot, meta: &StoredMeta, account: &AccountSharedData) {
if let Some(account_info) = self.accountinfo_from_shared_account_data(meta, account) {
self.notify_plugins_of_account_update(account_info, slot, false);
}
}
fn notify_account_restore_from_snapshot(&self, slot: Slot, account: &StoredAccountMeta) {
let mut measure_all = Measure::start("accountsdb-plugin-notify-account-restore-all");
let mut measure_copy = Measure::start("accountsdb-plugin-copy-stored-account-info");
let account = self.accountinfo_from_stored_account_meta(account);
measure_copy.stop();
inc_new_counter_debug!(
"accountsdb-plugin-copy-stored-account-info-us",
measure_copy.as_us() as usize,
100000,
100000
);
if let Some(account_info) = account {
self.notify_plugins_of_account_update(account_info, slot, true);
}
measure_all.stop();
inc_new_counter_debug!(
"accountsdb-plugin-notify-account-restore-all-us",
measure_all.as_us() as usize,
100000,
100000
);
}
fn notify_end_of_restore_from_snapshot(&self) {
let mut plugin_manager = self.plugin_manager.write().unwrap();
if plugin_manager.plugins.is_empty() {
return;
}
for plugin in plugin_manager.plugins.iter_mut() {
let mut measure = Measure::start("accountsdb-plugin-end-of-restore-from-snapshot");
match plugin.notify_end_of_startup() {
Err(err) => {
error!(
"Failed to notify the end of restore from snapshot, error: {} to plugin {}",
err,
plugin.name()
)
}
Ok(_) => {
trace!(
"Successfully notified the end of restore from snapshot to plugin {}",
plugin.name()
);
}
}
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-end-of-restore-from-snapshot",
measure.as_us() as usize
);
}
}
fn notify_slot_confirmed(&self, slot: Slot, parent: Option<Slot>) {
self.notify_slot_status(slot, parent, SlotStatus::Confirmed);
}
fn notify_slot_processed(&self, slot: Slot, parent: Option<Slot>) {
self.notify_slot_status(slot, parent, SlotStatus::Processed);
}
fn notify_slot_rooted(&self, slot: Slot, parent: Option<Slot>) {
self.notify_slot_status(slot, parent, SlotStatus::Rooted);
}
}
impl AccountsUpdateNotifierImpl {
pub fn new(plugin_manager: Arc<RwLock<AccountsDbPluginManager>>) -> Self {
AccountsUpdateNotifierImpl { plugin_manager }
}
fn accountinfo_from_shared_account_data<'a>(
&self,
meta: &'a StoredMeta,
account: &'a AccountSharedData,
) -> Option<ReplicaAccountInfo<'a>> {
Some(ReplicaAccountInfo {
pubkey: meta.pubkey.as_ref(),
lamports: account.lamports(),
owner: account.owner().as_ref(),
executable: account.executable(),
rent_epoch: account.rent_epoch(),
data: account.data(),
write_version: meta.write_version,
})
}
fn accountinfo_from_stored_account_meta<'a>(
&self,
stored_account_meta: &'a StoredAccountMeta,
) -> Option<ReplicaAccountInfo<'a>> {
Some(ReplicaAccountInfo {
pubkey: stored_account_meta.meta.pubkey.as_ref(),
lamports: stored_account_meta.account_meta.lamports,
owner: stored_account_meta.account_meta.owner.as_ref(),
executable: stored_account_meta.account_meta.executable,
rent_epoch: stored_account_meta.account_meta.rent_epoch,
data: stored_account_meta.data,
write_version: stored_account_meta.meta.write_version,
})
}
fn notify_plugins_of_account_update(
&self,
account: ReplicaAccountInfo,
slot: Slot,
is_startup: bool,
) {
let mut measure2 = Measure::start("accountsdb-plugin-notify_plugins_of_account_update");
let mut plugin_manager = self.plugin_manager.write().unwrap();
if plugin_manager.plugins.is_empty() {
return;
}
for plugin in plugin_manager.plugins.iter_mut() {
let mut measure = Measure::start("accountsdb-plugin-update-account");
match plugin.update_account(
ReplicaAccountInfoVersions::V0_0_1(&account),
slot,
is_startup,
) {
Err(err) => {
error!(
"Failed to update account {} at slot {}, error: {} to plugin {}",
bs58::encode(account.pubkey).into_string(),
slot,
err,
plugin.name()
)
}
Ok(_) => {
trace!(
"Successfully updated account {} at slot {} to plugin {}",
bs58::encode(account.pubkey).into_string(),
slot,
plugin.name()
);
}
}
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-update-account-us",
measure.as_us() as usize,
100000,
100000
);
}
measure2.stop();
inc_new_counter_debug!(
"accountsdb-plugin-notify_plugins_of_account_update-us",
measure2.as_us() as usize,
100000,
100000
);
}
pub fn notify_slot_status(&self, slot: Slot, parent: Option<Slot>, slot_status: SlotStatus) {
let mut plugin_manager = self.plugin_manager.write().unwrap();
if plugin_manager.plugins.is_empty() {
return;
}
for plugin in plugin_manager.plugins.iter_mut() {
let mut measure = Measure::start("accountsdb-plugin-update-slot");
match plugin.update_slot_status(slot, parent, slot_status.clone()) {
Err(err) => {
error!(
"Failed to update slot status at slot {}, error: {} to plugin {}",
slot,
err,
plugin.name()
)
}
Ok(_) => {
trace!(
"Successfully updated slot status at slot {} to plugin {}",
slot,
plugin.name()
);
}
}
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-update-slot-us",
measure.as_us() as usize,
1000,
1000
);
}
}
}

View File

@ -0,0 +1,55 @@
/// Managing the AccountsDb plugins
use {
libloading::{Library, Symbol},
log::*,
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::AccountsDbPlugin,
std::error::Error,
};
#[derive(Default, Debug)]
pub struct AccountsDbPluginManager {
pub plugins: Vec<Box<dyn AccountsDbPlugin>>,
libs: Vec<Library>,
}
impl AccountsDbPluginManager {
pub fn new() -> Self {
AccountsDbPluginManager {
plugins: Vec::default(),
libs: Vec::default(),
}
}
/// # Safety
///
/// This function loads the dynamically linked library specified in the path. The library
/// must do necessary initializations.
pub unsafe fn load_plugin(
&mut self,
libpath: &str,
config_file: &str,
) -> Result<(), Box<dyn Error>> {
type PluginConstructor = unsafe fn() -> *mut dyn AccountsDbPlugin;
let lib = Library::new(libpath)?;
let constructor: Symbol<PluginConstructor> = lib.get(b"_create_plugin")?;
let plugin_raw = constructor();
let mut plugin = Box::from_raw(plugin_raw);
plugin.on_load(config_file)?;
self.plugins.push(plugin);
self.libs.push(lib);
Ok(())
}
/// Unload all plugins and loaded plugin libraries, making sure to fire
/// their `on_plugin_unload()` methods so they can do any necessary cleanup.
pub fn unload(&mut self) {
for mut plugin in self.plugins.drain(..) {
info!("Unloading plugin for {:?}", plugin.name());
plugin.on_unload();
}
for lib in self.libs.drain(..) {
drop(lib);
}
}
}

View File

@ -0,0 +1,157 @@
use {
crate::{
accounts_update_notifier::AccountsUpdateNotifierImpl,
accountsdb_plugin_manager::AccountsDbPluginManager,
slot_status_observer::SlotStatusObserver,
},
crossbeam_channel::Receiver,
log::*,
serde_json,
solana_rpc::optimistically_confirmed_bank_tracker::BankNotification,
solana_runtime::accounts_update_notifier_interface::AccountsUpdateNotifier,
std::{
fs::File,
io::Read,
path::{Path, PathBuf},
sync::{Arc, RwLock},
thread,
},
thiserror::Error,
};
#[derive(Error, Debug)]
pub enum AccountsdbPluginServiceError {
#[error("Cannot open the the plugin config file")]
CannotOpenConfigFile(String),
#[error("Cannot read the the plugin config file")]
CannotReadConfigFile(String),
#[error("The config file is not in a valid Json format")]
InvalidConfigFileFormat(String),
#[error("Plugin library path is not specified in the config file")]
LibPathNotSet,
#[error("Invalid plugin path")]
InvalidPluginPath,
#[error("Cannot load plugin shared library")]
PluginLoadError(String),
}
/// The service managing the AccountsDb plugin workflow.
pub struct AccountsDbPluginService {
slot_status_observer: SlotStatusObserver,
plugin_manager: Arc<RwLock<AccountsDbPluginManager>>,
accounts_update_notifier: AccountsUpdateNotifier,
}
impl AccountsDbPluginService {
/// Creates and returns the AccountsDbPluginService.
/// # Arguments
/// * `confirmed_bank_receiver` - The receiver for confirmed bank notification
/// * `accountsdb_plugin_config_file` - The config file path for the plugin. The
/// config file controls the plugin responsible
/// for transporting the data to external data stores. It is defined in JSON format.
/// The `libpath` field should be pointed to the full path of the dynamic shared library
/// (.so file) to be loaded. The shared library must implement the `AccountsDbPlugin`
/// trait. And the shared library shall export a `C` function `_create_plugin` which
/// shall create the implementation of `AccountsDbPlugin` and returns to the caller.
/// The rest of the JSON fields' definition is up to to the concrete plugin implementation
/// It is usually used to configure the connection information for the external data store.
pub fn new(
confirmed_bank_receiver: Receiver<BankNotification>,
accountsdb_plugin_config_files: &[PathBuf],
) -> Result<Self, AccountsdbPluginServiceError> {
info!(
"Starting AccountsDbPluginService from config files: {:?}",
accountsdb_plugin_config_files
);
let mut plugin_manager = AccountsDbPluginManager::new();
for accountsdb_plugin_config_file in accountsdb_plugin_config_files {
Self::load_plugin(&mut plugin_manager, accountsdb_plugin_config_file)?;
}
let plugin_manager = Arc::new(RwLock::new(plugin_manager));
let accounts_update_notifier = Arc::new(RwLock::new(AccountsUpdateNotifierImpl::new(
plugin_manager.clone(),
)));
let slot_status_observer =
SlotStatusObserver::new(confirmed_bank_receiver, accounts_update_notifier.clone());
info!("Started AccountsDbPluginService");
Ok(AccountsDbPluginService {
slot_status_observer,
plugin_manager,
accounts_update_notifier,
})
}
fn load_plugin(
plugin_manager: &mut AccountsDbPluginManager,
accountsdb_plugin_config_file: &Path,
) -> Result<(), AccountsdbPluginServiceError> {
let mut file = match File::open(accountsdb_plugin_config_file) {
Ok(file) => file,
Err(err) => {
return Err(AccountsdbPluginServiceError::CannotOpenConfigFile(format!(
"Failed to open the plugin config file {:?}, error: {:?}",
accountsdb_plugin_config_file, err
)));
}
};
let mut contents = String::new();
if let Err(err) = file.read_to_string(&mut contents) {
return Err(AccountsdbPluginServiceError::CannotReadConfigFile(format!(
"Failed to read the plugin config file {:?}, error: {:?}",
accountsdb_plugin_config_file, err
)));
}
let result: serde_json::Value = match serde_json::from_str(&contents) {
Ok(value) => value,
Err(err) => {
return Err(AccountsdbPluginServiceError::InvalidConfigFileFormat(
format!(
"The config file {:?} is not in a valid Json format, error: {:?}",
accountsdb_plugin_config_file, err
),
));
}
};
let libpath = result["libpath"]
.as_str()
.ok_or(AccountsdbPluginServiceError::LibPathNotSet)?;
let config_file = accountsdb_plugin_config_file
.as_os_str()
.to_str()
.ok_or(AccountsdbPluginServiceError::InvalidPluginPath)?;
unsafe {
let result = plugin_manager.load_plugin(libpath, config_file);
if let Err(err) = result {
let msg = format!(
"Failed to load the plugin library: {:?}, error: {:?}",
libpath, err
);
return Err(AccountsdbPluginServiceError::PluginLoadError(msg));
}
}
Ok(())
}
pub fn get_accounts_update_notifier(&self) -> AccountsUpdateNotifier {
self.accounts_update_notifier.clone()
}
pub fn join(mut self) -> thread::Result<()> {
self.slot_status_observer.join()?;
self.plugin_manager.write().unwrap().unload();
Ok(())
}
}

View File

@ -0,0 +1,4 @@
pub mod accounts_update_notifier;
pub mod accountsdb_plugin_manager;
pub mod accountsdb_plugin_service;
pub mod slot_status_observer;

View File

@ -0,0 +1,80 @@
use {
crossbeam_channel::Receiver,
solana_rpc::optimistically_confirmed_bank_tracker::BankNotification,
solana_runtime::accounts_update_notifier_interface::AccountsUpdateNotifier,
std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::{self, Builder, JoinHandle},
},
};
#[derive(Debug)]
pub(crate) struct SlotStatusObserver {
bank_notification_receiver_service: Option<JoinHandle<()>>,
exit_updated_slot_server: Arc<AtomicBool>,
}
impl SlotStatusObserver {
pub fn new(
bank_notification_receiver: Receiver<BankNotification>,
accounts_update_notifier: AccountsUpdateNotifier,
) -> Self {
let exit_updated_slot_server = Arc::new(AtomicBool::new(false));
Self {
bank_notification_receiver_service: Some(Self::run_bank_notification_receiver(
bank_notification_receiver,
exit_updated_slot_server.clone(),
accounts_update_notifier,
)),
exit_updated_slot_server,
}
}
pub fn join(&mut self) -> thread::Result<()> {
self.exit_updated_slot_server.store(true, Ordering::Relaxed);
self.bank_notification_receiver_service
.take()
.map(JoinHandle::join)
.unwrap()
}
fn run_bank_notification_receiver(
bank_notification_receiver: Receiver<BankNotification>,
exit: Arc<AtomicBool>,
accounts_update_notifier: AccountsUpdateNotifier,
) -> JoinHandle<()> {
Builder::new()
.name("bank_notification_receiver".to_string())
.spawn(move || {
while !exit.load(Ordering::Relaxed) {
if let Ok(slot) = bank_notification_receiver.recv() {
match slot {
BankNotification::OptimisticallyConfirmed(slot) => {
accounts_update_notifier
.read()
.unwrap()
.notify_slot_confirmed(slot, None);
}
BankNotification::Frozen(bank) => {
accounts_update_notifier
.read()
.unwrap()
.notify_slot_processed(bank.slot(), Some(bank.parent_slot()));
}
BankNotification::Root(bank) => {
accounts_update_notifier
.read()
.unwrap()
.notify_slot_rooted(bank.slot(), Some(bank.parent_slot()));
}
}
}
}
})
.unwrap()
}
}

View File

@ -0,0 +1,33 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-accountsdb-plugin-postgres"
description = "The Solana AccountsDb plugin for PostgreSQL database."
version = "1.8.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-validator"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
bs58 = "0.4.0"
chrono = { version = "0.4.11", features = ["serde"] }
crossbeam-channel = "0.5"
log = "0.4.14"
postgres = { version = "0.19.1", features = ["with-chrono-0_4"] }
serde = "1.0.130"
serde_derive = "1.0.103"
serde_json = "1.0.67"
solana-accountsdb-plugin-interface = { path = "../accountsdb-plugin-interface", version = "=1.8.3" }
solana-logger = { path = "../logger", version = "=1.8.3" }
solana-measure = { path = "../measure", version = "=1.8.3" }
solana-metrics = { path = "../metrics", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
thiserror = "1.0.21"
tokio-postgres = "0.7.3"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -0,0 +1,5 @@
This is an example implementing the AccountsDb plugin for PostgreSQL database.
Please see the `src/accountsdb_plugin_postgres.rs` for the format of the plugin's configuration file.
To create the schema objects for the database, please use `scripts/create_schema.sql`.
`scripts/drop_schema.sql` can be used to tear down the schema objects.

View File

@ -0,0 +1,54 @@
/**
* This plugin implementation for PostgreSQL requires the following tables
*/
-- The table storing accounts
CREATE TABLE account (
pubkey BYTEA PRIMARY KEY,
owner BYTEA,
lamports BIGINT NOT NULL,
slot BIGINT NOT NULL,
executable BOOL NOT NULL,
rent_epoch BIGINT NOT NULL,
data BYTEA,
write_version BIGINT NOT NULL,
updated_on TIMESTAMP NOT NULL
);
-- The table storing slot information
CREATE TABLE slot (
slot BIGINT PRIMARY KEY,
parent BIGINT,
status varchar(16) NOT NULL,
updated_on TIMESTAMP NOT NULL
);
/**
* The following is for keeping historical data for accounts and is not required for plugin to work.
*/
-- The table storing historical data for accounts
CREATE TABLE account_audit (
pubkey BYTEA,
owner BYTEA,
lamports BIGINT NOT NULL,
slot BIGINT NOT NULL,
executable BOOL NOT NULL,
rent_epoch BIGINT NOT NULL,
data BYTEA,
write_version BIGINT NOT NULL,
updated_on TIMESTAMP NOT NULL
);
CREATE FUNCTION audit_account_update() RETURNS trigger AS $audit_account_update$
BEGIN
INSERT INTO account_audit (pubkey, owner, lamports, slot, executable, rent_epoch, data, write_version, updated_on)
VALUES (OLD.pubkey, OLD.owner, OLD.lamports, OLD.slot,
OLD.executable, OLD.rent_epoch, OLD.data, OLD.write_version, OLD.updated_on);
RETURN NEW;
END;
$audit_account_update$ LANGUAGE plpgsql;
CREATE TRIGGER account_update_trigger AFTER UPDATE OR DELETE ON account
FOR EACH ROW EXECUTE PROCEDURE audit_account_update();

View File

@ -0,0 +1,9 @@
/**
* Script for cleaning up the schema for PostgreSQL used for the AccountsDb plugin.
*/
DROP TRIGGER account_update_trigger ON account;
DROP FUNCTION audit_account_update;
DROP TABLE account_audit;
DROP TABLE account;
DROP TABLE slot;

View File

@ -0,0 +1,802 @@
# This a reference configuration file for the PostgreSQL database version 14.
# -----------------------------
# PostgreSQL configuration file
# -----------------------------
#
# This file consists of lines of the form:
#
# name = value
#
# (The "=" is optional.) Whitespace may be used. Comments are introduced with
# "#" anywhere on a line. The complete list of parameter names and allowed
# values can be found in the PostgreSQL documentation.
#
# The commented-out settings shown in this file represent the default values.
# Re-commenting a setting is NOT sufficient to revert it to the default value;
# you need to reload the server.
#
# This file is read on server startup and when the server receives a SIGHUP
# signal. If you edit the file on a running system, you have to SIGHUP the
# server for the changes to take effect, run "pg_ctl reload", or execute
# "SELECT pg_reload_conf()". Some parameters, which are marked below,
# require a server shutdown and restart to take effect.
#
# Any parameter can also be given as a command-line option to the server, e.g.,
# "postgres -c log_connections=on". Some parameters can be changed at run time
# with the "SET" SQL command.
#
# Memory units: B = bytes Time units: us = microseconds
# kB = kilobytes ms = milliseconds
# MB = megabytes s = seconds
# GB = gigabytes min = minutes
# TB = terabytes h = hours
# d = days
#------------------------------------------------------------------------------
# FILE LOCATIONS
#------------------------------------------------------------------------------
# The default values of these variables are driven from the -D command-line
# option or PGDATA environment variable, represented here as ConfigDir.
data_directory = '/var/lib/postgresql/14/main' # use data in another directory
# (change requires restart)
hba_file = '/etc/postgresql/14/main/pg_hba.conf' # host-based authentication file
# (change requires restart)
ident_file = '/etc/postgresql/14/main/pg_ident.conf' # ident configuration file
# (change requires restart)
# If external_pid_file is not explicitly set, no extra PID file is written.
external_pid_file = '/var/run/postgresql/14-main.pid' # write an extra PID file
# (change requires restart)
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------
# - Connection Settings -
#listen_addresses = 'localhost' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost'; use '*' for all
# (change requires restart)
listen_addresses = '*'
port = 5433 # (change requires restart)
max_connections = 200 # (change requires restart)
#superuser_reserved_connections = 3 # (change requires restart)
unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories
# (change requires restart)
#unix_socket_group = '' # (change requires restart)
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
# (change requires restart)
#bonjour = off # advertise server via Bonjour
# (change requires restart)
#bonjour_name = '' # defaults to the computer name
# (change requires restart)
# - TCP settings -
# see "man tcp" for details
#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;
# 0 selects the system default
#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;
# 0 selects the system default
#tcp_keepalives_count = 0 # TCP_KEEPCNT;
# 0 selects the system default
#tcp_user_timeout = 0 # TCP_USER_TIMEOUT, in milliseconds;
# 0 selects the system default
#client_connection_check_interval = 0 # time between checks for client
# disconnection while running queries;
# 0 for never
# - Authentication -
#authentication_timeout = 1min # 1s-600s
#password_encryption = scram-sha-256 # scram-sha-256 or md5
#db_user_namespace = off
# GSSAPI using Kerberos
#krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab'
#krb_caseins_users = off
# - SSL -
ssl = on
#ssl_ca_file = ''
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
#ssl_crl_file = ''
#ssl_crl_dir = ''
ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
#ssl_min_protocol_version = 'TLSv1.2'
#ssl_max_protocol_version = ''
#ssl_dh_params_file = ''
#ssl_passphrase_command = ''
#ssl_passphrase_command_supports_reload = off
#------------------------------------------------------------------------------
# RESOURCE USAGE (except WAL)
#------------------------------------------------------------------------------
# - Memory -
shared_buffers = 1GB # min 128kB
# (change requires restart)
#huge_pages = try # on, off, or try
# (change requires restart)
#huge_page_size = 0 # zero for system default
# (change requires restart)
#temp_buffers = 8MB # min 800kB
#max_prepared_transactions = 0 # zero disables the feature
# (change requires restart)
# Caution: it is not advisable to set max_prepared_transactions nonzero unless
# you actively intend to use prepared transactions.
#work_mem = 4MB # min 64kB
#hash_mem_multiplier = 1.0 # 1-1000.0 multiplier on hash table work_mem
#maintenance_work_mem = 64MB # min 1MB
#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem
#logical_decoding_work_mem = 64MB # min 64kB
#max_stack_depth = 2MB # min 100kB
#shared_memory_type = mmap # the default is the first option
# supported by the operating system:
# mmap
# sysv
# windows
# (change requires restart)
dynamic_shared_memory_type = posix # the default is the first option
# supported by the operating system:
# posix
# sysv
# windows
# mmap
# (change requires restart)
#min_dynamic_shared_memory = 0MB # (change requires restart)
# - Disk -
#temp_file_limit = -1 # limits per-process temp file space
# in kilobytes, or -1 for no limit
# - Kernel Resources -
#max_files_per_process = 1000 # min 64
# (change requires restart)
# - Cost-Based Vacuum Delay -
#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables)
#vacuum_cost_page_hit = 1 # 0-10000 credits
#vacuum_cost_page_miss = 2 # 0-10000 credits
#vacuum_cost_page_dirty = 20 # 0-10000 credits
#vacuum_cost_limit = 200 # 1-10000 credits
# - Background Writer -
#bgwriter_delay = 200ms # 10-10000ms between rounds
#bgwriter_lru_maxpages = 100 # max buffers written/round, 0 disables
#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round
#bgwriter_flush_after = 512kB # measured in pages, 0 disables
# - Asynchronous Behavior -
#backend_flush_after = 0 # measured in pages, 0 disables
effective_io_concurrency = 1000 # 1-1000; 0 disables prefetching
#maintenance_io_concurrency = 10 # 1-1000; 0 disables prefetching
#max_worker_processes = 8 # (change requires restart)
#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers
#max_parallel_maintenance_workers = 2 # taken from max_parallel_workers
#max_parallel_workers = 8 # maximum number of max_worker_processes that
# can be used in parallel operations
#parallel_leader_participation = on
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
# (change requires restart)
#------------------------------------------------------------------------------
# WRITE-AHEAD LOG
#------------------------------------------------------------------------------
# - Settings -
wal_level = minimal # minimal, replica, or logical
# (change requires restart)
fsync = off # flush data to disk for crash safety
# (turning this off can cause
# unrecoverable data corruption)
synchronous_commit = off # synchronization level;
# off, local, remote_write, remote_apply, or on
#wal_sync_method = fsync # the default is the first option
# supported by the operating system:
# open_datasync
# fdatasync (default on Linux and FreeBSD)
# fsync
# fsync_writethrough
# open_sync
full_page_writes = off # recover from partial page writes
#wal_log_hints = off # also do full page writes of non-critical updates
# (change requires restart)
#wal_compression = off # enable compression of full-page writes
#wal_init_zero = on # zero-fill new WAL files
#wal_recycle = on # recycle WAL files
#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers
# (change requires restart)
#wal_writer_delay = 200ms # 1-10000 milliseconds
#wal_writer_flush_after = 1MB # measured in pages, 0 disables
#wal_skip_threshold = 2MB
#commit_delay = 0 # range 0-100000, in microseconds
#commit_siblings = 5 # range 1-1000
# - Checkpoints -
#checkpoint_timeout = 5min # range 30s-1d
#checkpoint_completion_target = 0.9 # checkpoint target duration, 0.0 - 1.0
#checkpoint_flush_after = 256kB # measured in pages, 0 disables
#checkpoint_warning = 30s # 0 disables
max_wal_size = 1GB
min_wal_size = 80MB
# - Archiving -
#archive_mode = off # enables archiving; off, on, or always
# (change requires restart)
#archive_command = '' # command to use to archive a logfile segment
# placeholders: %p = path of file to archive
# %f = file name only
# e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0 # force a logfile segment switch after this
# number of seconds; 0 disables
# - Archive Recovery -
# These are only used in recovery mode.
#restore_command = '' # command to use to restore an archived logfile segment
# placeholders: %p = path of file to restore
# %f = file name only
# e.g. 'cp /mnt/server/archivedir/%f %p'
#archive_cleanup_command = '' # command to execute at every restartpoint
#recovery_end_command = '' # command to execute at completion of recovery
# - Recovery Target -
# Set these only when performing a targeted recovery.
#recovery_target = '' # 'immediate' to end recovery as soon as a
# consistent state is reached
# (change requires restart)
#recovery_target_name = '' # the named restore point to which recovery will proceed
# (change requires restart)
#recovery_target_time = '' # the time stamp up to which recovery will proceed
# (change requires restart)
#recovery_target_xid = '' # the transaction ID up to which recovery will proceed
# (change requires restart)
#recovery_target_lsn = '' # the WAL LSN up to which recovery will proceed
# (change requires restart)
#recovery_target_inclusive = on # Specifies whether to stop:
# just after the specified recovery target (on)
# just before the recovery target (off)
# (change requires restart)
#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID
# (change requires restart)
#recovery_target_action = 'pause' # 'pause', 'promote', 'shutdown'
# (change requires restart)
#------------------------------------------------------------------------------
# REPLICATION
#------------------------------------------------------------------------------
# - Sending Servers -
# Set these on the primary and on any standby that will send replication data.
max_wal_senders = 0 # max number of walsender processes
# (change requires restart)
#max_replication_slots = 10 # max number of replication slots
# (change requires restart)
#wal_keep_size = 0 # in megabytes; 0 disables
#max_slot_wal_keep_size = -1 # in megabytes; -1 disables
#wal_sender_timeout = 60s # in milliseconds; 0 disables
#track_commit_timestamp = off # collect timestamp of transaction commit
# (change requires restart)
# - Primary Server -
# These settings are ignored on a standby server.
#synchronous_standby_names = '' # standby servers that provide sync rep
# method to choose sync standbys, number of sync standbys,
# and comma-separated list of application_name
# from standby(s); '*' = all
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
# - Standby Servers -
# These settings are ignored on a primary server.
#primary_conninfo = '' # connection string to sending server
#primary_slot_name = '' # replication slot on sending server
#promote_trigger_file = '' # file name whose presence ends recovery
#hot_standby = on # "off" disallows queries during recovery
# (change requires restart)
#max_standby_archive_delay = 30s # max delay before canceling queries
# when reading WAL from archive;
# -1 allows indefinite delay
#max_standby_streaming_delay = 30s # max delay before canceling queries
# when reading streaming WAL;
# -1 allows indefinite delay
#wal_receiver_create_temp_slot = off # create temp slot if primary_slot_name
# is not set
#wal_receiver_status_interval = 10s # send replies at least this often
# 0 disables
#hot_standby_feedback = off # send info from standby to prevent
# query conflicts
#wal_receiver_timeout = 60s # time that receiver waits for
# communication from primary
# in milliseconds; 0 disables
#wal_retrieve_retry_interval = 5s # time to wait before retrying to
# retrieve WAL after a failed attempt
#recovery_min_apply_delay = 0 # minimum delay for applying changes during recovery
# - Subscribers -
# These settings are ignored on a publisher.
#max_logical_replication_workers = 4 # taken from max_worker_processes
# (change requires restart)
#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers
#------------------------------------------------------------------------------
# QUERY TUNING
#------------------------------------------------------------------------------
# - Planner Method Configuration -
#enable_async_append = on
#enable_bitmapscan = on
#enable_gathermerge = on
#enable_hashagg = on
#enable_hashjoin = on
#enable_incremental_sort = on
#enable_indexscan = on
#enable_indexonlyscan = on
#enable_material = on
#enable_memoize = on
#enable_mergejoin = on
#enable_nestloop = on
#enable_parallel_append = on
#enable_parallel_hash = on
#enable_partition_pruning = on
#enable_partitionwise_join = off
#enable_partitionwise_aggregate = off
#enable_seqscan = on
#enable_sort = on
#enable_tidscan = on
# - Planner Cost Constants -
#seq_page_cost = 1.0 # measured on an arbitrary scale
#random_page_cost = 4.0 # same scale as above
#cpu_tuple_cost = 0.01 # same scale as above
#cpu_index_tuple_cost = 0.005 # same scale as above
#cpu_operator_cost = 0.0025 # same scale as above
#parallel_setup_cost = 1000.0 # same scale as above
#parallel_tuple_cost = 0.1 # same scale as above
#min_parallel_table_scan_size = 8MB
#min_parallel_index_scan_size = 512kB
#effective_cache_size = 4GB
#jit_above_cost = 100000 # perform JIT compilation if available
# and query more expensive than this;
# -1 disables
#jit_inline_above_cost = 500000 # inline small functions if query is
# more expensive than this; -1 disables
#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if
# query is more expensive than this;
# -1 disables
# - Genetic Query Optimizer -
#geqo = on
#geqo_threshold = 12
#geqo_effort = 5 # range 1-10
#geqo_pool_size = 0 # selects default based on effort
#geqo_generations = 0 # selects default based on effort
#geqo_selection_bias = 2.0 # range 1.5-2.0
#geqo_seed = 0.0 # range 0.0-1.0
# - Other Planner Options -
#default_statistics_target = 100 # range 1-10000
#constraint_exclusion = partition # on, off, or partition
#cursor_tuple_fraction = 0.1 # range 0.0-1.0
#from_collapse_limit = 8
#jit = on # allow JIT compilation
#join_collapse_limit = 8 # 1 disables collapsing of explicit
# JOIN clauses
#plan_cache_mode = auto # auto, force_generic_plan or
# force_custom_plan
#------------------------------------------------------------------------------
# REPORTING AND LOGGING
#------------------------------------------------------------------------------
# - Where to Log -
#log_destination = 'stderr' # Valid values are combinations of
# stderr, csvlog, syslog, and eventlog,
# depending on platform. csvlog
# requires logging_collector to be on.
# This is used when logging to stderr:
#logging_collector = off # Enable capturing of stderr and csvlog
# into log files. Required to be on for
# csvlogs.
# (change requires restart)
# These are only used if logging_collector is on:
#log_directory = 'log' # directory where log files are written,
# can be absolute or relative to PGDATA
#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
# can include strftime() escapes
#log_file_mode = 0600 # creation mode for log files,
# begin with 0 to use octal notation
#log_rotation_age = 1d # Automatic rotation of logfiles will
# happen after that time. 0 disables.
#log_rotation_size = 10MB # Automatic rotation of logfiles will
# happen after that much log output.
# 0 disables.
#log_truncate_on_rotation = off # If on, an existing log file with the
# same name as the new log file will be
# truncated rather than appended to.
# But such truncation only occurs on
# time-driven rotation, not on restarts
# or size-driven rotation. Default is
# off, meaning append to existing files
# in all cases.
# These are relevant when logging to syslog:
#syslog_facility = 'LOCAL0'
#syslog_ident = 'postgres'
#syslog_sequence_numbers = on
#syslog_split_messages = on
# This is only relevant when logging to eventlog (Windows):
# (change requires restart)
#event_source = 'PostgreSQL'
# - When to Log -
#log_min_messages = warning # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# info
# notice
# warning
# error
# log
# fatal
# panic
#log_min_error_statement = error # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# info
# notice
# warning
# error
# log
# fatal
# panic (effectively off)
#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements
# and their durations, > 0 logs only
# statements running at least this number
# of milliseconds
#log_min_duration_sample = -1 # -1 is disabled, 0 logs a sample of statements
# and their durations, > 0 logs only a sample of
# statements running at least this number
# of milliseconds;
# sample fraction is determined by log_statement_sample_rate
#log_statement_sample_rate = 1.0 # fraction of logged statements exceeding
# log_min_duration_sample to be logged;
# 1.0 logs all such statements, 0.0 never logs
#log_transaction_sample_rate = 0.0 # fraction of transactions whose statements
# are logged regardless of their duration; 1.0 logs all
# statements from all transactions, 0.0 never logs
# - What to Log -
#debug_print_parse = off
#debug_print_rewritten = off
#debug_print_plan = off
#debug_pretty_print = on
#log_autovacuum_min_duration = -1 # log autovacuum activity;
# -1 disables, 0 logs all actions and
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
#log_checkpoints = off
#log_connections = off
#log_disconnections = off
#log_duration = off
#log_error_verbosity = default # terse, default, or verbose messages
#log_hostname = off
log_line_prefix = '%m [%p] %q%u@%d ' # special values:
# %a = application name
# %u = user name
# %d = database name
# %r = remote host and port
# %h = remote host
# %b = backend type
# %p = process ID
# %P = process ID of parallel group leader
# %t = timestamp without milliseconds
# %m = timestamp with milliseconds
# %n = timestamp with milliseconds (as a Unix epoch)
# %Q = query ID (0 if none or not computed)
# %i = command tag
# %e = SQL state
# %c = session ID
# %l = session line number
# %s = session start timestamp
# %v = virtual transaction ID
# %x = transaction ID (0 if none)
# %q = stop here in non-session
# processes
# %% = '%'
# e.g. '<%u%%%d> '
#log_lock_waits = off # log lock waits >= deadlock_timeout
#log_recovery_conflict_waits = off # log standby recovery conflict waits
# >= deadlock_timeout
#log_parameter_max_length = -1 # when logging statements, limit logged
# bind-parameter values to N bytes;
# -1 means print in full, 0 disables
#log_parameter_max_length_on_error = 0 # when logging an error, limit logged
# bind-parameter values to N bytes;
# -1 means print in full, 0 disables
#log_statement = 'none' # none, ddl, mod, all
#log_replication_commands = off
#log_temp_files = -1 # log temporary files equal or larger
# than the specified size in kilobytes;
# -1 disables, 0 logs all temp files
log_timezone = 'Etc/UTC'
#------------------------------------------------------------------------------
# PROCESS TITLE
#------------------------------------------------------------------------------
cluster_name = '14/main' # added to process titles if nonempty
# (change requires restart)
#update_process_title = on
#------------------------------------------------------------------------------
# STATISTICS
#------------------------------------------------------------------------------
# - Query and Index Statistics Collector -
#track_activities = on
#track_activity_query_size = 1024 # (change requires restart)
#track_counts = on
#track_io_timing = off
#track_wal_io_timing = off
#track_functions = none # none, pl, all
stats_temp_directory = '/var/run/postgresql/14-main.pg_stat_tmp'
# - Monitoring -
#compute_query_id = auto
#log_statement_stats = off
#log_parser_stats = off
#log_planner_stats = off
#log_executor_stats = off
#------------------------------------------------------------------------------
# AUTOVACUUM
#------------------------------------------------------------------------------
#autovacuum = on # Enable autovacuum subprocess? 'on'
# requires track_counts to also be on.
#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
# (change requires restart)
#autovacuum_naptime = 1min # time between autovacuum runs
#autovacuum_vacuum_threshold = 50 # min number of row updates before
# vacuum
#autovacuum_vacuum_insert_threshold = 1000 # min number of row inserts
# before vacuum; -1 disables insert
# vacuums
#autovacuum_analyze_threshold = 50 # min number of row updates before
# analyze
#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
#autovacuum_vacuum_insert_scale_factor = 0.2 # fraction of inserts over table
# size before insert vacuum
#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
# (change requires restart)
#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
# before forced vacuum
# (change requires restart)
#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for
# autovacuum, in milliseconds;
# -1 means use vacuum_cost_delay
#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
# autovacuum, -1 means use
# vacuum_cost_limit
#------------------------------------------------------------------------------
# CLIENT CONNECTION DEFAULTS
#------------------------------------------------------------------------------
# - Statement Behavior -
#client_min_messages = notice # values in order of decreasing detail:
# debug5
# debug4
# debug3
# debug2
# debug1
# log
# notice
# warning
# error
#search_path = '"$user", public' # schema names
#row_security = on
#default_table_access_method = 'heap'
#default_tablespace = '' # a tablespace name, '' uses the default
#default_toast_compression = 'pglz' # 'pglz' or 'lz4'
#temp_tablespaces = '' # a list of tablespace names, '' uses
# only default tablespace
#check_function_bodies = on
#default_transaction_isolation = 'read committed'
#default_transaction_read_only = off
#default_transaction_deferrable = off
#session_replication_role = 'origin'
#statement_timeout = 0 # in milliseconds, 0 is disabled
#lock_timeout = 0 # in milliseconds, 0 is disabled
#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled
#idle_session_timeout = 0 # in milliseconds, 0 is disabled
#vacuum_freeze_table_age = 150000000
#vacuum_freeze_min_age = 50000000
#vacuum_failsafe_age = 1600000000
#vacuum_multixact_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000
#vacuum_multixact_failsafe_age = 1600000000
#bytea_output = 'hex' # hex, escape
#xmlbinary = 'base64'
#xmloption = 'content'
#gin_pending_list_limit = 4MB
# - Locale and Formatting -
datestyle = 'iso, mdy'
#intervalstyle = 'postgres'
timezone = 'Etc/UTC'
#timezone_abbreviations = 'Default' # Select the set of available time zone
# abbreviations. Currently, there are
# Default
# Australia (historical usage)
# India
# You can create your own file in
# share/timezonesets/.
#extra_float_digits = 1 # min -15, max 3; any value >0 actually
# selects precise output mode
#client_encoding = sql_ascii # actually, defaults to database
# encoding
# These settings are initialized by initdb, but they can be changed.
lc_messages = 'C.UTF-8' # locale for system error message
# strings
lc_monetary = 'C.UTF-8' # locale for monetary formatting
lc_numeric = 'C.UTF-8' # locale for number formatting
lc_time = 'C.UTF-8' # locale for time formatting
# default configuration for text search
default_text_search_config = 'pg_catalog.english'
# - Shared Library Preloading -
#local_preload_libraries = ''
#session_preload_libraries = ''
#shared_preload_libraries = '' # (change requires restart)
#jit_provider = 'llvmjit' # JIT library to use
# - Other Defaults -
#dynamic_library_path = '$libdir'
#extension_destdir = '' # prepend path when loading extensions
# and shared objects (added by Debian)
#gin_fuzzy_search_limit = 0
#------------------------------------------------------------------------------
# LOCK MANAGEMENT
#------------------------------------------------------------------------------
#deadlock_timeout = 1s
#max_locks_per_transaction = 64 # min 10
# (change requires restart)
#max_pred_locks_per_transaction = 64 # min 10
# (change requires restart)
#max_pred_locks_per_relation = -2 # negative values mean
# (max_pred_locks_per_transaction
# / -max_pred_locks_per_relation) - 1
#max_pred_locks_per_page = 2 # min 0
#------------------------------------------------------------------------------
# VERSION AND PLATFORM COMPATIBILITY
#------------------------------------------------------------------------------
# - Previous PostgreSQL Versions -
#array_nulls = on
#backslash_quote = safe_encoding # on, off, or safe_encoding
#escape_string_warning = on
#lo_compat_privileges = off
#quote_all_identifiers = off
#standard_conforming_strings = on
#synchronize_seqscans = on
# - Other Platforms and Clients -
#transform_null_equals = off
#------------------------------------------------------------------------------
# ERROR HANDLING
#------------------------------------------------------------------------------
#exit_on_error = off # terminate session on any error?
#restart_after_crash = on # reinitialize after backend crash?
#data_sync_retry = off # retry or panic on failure to fsync
# data?
# (change requires restart)
#recovery_init_sync_method = fsync # fsync, syncfs (Linux 5.8+)
#------------------------------------------------------------------------------
# CONFIG FILE INCLUDES
#------------------------------------------------------------------------------
# These options allow settings to be loaded from files other than the
# default postgresql.conf. Note that these are directives, not variable
# assignments, so they can usefully be given more than once.
include_dir = 'conf.d' # include files ending in '.conf' from
# a directory, e.g., 'conf.d'
#include_if_exists = '...' # include file only if it exists
#include = '...' # include file
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
# Add settings for extensions here

View File

@ -0,0 +1,69 @@
use {log::*, std::collections::HashSet};
#[derive(Debug)]
pub(crate) struct AccountsSelector {
pub accounts: HashSet<Vec<u8>>,
pub owners: HashSet<Vec<u8>>,
pub select_all_accounts: bool,
}
impl AccountsSelector {
pub fn default() -> Self {
AccountsSelector {
accounts: HashSet::default(),
owners: HashSet::default(),
select_all_accounts: true,
}
}
pub fn new(accounts: &[String], owners: &[String]) -> Self {
info!(
"Creating AccountsSelector from accounts: {:?}, owners: {:?}",
accounts, owners
);
let select_all_accounts = accounts.iter().any(|key| key == "*");
if select_all_accounts {
return AccountsSelector {
accounts: HashSet::default(),
owners: HashSet::default(),
select_all_accounts,
};
}
let accounts = accounts
.iter()
.map(|key| bs58::decode(key).into_vec().unwrap())
.collect();
let owners = owners
.iter()
.map(|key| bs58::decode(key).into_vec().unwrap())
.collect();
AccountsSelector {
accounts,
owners,
select_all_accounts,
}
}
pub fn is_account_selected(&self, account: &[u8], owner: &[u8]) -> bool {
self.select_all_accounts || self.accounts.contains(account) || self.owners.contains(owner)
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
#[test]
fn test_create_accounts_selector() {
AccountsSelector::new(
&["9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin".to_string()],
&[],
);
AccountsSelector::new(
&[],
&["9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin".to_string()],
);
}
}

View File

@ -0,0 +1,346 @@
use solana_measure::measure::Measure;
/// Main entry for the PostgreSQL plugin
use {
crate::{
accounts_selector::AccountsSelector,
postgres_client::{ParallelPostgresClient, PostgresClientBuilder},
},
bs58,
log::*,
serde_derive::{Deserialize, Serialize},
serde_json,
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
AccountsDbPlugin, AccountsDbPluginError, ReplicaAccountInfoVersions, Result, SlotStatus,
},
solana_metrics::*,
std::{fs::File, io::Read},
thiserror::Error,
};
#[derive(Default)]
pub struct AccountsDbPluginPostgres {
client: Option<ParallelPostgresClient>,
accounts_selector: Option<AccountsSelector>,
}
impl std::fmt::Debug for AccountsDbPluginPostgres {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct AccountsDbPluginPostgresConfig {
pub host: Option<String>,
pub user: Option<String>,
pub port: Option<u16>,
pub connection_str: Option<String>,
pub threads: Option<usize>,
pub batch_size: Option<usize>,
pub panic_on_db_errors: Option<bool>,
}
#[derive(Error, Debug)]
pub enum AccountsDbPluginPostgresError {
#[error("Error connecting to the backend data store. Error message: ({msg})")]
DataStoreConnectionError { msg: String },
#[error("Error preparing data store schema. Error message: ({msg})")]
DataSchemaError { msg: String },
#[error("Error preparing data store schema. Error message: ({msg})")]
ConfigurationError { msg: String },
}
impl AccountsDbPlugin for AccountsDbPluginPostgres {
fn name(&self) -> &'static str {
"AccountsDbPluginPostgres"
}
/// Do initialization for the PostgreSQL plugin.
///
/// # Format of the config file:
/// * The `accounts_selector` section allows the user to controls accounts selections.
/// "accounts_selector" : {
/// "accounts" : \["pubkey-1", "pubkey-2", ..., "pubkey-n"\],
/// }
/// or:
/// "accounts_selector" = {
/// "owners" : \["pubkey-1", "pubkey-2", ..., "pubkey-m"\]
/// }
/// Accounts either satisyfing the accounts condition or owners condition will be selected.
/// When only owners is specified,
/// all accounts belonging to the owners will be streamed.
/// The accounts field support wildcard to select all accounts:
/// "accounts_selector" : {
/// "accounts" : \["*"\],
/// }
/// * "host", optional, specifies the PostgreSQL server.
/// * "user", optional, specifies the PostgreSQL user.
/// * "port", optional, specifies the PostgreSQL server's port.
/// * "connection_str", optional, the custom PostgreSQL connection string.
/// Please refer to https://docs.rs/postgres/0.19.2/postgres/config/struct.Config.html for the connection configuration.
/// When `connection_str` is set, the values in "host", "user" and "port" are ignored. If `connection_str` is not given,
/// `host` and `user` must be given.
/// * "threads" optional, specifies the number of worker threads for the plugin. A thread
/// maintains a PostgreSQL connection to the server. The default is '10'.
/// * "batch_size" optional, specifies the batch size of bulk insert when the AccountsDb is created
/// from restoring a snapshot. The default is '10'.
/// * "panic_on_db_errors", optional, contols if to panic when there are errors replicating data to the
/// PostgreSQL database. The default is 'false'.
/// # Examples
///
/// {
/// "libpath": "/home/solana/target/release/libsolana_accountsdb_plugin_postgres.so",
/// "host": "host_foo",
/// "user": "solana",
/// "threads": 10,
/// "accounts_selector" : {
/// "owners" : ["9oT9R5ZyRovSVnt37QvVoBttGpNqR3J7unkb567NP8k3"]
/// }
/// }
fn on_load(&mut self, config_file: &str) -> Result<()> {
solana_logger::setup_with_default("info");
info!(
"Loading plugin {:?} from config_file {:?}",
self.name(),
config_file
);
let mut file = File::open(config_file)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let result: serde_json::Value = serde_json::from_str(&contents).unwrap();
self.accounts_selector = Some(Self::create_accounts_selector_from_config(&result));
let result: serde_json::Result<AccountsDbPluginPostgresConfig> =
serde_json::from_str(&contents);
match result {
Err(err) => {
return Err(AccountsDbPluginError::ConfigFileReadError {
msg: format!(
"The config file is not in the JSON format expected: {:?}",
err
),
})
}
Ok(config) => {
let client = PostgresClientBuilder::build_pararallel_postgres_client(&config)?;
self.client = Some(client);
}
}
Ok(())
}
fn on_unload(&mut self) {
info!("Unloading plugin: {:?}", self.name());
match &mut self.client {
None => {}
Some(client) => {
client.join().unwrap();
}
}
}
fn update_account(
&mut self,
account: ReplicaAccountInfoVersions,
slot: u64,
is_startup: bool,
) -> Result<()> {
let mut measure_all = Measure::start("accountsdb-plugin-postgres-update-account-main");
match account {
ReplicaAccountInfoVersions::V0_0_1(account) => {
let mut measure_select =
Measure::start("accountsdb-plugin-postgres-update-account-select");
if let Some(accounts_selector) = &self.accounts_selector {
if !accounts_selector.is_account_selected(account.pubkey, account.owner) {
return Ok(());
}
} else {
return Ok(());
}
measure_select.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-select-us",
measure_select.as_us() as usize,
100000,
100000
);
debug!(
"Updating account {:?} with owner {:?} at slot {:?} using account selector {:?}",
bs58::encode(account.pubkey).into_string(),
bs58::encode(account.owner).into_string(),
slot,
self.accounts_selector.as_ref().unwrap()
);
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database."
.to_string(),
},
)));
}
Some(client) => {
let mut measure_update =
Measure::start("accountsdb-plugin-postgres-update-account-client");
let result = { client.update_account(account, slot, is_startup) };
measure_update.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-client-us",
measure_update.as_us() as usize,
100000,
100000
);
if let Err(err) = result {
return Err(AccountsDbPluginError::AccountsUpdateError {
msg: format!("Failed to persist the update of account to the PostgreSQL database. Error: {:?}", err)
});
}
}
}
}
}
measure_all.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-main-us",
measure_all.as_us() as usize,
100000,
100000
);
Ok(())
}
fn update_slot_status(
&mut self,
slot: u64,
parent: Option<u64>,
status: SlotStatus,
) -> Result<()> {
info!("Updating slot {:?} at with status {:?}", slot, status);
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database.".to_string(),
},
)));
}
Some(client) => {
let result = client.update_slot_status(slot, parent, status);
if let Err(err) = result {
return Err(AccountsDbPluginError::SlotStatusUpdateError{
msg: format!("Failed to persist the update of slot to the PostgreSQL database. Error: {:?}", err)
});
}
}
}
Ok(())
}
fn notify_end_of_startup(&mut self) -> Result<()> {
info!("Notifying the end of startup for accounts notifications");
match &mut self.client {
None => {
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError {
msg: "There is no connection to the PostgreSQL database.".to_string(),
},
)));
}
Some(client) => {
let result = client.notify_end_of_startup();
if let Err(err) = result {
return Err(AccountsDbPluginError::SlotStatusUpdateError{
msg: format!("Failed to notify the end of startup for accounts notifications. Error: {:?}", err)
});
}
}
}
Ok(())
}
}
impl AccountsDbPluginPostgres {
fn create_accounts_selector_from_config(config: &serde_json::Value) -> AccountsSelector {
let accounts_selector = &config["accounts_selector"];
if accounts_selector.is_null() {
AccountsSelector::default()
} else {
let accounts = &accounts_selector["accounts"];
let accounts: Vec<String> = if accounts.is_array() {
accounts
.as_array()
.unwrap()
.iter()
.map(|val| val.as_str().unwrap().to_string())
.collect()
} else {
Vec::default()
};
let owners = &accounts_selector["owners"];
let owners: Vec<String> = if owners.is_array() {
owners
.as_array()
.unwrap()
.iter()
.map(|val| val.as_str().unwrap().to_string())
.collect()
} else {
Vec::default()
};
AccountsSelector::new(&accounts, &owners)
}
}
pub fn new() -> Self {
AccountsDbPluginPostgres {
client: None,
accounts_selector: None,
}
}
}
#[no_mangle]
#[allow(improper_ctypes_definitions)]
/// # Safety
///
/// This function returns the AccountsDbPluginPostgres pointer as trait AccountsDbPlugin.
pub unsafe extern "C" fn _create_plugin() -> *mut dyn AccountsDbPlugin {
let plugin = AccountsDbPluginPostgres::new();
let plugin: Box<dyn AccountsDbPlugin> = Box::new(plugin);
Box::into_raw(plugin)
}
#[cfg(test)]
pub(crate) mod tests {
use {super::*, serde_json};
#[test]
fn test_accounts_selector_from_config() {
let config = "{\"accounts_selector\" : { \
\"owners\" : [\"9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin\"] \
}}";
let config: serde_json::Value = serde_json::from_str(config).unwrap();
AccountsDbPluginPostgres::create_accounts_selector_from_config(&config);
}
}

View File

@ -0,0 +1,3 @@
pub mod accounts_selector;
pub mod accountsdb_plugin_postgres;
pub mod postgres_client;

View File

@ -0,0 +1,879 @@
#![allow(clippy::integer_arithmetic)]
/// A concurrent implementation for writing accounts into the PostgreSQL in parallel.
use {
crate::accountsdb_plugin_postgres::{
AccountsDbPluginPostgresConfig, AccountsDbPluginPostgresError,
},
chrono::Utc,
crossbeam_channel::{bounded, Receiver, RecvTimeoutError, Sender},
log::*,
postgres::{Client, NoTls, Statement},
solana_accountsdb_plugin_interface::accountsdb_plugin_interface::{
AccountsDbPluginError, ReplicaAccountInfo, SlotStatus,
},
solana_measure::measure::Measure,
solana_metrics::*,
solana_sdk::timing::AtomicInterval,
std::{
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
Arc, Mutex,
},
thread::{self, sleep, Builder, JoinHandle},
time::Duration,
},
tokio_postgres::types::ToSql,
};
/// The maximum asynchronous requests allowed in the channel to avoid excessive
/// memory usage. The downside -- calls after this threshold is reached can get blocked.
const MAX_ASYNC_REQUESTS: usize = 40960;
const DEFAULT_POSTGRES_PORT: u16 = 5432;
const DEFAULT_THREADS_COUNT: usize = 100;
const DEFAULT_ACCOUNTS_INSERT_BATCH_SIZE: usize = 10;
const ACCOUNT_COLUMN_COUNT: usize = 9;
const DEFAULT_PANIC_ON_DB_ERROR: bool = false;
struct PostgresSqlClientWrapper {
client: Client,
update_account_stmt: Statement,
bulk_account_insert_stmt: Statement,
update_slot_with_parent_stmt: Statement,
update_slot_without_parent_stmt: Statement,
}
pub struct SimplePostgresClient {
batch_size: usize,
pending_account_updates: Vec<DbAccountInfo>,
client: Mutex<PostgresSqlClientWrapper>,
}
struct PostgresClientWorker {
client: SimplePostgresClient,
/// Indicating if accounts notification during startup is done.
is_startup_done: bool,
}
impl Eq for DbAccountInfo {}
#[derive(Clone, PartialEq, Debug)]
pub struct DbAccountInfo {
pub pubkey: Vec<u8>,
pub lamports: i64,
pub owner: Vec<u8>,
pub executable: bool,
pub rent_epoch: i64,
pub data: Vec<u8>,
pub slot: i64,
pub write_version: i64,
}
pub(crate) fn abort() -> ! {
#[cfg(not(test))]
{
// standard error is usually redirected to a log file, cry for help on standard output as
// well
eprintln!("Validator process aborted. The validator log may contain further details");
std::process::exit(1);
}
#[cfg(test)]
panic!("process::exit(1) is intercepted for friendly test failure...");
}
impl DbAccountInfo {
fn new<T: ReadableAccountInfo>(account: &T, slot: u64) -> DbAccountInfo {
let data = account.data().to_vec();
Self {
pubkey: account.pubkey().to_vec(),
lamports: account.lamports() as i64,
owner: account.owner().to_vec(),
executable: account.executable(),
rent_epoch: account.rent_epoch() as i64,
data,
slot: slot as i64,
write_version: account.write_version(),
}
}
}
pub trait ReadableAccountInfo: Sized {
fn pubkey(&self) -> &[u8];
fn owner(&self) -> &[u8];
fn lamports(&self) -> i64;
fn executable(&self) -> bool;
fn rent_epoch(&self) -> i64;
fn data(&self) -> &[u8];
fn write_version(&self) -> i64;
}
impl ReadableAccountInfo for DbAccountInfo {
fn pubkey(&self) -> &[u8] {
&self.pubkey
}
fn owner(&self) -> &[u8] {
&self.owner
}
fn lamports(&self) -> i64 {
self.lamports
}
fn executable(&self) -> bool {
self.executable
}
fn rent_epoch(&self) -> i64 {
self.rent_epoch
}
fn data(&self) -> &[u8] {
&self.data
}
fn write_version(&self) -> i64 {
self.write_version
}
}
impl<'a> ReadableAccountInfo for ReplicaAccountInfo<'a> {
fn pubkey(&self) -> &[u8] {
self.pubkey
}
fn owner(&self) -> &[u8] {
self.owner
}
fn lamports(&self) -> i64 {
self.lamports as i64
}
fn executable(&self) -> bool {
self.executable
}
fn rent_epoch(&self) -> i64 {
self.rent_epoch as i64
}
fn data(&self) -> &[u8] {
self.data
}
fn write_version(&self) -> i64 {
self.write_version as i64
}
}
pub trait PostgresClient {
fn join(&mut self) -> thread::Result<()> {
Ok(())
}
fn update_account(
&mut self,
account: DbAccountInfo,
is_startup: bool,
) -> Result<(), AccountsDbPluginError>;
fn update_slot_status(
&mut self,
slot: u64,
parent: Option<u64>,
status: SlotStatus,
) -> Result<(), AccountsDbPluginError>;
fn notify_end_of_startup(&mut self) -> Result<(), AccountsDbPluginError>;
}
impl SimplePostgresClient {
fn connect_to_db(
config: &AccountsDbPluginPostgresConfig,
) -> Result<Client, AccountsDbPluginError> {
let port = config.port.unwrap_or(DEFAULT_POSTGRES_PORT);
let connection_str = if let Some(connection_str) = &config.connection_str {
connection_str.clone()
} else {
if config.host.is_none() || config.user.is_none() {
let msg = format!(
"\"connection_str\": {:?}, or \"host\": {:?} \"user\": {:?} must be specified",
config.connection_str, config.host, config.user
);
return Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::ConfigurationError { msg },
)));
}
format!(
"host={} user={} port={}",
config.host.as_ref().unwrap(),
config.user.as_ref().unwrap(),
port
)
};
match Client::connect(&connection_str, NoTls) {
Err(err) => {
let msg = format!(
"Error in connecting to the PostgreSQL database: {:?} connection_str: {:?}",
err, connection_str
);
error!("{}", msg);
Err(AccountsDbPluginError::Custom(Box::new(
AccountsDbPluginPostgresError::DataStoreConnectionError { msg },
)))
}
Ok(client) => Ok(client),
}
}
fn build_bulk_account_insert_statement(
client: &mut Client,
config: &AccountsDbPluginPostgresConfig,
) -> Result<Statement, AccountsDbPluginError> {
let batch_size = config
.batch_size
.unwrap_or(DEFAULT_ACCOUNTS_INSERT_BATCH_SIZE);
let mut stmt = String::from("INSERT INTO account AS acct (pubkey, slot, owner, lamports, executable, rent_epoch, data, write_version, updated_on) VALUES");
for j in 0..batch_size {
let row = j * ACCOUNT_COLUMN_COUNT;
let val_str = format!(
"(${}, ${}, ${}, ${}, ${}, ${}, ${}, ${}, ${})",
row + 1,
row + 2,
row + 3,
row + 4,
row + 5,
row + 6,
row + 7,
row + 8,
row + 9,
);
if j == 0 {
stmt = format!("{} {}", &stmt, val_str);
} else {
stmt = format!("{}, {}", &stmt, val_str);
}
}
let handle_conflict = "ON CONFLICT (pubkey) DO UPDATE SET slot=excluded.slot, owner=excluded.owner, lamports=excluded.lamports, executable=excluded.executable, rent_epoch=excluded.rent_epoch, \
data=excluded.data, write_version=excluded.write_version, updated_on=excluded.updated_on WHERE acct.slot < excluded.slot OR (\
acct.slot = excluded.slot AND acct.write_version < excluded.write_version)";
stmt = format!("{} {}", stmt, handle_conflict);
info!("{}", stmt);
let bulk_stmt = client.prepare(&stmt);
match bulk_stmt {
Err(err) => {
return Err(AccountsDbPluginError::Custom(Box::new(AccountsDbPluginPostgresError::DataSchemaError {
msg: format!(
"Error in preparing for the accounts update PostgreSQL database: {} host: {:?} user: {:?} config: {:?}",
err, config.host, config.user, config
),
})));
}
Ok(update_account_stmt) => Ok(update_account_stmt),
}
}
fn build_single_account_upsert_statement(
client: &mut Client,
config: &AccountsDbPluginPostgresConfig,
) -> Result<Statement, AccountsDbPluginError> {
let stmt = "INSERT INTO account AS acct (pubkey, slot, owner, lamports, executable, rent_epoch, data, write_version, updated_on) \
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) \
ON CONFLICT (pubkey) DO UPDATE SET slot=excluded.slot, owner=excluded.owner, lamports=excluded.lamports, executable=excluded.executable, rent_epoch=excluded.rent_epoch, \
data=excluded.data, write_version=excluded.write_version, updated_on=excluded.updated_on WHERE acct.slot < excluded.slot OR (\
acct.slot = excluded.slot AND acct.write_version < excluded.write_version)";
let stmt = client.prepare(stmt);
match stmt {
Err(err) => {
return Err(AccountsDbPluginError::Custom(Box::new(AccountsDbPluginPostgresError::DataSchemaError {
msg: format!(
"Error in preparing for the accounts update PostgreSQL database: {} host: {:?} user: {:?} config: {:?}",
err, config.host, config.user, config
),
})));
}
Ok(update_account_stmt) => Ok(update_account_stmt),
}
}
fn build_slot_upsert_statement_with_parent(
client: &mut Client,
config: &AccountsDbPluginPostgresConfig,
) -> Result<Statement, AccountsDbPluginError> {
let stmt = "INSERT INTO slot (slot, parent, status, updated_on) \
VALUES ($1, $2, $3, $4) \
ON CONFLICT (slot) DO UPDATE SET parent=excluded.parent, status=excluded.status, updated_on=excluded.updated_on";
let stmt = client.prepare(stmt);
match stmt {
Err(err) => {
return Err(AccountsDbPluginError::Custom(Box::new(AccountsDbPluginPostgresError::DataSchemaError {
msg: format!(
"Error in preparing for the slot update PostgreSQL database: {} host: {:?} user: {:?} config: {:?}",
err, config.host, config.user, config
),
})));
}
Ok(stmt) => Ok(stmt),
}
}
fn build_slot_upsert_statement_without_parent(
client: &mut Client,
config: &AccountsDbPluginPostgresConfig,
) -> Result<Statement, AccountsDbPluginError> {
let stmt = "INSERT INTO slot (slot, status, updated_on) \
VALUES ($1, $2, $3) \
ON CONFLICT (slot) DO UPDATE SET status=excluded.status, updated_on=excluded.updated_on";
let stmt = client.prepare(stmt);
match stmt {
Err(err) => {
return Err(AccountsDbPluginError::Custom(Box::new(AccountsDbPluginPostgresError::DataSchemaError {
msg: format!(
"Error in preparing for the slot update PostgreSQL database: {} host: {:?} user: {:?} config: {:?}",
err, config.host, config.user, config
),
})));
}
Ok(stmt) => Ok(stmt),
}
}
/// Internal function for updating or inserting a single account
fn upsert_account_internal(
account: &DbAccountInfo,
statement: &Statement,
client: &mut Client,
) -> Result<(), AccountsDbPluginError> {
let lamports = account.lamports() as i64;
let rent_epoch = account.rent_epoch() as i64;
let updated_on = Utc::now().naive_utc();
let result = client.query(
statement,
&[
&account.pubkey(),
&account.slot,
&account.owner(),
&lamports,
&account.executable(),
&rent_epoch,
&account.data(),
&account.write_version(),
&updated_on,
],
);
if let Err(err) = result {
let msg = format!(
"Failed to persist the update of account to the PostgreSQL database. Error: {:?}",
err
);
error!("{}", msg);
return Err(AccountsDbPluginError::AccountsUpdateError { msg });
}
Ok(())
}
/// Update or insert a single account
fn upsert_account(&mut self, account: &DbAccountInfo) -> Result<(), AccountsDbPluginError> {
let client = self.client.get_mut().unwrap();
let statement = &client.update_account_stmt;
let client = &mut client.client;
Self::upsert_account_internal(account, statement, client)
}
/// Insert accounts in batch to reduce network overhead
fn insert_accounts_in_batch(
&mut self,
account: DbAccountInfo,
) -> Result<(), AccountsDbPluginError> {
self.pending_account_updates.push(account);
if self.pending_account_updates.len() == self.batch_size {
let mut measure = Measure::start("accountsdb-plugin-postgres-prepare-values");
let mut values: Vec<&(dyn ToSql + Sync)> =
Vec::with_capacity(self.batch_size * ACCOUNT_COLUMN_COUNT);
let updated_on = Utc::now().naive_utc();
for j in 0..self.batch_size {
let account = &self.pending_account_updates[j];
values.push(&account.pubkey);
values.push(&account.slot);
values.push(&account.owner);
values.push(&account.lamports);
values.push(&account.executable);
values.push(&account.rent_epoch);
values.push(&account.data);
values.push(&account.write_version);
values.push(&updated_on);
}
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-prepare-values-us",
measure.as_us() as usize,
10000,
10000
);
let mut measure = Measure::start("accountsdb-plugin-postgres-update-account");
let client = self.client.get_mut().unwrap();
let result = client
.client
.query(&client.bulk_account_insert_stmt, &values);
self.pending_account_updates.clear();
if let Err(err) = result {
let msg = format!(
"Failed to persist the update of account to the PostgreSQL database. Error: {:?}",
err
);
error!("{}", msg);
return Err(AccountsDbPluginError::AccountsUpdateError { msg });
}
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-us",
measure.as_us() as usize,
10000,
10000
);
inc_new_counter_debug!(
"accountsdb-plugin-postgres-update-account-count",
self.batch_size,
10000,
10000
);
}
Ok(())
}
/// Flush any left over accounts in batch which are not processed in the last batch
fn flush_buffered_writes(&mut self) -> Result<(), AccountsDbPluginError> {
if self.pending_account_updates.is_empty() {
return Ok(());
}
let client = self.client.get_mut().unwrap();
let statement = &client.update_account_stmt;
let client = &mut client.client;
for account in self.pending_account_updates.drain(..) {
Self::upsert_account_internal(&account, statement, client)?;
}
Ok(())
}
pub fn new(config: &AccountsDbPluginPostgresConfig) -> Result<Self, AccountsDbPluginError> {
info!("Creating SimplePostgresClient...");
let mut client = Self::connect_to_db(config)?;
let bulk_account_insert_stmt =
Self::build_bulk_account_insert_statement(&mut client, config)?;
let update_account_stmt = Self::build_single_account_upsert_statement(&mut client, config)?;
let update_slot_with_parent_stmt =
Self::build_slot_upsert_statement_with_parent(&mut client, config)?;
let update_slot_without_parent_stmt =
Self::build_slot_upsert_statement_without_parent(&mut client, config)?;
let batch_size = config
.batch_size
.unwrap_or(DEFAULT_ACCOUNTS_INSERT_BATCH_SIZE);
info!("Created SimplePostgresClient.");
Ok(Self {
batch_size,
pending_account_updates: Vec::with_capacity(batch_size),
client: Mutex::new(PostgresSqlClientWrapper {
client,
update_account_stmt,
bulk_account_insert_stmt,
update_slot_with_parent_stmt,
update_slot_without_parent_stmt,
}),
})
}
}
impl PostgresClient for SimplePostgresClient {
fn update_account(
&mut self,
account: DbAccountInfo,
is_startup: bool,
) -> Result<(), AccountsDbPluginError> {
trace!(
"Updating account {} with owner {} at slot {}",
bs58::encode(account.pubkey()).into_string(),
bs58::encode(account.owner()).into_string(),
account.slot,
);
if !is_startup {
return self.upsert_account(&account);
}
self.insert_accounts_in_batch(account)
}
fn update_slot_status(
&mut self,
slot: u64,
parent: Option<u64>,
status: SlotStatus,
) -> Result<(), AccountsDbPluginError> {
info!("Updating slot {:?} at with status {:?}", slot, status);
let slot = slot as i64; // postgres only supports i64
let parent = parent.map(|parent| parent as i64);
let updated_on = Utc::now().naive_utc();
let status_str = status.as_str();
let client = self.client.get_mut().unwrap();
let result = match parent {
Some(parent) => client.client.execute(
&client.update_slot_with_parent_stmt,
&[&slot, &parent, &status_str, &updated_on],
),
None => client.client.execute(
&client.update_slot_without_parent_stmt,
&[&slot, &status_str, &updated_on],
),
};
match result {
Err(err) => {
let msg = format!(
"Failed to persist the update of slot to the PostgreSQL database. Error: {:?}",
err
);
error!("{:?}", msg);
return Err(AccountsDbPluginError::SlotStatusUpdateError { msg });
}
Ok(rows) => {
assert_eq!(1, rows, "Expected one rows to be updated a time");
}
}
Ok(())
}
fn notify_end_of_startup(&mut self) -> Result<(), AccountsDbPluginError> {
self.flush_buffered_writes()
}
}
struct UpdateAccountRequest {
account: DbAccountInfo,
is_startup: bool,
}
struct UpdateSlotRequest {
slot: u64,
parent: Option<u64>,
slot_status: SlotStatus,
}
enum DbWorkItem {
UpdateAccount(UpdateAccountRequest),
UpdateSlot(UpdateSlotRequest),
}
impl PostgresClientWorker {
fn new(config: AccountsDbPluginPostgresConfig) -> Result<Self, AccountsDbPluginError> {
let result = SimplePostgresClient::new(&config);
match result {
Ok(client) => Ok(PostgresClientWorker {
client,
is_startup_done: false,
}),
Err(err) => {
error!("Error in creating SimplePostgresClient: {}", err);
Err(err)
}
}
}
fn do_work(
&mut self,
receiver: Receiver<DbWorkItem>,
exit_worker: Arc<AtomicBool>,
is_startup_done: Arc<AtomicBool>,
startup_done_count: Arc<AtomicUsize>,
panic_on_db_errors: bool,
) -> Result<(), AccountsDbPluginError> {
while !exit_worker.load(Ordering::Relaxed) {
let mut measure = Measure::start("accountsdb-plugin-postgres-worker-recv");
let work = receiver.recv_timeout(Duration::from_millis(500));
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-postgres-worker-recv-us",
measure.as_us() as usize,
100000,
100000
);
match work {
Ok(work) => match work {
DbWorkItem::UpdateAccount(request) => {
if let Err(err) = self
.client
.update_account(request.account, request.is_startup)
{
error!("Failed to update account: ({})", err);
if panic_on_db_errors {
abort();
}
}
}
DbWorkItem::UpdateSlot(request) => {
if let Err(err) = self.client.update_slot_status(
request.slot,
request.parent,
request.slot_status,
) {
error!("Failed to update slot: ({})", err);
if panic_on_db_errors {
abort();
}
}
}
},
Err(err) => match err {
RecvTimeoutError::Timeout => {
if !self.is_startup_done && is_startup_done.load(Ordering::Relaxed) {
if let Err(err) = self.client.notify_end_of_startup() {
error!("Error in notifying end of startup: ({})", err);
if panic_on_db_errors {
abort();
}
}
self.is_startup_done = true;
startup_done_count.fetch_add(1, Ordering::Relaxed);
}
continue;
}
_ => {
error!("Error in receiving the item {:?}", err);
if panic_on_db_errors {
abort();
}
break;
}
},
}
}
Ok(())
}
}
pub struct ParallelPostgresClient {
workers: Vec<JoinHandle<Result<(), AccountsDbPluginError>>>,
exit_worker: Arc<AtomicBool>,
is_startup_done: Arc<AtomicBool>,
startup_done_count: Arc<AtomicUsize>,
initialized_worker_count: Arc<AtomicUsize>,
sender: Sender<DbWorkItem>,
last_report: AtomicInterval,
}
impl ParallelPostgresClient {
pub fn new(config: &AccountsDbPluginPostgresConfig) -> Result<Self, AccountsDbPluginError> {
info!("Creating ParallelPostgresClient...");
let (sender, receiver) = bounded(MAX_ASYNC_REQUESTS);
let exit_worker = Arc::new(AtomicBool::new(false));
let mut workers = Vec::default();
let is_startup_done = Arc::new(AtomicBool::new(false));
let startup_done_count = Arc::new(AtomicUsize::new(0));
let worker_count = config.threads.unwrap_or(DEFAULT_THREADS_COUNT);
let initialized_worker_count = Arc::new(AtomicUsize::new(0));
for i in 0..worker_count {
let cloned_receiver = receiver.clone();
let exit_clone = exit_worker.clone();
let is_startup_done_clone = is_startup_done.clone();
let startup_done_count_clone = startup_done_count.clone();
let initialized_worker_count_clone = initialized_worker_count.clone();
let config = config.clone();
let worker = Builder::new()
.name(format!("worker-{}", i))
.spawn(move || -> Result<(), AccountsDbPluginError> {
let panic_on_db_errors = *config
.panic_on_db_errors
.as_ref()
.unwrap_or(&DEFAULT_PANIC_ON_DB_ERROR);
let result = PostgresClientWorker::new(config);
match result {
Ok(mut worker) => {
initialized_worker_count_clone.fetch_add(1, Ordering::Relaxed);
worker.do_work(
cloned_receiver,
exit_clone,
is_startup_done_clone,
startup_done_count_clone,
panic_on_db_errors,
)?;
Ok(())
}
Err(err) => {
error!("Error when making connection to database: ({})", err);
if panic_on_db_errors {
abort();
}
Err(err)
}
}
})
.unwrap();
workers.push(worker);
}
info!("Created ParallelPostgresClient.");
Ok(Self {
last_report: AtomicInterval::default(),
workers,
exit_worker,
is_startup_done,
startup_done_count,
initialized_worker_count,
sender,
})
}
pub fn join(&mut self) -> thread::Result<()> {
self.exit_worker.store(true, Ordering::Relaxed);
while !self.workers.is_empty() {
let worker = self.workers.pop();
if worker.is_none() {
break;
}
let worker = worker.unwrap();
let result = worker.join().unwrap();
if result.is_err() {
error!("The worker thread has failed: {:?}", result);
}
}
Ok(())
}
pub fn update_account(
&mut self,
account: &ReplicaAccountInfo,
slot: u64,
is_startup: bool,
) -> Result<(), AccountsDbPluginError> {
if self.last_report.should_update(30000) {
datapoint_debug!(
"postgres-plugin-stats",
("message-queue-length", self.sender.len() as i64, i64),
);
}
let mut measure = Measure::start("accountsdb-plugin-posgres-create-work-item");
let wrk_item = DbWorkItem::UpdateAccount(UpdateAccountRequest {
account: DbAccountInfo::new(account, slot),
is_startup,
});
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-posgres-create-work-item-us",
measure.as_us() as usize,
100000,
100000
);
let mut measure = Measure::start("accountsdb-plugin-posgres-send-msg");
if let Err(err) = self.sender.send(wrk_item) {
return Err(AccountsDbPluginError::AccountsUpdateError {
msg: format!(
"Failed to update the account {:?}, error: {:?}",
bs58::encode(account.pubkey()).into_string(),
err
),
});
}
measure.stop();
inc_new_counter_debug!(
"accountsdb-plugin-posgres-send-msg-us",
measure.as_us() as usize,
100000,
100000
);
Ok(())
}
pub fn update_slot_status(
&mut self,
slot: u64,
parent: Option<u64>,
status: SlotStatus,
) -> Result<(), AccountsDbPluginError> {
if let Err(err) = self.sender.send(DbWorkItem::UpdateSlot(UpdateSlotRequest {
slot,
parent,
slot_status: status,
})) {
return Err(AccountsDbPluginError::SlotStatusUpdateError {
msg: format!("Failed to update the slot {:?}, error: {:?}", slot, err),
});
}
Ok(())
}
pub fn notify_end_of_startup(&mut self) -> Result<(), AccountsDbPluginError> {
info!("Notifying the end of startup");
// Ensure all items in the queue has been received by the workers
while !self.sender.is_empty() {
sleep(Duration::from_millis(100));
}
self.is_startup_done.store(true, Ordering::Relaxed);
// Wait for all worker threads to be done with flushing
while self.startup_done_count.load(Ordering::Relaxed)
!= self.initialized_worker_count.load(Ordering::Relaxed)
{
info!(
"Startup done count: {}, good worker thread count: {}",
self.startup_done_count.load(Ordering::Relaxed),
self.initialized_worker_count.load(Ordering::Relaxed)
);
sleep(Duration::from_millis(100));
}
info!("Done with notifying the end of startup");
Ok(())
}
}
pub struct PostgresClientBuilder {}
impl PostgresClientBuilder {
pub fn build_pararallel_postgres_client(
config: &AccountsDbPluginPostgresConfig,
) -> Result<ParallelPostgresClient, AccountsDbPluginError> {
ParallelPostgresClient::new(config)
}
pub fn build_simple_postgres_client(
config: &AccountsDbPluginPostgresConfig,
) -> Result<SimplePostgresClient, AccountsDbPluginError> {
SimplePostgresClient::new(config)
}
}

View File

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

View File

@ -4,11 +4,7 @@ use crossbeam_channel::unbounded;
use log::*;
use rand::{thread_rng, Rng};
use rayon::prelude::*;
use solana_core::{
banking_stage::{create_test_recorder, BankingStage},
poh_recorder::PohRecorder,
poh_recorder::WorkingBankEntry,
};
use solana_core::banking_stage::BankingStage;
use solana_gossip::{cluster_info::ClusterInfo, cluster_info::Node};
use solana_ledger::{
blockstore::Blockstore,
@ -17,8 +13,10 @@ use solana_ledger::{
};
use solana_measure::measure::Measure;
use solana_perf::packet::to_packets_chunked;
use solana_poh::poh_recorder::{create_test_recorder, PohRecorder, WorkingBankEntry};
use solana_runtime::{
accounts_background_service::AbsRequestSender, bank::Bank, bank_forks::BankForks,
cost_model::CostModel,
};
use solana_sdk::{
hash::Hash,
@ -28,8 +26,9 @@ use solana_sdk::{
timing::{duration_as_us, timestamp},
transaction::Transaction,
};
use solana_streamer::socket::SocketAddrSpace;
use std::{
sync::{atomic::Ordering, mpsc::Receiver, Arc, Mutex},
sync::{atomic::Ordering, mpsc::Receiver, Arc, Mutex, RwLock},
thread::sleep,
time::{Duration, Instant},
};
@ -77,7 +76,7 @@ fn make_accounts_txs(
.into_par_iter()
.map(|_| {
let mut new = dummy.clone();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
if !same_payer {
new.message.account_keys[0] = solana_sdk::pubkey::new_rand();
}
@ -168,6 +167,7 @@ fn main() {
let (verified_sender, verified_receiver) = unbounded();
let (vote_sender, vote_receiver) = unbounded();
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
let (replay_vote_sender, _replay_vote_receiver) = unbounded();
let bank0 = Bank::new(&genesis_config);
let mut bank_forks = BankForks::new(bank0);
@ -188,7 +188,7 @@ fn main() {
genesis_config.hash(),
);
// Ignore any pesky duplicate signature errors in the case we are using single-payer
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
fund.signatures = vec![Signature::new(&sig[0..64])];
let x = bank.process_transaction(&fund);
x.unwrap();
@ -198,7 +198,7 @@ fn main() {
if !skip_sanity {
//sanity check, make sure all the transactions can execute sequentially
transactions.iter().for_each(|tx| {
let res = bank.process_transaction(&tx);
let res = bank.process_transaction(tx);
assert!(res.is_ok(), "sanity test transactions error: {:?}", res);
});
bank.clear_signatures();
@ -218,15 +218,21 @@ fn main() {
);
let (exit, poh_recorder, poh_service, signal_receiver) =
create_test_recorder(&bank, &blockstore, None);
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
let cluster_info = ClusterInfo::new(
Node::new_localhost().info,
Arc::new(Keypair::new()),
SocketAddrSpace::Unspecified,
);
let cluster_info = Arc::new(cluster_info);
let banking_stage = BankingStage::new(
&cluster_info,
&poh_recorder,
verified_receiver,
tpu_vote_receiver,
vote_receiver,
None,
replay_vote_sender,
Arc::new(RwLock::new(CostModel::default())),
);
poh_recorder.lock().unwrap().set_bank(&bank);
@ -354,7 +360,7 @@ fn main() {
if bank.slot() > 0 && bank.slot() % 16 == 0 {
for tx in transactions.iter_mut() {
tx.message.recent_blockhash = bank.last_blockhash();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
tx.signatures[0] = Signature::new(&sig[0..64]);
}
verified = to_packets_chunked(&transactions.clone(), packets_per_chunk);
@ -379,6 +385,7 @@ fn main() {
);
drop(verified_sender);
drop(tpu_vote_sender);
drop(vote_sender);
exit.store(true, Ordering::Relaxed);
banking_stage.join().unwrap();

View File

@ -1,6 +1,6 @@
[package]
name = "solana-banks-client"
version = "1.7.0"
version = "1.8.3"
description = "Solana banks client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@ -11,20 +11,20 @@ edition = "2018"
[dependencies]
bincode = "1.3.1"
borsh = "0.8.1"
borsh-derive = "0.8.1"
borsh = "0.9.0"
borsh-derive = "0.9.0"
futures = "0.3"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "=1.7.0" }
solana-program = { path = "../sdk/program", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-banks-interface = { path = "../banks-interface", version = "=1.8.3" }
solana-program = { path = "../sdk/program", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
tarpc = { version = "0.24.1", features = ["full"] }
tokio = { version = "1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }
[dev-dependencies]
solana-runtime = { path = "../runtime", version = "=1.7.0" }
solana-banks-server = { path = "../banks-server", version = "=1.7.0" }
solana-runtime = { path = "../runtime", version = "=1.8.3" }
solana-banks-server = { path = "../banks-server", version = "=1.8.3" }
[lib]
crate-type = ["lib"]

View File

@ -10,8 +10,14 @@ use futures::{future::join_all, Future, FutureExt};
pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus};
use solana_banks_interface::{BanksRequest, BanksResponse};
use solana_program::{
clock::Slot, fee_calculator::FeeCalculator, hash::Hash, program_pack::Pack, pubkey::Pubkey,
rent::Rent, sysvar,
clock::Clock,
clock::Slot,
fee_calculator::FeeCalculator,
hash::Hash,
program_pack::Pack,
pubkey::Pubkey,
rent::Rent,
sysvar::{self, Sysvar},
};
use solana_sdk::{
account::{from_account, Account},
@ -63,7 +69,7 @@ impl BanksClient {
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, Slot)>> + '_ {
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, u64)>> + '_ {
self.inner
.get_fees_with_commitment_and_context(ctx, commitment)
}
@ -85,6 +91,14 @@ impl BanksClient {
self.inner.get_slot_with_context(ctx, commitment)
}
pub fn get_block_height_with_context(
&mut self,
ctx: Context,
commitment: CommitmentLevel,
) -> impl Future<Output = io::Result<Slot>> + '_ {
self.inner.get_block_height_with_context(ctx, commitment)
}
pub fn process_transaction_with_commitment_and_context(
&mut self,
ctx: Context,
@ -115,24 +129,39 @@ impl BanksClient {
self.send_transaction_with_context(context::current(), transaction)
}
/// Return the cluster clock
pub fn get_clock(&mut self) -> impl Future<Output = io::Result<Clock>> + '_ {
self.get_account(sysvar::clock::id()).map(|result| {
let clock_sysvar = result?
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Clock sysvar not present"))?;
from_account::<Clock, _>(&clock_sysvar).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "Failed to deserialize Clock sysvar")
})
})
}
/// 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)>> + '_ {
) -> impl Future<Output = io::Result<(FeeCalculator, Hash, u64)>> + '_ {
self.get_fees_with_commitment_and_context(context::current(), CommitmentLevel::default())
}
/// Return the cluster Sysvar
pub fn get_sysvar<T: Sysvar>(&mut self) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(T::id()).map(|result| {
let sysvar = result?
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Sysvar not present"))?;
from_account::<T, _>(&sysvar)
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to deserialize sysvar"))
})
}
/// 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")
})
})
self.get_sysvar::<Rent>()
}
/// Return a recent, rooted blockhash from the server. The cluster will only accept
@ -192,12 +221,18 @@ impl BanksClient {
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.
/// Return the most recent rooted slot. All transactions at or below this slot
/// are said to be finalized. The cluster will not fork to a higher slot.
pub fn get_root_slot(&mut self) -> impl Future<Output = io::Result<Slot>> + '_ {
self.get_slot_with_context(context::current(), CommitmentLevel::default())
}
/// Return the most recent rooted block height. All transactions at or below this height
/// are said to be finalized. The cluster will not fork to a higher block height.
pub fn get_root_block_height(&mut self) -> impl Future<Output = io::Result<Slot>> + '_ {
self.get_block_height_with_context(context::current(), CommitmentLevel::default())
}
/// 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(
@ -350,7 +385,9 @@ mod tests {
let message = Message::new(&[instruction], Some(&mint_pubkey));
Runtime::new()?.block_on(async {
let client_transport = start_local_server(bank_forks, block_commitment_cache).await;
let client_transport =
start_local_server(bank_forks, block_commitment_cache, Duration::from_millis(1))
.await;
let mut banks_client = start_client(client_transport).await?;
let recent_blockhash = banks_client.get_recent_blockhash().await?;
@ -377,13 +414,15 @@ mod tests {
let mint_pubkey = &genesis.mint_keypair.pubkey();
let bob_pubkey = solana_sdk::pubkey::new_rand();
let instruction = system_instruction::transfer(&mint_pubkey, &bob_pubkey, 1);
let message = Message::new(&[instruction], Some(&mint_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, block_commitment_cache).await;
let client_transport =
start_local_server(bank_forks, block_commitment_cache, Duration::from_millis(1))
.await;
let mut banks_client = start_client(client_transport).await?;
let (_, recent_blockhash, last_valid_slot) = banks_client.get_fees().await?;
let (_, recent_blockhash, last_valid_block_height) = banks_client.get_fees().await?;
let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash);
let signature = transaction.signatures[0];
banks_client.send_transaction(transaction).await?;
@ -391,8 +430,8 @@ mod tests {
let mut status = banks_client.get_transaction_status(signature).await?;
while status.is_none() {
let root_slot = banks_client.get_root_slot().await?;
if root_slot > last_valid_slot {
let root_block_height = banks_client.get_root_block_height().await?;
if root_block_height > last_valid_block_height {
break;
}
sleep(Duration::from_millis(100)).await;

View File

@ -1,6 +1,6 @@
[package]
name = "solana-banks-interface"
version = "1.7.0"
version = "1.8.3"
description = "Solana banks RPC interface"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@ -12,7 +12,7 @@ edition = "2018"
[dependencies]
mio = "0.7.6"
serde = { version = "1.0.122", features = ["derive"] }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
tarpc = { version = "0.24.1", features = ["full"] }
[dev-dependencies]

View File

@ -34,6 +34,7 @@ pub trait Banks {
async fn get_transaction_status_with_context(signature: Signature)
-> Option<TransactionStatus>;
async fn get_slot_with_context(commitment: CommitmentLevel) -> Slot;
async fn get_block_height_with_context(commitment: CommitmentLevel) -> u64;
async fn process_transaction_with_commitment_and_context(
transaction: Transaction,
commitment: CommitmentLevel,

View File

@ -1,6 +1,6 @@
[package]
name = "solana-banks-server"
version = "1.7.0"
version = "1.8.3"
description = "Solana banks server"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@ -14,10 +14,10 @@ bincode = "1.3.1"
futures = "0.3"
log = "0.4.11"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "=1.7.0" }
solana-runtime = { path = "../runtime", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-metrics = { path = "../metrics", version = "=1.7.0" }
solana-banks-interface = { path = "../banks-interface", version = "=1.8.3" }
solana-runtime = { path = "../runtime", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
solana-metrics = { path = "../metrics", version = "=1.8.3" }
tarpc = { version = "0.24.1", features = ["full"] }
tokio = { version = "1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }

View File

@ -12,6 +12,7 @@ use solana_sdk::{
account::Account,
clock::Slot,
commitment_config::CommitmentLevel,
feature_set::FeatureSet,
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
@ -43,6 +44,7 @@ struct BanksServer {
bank_forks: Arc<RwLock<BankForks>>,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
transaction_sender: Sender<TransactionInfo>,
poll_signature_status_sleep_duration: Duration,
}
impl BanksServer {
@ -54,11 +56,13 @@ impl BanksServer {
bank_forks: Arc<RwLock<BankForks>>,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
transaction_sender: Sender<TransactionInfo>,
poll_signature_status_sleep_duration: Duration,
) -> Self {
Self {
bank_forks,
block_commitment_cache,
transaction_sender,
poll_signature_status_sleep_duration,
}
}
@ -81,6 +85,7 @@ impl BanksServer {
fn new_loopback(
bank_forks: Arc<RwLock<BankForks>>,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
poll_signature_status_sleep_duration: Duration,
) -> Self {
let (transaction_sender, transaction_receiver) = channel();
let bank = bank_forks.read().unwrap().working_bank();
@ -95,7 +100,12 @@ impl BanksServer {
.name("solana-bank-forks-client".to_string())
.spawn(move || Self::run(server_bank_forks, transaction_receiver))
.unwrap();
Self::new(bank_forks, block_commitment_cache, transaction_sender)
Self::new(
bank_forks,
block_commitment_cache,
transaction_sender,
poll_signature_status_sleep_duration,
)
}
fn slot(&self, commitment: CommitmentLevel) -> Slot {
@ -113,16 +123,16 @@ impl BanksServer {
self,
signature: &Signature,
blockhash: &Hash,
last_valid_slot: Slot,
last_valid_block_height: u64,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>> {
let mut status = self
.bank(commitment)
.get_signature_status_with_blockhash(signature, blockhash);
while status.is_none() {
sleep(Duration::from_millis(200)).await;
sleep(self.poll_signature_status_sleep_duration).await;
let bank = self.bank(commitment);
if bank.slot() > last_valid_slot {
if bank.block_height() > last_valid_block_height {
break;
}
status = bank.get_signature_status_with_blockhash(signature, blockhash);
@ -131,10 +141,13 @@ impl BanksServer {
}
}
fn verify_transaction(transaction: &Transaction) -> transaction::Result<()> {
fn verify_transaction(
transaction: &Transaction,
feature_set: &Arc<FeatureSet>,
) -> transaction::Result<()> {
if let Err(err) = transaction.verify() {
Err(err)
} else if let Err(err) = transaction.verify_precompiles() {
} else if let Err(err) = transaction.verify_precompiles(feature_set) {
Err(err)
} else {
Ok(())
@ -145,16 +158,19 @@ fn verify_transaction(transaction: &Transaction) -> transaction::Result<()> {
impl Banks for BanksServer {
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
let blockhash = &transaction.message.recent_blockhash;
let last_valid_slot = self
let last_valid_block_height = self
.bank_forks
.read()
.unwrap()
.root_bank()
.get_blockhash_last_valid_slot(&blockhash)
.get_blockhash_last_valid_block_height(blockhash)
.unwrap();
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
let info =
TransactionInfo::new(signature, serialize(&transaction).unwrap(), last_valid_slot);
let info = TransactionInfo::new(
signature,
serialize(&transaction).unwrap(),
last_valid_block_height,
);
self.transaction_sender.send(info).unwrap();
}
@ -162,11 +178,13 @@ impl Banks for BanksServer {
self,
_: Context,
commitment: CommitmentLevel,
) -> (FeeCalculator, Hash, Slot) {
) -> (FeeCalculator, Hash, u64) {
let bank = self.bank(commitment);
let (blockhash, fee_calculator) = bank.last_blockhash_with_fee_calculator();
let last_valid_slot = bank.get_blockhash_last_valid_slot(&blockhash).unwrap();
(fee_calculator, blockhash, last_valid_slot)
let last_valid_block_height = bank
.get_blockhash_last_valid_block_height(&blockhash)
.unwrap();
(fee_calculator, blockhash, last_valid_block_height)
}
async fn get_transaction_status_with_context(
@ -209,29 +227,33 @@ impl Banks for BanksServer {
self.slot(commitment)
}
async fn get_block_height_with_context(self, _: Context, commitment: CommitmentLevel) -> u64 {
self.bank(commitment).block_height()
}
async fn process_transaction_with_commitment_and_context(
self,
_: Context,
transaction: Transaction,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>> {
if let Err(err) = verify_transaction(&transaction) {
if let Err(err) = verify_transaction(&transaction, &self.bank(commitment).feature_set) {
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)
let last_valid_block_height = self
.bank(commitment)
.get_blockhash_last_valid_block_height(blockhash)
.unwrap();
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
let info =
TransactionInfo::new(signature, serialize(&transaction).unwrap(), last_valid_slot);
let info = TransactionInfo::new(
signature,
serialize(&transaction).unwrap(),
last_valid_block_height,
);
self.transaction_sender.send(info).unwrap();
self.poll_signature_status(&signature, blockhash, last_valid_slot, commitment)
self.poll_signature_status(&signature, blockhash, last_valid_block_height, commitment)
.await
}
@ -249,8 +271,13 @@ impl Banks for BanksServer {
pub async fn start_local_server(
bank_forks: Arc<RwLock<BankForks>>,
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
poll_signature_status_sleep_duration: Duration,
) -> UnboundedChannel<Response<BanksResponse>, ClientMessage<BanksRequest>> {
let banks_server = BanksServer::new_loopback(bank_forks, block_commitment_cache);
let banks_server = BanksServer::new_loopback(
bank_forks,
block_commitment_cache,
poll_signature_status_sleep_duration,
);
let (client_transport, server_transport) = transport::channel::unbounded();
let server = server::new(server::Config::default())
.incoming(stream::once(future::ready(server_transport)))
@ -285,8 +312,12 @@ pub async fn start_tcp_server(
SendTransactionService::new(tpu_addr, &bank_forks, receiver);
let server =
BanksServer::new(bank_forks.clone(), block_commitment_cache.clone(), sender);
let server = BanksServer::new(
bank_forks.clone(),
block_commitment_cache.clone(),
sender,
Duration::from_millis(200),
);
chan.respond_with(server.serve()).execute()
})
// Max 10 channels.

View File

@ -2,7 +2,7 @@
use log::*;
use solana_metrics::{datapoint_warn, inc_new_counter_info};
use solana_runtime::{bank::Bank, bank_forks::BankForks};
use solana_sdk::{clock::Slot, signature::Signature};
use solana_sdk::signature::Signature;
use std::{
collections::HashMap,
net::{SocketAddr, UdpSocket},
@ -24,15 +24,19 @@ pub struct SendTransactionService {
pub struct TransactionInfo {
pub signature: Signature,
pub wire_transaction: Vec<u8>,
pub last_valid_slot: Slot,
pub last_valid_block_height: u64,
}
impl TransactionInfo {
pub fn new(signature: Signature, wire_transaction: Vec<u8>, last_valid_slot: Slot) -> Self {
pub fn new(
signature: Signature,
wire_transaction: Vec<u8>,
last_valid_block_height: u64,
) -> Self {
Self {
signature,
wire_transaction,
last_valid_slot,
last_valid_block_height,
}
}
}
@ -124,7 +128,7 @@ impl SendTransactionService {
result.rooted += 1;
inc_new_counter_info!("send_transaction_service-rooted", 1);
false
} else if transaction_info.last_valid_slot < root_bank.slot() {
} else if transaction_info.last_valid_block_height < root_bank.block_height() {
info!("Dropping expired transaction: {}", signature);
result.expired += 1;
inc_new_counter_info!("send_transaction_service-expired", 1);
@ -138,8 +142,8 @@ impl SendTransactionService {
result.retried += 1;
inc_new_counter_info!("send_transaction_service-retry", 1);
Self::send_transaction(
&send_socket,
&tpu_address,
send_socket,
tpu_address,
&transaction_info.wire_transaction,
);
true

View File

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

View File

@ -451,13 +451,13 @@ fn swapper<T>(
let to_swap_txs: Vec<_> = to_swap
.par_iter()
.map(|(signer, swap, profit)| {
let s: &Keypair = &signer;
let s: &Keypair = signer;
let owner = &signer.pubkey();
let instruction = exchange_instruction::swap_request(
owner,
&swap.0.pubkey,
&swap.1.pubkey,
&profit,
profit,
);
let message = Message::new(&[instruction], Some(&s.pubkey()));
Transaction::new(&[s], message, blockhash)
@ -600,7 +600,7 @@ fn trader<T>(
src,
),
];
let message = Message::new(&instructions, Some(&owner_pubkey));
let message = Message::new(&instructions, Some(owner_pubkey));
Transaction::new(&[owner.as_ref(), trade], message, blockhash)
})
.collect();
@ -739,7 +739,7 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
let mut to_fund_txs: Vec<_> = chunk
.par_iter()
.map(|(k, m)| {
let instructions = system_instruction::transfer_many(&k.pubkey(), &m);
let instructions = system_instruction::transfer_many(&k.pubkey(), m);
let message = Message::new(&instructions, Some(&k.pubkey()));
(k.clone(), Transaction::new_unsigned(message))
})
@ -777,7 +777,7 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
let mut waits = 0;
loop {
sleep(Duration::from_millis(200));
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, &tx, amount));
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, tx, amount));
if to_fund_txs.is_empty() {
break;
}
@ -836,7 +836,7 @@ pub fn create_token_accounts<T: Client>(
);
let request_ix =
exchange_instruction::account_request(owner_pubkey, &new_keypair.pubkey());
let message = Message::new(&[create_ix, request_ix], Some(&owner_pubkey));
let message = Message::new(&[create_ix, request_ix], Some(owner_pubkey));
(
(from_keypair, new_keypair),
Transaction::new_unsigned(message),
@ -872,7 +872,7 @@ pub fn create_token_accounts<T: Client>(
let mut waits = 0;
while !to_create_txs.is_empty() {
sleep(Duration::from_millis(200));
to_create_txs.retain(|(_, tx)| !verify_transaction(client, &tx));
to_create_txs.retain(|(_, tx)| !verify_transaction(client, tx));
if to_create_txs.is_empty() {
break;
}
@ -958,7 +958,7 @@ fn compute_and_report_stats(maxes: &Arc<RwLock<Vec<(String, SampleStats)>>>, tot
fn generate_keypairs(num: u64) -> Vec<Keypair> {
let mut seed = [0_u8; 32];
seed.copy_from_slice(&Keypair::new().pubkey().as_ref());
seed.copy_from_slice(Keypair::new().pubkey().as_ref());
let mut rnd = GenKeys::new(seed);
rnd.gen_n_keypairs(num)
}
@ -989,7 +989,7 @@ pub fn airdrop_lamports<T: Client>(
let (blockhash, _fee_calculator, _last_valid_slot) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::processed())
.expect("Failed to get blockhash");
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), amount_to_drop, blockhash) {
match request_airdrop_transaction(faucet_addr, &id.pubkey(), amount_to_drop, blockhash) {
Ok(transaction) => {
let signature = client.async_send_transaction(transaction).unwrap();

View File

@ -7,6 +7,7 @@ use crate::bench::{airdrop_lamports, create_client_accounts_file, do_bench_excha
use log::*;
use solana_gossip::gossip_service::{discover_cluster, get_multi_client};
use solana_sdk::signature::Signer;
use solana_streamer::socket::SocketAddrSpace;
fn main() {
solana_logger::setup();
@ -55,11 +56,12 @@ fn main() {
);
} else {
info!("Connecting to the cluster");
let nodes = discover_cluster(&entrypoint_addr, num_nodes).unwrap_or_else(|_| {
panic!("Failed to discover nodes");
});
let nodes = discover_cluster(&entrypoint_addr, num_nodes, SocketAddrSpace::Unspecified)
.unwrap_or_else(|_| {
panic!("Failed to discover nodes");
});
let (client, num_clients) = get_multi_client(&nodes);
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
info!("{} nodes found", num_clients);
if num_clients < num_nodes {

View File

@ -15,6 +15,7 @@ use solana_sdk::{
genesis_config::create_genesis_config,
signature::{Keypair, Signer},
};
use solana_streamer::socket::SocketAddrSpace;
use std::{process::exit, sync::mpsc::channel, time::Duration};
#[test]
@ -43,13 +44,19 @@ fn test_exchange_local_cluster() {
} = config;
let accounts_in_groups = batch_size * account_groups;
let cluster = LocalCluster::new(&mut ClusterConfig {
node_stakes: vec![100_000; NUM_NODES],
cluster_lamports: 100_000_000_000_000,
validator_configs: make_identical_validator_configs(&ValidatorConfig::default(), NUM_NODES),
native_instruction_processors: [solana_exchange_program!()].to_vec(),
..ClusterConfig::default()
});
let cluster = LocalCluster::new(
&mut ClusterConfig {
node_stakes: vec![100_000; NUM_NODES],
cluster_lamports: 100_000_000_000_000,
validator_configs: make_identical_validator_configs(
&ValidatorConfig::default(),
NUM_NODES,
),
native_instruction_processors: [solana_exchange_program!()].to_vec(),
..ClusterConfig::default()
},
SocketAddrSpace::Unspecified,
);
let faucet_keypair = Keypair::new();
cluster.transfer(
@ -66,13 +73,17 @@ fn test_exchange_local_cluster() {
.expect("faucet_addr");
info!("Connecting to the cluster");
let nodes =
discover_cluster(&cluster.entry_point_info.gossip, NUM_NODES).unwrap_or_else(|err| {
error!("Failed to discover {} nodes: {:?}", NUM_NODES, err);
exit(1);
});
let nodes = discover_cluster(
&cluster.entry_point_info.gossip,
NUM_NODES,
SocketAddrSpace::Unspecified,
)
.unwrap_or_else(|err| {
error!("Failed to discover {} nodes: {:?}", NUM_NODES, err);
exit(1);
});
let (client, num_clients) = get_multi_client(&nodes);
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
info!("clients: {}", num_clients);
assert!(num_clients >= NUM_NODES);

View File

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

View File

@ -18,7 +18,7 @@ fn producer(addr: &SocketAddr, exit: Arc<AtomicBool>) -> JoinHandle<()> {
msgs.packets.resize(10, Packet::default());
for w in msgs.packets.iter_mut() {
w.meta.size = PACKET_DATA_SIZE;
w.meta.set_addr(&addr);
w.meta.set_addr(addr);
}
let msgs = Arc::new(msgs);
spawn(move || loop {
@ -92,6 +92,7 @@ fn main() -> Result<()> {
recycler.clone(),
"bench-streamer-test",
1,
true,
));
}

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-bench-tps"
version = "1.7.0"
version = "1.8.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -15,23 +15,24 @@ log = "0.4.11"
rayon = "1.5.0"
serde_json = "1.0.56"
serde_yaml = "0.8.13"
solana-clap-utils = { path = "../clap-utils", version = "=1.7.0" }
solana-core = { path = "../core", version = "=1.7.0" }
solana-genesis = { path = "../genesis", version = "=1.7.0" }
solana-client = { path = "../client", version = "=1.7.0" }
solana-faucet = { path = "../faucet", version = "=1.7.0" }
solana-gossip = { path = "../gossip", version = "=1.7.0" }
solana-logger = { path = "../logger", version = "=1.7.0" }
solana-metrics = { path = "../metrics", version = "=1.7.0" }
solana-measure = { path = "../measure", version = "=1.7.0" }
solana-net-utils = { path = "../net-utils", version = "=1.7.0" }
solana-runtime = { path = "../runtime", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-version = { path = "../version", version = "=1.7.0" }
solana-clap-utils = { path = "../clap-utils", version = "=1.8.3" }
solana-core = { path = "../core", version = "=1.8.3" }
solana-genesis = { path = "../genesis", version = "=1.8.3" }
solana-client = { path = "../client", version = "=1.8.3" }
solana-faucet = { path = "../faucet", version = "=1.8.3" }
solana-gossip = { path = "../gossip", version = "=1.8.3" }
solana-logger = { path = "../logger", version = "=1.8.3" }
solana-metrics = { path = "../metrics", version = "=1.8.3" }
solana-measure = { path = "../measure", version = "=1.8.3" }
solana-net-utils = { path = "../net-utils", version = "=1.8.3" }
solana-runtime = { path = "../runtime", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
solana-streamer = { path = "../streamer", version = "=1.8.3" }
solana-version = { path = "../version", version = "=1.8.3" }
[dev-dependencies]
serial_test = "0.4.0"
solana-local-cluster = { path = "../local-cluster", version = "=1.7.0" }
solana-local-cluster = { path = "../local-cluster", version = "=1.8.3" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -544,12 +544,12 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
// re-sign retained to_fund_txes with updated blockhash
self.sign(blockhash);
self.send(&client);
self.send(client);
// Sleep a few slots to allow transactions to process
sleep(Duration::from_secs(1));
self.verify(&client, to_lamports);
self.verify(client, to_lamports);
// retry anything that seems to have dropped through cracks
// again since these txs are all or nothing, they're fine to
@ -564,7 +564,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
let to_fund_txs: Vec<(&Keypair, Transaction)> = to_fund
.par_iter()
.map(|(k, t)| {
let instructions = system_instruction::transfer_many(&k.pubkey(), &t);
let instructions = system_instruction::transfer_many(&k.pubkey(), t);
let message = Message::new(&instructions, Some(&k.pubkey()));
(*k, Transaction::new_unsigned(message))
})
@ -617,7 +617,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
return None;
}
let verified = if verify_funding_transfer(&client, &tx, to_lamports) {
let verified = if verify_funding_transfer(&client, tx, to_lamports) {
verified_txs.fetch_add(1, Ordering::Relaxed);
Some(k.pubkey())
} else {
@ -733,7 +733,7 @@ pub fn airdrop_lamports<T: Client>(
);
let (blockhash, _fee_calculator) = get_recent_blockhash(client);
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => {
let mut tries = 0;
loop {

View File

@ -7,6 +7,7 @@ use solana_gossip::gossip_service::{discover_cluster, get_client, get_multi_clie
use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_program;
use solana_streamer::socket::SocketAddrSpace;
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc};
/// Number of signatures for all transactions in ~1 week at ~100K TPS
@ -39,7 +40,7 @@ fn main() {
let keypair_count = *tx_count * keypair_multiplier;
if *write_to_client_file {
info!("Generating {} keypairs", keypair_count);
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
let (keypairs, _) = generate_keypairs(id, keypair_count as u64);
let num_accounts = keypairs.len() as u64;
let max_fee =
FeeRateGovernor::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
@ -68,13 +69,14 @@ fn main() {
}
info!("Connecting to the cluster");
let nodes = discover_cluster(&entrypoint_addr, *num_nodes).unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1);
});
let nodes = discover_cluster(entrypoint_addr, *num_nodes, SocketAddrSpace::Unspecified)
.unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1);
});
let client = if *multi_client {
let (client, num_clients) = get_multi_client(&nodes);
let (client, num_clients) = get_multi_client(&nodes, &SocketAddrSpace::Unspecified);
if nodes.len() < num_clients {
eprintln!(
"Error: Insufficient nodes discovered. Expecting {} or more",
@ -88,7 +90,7 @@ fn main() {
let mut target_client = None;
for node in nodes {
if node.id == *target_node {
target_client = Some(Arc::new(get_client(&[node])));
target_client = Some(Arc::new(get_client(&[node], &SocketAddrSpace::Unspecified)));
break;
}
}
@ -97,7 +99,7 @@ fn main() {
exit(1);
})
} else {
Arc::new(get_client(&nodes))
Arc::new(get_client(&nodes, &SocketAddrSpace::Unspecified))
};
let keypairs = if *read_from_client_file {
@ -135,7 +137,7 @@ fn main() {
generate_and_fund_keypairs(
client.clone(),
Some(*faucet_addr),
&id,
id,
keypair_count,
*num_lamports_per_account,
)

View File

@ -13,6 +13,7 @@ use solana_local_cluster::{
validator_configs::make_identical_validator_configs,
};
use solana_sdk::signature::{Keypair, Signer};
use solana_streamer::socket::SocketAddrSpace;
use std::{
sync::{mpsc::channel, Arc},
time::Duration,
@ -23,13 +24,19 @@ fn test_bench_tps_local_cluster(config: Config) {
solana_logger::setup();
const NUM_NODES: usize = 1;
let cluster = LocalCluster::new(&mut ClusterConfig {
node_stakes: vec![999_990; NUM_NODES],
cluster_lamports: 200_000_000,
validator_configs: make_identical_validator_configs(&ValidatorConfig::default(), NUM_NODES),
native_instruction_processors,
..ClusterConfig::default()
});
let cluster = LocalCluster::new(
&mut ClusterConfig {
node_stakes: vec![999_990; NUM_NODES],
cluster_lamports: 200_000_000,
validator_configs: make_identical_validator_configs(
&ValidatorConfig::default(),
NUM_NODES,
),
native_instruction_processors,
..ClusterConfig::default()
},
SocketAddrSpace::Unspecified,
);
let faucet_keypair = Keypair::new();
cluster.transfer(

View File

@ -137,7 +137,7 @@ all_test_steps() {
^ci/test-coverage.sh \
^scripts/coverage.sh \
; then
command_step coverage ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image ci/test-coverage.sh" 30
command_step coverage ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_nightly_docker_image ci/test-coverage.sh" 40
wait_step
else
annotate --style info --context test-coverage \
@ -148,6 +148,33 @@ all_test_steps() {
command_step stable ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-stable.sh" 60
wait_step
# BPF test suite
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-bpf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
; then
cat >> "$output_file" <<"EOF"
- command: "ci/test-stable-bpf.sh"
name: "stable-bpf"
timeout_in_minutes: 20
artifact_paths: "bpf-dumps.tar.bz2"
agents:
- "queue=default"
EOF
else
annotate --style info \
"Stable-BPF skipped as no relevant files were modified"
fi
# Perf test suite
if affects \
.rs$ \
@ -165,7 +192,7 @@ all_test_steps() {
cat >> "$output_file" <<"EOF"
- command: "ci/test-stable-perf.sh"
name: "stable-perf"
timeout_in_minutes: 40
timeout_in_minutes: 20
artifact_paths: "log-*.txt"
agents:
- "queue=cuda"

View File

@ -3,13 +3,19 @@
# Pull requests to not run these steps.
steps:
- command: "ci/publish-tarball.sh"
agents:
- "queue=release-build"
timeout_in_minutes: 60
name: "publish tarball"
- wait
- command: "sdk/docker-solana/build.sh"
agents:
- "queue=release-build"
timeout_in_minutes: 60
name: "publish docker"
- command: "ci/publish-crate.sh"
agents:
- "queue=release-build"
timeout_in_minutes: 240
name: "publish crate"
branches: "!master"

View File

@ -28,16 +28,29 @@ cargo_audit_ignores=(
# 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
# generic-array: arr! macro erases lifetimes
#
# Blocked on libsecp256k1 releasing with upgraded dependencies
# https://github.com/paritytech/libsecp256k1/issues/66
--ignore RUSTSEC-2020-0146
# hyper: Lenient `hyper` header parsing of `Content-Length` could allow request smuggling
#
# Blocked on jsonrpc removing dependency on unmaintained `websocket`
# https://github.com/paritytech/jsonrpc/issues/605
--ignore RUSTSEC-2021-0078
# hyper: Integer overflow in `hyper`'s parsing of the `Transfer-Encoding` header leads to data loss
#
# Blocked on jsonrpc removing dependency on unmaintained `websocket`
# https://github.com/paritytech/jsonrpc/issues/605
--ignore RUSTSEC-2021-0079
# chrono: Potential segfault in `localtime_r` invocations
#
# Blocked due to no safe upgrade
# https://github.com/chronotope/chrono/issues/499
--ignore RUSTSEC-2020-0159
)
scripts/cargo-for-all-lock-files.sh stable audit "${cargo_audit_ignores[@]}"

View File

@ -74,10 +74,13 @@ else
export CI_BUILD_ID=
export CI_COMMIT=
export CI_JOB_ID=
export CI_OS_NAME=
export CI_PULL_REQUEST=
export CI_REPO_SLUG=
export CI_TAG=
# Don't override ci/run-local.sh
if [[ -z $CI_LOCAL_RUN ]]; then
export CI_OS_NAME=
fi
fi
cat <<EOF

View File

@ -127,7 +127,7 @@ startNode() {
waitForNodeToInit() {
declare initCompleteFile=$1
while [[ ! -r $initCompleteFile ]]; do
if [[ $SECONDS -ge 240 ]]; then
if [[ $SECONDS -ge 300 ]]; then
echo "^^^ +++"
echo "Error: $initCompleteFile not found in $SECONDS seconds"
exit 1

View File

@ -12,10 +12,14 @@ import json
import subprocess
import sys;
real_file = os.path.realpath(__file__)
ci_path = os.path.dirname(real_file)
src_root = os.path.dirname(ci_path)
def load_metadata():
cmd = f'{src_root}/cargo metadata --no-deps --format-version=1'
return json.loads(subprocess.Popen(
'cargo metadata --no-deps --format-version=1',
shell=True, stdout=subprocess.PIPE).communicate()[0])
cmd, shell=True, stdout=subprocess.PIPE).communicate()[0])
def get_packages():
metadata = load_metadata()

55
ci/run-local.sh Executable file
View File

@ -0,0 +1,55 @@
#!/usr/bin/env bash
cd "$(dirname "$0")/.."
export CI_LOCAL_RUN=true
set -e
case $(uname -o) in
*/Linux)
export CI_OS_NAME=linux
;;
*)
echo "local CI runs are only supported on Linux" 1>&2
exit 1
;;
esac
steps=()
steps+=(test-sanity)
steps+=(shellcheck)
steps+=(test-checks)
steps+=(test-coverage)
steps+=(test-stable)
steps+=(test-stable-bpf)
steps+=(test-stable-perf)
steps+=(test-downstream-builds)
steps+=(test-bench)
steps+=(test-local-cluster)
step_index=0
if [[ -n "$1" ]]; then
start_step="$1"
while [[ $step_index -lt ${#steps[@]} ]]; do
step="${steps[$step_index]}"
if [[ "$step" = "$start_step" ]]; then
break
fi
step_index=$((step_index + 1))
done
if [[ $step_index -eq ${#steps[@]} ]]; then
echo "unexpected start step: \"$start_step\"" 1>&2
exit 1
else
echo "** starting at step: \"$start_step\" **"
echo
fi
fi
while [[ $step_index -lt ${#steps[@]} ]]; do
step="${steps[$step_index]}"
cmd="ci/${step}.sh"
$cmd
step_index=$((step_index + 1))
done

View File

@ -7,7 +7,7 @@ source multinode-demo/common.sh
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
SOLANA_RUN_SH_VALIDATOR_ARGS="--snapshot-interval-slots 200" timeout 120 ./run.sh &
SOLANA_RUN_SH_VALIDATOR_ARGS="--snapshot-interval-slots 200" timeout 120 ./scripts/run.sh &
pid=$!
attempts=20

View File

@ -76,7 +76,7 @@ RestartForceExitStatus=SIGPIPE
TimeoutStartSec=10
TimeoutStopSec=0
KillMode=process
LimitNOFILE=700000
LimitNOFILE=1000000
[Install]
WantedBy=multi-user.target

View File

@ -8,5 +8,5 @@ source "$HERE"/utils.sh
ensure_env || exit 1
# Allow more files to be opened by a user
echo "* - nofile 700000" > /etc/security/limits.d/90-solana-nofiles.conf
echo "* - nofile 1000000" > /etc/security/limits.d/90-solana-nofiles.conf

View File

@ -49,6 +49,10 @@ _ "$cargo" nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
_ "$cargo" nightly bench --manifest-path gossip/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run poh benches
_ "$cargo" nightly bench --manifest-path poh/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} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"

View File

@ -14,7 +14,7 @@ scripts/increment-cargo-version.sh check
# Disallow uncommitted Cargo.lock changes
(
_ scripts/cargo-for-all-lock-files.sh tree
_ scripts/cargo-for-all-lock-files.sh tree >/dev/null
set +e
if ! _ git diff --exit-code; then
echo -e "\nError: Uncommitted Cargo.lock changes" 1>&2
@ -35,8 +35,10 @@ echo --- build environment
"$cargo" stable clippy --version --verbose
"$cargo" nightly clippy --version --verbose
# audit is done only with stable
# audit is done only with "$cargo stable"
"$cargo" stable audit --version
grcov --version
)
export RUST_BACKTRACE=1
@ -65,7 +67,8 @@ _ ci/order-crates-for-publishing.py
# -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 --deny=clippy::integer_arithmetic
_ "$cargo" nightly clippy -Zunstable-options --workspace --all-targets -- \
--deny=warnings --deny=clippy::integer_arithmetic --allow=clippy::inconsistent_struct_constructor
_ "$cargo" stable fmt --all -- --check

9
ci/test-downstream-builds.sh Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
cd "$(dirname "$0")/.."
export CI_LOCAL_RUN=true
set -ex
scripts/build-downstream-projects.sh

1
ci/test-stable-bpf.sh Symbolic link
View File

@ -0,0 +1 @@
test-stable.sh

View File

@ -21,10 +21,6 @@ export RUST_BACKTRACE=1
export RUSTFLAGS="-D warnings"
source scripts/ulimit-n.sh
# 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
# Limit compiler jobs to reduce memory usage
# on machines with 2gb/thread of memory
NPROC=$(nproc)
@ -35,17 +31,25 @@ case $testName in
test-stable)
_ "$cargo" stable test --jobs "$NPROC" --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
;;
test-stable-perf)
test-stable-bpf)
# 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
# rustfilt required for dumping BPF assembly listings
"$cargo" install rustfilt
# solana-keygen required when building C programs
_ "$cargo" build --manifest-path=keygen/Cargo.toml
export PATH="$PWD/target/debug":$PATH
cargo_build_bpf="$(realpath ./cargo-build-bpf)"
# BPF solana-sdk legacy compile test
./cargo-build-bpf --manifest-path sdk/Cargo.toml
"$cargo_build_bpf" --manifest-path sdk/Cargo.toml
# BPF Program unit tests
"$cargo" test --manifest-path programs/bpf/Cargo.toml
cargo-build-bpf --manifest-path programs/bpf/Cargo.toml --bpf-sdk sdk/bpf
"$cargo_build_bpf" --manifest-path programs/bpf/Cargo.toml --bpf-sdk sdk/bpf
# BPF program system tests
_ make -C programs/bpf/c tests
@ -53,11 +57,32 @@ test-stable-perf)
--manifest-path programs/bpf/Cargo.toml \
--no-default-features --features=bpf_c,bpf_rust -- --nocapture
# Dump BPF program assembly listings
for bpf_test in programs/bpf/rust/*; do
if pushd "$bpf_test"; then
"$cargo_build_bpf" --dump
popd
fi
done
# BPF program instruction count assertion
bpf_target_path=programs/bpf/target
_ "$cargo" stable test \
--manifest-path programs/bpf/Cargo.toml \
--no-default-features --features=bpf_c,bpf_rust assert_instruction_count \
-- --nocapture &> "${bpf_target_path}"/deploy/instuction_counts.txt
bpf_dump_archive="bpf-dumps.tar.bz2"
rm -f "$bpf_dump_archive"
tar cjvf "$bpf_dump_archive" "${bpf_target_path}"/{deploy/*.txt,bpfel-unknown-unknown/release/*.so}
exit 0
;;
test-stable-perf)
if [[ $(uname) = Linux ]]; then
# Enable persistence mode to keep the CUDA kernel driver loaded, avoiding a
# lengthy and unexpected delay the first time CUDA is involved when the driver
# is not yet loaded.
sudo --non-interactive ./net/scripts/enable-nvidia-persistence-mode.sh
sudo --non-interactive ./net/scripts/enable-nvidia-persistence-mode.sh || true
rm -rf target/perf-libs
./fetch-perf-libs.sh

View File

@ -1,6 +1,6 @@
[package]
name = "solana-clap-utils"
version = "1.7.0"
version = "1.8.3"
description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@ -12,10 +12,10 @@ edition = "2018"
[dependencies]
clap = "2.33.0"
rpassword = "4.0"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-remote-wallet = { path = "../remote-wallet", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
thiserror = "1.0.21"
tiny-bip39 = "0.8.0"
tiny-bip39 = "0.8.1"
uriparse = "0.6.3"
url = "2.1.0"
chrono = "0.4"

View File

@ -1,3 +1,14 @@
//! Loading signers and keypairs from the command line.
//!
//! This module contains utilities for loading [Signer]s and [Keypair]s from
//! standard signing sources, from the command line, as in the Solana CLI.
//!
//! The key function here is [`signer_from_path`], which loads a `Signer` from
//! one of several possible sources by interpreting a "path" command line
//! argument. Its documentation includes a description of all possible signing
//! sources supported by the Solana CLI. Many other functions here are
//! variations on, or delegate to, `signer_from_path`.
use {
crate::{
input_parsers::{pubkeys_sigs_of, STDOUT_OUTFILE_TOKEN},
@ -24,9 +35,11 @@ use {
},
},
std::{
cell::RefCell,
convert::TryFrom,
error,
io::{stdin, stdout, Write},
ops::Deref,
process::exit,
str::FromStr,
sync::Arc,
@ -89,33 +102,142 @@ impl CliSignerInfo {
.collect()
}
}
#[derive(Debug)]
/// A command line argument that loads a default signer in absence of other signers.
///
/// This type manages a default signing source which may be overridden by other
/// signing sources via its [`generate_unique_signers`] method.
///
/// [`generate_unique_signers`]: DefaultSigner::generate_unique_signers
///
/// `path` is a signing source as documented by [`signer_from_path`], and
/// `arg_name` is the name of its [clap] command line argument, which is passed
/// to `signer_from_path` as its `keypair_name` argument.
#[derive(Debug, Default)]
pub struct DefaultSigner {
/// The name of the signers command line argument.
pub arg_name: String,
/// The signing source.
pub path: String,
is_path_checked: RefCell<bool>,
}
impl DefaultSigner {
pub fn new(path: String) -> Self {
/// Create a new `DefaultSigner`.
///
/// `path` is a signing source as documented by [`signer_from_path`], and
/// `arg_name` is the name of its [clap] command line argument, which is
/// passed to `signer_from_path` as its `keypair_name` argument.
///
/// [clap]: https://docs.rs/clap
///
/// # Examples
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::DefaultSigner;
/// use solana_clap_utils::offline::OfflineArgs;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"))
/// .offline_args();
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
///
/// let default_signer = DefaultSigner::new("keypair", &keypair_str);
/// # assert!(default_signer.arg_name.len() > 0);
/// assert_eq!(default_signer.path, keypair_str);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn new<AN: AsRef<str>, P: AsRef<str>>(arg_name: AN, path: P) -> Self {
let arg_name = arg_name.as_ref().to_string();
let path = path.as_ref().to_string();
Self {
arg_name: "keypair".to_string(),
arg_name,
path,
..Self::default()
}
}
pub fn from_path(path: String) -> Result<Self, Box<dyn error::Error>> {
std::fs::metadata(&path)
.map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"No default signer found, run \"solana-keygen new -o {}\" to create a new one",
path
),
)
.into()
})
.map(|_| Self::new(path))
fn path(&self) -> Result<&str, Box<dyn std::error::Error>> {
if !self.is_path_checked.borrow().deref() {
parse_signer_source(&self.path)
.and_then(|s| {
if let SignerSourceKind::Filepath(path) = &s.kind {
std::fs::metadata(path).map(|_| ()).map_err(|e| e.into())
} else {
Ok(())
}
})
.map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"No default signer found, run \"solana-keygen new -o {}\" to create a new one",
self.path
),
)
})?;
*self.is_path_checked.borrow_mut() = true;
}
Ok(&self.path)
}
/// Generate a unique set of signers, possibly excluding this default signer.
///
/// This function allows a command line application to have a default
/// signer, perhaps representing a default wallet, but to override that
/// signer and instead sign with one or more other signers.
///
/// `bulk_signers` is a vector of signers, all of which are optional. If any
/// of those signers is `None`, then the default signer will be loaded; if
/// all of those signers are `Some`, then the default signer will not be
/// loaded.
///
/// The returned value includes all of the `bulk_signers` that were not
/// `None`, and maybe the default signer, if it was loaded.
///
/// # Examples
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::{DefaultSigner, signer_from_path};
/// use solana_clap_utils::offline::OfflineArgs;
/// use solana_sdk::signer::Signer;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"))
/// .arg(Arg::with_name("payer")
/// .long("payer")
/// .help("The account paying for the transaction"))
/// .offline_args();
///
/// let mut wallet_manager = None;
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
/// let maybe_payer = clap_matches.value_of("payer");
///
/// let default_signer = DefaultSigner::new("keypair", &keypair_str);
/// let maybe_payer_signer = maybe_payer.map(|payer| {
/// signer_from_path(&clap_matches, payer, "payer", &mut wallet_manager)
/// }).transpose()?;
/// let bulk_signers = vec![maybe_payer_signer];
///
/// let unique_signers = default_signer.generate_unique_signers(
/// bulk_signers,
/// &clap_matches,
/// &mut wallet_manager,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn generate_unique_signers(
&self,
bulk_signers: Vec<Option<Box<dyn Signer>>>,
@ -140,21 +262,111 @@ impl DefaultSigner {
})
}
/// Loads the default [Signer] from one of several possible sources.
///
/// The `path` is not strictly a file system path, but is interpreted as
/// various types of _signing source_, depending on its format, one of which
/// is a path to a keypair file. Some sources may require user interaction
/// in the course of calling this function.
///
/// This simply delegates to the [`signer_from_path`] free function, passing
/// it the `DefaultSigner`s `path` and `arg_name` fields as the `path` and
/// `keypair_name` arguments.
///
/// See the [`signer_from_path`] free function for full documentation of how
/// this function interprets its arguments.
///
/// # Examples
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::DefaultSigner;
/// use solana_clap_utils::offline::OfflineArgs;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"))
/// .offline_args();
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
/// let default_signer = DefaultSigner::new("keypair", &keypair_str);
/// let mut wallet_manager = None;
///
/// let signer = default_signer.signer_from_path(
/// &clap_matches,
/// &mut wallet_manager,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn signer_from_path(
&self,
matches: &ArgMatches,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
signer_from_path(matches, &self.path, &self.arg_name, wallet_manager)
signer_from_path(matches, self.path()?, &self.arg_name, wallet_manager)
}
/// Loads the default [Signer] from one of several possible sources.
///
/// The `path` is not strictly a file system path, but is interpreted as
/// various types of _signing source_, depending on its format, one of which
/// is a path to a keypair file. Some sources may require user interaction
/// in the course of calling this function.
///
/// This simply delegates to the [`signer_from_path_with_config`] free
/// function, passing it the `DefaultSigner`s `path` and `arg_name` fields
/// as the `path` and `keypair_name` arguments.
///
/// See the [`signer_from_path`] free function for full documentation of how
/// this function interprets its arguments.
///
/// # Examples
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::{SignerFromPathConfig, DefaultSigner};
/// use solana_clap_utils::offline::OfflineArgs;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"))
/// .offline_args();
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
/// let default_signer = DefaultSigner::new("keypair", &keypair_str);
/// let mut wallet_manager = None;
///
/// // Allow pubkey signers without accompanying signatures
/// let config = SignerFromPathConfig {
/// allow_null_signer: true,
/// };
///
/// let signer = default_signer.signer_from_path_with_config(
/// &clap_matches,
/// &mut wallet_manager,
/// &config,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn signer_from_path_with_config(
&self,
matches: &ArgMatches,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
config: &SignerFromPathConfig,
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
signer_from_path_with_config(matches, &self.path, &self.arg_name, wallet_manager, config)
signer_from_path_with_config(
matches,
self.path()?,
&self.arg_name,
wallet_manager,
config,
)
}
}
@ -234,6 +446,15 @@ pub(crate) fn parse_signer_source<S: AsRef<str>>(
let source = {
#[cfg(target_family = "windows")]
{
// trim matched single-quotes since cmd.exe won't
let mut source = source;
while let Some(trimmed) = source.strip_prefix('\'') {
source = if let Some(trimmed) = trimmed.strip_suffix('\'') {
trimmed
} else {
break;
}
}
source.replace("\\", "/")
}
#[cfg(not(target_family = "windows"))]
@ -277,7 +498,9 @@ pub(crate) fn parse_signer_source<S: AsRef<str>>(
ASK_KEYWORD => Ok(SignerSource::new_legacy(SignerSourceKind::Prompt)),
_ => match Pubkey::from_str(source.as_str()) {
Ok(pubkey) => Ok(SignerSource::new(SignerSourceKind::Pubkey(pubkey))),
Err(_) => Ok(SignerSource::new(SignerSourceKind::Filepath(source))),
Err(_) => std::fs::metadata(source.as_str())
.map(|_| SignerSource::new(SignerSourceKind::Filepath(source)))
.map_err(|err| err.into()),
},
}
}
@ -298,19 +521,167 @@ pub fn presigner_from_pubkey_sigs(
})
}
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct SignerFromPathConfig {
pub allow_null_signer: bool,
}
impl Default for SignerFromPathConfig {
fn default() -> Self {
Self {
allow_null_signer: false,
}
}
}
/// Loads a [Signer] from one of several possible sources.
///
/// The `path` is not strictly a file system path, but is interpreted as various
/// types of _signing source_, depending on its format, one of which is a path
/// to a keypair file. Some sources may require user interaction in the course
/// of calling this function.
///
/// The result of this function is a boxed object of the [Signer] trait. To load
/// a concrete [Keypair], use the [keypair_from_path] function, though note that
/// it does not support all signer sources.
///
/// The `matches` argument is the same set of parsed [clap] matches from which
/// `path` was parsed. It is used to parse various additional command line
/// arguments, depending on which signing source is requested, as described
/// below in "Signing sources".
///
/// [clap]: https//docs.rs/clap
///
/// The `keypair_name` argument is the "name" of the signer, and is typically
/// the name of the clap argument from which the `path` argument was parsed,
/// like "keypair", "from", or "fee-payer". It is used solely for interactively
/// prompting the user, either when entering seed phrases or selecting from
/// multiple hardware wallets.
///
/// The `wallet_manager` is used for establishing connections to a hardware
/// device such as Ledger. If `wallet_manager` is a reference to `None`, and a
/// hardware signer is requested, then this function will attempt to create a
/// wallet manager, assigning it to the mutable `wallet_manager` reference. This
/// argument is typically a reference to `None`.
///
/// # Signing sources
///
/// The `path` argument can simply be a path to a keypair file, but it may also
/// be interpreted in several other ways, in the following order.
///
/// Firstly, the `path` argument may be interpreted as a [URI], with the URI
/// scheme indicating where to load the signer from. If it parses as a URI, then
/// the following schemes are supported:
///
/// - `file:` &mdash; Read the keypair from a JSON keypair file. The path portion
/// of the URI is the file path.
///
/// - `stdin:` &mdash; Read the keypair from stdin, in the JSON format used by
/// the keypair file.
///
/// Non-scheme parts of the URI are ignored.
///
/// - `prompt:` &mdash; The user will be prompted at the command line
/// for their seed phrase and passphrase.
///
/// In this URI the [query string][qs] may contain zero or one of the
/// following key/value pairs that determine the [BIP44 derivation path][dp]
/// of the private key from the seed:
///
/// - `key` &mdash; In this case the value is either one or two numerical
/// indexes separated by a slash, which represent the "account", and
/// "change" components of the BIP44 derivation path. Example: `key=0/0`.
///
/// - `full-path` &mdash; In this case the value is a full derivation path,
/// and the user is responsible for ensuring it is correct. Example:
/// `full-path=m/44/501/0/0/0`.
///
/// If neither is provided, then the default derivation path is used.
///
/// Note that when specifying derivation paths, this routine will convert all
/// indexes into ["hardened"] indexes, even if written as "normal" indexes.
///
/// Other components of the URI besides the scheme and query string are ignored.
///
/// If the "skip_seed_phrase_validation" argument, as defined in
/// [SKIP_SEED_PHRASE_VALIDATION_ARG] is found in `matches`, then the keypair
/// seed will be generated directly from the seed phrase, without parsing or
/// validating it as a BIP39 seed phrase. This allows the use of non-BIP39 seed
/// phrases.
///
/// - `usb:` &mdash; Use a USB hardware device as the signer. In this case, the
/// URI host indicates the device type, and is required. The only currently valid host
/// value is "ledger".
///
/// Optionally, the first segment of the URI path indicates the base-58
/// encoded pubkey of the wallet, and the "account" and "change" indices of
/// the derivation path can be specified with the `key=` query parameter, as
/// with the `prompt:` URI.
///
/// Examples:
///
/// - `usb://ledger`
/// - `usb://ledger?key=0/0`
/// - `usb://ledger/9rPVSygg3brqghvdZ6wsL2i5YNQTGhXGdJzF65YxaCQd`
/// - `usb://ledger/9rPVSygg3brqghvdZ6wsL2i5YNQTGhXGdJzF65YxaCQd?key=0/0`
///
/// Next the `path` argument may be one of the following strings:
///
/// - `-` &mdash; Read the keypair from stdin. This is the same as the `stdin:`
/// URI scheme.
///
/// - `ASK` &mdash; The user will be prompted at the command line for their seed
/// phrase and passphrase. _This uses a legacy key derivation method and should
/// usually be avoided in favor of `prompt:`._
///
/// Next, if the `path` argument parses as a base-58 public key, then the signer
/// is created without a private key, but with presigned signatures, each parsed
/// from the additional command line arguments, provided by the `matches`
/// argument.
///
/// In this case, the remaining command line arguments are searched for clap
/// arguments named "signer", as defined by [SIGNER_ARG], and each is parsed as
/// a key-value pair of the form "pubkey=signature", where `pubkey` is the same
/// base-58 public key, and `signature` is a serialized signature produced by
/// the corresponding keypair. One of the "signer" signatures must be for the
/// pubkey specified in `path` or this function will return an error; unless the
/// "sign_only" clap argument, as defined by [SIGN_ONLY_ARG], is present in
/// `matches`, in which case the signer will be created with no associated
/// signatures.
///
/// Finally, if `path`, interpreted as a file path, represents a file on disk,
/// then the signer is created by reading that file as a JSON-serialized
/// keypair. This is the same as the `file:` URI scheme.
///
/// [qs]: https://en.wikipedia.org/wiki/Query_string
/// [dp]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
/// [URI]: https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
/// ["hardened"]: https://wiki.trezor.io/Hardened_and_non-hardened_derivation
///
/// # Examples
///
/// This shows a reasonable way to set up clap to parse all possible signer
/// sources. Note the use of the [`OfflineArgs::offline_args`] method to add
/// correct clap definitions of the `--signer` and `--sign-only` arguments, as
/// required by the base-58 pubkey offline signing method.
///
/// [`OfflineArgs::offline_args`]: crate::offline::OfflineArgs::offline_args
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::signer_from_path;
/// use solana_clap_utils::offline::OfflineArgs;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"))
/// .offline_args();
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
/// let mut wallet_manager = None;
/// let signer = signer_from_path(
/// &clap_matches,
/// &keypair_str,
/// "keypair",
/// &mut wallet_manager,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn signer_from_path(
matches: &ArgMatches,
path: &str,
@ -321,6 +692,63 @@ pub fn signer_from_path(
signer_from_path_with_config(matches, path, keypair_name, wallet_manager, &config)
}
/// Loads a [Signer] from one of several possible sources.
///
/// The `path` is not strictly a file system path, but is interpreted as various
/// types of _signing source_, depending on its format, one of which is a path
/// to a keypair file. Some sources may require user interaction in the course
/// of calling this function.
///
/// This is the same as [`signer_from_path`] except that it additionaolly
/// accepts a [`SignerFromPathConfig`] argument.
///
/// If the `allow_null_signer` field of `config` is `true`, then pubkey signers
/// are allowed to have zero associated signatures via additional "signer"
/// command line arguments. It the same effect as if the "sign_only" clap
/// argument is present.
///
/// See [`signer_from_path`] for full documentation of how this function
/// interprets its arguments.
///
/// # Examples
///
/// This shows a reasonable way to set up clap to parse all possible signer
/// sources. Note the use of the [`OfflineArgs::offline_args`] method to add
/// correct clap definitions of the `--signer` and `--sign-only` arguments, as
/// required by the base-58 pubkey offline signing method.
///
/// [`OfflineArgs::offline_args`]: crate::offline::OfflineArgs::offline_args
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::{signer_from_path_with_config, SignerFromPathConfig};
/// use solana_clap_utils::offline::OfflineArgs;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"))
/// .offline_args();
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
/// let mut wallet_manager = None;
///
/// // Allow pubkey signers without accompanying signatures
/// let config = SignerFromPathConfig {
/// allow_null_signer: true,
/// };
///
/// let signer = signer_from_path_with_config(
/// &clap_matches,
/// &keypair_str,
/// "keypair",
/// &mut wallet_manager,
/// &config,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn signer_from_path_with_config(
matches: &ArgMatches,
path: &str,
@ -391,6 +819,43 @@ pub fn signer_from_path_with_config(
}
}
/// Loads the pubkey of a [Signer] from one of several possible sources.
///
/// The `path` is not strictly a file system path, but is interpreted as various
/// types of _signing source_, depending on its format, one of which is a path
/// to a keypair file. Some sources may require user interaction in the course
/// of calling this function.
///
/// The only difference between this function and [`signer_from_path`] is in the
/// case of a "pubkey" path: this function does not require that accompanying
/// command line arguments contain an offline signature.
///
/// See [`signer_from_path`] for full documentation of how this function
/// interprets its arguments.
///
/// # Examples
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::pubkey_from_path;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"));
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
/// let mut wallet_manager = None;
/// let pubkey = pubkey_from_path(
/// &clap_matches,
/// &keypair_str,
/// "keypair",
/// &mut wallet_manager,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn pubkey_from_path(
matches: &ArgMatches,
path: &str,
@ -480,7 +945,7 @@ pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
/// Prompts user for a passphrase and then asks for confirmirmation to check for mistakes
pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>> {
let passphrase = prompt_password_stderr(&prompt)?;
let passphrase = prompt_password_stderr(prompt)?;
if !passphrase.is_empty() {
let confirmed = rpassword::prompt_password_stderr("Enter same passphrase again: ")?;
if confirmed != passphrase {
@ -490,7 +955,46 @@ pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>>
Ok(passphrase)
}
/// Parses a path into a SignerSource and returns a Keypair for supporting SignerSourceKinds
/// Loads a [Keypair] from one of several possible sources.
///
/// The `path` is not strictly a file system path, but is interpreted as various
/// types of _signing source_, depending on its format, one of which is a path
/// to a keypair file. Some sources may require user interaction in the course
/// of calling this function.
///
/// This is the same as [`signer_from_path`] except that it only supports
/// signing sources that can result in a [Keypair]: prompt for seed phrase,
/// keypair file, and stdin.
///
/// If `confirm_pubkey` is `true` then after deriving the pubkey, the user will
/// be prompted to confirm that the pubkey is as expected.
///
/// See [`signer_from_path`] for full documentation of how this function
/// interprets its arguments.
///
/// # Examples
///
/// ```no_run
/// use clap::{App, Arg, value_t_or_exit};
/// use solana_clap_utils::keypair::keypair_from_path;
///
/// let clap_app = App::new("my-program")
/// // The argument we'll parse as a signer "path"
/// .arg(Arg::with_name("keypair")
/// .required(true)
/// .help("The default signer"));
///
/// let clap_matches = clap_app.get_matches();
/// let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
///
/// let signer = keypair_from_path(
/// &clap_matches,
/// &keypair_str,
/// "keypair",
/// false,
/// )?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn keypair_from_path(
matches: &ArgMatches,
path: &str,
@ -540,9 +1044,10 @@ pub fn keypair_from_path(
}
}
/// Reads user input from stdin to retrieve a seed phrase and passphrase for keypair derivation
/// Optionally skips validation of seed phrase
/// Optionally confirms recovered public key
/// Reads user input from stdin to retrieve a seed phrase and passphrase for keypair derivation.
///
/// Optionally skips validation of seed phrase. Optionally confirms recovered
/// public key.
pub fn keypair_from_seed_phrase(
keypair_name: &str,
skip_validation: bool,
@ -560,9 +1065,9 @@ pub fn keypair_from_seed_phrase(
let keypair = if skip_validation {
let passphrase = prompt_passphrase(&passphrase_prompt)?;
if legacy {
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)?
keypair_from_seed_phrase_and_passphrase(seed_phrase, &passphrase)?
} else {
let seed = generate_seed_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase);
let seed = generate_seed_from_seed_phrase_and_passphrase(seed_phrase, &passphrase);
keypair_from_seed_and_derivation_path(&seed, derivation_path)?
}
} else {
@ -590,7 +1095,7 @@ pub fn keypair_from_seed_phrase(
if legacy {
keypair_from_seed(seed.as_bytes())?
} else {
keypair_from_seed_and_derivation_path(&seed.as_bytes(), derivation_path)?
keypair_from_seed_and_derivation_path(seed.as_bytes(), derivation_path)?
}
};
@ -619,9 +1124,13 @@ fn sanitize_seed_phrase(seed_phrase: &str) -> String {
#[cfg(test)]
mod tests {
use super::*;
use crate::offline::OfflineArgs;
use clap::{value_t_or_exit, App, Arg};
use solana_remote_wallet::locator::Manufacturer;
use solana_remote_wallet::remote_wallet::initialize_wallet_manager;
use solana_sdk::signer::keypair::write_keypair_file;
use solana_sdk::system_instruction;
use tempfile::NamedTempFile;
use tempfile::{NamedTempFile, TempDir};
#[test]
fn test_sanitize_seed_phrase() {
@ -751,6 +1260,10 @@ mod tests {
// Catchall into SignerSource::Filepath fails
let junk = "sometextthatisnotapubkeyorfile".to_string();
assert!(Pubkey::from_str(&junk).is_err());
assert!(matches!(
parse_signer_source(&junk),
Err(SignerSourceError::IoError(_))
));
let prompt = "prompt:".to_string();
assert!(matches!(
@ -776,4 +1289,41 @@ mod tests {
} if p == relative_path_str)
);
}
#[test]
fn signer_from_path_with_file() -> Result<(), Box<dyn std::error::Error>> {
let dir = TempDir::new()?;
let dir = dir.path();
let keypair_path = dir.join("id.json");
let keypair_path_str = keypair_path.to_str().expect("utf-8");
let keypair = Keypair::new();
write_keypair_file(&keypair, &keypair_path)?;
let args = vec!["program", keypair_path_str];
let clap_app = App::new("my-program")
.arg(
Arg::with_name("keypair")
.required(true)
.help("The signing keypair"),
)
.offline_args();
let clap_matches = clap_app.get_matches_from(args);
let keypair_str = value_t_or_exit!(clap_matches, "keypair", String);
let wallet_manager = initialize_wallet_manager()?;
let signer = signer_from_path(
&clap_matches,
&keypair_str,
"signer",
&mut Some(wallet_manager),
)?;
assert_eq!(keypair.pubkey(), signer.pubkey());
Ok(())
}
}

View File

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

View File

@ -107,24 +107,24 @@ mod test {
#[test]
fn compute_websocket_url() {
assert_eq!(
Config::compute_websocket_url(&"http://api.devnet.solana.com"),
Config::compute_websocket_url("http://api.devnet.solana.com"),
"ws://api.devnet.solana.com/".to_string()
);
assert_eq!(
Config::compute_websocket_url(&"https://api.devnet.solana.com"),
Config::compute_websocket_url("https://api.devnet.solana.com"),
"wss://api.devnet.solana.com/".to_string()
);
assert_eq!(
Config::compute_websocket_url(&"http://example.com:8899"),
Config::compute_websocket_url("http://example.com:8899"),
"ws://example.com:8900/".to_string()
);
assert_eq!(
Config::compute_websocket_url(&"https://example.com:1234"),
Config::compute_websocket_url("https://example.com:1234"),
"wss://example.com:1235/".to_string()
);
assert_eq!(Config::compute_websocket_url(&"garbage"), String::new());
assert_eq!(Config::compute_websocket_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.7.0"
version = "1.8.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -12,20 +12,20 @@ documentation = "https://docs.rs/solana-cli-output"
[dependencies]
base64 = "0.13.0"
chrono = { version = "0.4.11", features = ["serde"] }
console = "0.11.3"
clap = "2.33.0"
console = "0.14.1"
humantime = "2.0.1"
Inflector = "0.11.4"
indicatif = "0.15.0"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.0" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.0" }
solana-client = { path = "../client", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.0" }
solana-account-decoder = { path = "../account-decoder", version = "=1.8.3" }
solana-clap-utils = { path = "../clap-utils", version = "=1.8.3" }
solana-client = { path = "../client", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
solana-transaction-status = { path = "../transaction-status", version = "=1.8.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.8.3" }
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
[package.metadata.docs.rs]

View File

@ -8,6 +8,7 @@ use {
QuietDisplay, VerboseDisplay,
},
chrono::{Local, TimeZone},
clap::ArgMatches,
console::{style, Emoji},
inflector::cases::titlecase::to_title_case,
serde::{Deserialize, Serialize},
@ -25,10 +26,10 @@ use {
native_token::lamports_to_sol,
pubkey::Pubkey,
signature::Signature,
stake::state::{Authorized, Lockup},
stake_history::StakeHistoryEntry,
transaction::{Transaction, TransactionError},
},
solana_stake_program::stake_state::{Authorized, Lockup},
solana_transaction_status::{
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
UiTransactionStatusMeta,
@ -47,7 +48,7 @@ use {
static WARNING: Emoji = Emoji("⚠️", "!");
#[derive(PartialEq)]
#[derive(PartialEq, Debug)]
pub enum OutputFormat {
Display,
Json,
@ -77,6 +78,21 @@ impl OutputFormat {
OutputFormat::JsonCompact => serde_json::to_value(item).unwrap().to_string(),
}
}
pub fn from_matches(matches: &ArgMatches<'_>, output_name: &str, verbose: bool) -> Self {
matches
.value_of(output_name)
.map(|value| match value {
"json" => OutputFormat::Json,
"json-compact" => OutputFormat::JsonCompact,
_ => unreachable!(),
})
.unwrap_or(if verbose {
OutputFormat::DisplayVerbose
} else {
OutputFormat::Display
})
}
}
#[derive(Serialize, Deserialize)]
@ -233,6 +249,10 @@ pub struct CliEpochInfo {
pub epoch_info: EpochInfo,
#[serde(skip)]
pub average_slot_time_ms: u64,
#[serde(skip)]
pub start_block_time: Option<UnixTimestamp>,
#[serde(skip)]
pub current_block_time: Option<UnixTimestamp>,
}
impl QuietDisplay for CliEpochInfo {}
@ -277,21 +297,41 @@ impl fmt::Display for CliEpochInfo {
remaining_slots_in_epoch
),
)?;
let (time_elapsed, annotation) = if let (Some(start_block_time), Some(current_block_time)) =
(self.start_block_time, self.current_block_time)
{
(
Duration::from_secs((current_block_time - start_block_time) as u64),
None,
)
} else {
(
slot_to_duration(self.epoch_info.slot_index, self.average_slot_time_ms),
Some("* estimated based on current slot durations"),
)
};
let time_remaining = slot_to_duration(remaining_slots_in_epoch, self.average_slot_time_ms);
writeln_name_value(
f,
"Epoch Completed Time:",
&format!(
"{}/{} ({} remaining)",
slot_to_human_time(self.epoch_info.slot_index, self.average_slot_time_ms),
slot_to_human_time(self.epoch_info.slots_in_epoch, self.average_slot_time_ms),
slot_to_human_time(remaining_slots_in_epoch, self.average_slot_time_ms)
"{}{}/{} ({} remaining)",
humantime::format_duration(time_elapsed).to_string(),
if annotation.is_some() { "*" } else { "" },
humantime::format_duration(time_elapsed + time_remaining).to_string(),
humantime::format_duration(time_remaining).to_string(),
),
)
)?;
if let Some(annotation) = annotation {
writeln!(f)?;
writeln!(f, "{}", annotation)?;
}
Ok(())
}
}
fn slot_to_human_time(slot: Slot, slot_time_ms: u64) -> String {
humantime::format_duration(Duration::from_secs((slot * slot_time_ms) / 1000)).to_string()
fn slot_to_duration(slot: Slot, slot_time_ms: u64) -> Duration {
Duration::from_secs((slot * slot_time_ms) / 1000)
}
#[derive(Serialize, Deserialize, Default)]
@ -323,6 +363,8 @@ pub struct CliValidators {
pub total_current_stake: u64,
pub total_delinquent_stake: u64,
pub validators: Vec<CliValidator>,
pub average_skip_rate: f64,
pub average_stake_weighted_skip_rate: f64,
#[serde(skip_serializing)]
pub validators_sort_order: CliValidatorsSortOrder,
#[serde(skip_serializing)]
@ -486,6 +528,18 @@ impl fmt::Display for CliValidators {
writeln!(f, "{}", header)?;
}
writeln!(f)?;
writeln_name_value(
f,
"Average Stake-Weighted Skip Rate:",
&format!("{:.2}%", self.average_stake_weighted_skip_rate,),
)?;
writeln_name_value(
f,
"Average Unweighted Skip Rate: ",
&format!("{:.2}%", self.average_skip_rate),
)?;
writeln!(f)?;
writeln_name_value(
f,
@ -522,7 +576,7 @@ impl fmt::Display for CliValidators {
for (version, info) in self.stake_by_version.iter() {
writeln!(
f,
"{:<8} - {:3} current validators ({:>5.2}%){}",
"{:<8} - {:4} current validators ({:>5.2}%){}",
version,
info.current_validators,
100. * info.current_active_stake as f64 / self.total_active_stake as f64,
@ -733,6 +787,7 @@ pub struct CliEpochReward {
pub post_balance: u64, // lamports
pub percent_change: f64,
pub apr: Option<f64>,
pub commission: Option<u8>,
}
#[derive(Serialize, Deserialize)]
@ -777,23 +832,27 @@ impl fmt::Display for CliKeyedEpochRewards {
writeln!(f, "Epoch Rewards:")?;
writeln!(
f,
" {:<44} {:<18} {:<18} {:>14} {:>14}",
"Address", "Amount", "New Balance", "Percent Change", "APR"
" {:<44} {:<18} {:<18} {:>14} {:>14} {:>10}",
"Address", "Amount", "New Balance", "Percent Change", "APR", "Commission"
)?;
for keyed_reward in &self.rewards {
match &keyed_reward.reward {
Some(reward) => {
writeln!(
f,
" {:<44} ◎{:<17.9} ◎{:<17.9} {:>13.2}% {}",
" {:<44} ◎{:<17.9} ◎{:<17.9} {:>13.9}% {:>14} {:>10}",
keyed_reward.address,
lamports_to_sol(reward.amount),
lamports_to_sol(reward.post_balance),
reward.percent_change,
reward
.apr
.map(|apr| format!("{:>13.2}%", apr))
.map(|apr| format!("{:.2}%", apr))
.unwrap_or_default(),
reward
.commission
.map(|commission| format!("{}%", commission))
.unwrap_or_else(|| "-".to_string())
)?;
}
None => {
@ -910,13 +969,13 @@ fn show_epoch_rewards(
writeln!(f, "Epoch Rewards:")?;
writeln!(
f,
" {:<6} {:<11} {:<18} {:<18} {:>14} {:>14}",
"Epoch", "Reward Slot", "Amount", "New Balance", "Percent Change", "APR"
" {:<6} {:<11} {:<18} {:<18} {:>14} {:>14} {:>10}",
"Epoch", "Reward Slot", "Amount", "New Balance", "Percent Change", "APR", "Commission"
)?;
for reward in epoch_rewards {
writeln!(
f,
" {:<6} {:<11} ◎{:<17.9} ◎{:<17.9} {:>13.2}% {}",
" {:<6} {:<11} ◎{:<17.9} ◎{:<17.9} {:>13.9}% {:>14} {:>10}",
reward.epoch,
reward.effective_slot,
lamports_to_sol(reward.amount),
@ -924,8 +983,12 @@ fn show_epoch_rewards(
reward.percent_change,
reward
.apr
.map(|apr| format!("{:>13.2}%", apr))
.map(|apr| format!("{:.2}%", apr))
.unwrap_or_default(),
reward
.commission
.map(|commission| format!("{}%", commission))
.unwrap_or_else(|| "-".to_string())
)?;
}
}
@ -1287,7 +1350,7 @@ impl fmt::Display for CliValidatorInfo {
writeln_name_value(
f,
&format!(" {}:", to_title_case(key)),
&value.as_str().unwrap_or("?"),
value.as_str().unwrap_or("?"),
)?;
}
Ok(())
@ -1325,8 +1388,8 @@ impl fmt::Display for CliVoteAccount {
build_balance_message(self.account_balance, self.use_lamports_unit, true)
)?;
writeln!(f, "Validator Identity: {}", self.validator_identity)?;
writeln!(f, "Authorized Voters: {}", self.authorized_voters)?;
writeln!(f, "Authorized Withdrawer: {}", self.authorized_withdrawer)?;
writeln!(f, "Vote Authority: {}", self.authorized_voters)?;
writeln!(f, "Withdraw Authority: {}", self.authorized_withdrawer)?;
writeln!(f, "Credits: {}", self.credits)?;
writeln!(f, "Commission: {}%", self.commission)?;
writeln!(
@ -1513,15 +1576,19 @@ impl fmt::Display for CliInflation {
"Staking rate: {:>5.2}%",
self.current_rate.validator * 100.
)?;
writeln!(
f,
"Foundation rate: {:>5.2}%",
self.current_rate.foundation * 100.
)
if self.current_rate.foundation > 0. {
writeln!(
f,
"Foundation rate: {:>5.2}%",
self.current_rate.foundation * 100.
)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize, Default)]
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CliSignOnlyData {
pub blockhash: String,
@ -1669,6 +1736,7 @@ pub struct CliFeesInner {
pub blockhash: String,
pub lamports_per_signature: u64,
pub last_valid_slot: Option<Slot>,
pub last_valid_block_height: Option<Slot>,
}
impl QuietDisplay for CliFeesInner {}
@ -1682,11 +1750,11 @@ impl fmt::Display for CliFeesInner {
"Lamports per signature:",
&self.lamports_per_signature.to_string(),
)?;
let last_valid_slot = self
.last_valid_slot
let last_valid_block_height = self
.last_valid_block_height
.map(|s| s.to_string())
.unwrap_or_default();
writeln_name_value(f, "Last valid slot:", &last_valid_slot)
writeln_name_value(f, "Last valid block height:", &last_valid_block_height)
}
}
@ -1715,6 +1783,7 @@ impl CliFees {
blockhash: Hash,
lamports_per_signature: u64,
last_valid_slot: Option<Slot>,
last_valid_block_height: Option<Slot>,
) -> Self {
Self {
inner: Some(CliFeesInner {
@ -1722,6 +1791,7 @@ impl CliFees {
blockhash: blockhash.to_string(),
lamports_per_signature,
last_valid_slot,
last_valid_block_height,
}),
}
}
@ -1768,7 +1838,7 @@ impl fmt::Display for CliTokenAccount {
writeln_name_value(
f,
"Close authority:",
&account.close_authority.as_ref().unwrap_or(&String::new()),
account.close_authority.as_ref().unwrap_or(&String::new()),
)?;
Ok(())
}
@ -1860,6 +1930,9 @@ pub struct CliUpgradeableProgram {
pub authority: String,
pub last_deploy_slot: u64,
pub data_len: usize,
pub lamports: u64,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliUpgradeableProgram {}
impl VerboseDisplay for CliUpgradeableProgram {}
@ -1880,12 +1953,78 @@ impl fmt::Display for CliUpgradeableProgram {
"Data Length:",
&format!("{:?} ({:#x?}) bytes", self.data_len, self.data_len),
)?;
writeln_name_value(
f,
"Balance:",
&build_balance_message(self.lamports, self.use_lamports_unit, true),
)?;
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliUpgradeablePrograms {
pub programs: Vec<CliUpgradeableProgram>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliUpgradeablePrograms {}
impl VerboseDisplay for CliUpgradeablePrograms {}
impl fmt::Display for CliUpgradeablePrograms {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln!(
f,
"{}",
style(format!(
"{:<44} | {:<9} | {:<44} | {}",
"Program Id", "Slot", "Authority", "Balance"
))
.bold()
)?;
for program in self.programs.iter() {
writeln!(
f,
"{}",
&format!(
"{:<44} | {:<9} | {:<44} | {}",
program.program_id,
program.last_deploy_slot,
program.authority,
build_balance_message(program.lamports, self.use_lamports_unit, true)
)
)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliUpgradeableProgramClosed {
pub program_id: String,
pub lamports: u64,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl QuietDisplay for CliUpgradeableProgramClosed {}
impl VerboseDisplay for CliUpgradeableProgramClosed {}
impl fmt::Display for CliUpgradeableProgramClosed {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln!(
f,
"Closed Program Id {}, {} reclaimed",
&self.program_id,
&build_balance_message(self.lamports, self.use_lamports_unit, true)
)?;
Ok(())
}
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliUpgradeableBuffer {
pub address: String,
pub authority: String,
@ -1970,6 +2109,11 @@ pub fn return_signers_with_config(
output_format: &OutputFormat,
config: &ReturnSignersConfig,
) -> Result<String, Box<dyn std::error::Error>> {
let cli_command = return_signers_data(tx, config);
Ok(output_format.formatted_string(&cli_command))
}
pub fn return_signers_data(tx: &Transaction, config: &ReturnSignersConfig) -> CliSignOnlyData {
let verify_results = tx.verify_with_results();
let mut signers = Vec::new();
let mut absent = Vec::new();
@ -1994,19 +2138,17 @@ pub fn return_signers_with_config(
None
};
let cli_command = CliSignOnlyData {
CliSignOnlyData {
blockhash: tx.message.recent_blockhash.to_string(),
message,
signers,
absent,
bad_sig,
};
Ok(output_format.formatted_string(&cli_command))
}
}
pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
let object: Value = serde_json::from_str(&reply).unwrap();
let object: Value = serde_json::from_str(reply).unwrap();
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
let blockhash = blockhash_str.parse::<Hash>().unwrap();
let mut present_signers: Vec<(Pubkey, Signature)> = Vec::new();
@ -2136,8 +2278,8 @@ impl fmt::Display for CliBlock {
writeln!(f, "Rewards:")?;
writeln!(
f,
" {:<44} {:^15} {:<15} {:<20} {:>14}",
"Address", "Type", "Amount", "New Balance", "Percent Change"
" {:<44} {:^15} {:<15} {:<20} {:>14} {:>10}",
"Address", "Type", "Amount", "New Balance", "Percent Change", "Commission"
)?;
for reward in rewards {
let sign = if reward.lamports < 0 { "-" } else { "" };
@ -2145,7 +2287,7 @@ impl fmt::Display for CliBlock {
total_rewards += reward.lamports;
writeln!(
f,
" {:<44} {:^15} {:>15} {}",
" {:<44} {:^15} {:>15} {} {}",
reward.pubkey,
if let Some(reward_type) = reward.reward_type {
format!("{}", reward_type)
@ -2167,7 +2309,11 @@ impl fmt::Display for CliBlock {
/ (reward.post_balance as f64 - reward.lamports as f64))
* 100.0
)
}
},
reward
.commission
.map(|commission| format!("{:>9}%", commission))
.unwrap_or_else(|| " -".to_string())
)?;
}
@ -2380,6 +2526,7 @@ impl VerboseDisplay for CliGossipNodes {}
#[cfg(test)]
mod tests {
use super::*;
use clap::{App, Arg};
use solana_sdk::{
message::Message,
pubkey::Pubkey,
@ -2408,6 +2555,10 @@ mod tests {
fn try_sign_message(&self, _message: &[u8]) -> Result<Signature, SignerError> {
Ok(Signature::new(&[1u8; 64]))
}
fn is_interactive(&self) -> bool {
false
}
}
let present: Box<dyn Signer> = Box::new(keypair_from_seed(&[2u8; 32]).unwrap());
@ -2436,6 +2587,22 @@ mod tests {
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
let res_data = return_signers_data(&tx, &ReturnSignersConfig::default());
assert_eq!(
res_data,
CliSignOnlyData {
blockhash: blockhash.to_string(),
message: None,
signers: vec![format!(
"{}={}",
present.pubkey().to_string(),
tx.signatures[1]
)],
absent: vec![absent.pubkey().to_string()],
bad_sig: vec![bad.pubkey().to_string()],
}
);
let expected_msg = "AwECBwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDgTl3Dqh9\
F19Wo1Rmw0x+zMuNipG07jeiXfYPW4/Js5QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\
BAQEBAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQUFBQUF\
@ -2449,10 +2616,26 @@ mod tests {
let res = return_signers_with_config(&tx, &OutputFormat::JsonCompact, &config).unwrap();
let sign_only = parse_sign_only_reply_string(&res);
assert_eq!(sign_only.blockhash, blockhash);
assert_eq!(sign_only.message, Some(expected_msg));
assert_eq!(sign_only.message, Some(expected_msg.clone()));
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
let res_data = return_signers_data(&tx, &config);
assert_eq!(
res_data,
CliSignOnlyData {
blockhash: blockhash.to_string(),
message: Some(expected_msg),
signers: vec![format!(
"{}={}",
present.pubkey().to_string(),
tx.signatures[1]
)],
absent: vec![absent.pubkey().to_string()],
bad_sig: vec![bad.pubkey().to_string()],
}
);
}
#[test]
@ -2501,4 +2684,50 @@ mod tests {
"verbose"
);
}
#[test]
fn test_output_format_from_matches() {
let app = App::new("test").arg(
Arg::with_name("output_format")
.long("output")
.value_name("FORMAT")
.global(true)
.takes_value(true)
.possible_values(&["json", "json-compact"])
.help("Return information in specified output format"),
);
let matches = app
.clone()
.get_matches_from(vec!["test", "--output", "json"]);
assert_eq!(
OutputFormat::from_matches(&matches, "output_format", false),
OutputFormat::Json
);
assert_eq!(
OutputFormat::from_matches(&matches, "output_format", true),
OutputFormat::Json
);
let matches = app
.clone()
.get_matches_from(vec!["test", "--output", "json-compact"]);
assert_eq!(
OutputFormat::from_matches(&matches, "output_format", false),
OutputFormat::JsonCompact
);
assert_eq!(
OutputFormat::from_matches(&matches, "output_format", true),
OutputFormat::JsonCompact
);
let matches = app.clone().get_matches_from(vec!["test"]);
assert_eq!(
OutputFormat::from_matches(&matches, "output_format", false),
OutputFormat::Display
);
assert_eq!(
OutputFormat::from_matches(&matches, "output_format", true),
OutputFormat::DisplayVerbose
);
}
}

View File

@ -5,7 +5,7 @@ use {
indicatif::{ProgressBar, ProgressStyle},
solana_sdk::{
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol,
program_utils::limited_deserialize, pubkey::Pubkey, transaction::Transaction,
program_utils::limited_deserialize, pubkey::Pubkey, stake, transaction::Transaction,
},
solana_transaction_status::UiTransactionStatusMeta,
spl_memo::id as spl_memo_id,
@ -140,7 +140,7 @@ fn format_account_mode(message: &Message, index: usize) -> String {
} else {
"-"
},
if message.is_writable(index, /*demote_sysvar_write_locks=*/ true) {
if message.is_writable(index, /*demote_program_write_locks=*/ true) {
"w" // comment for consistent rust fmt (no joking; lol)
} else {
"-"
@ -244,10 +244,9 @@ pub fn write_transaction<W: io::Write>(
writeln!(w, "{} {:?}", prefix, vote_instruction)?;
raw = false;
}
} else if program_pubkey == solana_stake_program::id() {
if let Ok(stake_instruction) = limited_deserialize::<
solana_stake_program::stake_instruction::StakeInstruction,
>(&instruction.data)
} else if program_pubkey == stake::program::id() {
if let Ok(stake_instruction) =
limited_deserialize::<stake::instruction::StakeInstruction>(&instruction.data)
{
writeln!(w, "{} {:?}", prefix, stake_instruction)?;
raw = false;

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "1.7.0"
version = "1.8.3"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -16,7 +16,8 @@ chrono = { version = "0.4.11", features = ["serde"] }
clap = "2.33.1"
criterion-stats = "0.3.0"
ctrlc = { version = "3.1.5", features = ["termination"] }
console = "0.11.3"
console = "0.14.1"
const_format = "0.2.14"
dirs-next = "2.0.0"
log = "0.4.11"
Inflector = "0.11.4"
@ -25,33 +26,34 @@ humantime = "2.0.1"
num-traits = "0.2"
pretty-hex = "0.2.1"
reqwest = { version = "0.11.2", default-features = false, features = ["blocking", "rustls-tls", "json"] }
semver = "1.0.4"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.0" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.7.0" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.0" }
solana-cli-config = { path = "../cli-config", version = "=1.7.0" }
solana-cli-output = { path = "../cli-output", version = "=1.7.0" }
solana-client = { path = "../client", version = "=1.7.0" }
solana-config-program = { path = "../programs/config", version = "=1.7.0" }
solana-faucet = { path = "../faucet", version = "=1.7.0" }
solana-logger = { path = "../logger", version = "=1.7.0" }
solana-net-utils = { path = "../net-utils", version = "=1.7.0" }
solana-account-decoder = { path = "../account-decoder", version = "=1.8.3" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.8.3" }
solana-clap-utils = { path = "../clap-utils", version = "=1.8.3" }
solana-cli-config = { path = "../cli-config", version = "=1.8.3" }
solana-cli-output = { path = "../cli-output", version = "=1.8.3" }
solana-client = { path = "../client", version = "=1.8.3" }
solana-config-program = { path = "../programs/config", version = "=1.8.3" }
solana-faucet = { path = "../faucet", version = "=1.8.3" }
solana-logger = { path = "../logger", version = "=1.8.3" }
solana-net-utils = { path = "../net-utils", version = "=1.8.3" }
solana_rbpf = "=0.2.11"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.0" }
solana-version = { path = "../version", version = "=1.7.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.0" }
solana-remote-wallet = { path = "../remote-wallet", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
solana-transaction-status = { path = "../transaction-status", version = "=1.8.3" }
solana-version = { path = "../version", version = "=1.8.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.8.3" }
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
thiserror = "1.0.21"
tiny-bip39 = "0.7.0"
tiny-bip39 = "0.8.1"
url = "2.1.1"
[dev-dependencies]
solana-core = { path = "../core", version = "=1.7.0" }
solana-core = { path = "../core", version = "=1.8.3" }
solana-streamer = { path = "../streamer", version = "=1.8.3" }
tempfile = "3.1.0"
[[bin]]

202
cli/src/clap_app.rs Normal file
View File

@ -0,0 +1,202 @@
use crate::{
cli::*, cluster_query::*, feature::*, inflation::*, nonce::*, program::*, stake::*,
validator_info::*, vote::*, wallet::*,
};
use clap::{App, AppSettings, Arg, ArgGroup, SubCommand};
use solana_clap_utils::{self, input_validators::*, keypair::*};
use solana_cli_config::CONFIG_FILE;
pub fn get_clap_app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, 'v> {
App::new(name)
.about(about)
.version(version)
.setting(AppSettings::SubcommandRequiredElseHelp)
.arg({
let arg = Arg::with_name("config_file")
.short("C")
.long("config")
.value_name("FILEPATH")
.takes_value(true)
.global(true)
.help("Configuration file to use");
if let Some(ref config_file) = *CONFIG_FILE {
arg.default_value(config_file)
} else {
arg
}
})
.arg(
Arg::with_name("json_rpc_url")
.short("u")
.long("url")
.value_name("URL_OR_MONIKER")
.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]",
),
)
.arg(
Arg::with_name("websocket_url")
.long("ws")
.value_name("URL")
.takes_value(true)
.global(true)
.validator(is_url)
.help("WebSocket URL for the solana cluster"),
)
.arg(
Arg::with_name("keypair")
.short("k")
.long("keypair")
.value_name("KEYPAIR")
.global(true)
.takes_value(true)
.help("Filepath or URL to a keypair"),
)
.arg(
Arg::with_name("commitment")
.long("commitment")
.takes_value(true)
.possible_values(&[
"processed",
"confirmed",
"finalized",
"recent", // Deprecated as of v1.5.5
"single", // Deprecated as of v1.5.5
"singleGossip", // Deprecated as of v1.5.5
"root", // Deprecated as of v1.5.5
"max", // Deprecated as of v1.5.5
])
.value_name("COMMITMENT_LEVEL")
.hide_possible_values(true)
.global(true)
.help("Return information at the selected commitment level [possible values: processed, confirmed, finalized]"),
)
.arg(
Arg::with_name("verbose")
.long("verbose")
.short("v")
.global(true)
.help("Show additional information"),
)
.arg(
Arg::with_name("no_address_labels")
.long("no-address-labels")
.global(true)
.help("Do not use address labels in the output"),
)
.arg(
Arg::with_name("output_format")
.long("output")
.value_name("FORMAT")
.global(true)
.takes_value(true)
.possible_values(&["json", "json-compact"])
.help("Return information in specified output format"),
)
.arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
.global(true)
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
)
.arg(
Arg::with_name("rpc_timeout")
.long("rpc-timeout")
.value_name("SECONDS")
.takes_value(true)
.default_value(DEFAULT_RPC_TIMEOUT_SECONDS)
.global(true)
.hidden(true)
.help("Timeout value for RPC requests"),
)
.arg(
Arg::with_name("confirm_transaction_initial_timeout")
.long("confirm-timeout")
.value_name("SECONDS")
.takes_value(true)
.default_value(DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS)
.global(true)
.hidden(true)
.help("Timeout value for initial transaction status"),
)
.cluster_query_subcommands()
.feature_subcommands()
.inflation_subcommands()
.nonce_subcommands()
.program_subcommands()
.stake_subcommands()
.validator_info_subcommands()
.vote_subcommands()
.wallet_subcommands()
.subcommand(
SubCommand::with_name("config")
.about("Solana command-line tool configuration settings")
.aliases(&["get", "set"])
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
SubCommand::with_name("get")
.about("Get current config settings")
.arg(
Arg::with_name("specific_setting")
.index(1)
.value_name("CONFIG_FIELD")
.takes_value(true)
.possible_values(&[
"json_rpc_url",
"websocket_url",
"keypair",
"commitment",
])
.help("Return a specific config setting"),
),
)
.subcommand(
SubCommand::with_name("set")
.about("Set a config setting")
.group(
ArgGroup::with_name("config_settings")
.args(&["json_rpc_url", "websocket_url", "keypair", "commitment"])
.multiple(true)
.required(true),
),
)
.subcommand(
SubCommand::with_name("import-address-labels")
.about("Import a list of address labels")
.arg(
Arg::with_name("filename")
.index(1)
.value_name("FILENAME")
.takes_value(true)
.help("YAML file of address labels"),
),
)
.subcommand(
SubCommand::with_name("export-address-labels")
.about("Export the current address labels")
.arg(
Arg::with_name("filename")
.index(1)
.value_name("FILENAME")
.takes_value(true)
.help("YAML file to receive the current address labels"),
),
),
)
.subcommand(
SubCommand::with_name("completion")
.about("Generate completion scripts for various shells")
.arg(
Arg::with_name("shell")
.long("shell")
.short("s")
.takes_value(true)
.possible_values(&["bash", "fish", "zsh", "powershell", "elvish"])
.default_value("bash")
)
)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
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 clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
use console::{style, Emoji};
@ -24,11 +23,12 @@ use solana_client::{
pubsub_client::PubsubClient,
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
rpc_config::{
RpcAccountInfoConfig, RpcBlockConfig, RpcLargestAccountsConfig, RpcLargestAccountsFilter,
RpcProgramAccountsConfig, RpcTransactionConfig, RpcTransactionLogsConfig,
RpcTransactionLogsFilter,
RpcAccountInfoConfig, RpcBlockConfig, RpcGetVoteAccountsConfig, RpcLargestAccountsConfig,
RpcLargestAccountsFilter, RpcProgramAccountsConfig, RpcTransactionConfig,
RpcTransactionLogsConfig, RpcTransactionLogsFilter,
},
rpc_filter,
rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE,
rpc_response::SlotInfo,
};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
@ -46,7 +46,9 @@ use solana_sdk::{
rent::Rent,
rpc_port::DEFAULT_RPC_PORT_STR,
signature::Signature,
slot_history, system_instruction, system_program,
slot_history,
stake::{self, state::StakeState},
system_instruction, system_program,
sysvar::{
self,
slot_history::SlotHistory,
@ -55,7 +57,6 @@ use solana_sdk::{
timing,
transaction::Transaction,
};
use solana_stake_program::stake_state::StakeState;
use solana_transaction_status::UiTransactionEncoding;
use solana_vote_program::vote_state::VoteState;
use std::{
@ -121,7 +122,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.long("our-localhost")
.takes_value(false)
.value_name("PORT")
.default_value(&DEFAULT_RPC_PORT_STR)
.default_value(DEFAULT_RPC_PORT_STR)
.validator(is_port)
.help("Guess Identity pubkey and validator rpc node assuming local (possibly private) validator"),
)
@ -175,7 +176,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.takes_value(true)
.value_name("EPOCH")
.validator(is_epoch)
.help("Epoch to show leader schedule for. (default: current)")
.help("Epoch to show leader schedule for. [default: current]")
)
)
.subcommand(
@ -381,6 +382,25 @@ impl ClusterQuerySubCommands for App<'_, '_> {
])
.default_value("stake")
.help("Sort order (does not affect JSON output)"),
)
.arg(
Arg::with_name("keep_unstaked_delinquents")
.long("keep-unstaked-delinquents")
.takes_value(false)
.help("Don't discard unstaked, delinquent validators")
)
.arg(
Arg::with_name("delinquent_slot_distance")
.long("delinquent-slot-distance")
.takes_value(true)
.value_name("SLOT_DISTANCE")
.validator(is_slot)
.help(
concatcp!(
"Minimum slot distance from the tip to consider a validator delinquent. [default: ",
DELINQUENT_VALIDATOR_SLOT_DISTANCE,
"]",
))
),
)
.subcommand(
@ -616,6 +636,8 @@ pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo,
let use_lamports_unit = matches.is_present("lamports");
let number_validators = matches.is_present("number");
let reverse_sort = matches.is_present("reverse");
let keep_unstaked_delinquents = matches.is_present("keep_unstaked_delinquents");
let delinquent_slot_distance = value_of(matches, "delinquent_slot_distance");
let sort_order = match value_t_or_exit!(matches, "sort", String).as_str() {
"delinquent" => CliValidatorsSortOrder::Delinquent,
@ -636,6 +658,8 @@ pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo,
sort_order,
reverse_sort,
number_validators,
keep_unstaked_delinquents,
delinquent_slot_distance,
},
signers: vec![],
})
@ -937,18 +961,19 @@ pub fn process_fees(
*recent_blockhash,
fee_calculator.lamports_per_signature,
None,
None,
)
} else {
CliFees::none()
}
} else {
let result = rpc_client.get_recent_blockhash_with_commitment(config.commitment)?;
let (recent_blockhash, fee_calculator, last_valid_slot) = result.value;
let result = rpc_client.get_fees_with_commitment(config.commitment)?;
CliFees::some(
result.context.slot,
recent_blockhash,
fee_calculator.lamports_per_signature,
Some(last_valid_slot),
result.value.blockhash,
result.value.fee_calculator.lamports_per_signature,
None,
Some(result.value.last_valid_block_height),
)
};
Ok(config.output_format.formatted_string(&fees))
@ -1075,9 +1100,15 @@ pub fn process_get_epoch_info(rpc_client: &RpcClient, config: &CliConfig) -> Pro
(secs as u64).saturating_mul(1000).checked_div(slots)
})
.unwrap_or(clock::DEFAULT_MS_PER_SLOT);
let start_block_time = rpc_client
.get_block_time(epoch_info.absolute_slot - epoch_info.slot_index)
.ok();
let current_block_time = rpc_client.get_block_time(epoch_info.absolute_slot).ok();
let epoch_info = CliEpochInfo {
epoch_info,
average_slot_time_ms,
start_block_time,
current_block_time,
};
Ok(config.output_format.formatted_string(&epoch_info))
}
@ -1690,7 +1721,7 @@ pub fn process_show_stakes(
// Filter by `StakeState::Stake(_, _)`
rpc_filter::RpcFilterType::Memcmp(rpc_filter::Memcmp {
offset: 0,
bytes: rpc_filter::MemcmpEncodedBytes::Binary(
bytes: rpc_filter::MemcmpEncodedBytes::Base58(
bs58::encode([2, 0, 0, 0]).into_string(),
),
encoding: Some(rpc_filter::MemcmpEncoding::Binary),
@ -1698,7 +1729,7 @@ pub fn process_show_stakes(
// 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(
bytes: rpc_filter::MemcmpEncodedBytes::Base58(
vote_account_pubkeys[0].to_string(),
),
encoding: Some(rpc_filter::MemcmpEncoding::Binary),
@ -1707,7 +1738,7 @@ pub fn process_show_stakes(
}
}
let all_stake_accounts = rpc_client
.get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?;
.get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?;
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(|| {
@ -1718,8 +1749,6 @@ pub fn process_show_stakes(
let stake_history = 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 mut stake_accounts: Vec<CliKeyedStakeState> = vec![];
for (stake_pubkey, stake_account) in all_stake_accounts {
@ -1735,7 +1764,6 @@ pub fn process_show_stakes(
use_lamports_unit,
&stake_history,
&clock,
stake_program_v2_enabled,
),
});
}
@ -1754,7 +1782,6 @@ pub fn process_show_stakes(
use_lamports_unit,
&stake_history,
&clock,
stake_program_v2_enabled,
),
});
}
@ -1785,11 +1812,17 @@ pub fn process_show_validators(
validators_sort_order: CliValidatorsSortOrder,
validators_reverse_sort: bool,
number_validators: bool,
keep_unstaked_delinquents: bool,
delinquent_slot_distance: Option<Slot>,
) -> ProcessResult {
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message("Fetching vote accounts...");
let epoch_info = rpc_client.get_epoch_info()?;
let vote_accounts = rpc_client.get_vote_accounts()?;
let vote_accounts = rpc_client.get_vote_accounts_with_config(RpcGetVoteAccountsConfig {
keep_unstaked_delinquents: Some(keep_unstaked_delinquents),
delinquent_slot_distance,
..RpcGetVoteAccountsConfig::default()
})?;
progress_bar.set_message("Fetching block production...");
let skip_rate: HashMap<_, _> = rpc_client
@ -1888,14 +1921,40 @@ pub fn process_show_validators(
entry.delinquent_active_stake += validator.activated_stake;
}
let validators: Vec<_> = current_validators
.into_iter()
.chain(delinquent_validators.into_iter())
.collect();
let (average_skip_rate, average_stake_weighted_skip_rate) = {
let mut skip_rate_len = 0;
let mut skip_rate_sum = 0.;
let mut skip_rate_weighted_sum = 0.;
for validator in validators.iter() {
if let Some(skip_rate) = validator.skip_rate {
skip_rate_sum += skip_rate;
skip_rate_len += 1;
skip_rate_weighted_sum += skip_rate * validator.activated_stake as f64;
}
}
if skip_rate_len > 0 && total_active_stake > 0 {
(
skip_rate_sum / skip_rate_len as f64,
skip_rate_weighted_sum / total_active_stake as f64,
)
} else {
(100., 100.) // Impossible?
}
};
let cli_validators = CliValidators {
total_active_stake,
total_current_stake,
total_delinquent_stake,
validators: current_validators
.into_iter()
.chain(delinquent_validators.into_iter())
.collect(),
validators,
average_skip_rate,
average_stake_weighted_skip_rate,
validators_sort_order,
validators_reverse_sort,
number_validators,
@ -2082,7 +2141,7 @@ pub fn process_calculate_rent(
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{app, parse_command};
use crate::{clap_app::get_clap_app, cli::parse_command};
use solana_sdk::signature::{write_keypair, Keypair};
use std::str::FromStr;
use tempfile::NamedTempFile;
@ -2094,11 +2153,11 @@ mod tests {
#[test]
fn test_parse_command() {
let test_commands = app("test", "desc", "version");
let test_commands = get_clap_app("test", "desc", "version");
let default_keypair = Keypair::new();
let (default_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
let default_signer = DefaultSigner::new(default_keypair_file);
let default_signer = DefaultSigner::new("", &default_keypair_file);
let test_cluster_version = test_commands
.clone()

View File

@ -10,6 +10,7 @@ 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::{
account::Account,
clock::Slot,
feature::{self, Feature},
feature_set::FEATURE_NAMES,
@ -17,7 +18,12 @@ use solana_sdk::{
pubkey::Pubkey,
transaction::Transaction,
};
use std::{collections::HashMap, fmt, sync::Arc};
use std::{
cmp::Ordering,
collections::{HashMap, HashSet},
fmt,
sync::Arc,
};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ForceActivation {
@ -221,44 +227,103 @@ pub fn process_feature_subcommand(
}
}
fn active_stake_by_feature_set(rpc_client: &RpcClient) -> Result<HashMap<u32, f64>, ClientError> {
#[derive(Debug, Default)]
struct WorkingFeatureSetStatsEntry {
stake: u64,
rpc_nodes_count: u32,
software_versions: HashSet<Option<semver::Version>>,
}
type WorkingFeatureSetStats = HashMap<u32, WorkingFeatureSetStatsEntry>;
#[derive(Debug, Default)]
struct FeatureSetStatsEntry {
stake_percent: f64,
rpc_nodes_percent: f32,
software_versions: Vec<Option<semver::Version>>,
}
type FeatureSetStats = HashMap<u32, FeatureSetStatsEntry>;
fn feature_set_stats(rpc_client: &RpcClient) -> Result<FeatureSetStats, ClientError> {
// Validator identity -> feature set
let feature_set_map = rpc_client
let feature_sets = rpc_client
.get_cluster_nodes()?
.into_iter()
.map(|contact_info| (contact_info.pubkey, contact_info.feature_set))
.collect::<HashMap<_, _>>();
.map(|contact_info| {
(
contact_info.pubkey,
contact_info.feature_set,
contact_info.rpc.is_some(),
contact_info
.version
.and_then(|v| semver::Version::parse(&v).ok()),
)
})
.collect::<Vec<_>>();
let vote_accounts = rpc_client.get_vote_accounts()?;
let total_active_stake: u64 = vote_accounts
.current
let mut total_active_stake: u64 = vote_accounts
.delinquent
.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<u32, u64> = 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;
let vote_stakes = vote_accounts
.current
.into_iter()
.map(|vote_account| {
total_active_stake += vote_account.activated_stake;
(vote_account.node_pubkey, vote_account.activated_stake)
})
.collect::<HashMap<_, _>>();
let mut feature_set_stats: WorkingFeatureSetStats = HashMap::new();
let mut total_rpc_nodes = 0;
for (node_id, feature_set, is_rpc, version) in feature_sets {
let feature_set = feature_set.unwrap_or(0);
let feature_set_entry = feature_set_stats.entry(feature_set).or_default();
feature_set_entry.software_versions.insert(version);
if let Some(vote_stake) = vote_stakes.get(&node_id) {
feature_set_entry.stake += *vote_stake;
}
if is_rpc {
feature_set_entry.rpc_nodes_count += 1;
total_rpc_nodes += 1;
}
}
Ok(active_stake_by_feature_set
Ok(feature_set_stats
.into_iter()
.map(|(feature_set, active_stake)| {
(
.filter_map(
|(
feature_set,
active_stake as f64 * 100. / total_active_stake as f64,
)
})
WorkingFeatureSetStatsEntry {
stake,
rpc_nodes_count,
software_versions,
},
)| {
let stake_percent = (stake as f64 / total_active_stake as f64) * 100.;
let rpc_nodes_percent = (rpc_nodes_count as f32 / total_rpc_nodes as f32) * 100.;
let mut software_versions = software_versions.into_iter().collect::<Vec<_>>();
software_versions.sort();
if stake_percent >= 0.001 || rpc_nodes_percent >= 0.001 {
Some((
feature_set,
FeatureSetStatsEntry {
stake_percent,
rpc_nodes_percent,
software_versions,
},
))
} else {
None
}
},
)
.collect())
}
@ -266,50 +331,189 @@ fn active_stake_by_feature_set(rpc_client: &RpcClient) -> Result<HashMap<u32, f6
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_set_stats = feature_set_stats(rpc_client)?;
let feature_activation_allowed = active_stake_by_feature_set
let (stake_allowed, rpc_allowed) = feature_set_stats
.get(&my_feature_set)
.map(|percentage| *percentage >= 95.)
.unwrap_or(false);
.map(
|FeatureSetStatsEntry {
stake_percent,
rpc_nodes_percent,
..
}| (*stake_percent >= 95., *rpc_nodes_percent >= 95.),
)
.unwrap_or((false, false));
if !feature_activation_allowed && !quiet {
if active_stake_by_feature_set.get(&my_feature_set).is_none() {
if !stake_allowed && !rpc_allowed && !quiet {
if feature_set_stats.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()
);
if !stake_allowed {
print!(
"\n{}",
style("To activate features the stake must be >= 95%")
.bold()
.red()
);
}
if !rpc_allowed {
print!(
"\n{}",
style("To activate features the RPC nodes must be >= 95%")
.bold()
.red()
);
}
}
println!(
"\n\n{}",
style(format!("Tool Feature Set: {}", my_feature_set)).bold()
);
let mut feature_set_stats = feature_set_stats.into_iter().collect::<Vec<_>>();
feature_set_stats.sort_by(|l, r| {
match l.1.software_versions[0]
.cmp(&r.1.software_versions[0])
.reverse()
{
Ordering::Equal => {
match l
.1
.stake_percent
.partial_cmp(&r.1.stake_percent)
.unwrap()
.reverse()
{
Ordering::Equal => {
l.1.rpc_nodes_percent
.partial_cmp(&r.1.rpc_nodes_percent)
.unwrap()
.reverse()
}
o => o,
}
}
o => o,
}
});
let software_versions_title = "Software Version";
let feature_set_title = "Feature Set";
let stake_percent_title = "Stake";
let rpc_percent_title = "RPC";
let mut stats_output = Vec::new();
let mut max_software_versions_len = software_versions_title.len();
let mut max_feature_set_len = feature_set_title.len();
let mut max_stake_percent_len = stake_percent_title.len();
let mut max_rpc_percent_len = rpc_percent_title.len();
for (
feature_set,
FeatureSetStatsEntry {
stake_percent,
rpc_nodes_percent,
software_versions,
},
) in feature_set_stats.into_iter()
{
let me = feature_set == my_feature_set;
let feature_set = if feature_set == 0 {
"unknown".to_string()
} else {
feature_set.to_string()
};
let stake_percent = format!("{:.2}%", stake_percent);
let rpc_percent = format!("{:.2}%", rpc_nodes_percent);
let mut has_unknown = false;
let mut software_versions = software_versions
.iter()
.filter_map(|v| {
if v.is_none() {
has_unknown = true;
}
v.as_ref()
})
.map(ToString::to_string)
.collect::<Vec<_>>();
if has_unknown {
software_versions.push("unknown".to_string());
}
let software_versions = software_versions.join(", ");
max_software_versions_len = max_software_versions_len.max(software_versions.len());
max_feature_set_len = max_feature_set_len.max(feature_set.len());
max_stake_percent_len = max_stake_percent_len.max(stake_percent.len());
max_rpc_percent_len = max_rpc_percent_len.max(rpc_percent.len());
stats_output.push((
software_versions,
feature_set,
stake_percent,
rpc_percent,
me,
));
}
println!(
"{}",
style(format!("Tool Feature Set: {}", my_feature_set)).bold()
style(format!(
"{1:<0$} {3:<2$} {5:<4$} {7:<6$}",
max_software_versions_len,
software_versions_title,
max_feature_set_len,
feature_set_title,
max_stake_percent_len,
stake_percent_title,
max_rpc_percent_len,
rpc_percent_title,
))
.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 - {:.2}%", percentage);
} else {
println!(
" {:<10} - {:.2}% {}",
feature_set,
percentage,
if *feature_set == my_feature_set {
" <-- me"
} else {
""
}
);
}
for (software_versions, feature_set, stake_percent, rpc_percent, me) in stats_output {
println!(
"{1:<0$} {3:>2$} {5:>4$} {7:>6$} {8}",
max_software_versions_len,
software_versions,
max_feature_set_len,
feature_set,
max_stake_percent_len,
stake_percent,
max_rpc_percent_len,
rpc_percent,
if me { "<-- me" } else { "" },
);
}
println!();
}
Ok(feature_activation_allowed)
Ok(stake_allowed && rpc_allowed)
}
fn status_from_account(account: Account) -> Option<CliFeatureStatus> {
feature::from_account(&account).map(|feature| match feature.activated_at {
None => CliFeatureStatus::Pending,
Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
})
}
fn get_feature_status(
rpc_client: &RpcClient,
feature_id: &Pubkey,
) -> Result<Option<CliFeatureStatus>, Box<dyn std::error::Error>> {
rpc_client
.get_account(feature_id)
.map(status_from_account)
.map_err(|e| e.into())
}
pub fn get_feature_is_active(
rpc_client: &RpcClient,
feature_id: &Pubkey,
) -> Result<bool, Box<dyn std::error::Error>> {
get_feature_status(rpc_client, feature_id)
.map(|status| matches!(status, Some(CliFeatureStatus::Active(_))))
}
fn process_status(
@ -327,11 +531,7 @@ fn process_status(
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),
};
if let Some(feature_status) = status_from_account(account) {
features.push(CliFeature {
id: feature_id.to_string(),
description: feature_name.to_string(),

View File

@ -102,7 +102,7 @@ fn process_rewards(
rewards_epoch: Option<Epoch>,
) -> ProcessResult {
let rewards = rpc_client
.get_inflation_reward(&addresses, rewards_epoch)
.get_inflation_reward(addresses, rewards_epoch)
.map_err(|err| {
if let Some(epoch) = rewards_epoch {
format!("Rewards not available for epoch {}", epoch)

View File

@ -18,9 +18,13 @@ macro_rules! pubkey {
};
}
#[macro_use]
extern crate const_format;
extern crate serde_derive;
pub mod checks;
pub mod clap_app;
pub mod cli;
pub mod cluster_query;
pub mod feature;
@ -33,3 +37,4 @@ pub mod stake;
pub mod test_utils;
pub mod validator_info;
pub mod vote;
pub mod wallet;

View File

@ -1,18 +1,15 @@
use clap::{
crate_description, crate_name, value_t_or_exit, AppSettings, Arg, ArgGroup, ArgMatches,
SubCommand,
};
use clap::{crate_description, crate_name, value_t_or_exit, ArgMatches};
use console::style;
use solana_clap_utils::{
input_validators::{is_url, is_url_or_moniker, normalize_to_url_if_moniker},
keypair::{CliSigners, DefaultSigner, SKIP_SEED_PHRASE_VALIDATION_ARG},
input_validators::normalize_to_url_if_moniker,
keypair::{CliSigners, DefaultSigner},
DisplayError,
};
use solana_cli::cli::{
app, parse_command, process_command, CliCommandInfo, CliConfig, SettingType,
DEFAULT_RPC_TIMEOUT_SECONDS,
use solana_cli::{
clap_app::get_clap_app,
cli::{parse_command, process_command, CliCommandInfo, CliConfig, SettingType},
};
use solana_cli_config::{Config, CONFIG_FILE};
use solana_cli_config::Config;
use solana_cli_output::{display::println_name_value, OutputFormat};
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
@ -167,23 +164,29 @@ pub fn parse_args<'a>(
let rpc_timeout = value_t_or_exit!(matches, "rpc_timeout", u64);
let rpc_timeout = Duration::from_secs(rpc_timeout);
let confirm_transaction_initial_timeout =
value_t_or_exit!(matches, "confirm_transaction_initial_timeout", u64);
let confirm_transaction_initial_timeout =
Duration::from_secs(confirm_transaction_initial_timeout);
let (_, websocket_url) = CliConfig::compute_websocket_url_setting(
matches.value_of("websocket_url").unwrap_or(""),
&config.websocket_url,
matches.value_of("json_rpc_url").unwrap_or(""),
&config.json_rpc_url,
);
let default_signer_arg_name = "keypair".to_string();
let (_, default_signer_path) = CliConfig::compute_keypair_path_setting(
matches.value_of("keypair").unwrap_or(""),
matches.value_of(&default_signer_arg_name).unwrap_or(""),
&config.keypair_path,
);
let default_signer = DefaultSigner::from_path(default_signer_path.clone())?;
let default_signer = DefaultSigner::new(default_signer_arg_name, &default_signer_path);
let CliCommandInfo {
command,
mut signers,
} = parse_command(&matches, &default_signer, &mut wallet_manager)?;
} = parse_command(matches, &default_signer, &mut wallet_manager)?;
if signers.is_empty() {
if let Ok(signer_info) =
@ -194,18 +197,7 @@ pub fn parse_args<'a>(
}
let verbose = matches.is_present("verbose");
let output_format = matches
.value_of("output_format")
.map(|value| match value {
"json" => OutputFormat::Json,
"json-compact" => OutputFormat::JsonCompact,
_ => unreachable!(),
})
.unwrap_or(if verbose {
OutputFormat::DisplayVerbose
} else {
OutputFormat::Display
});
let output_format = OutputFormat::from_matches(matches, "output_format", verbose);
let (_, commitment) = CliConfig::compute_commitment_config(
matches.value_of("commitment").unwrap_or(""),
@ -234,6 +226,7 @@ pub fn parse_args<'a>(
preflight_commitment: Some(commitment.commitment),
..RpcSendTransactionConfig::default()
},
confirm_transaction_initial_timeout,
address_labels,
},
signers,
@ -242,178 +235,21 @@ pub fn parse_args<'a>(
fn main() -> Result<(), Box<dyn error::Error>> {
solana_logger::setup_with_default("off");
let matches = app(
let matches = get_clap_app(
crate_name!(),
crate_description!(),
solana_version::version!(),
)
.arg({
let arg = Arg::with_name("config_file")
.short("C")
.long("config")
.value_name("FILEPATH")
.takes_value(true)
.global(true)
.help("Configuration file to use");
if let Some(ref config_file) = *CONFIG_FILE {
arg.default_value(&config_file)
} else {
arg
}
})
.arg(
Arg::with_name("json_rpc_url")
.short("u")
.long("url")
.value_name("URL_OR_MONIKER")
.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]",
),
)
.arg(
Arg::with_name("websocket_url")
.long("ws")
.value_name("URL")
.takes_value(true)
.global(true)
.validator(is_url)
.help("WebSocket URL for the solana cluster"),
)
.arg(
Arg::with_name("keypair")
.short("k")
.long("keypair")
.value_name("KEYPAIR")
.global(true)
.takes_value(true)
.help("Filepath or URL to a keypair"),
)
.arg(
Arg::with_name("commitment")
.long("commitment")
.takes_value(true)
.possible_values(&[
"processed",
"confirmed",
"finalized",
"recent", // Deprecated as of v1.5.5
"single", // Deprecated as of v1.5.5
"singleGossip", // Deprecated as of v1.5.5
"root", // Deprecated as of v1.5.5
"max", // Deprecated as of v1.5.5
])
.value_name("COMMITMENT_LEVEL")
.hide_possible_values(true)
.global(true)
.help("Return information at the selected commitment level [possible values: processed, confirmed, finalized]"),
)
.arg(
Arg::with_name("verbose")
.long("verbose")
.short("v")
.global(true)
.help("Show additional information"),
)
.arg(
Arg::with_name("no_address_labels")
.long("no-address-labels")
.global(true)
.help("Do not use address labels in the output"),
)
.arg(
Arg::with_name("output_format")
.long("output")
.value_name("FORMAT")
.global(true)
.takes_value(true)
.possible_values(&["json", "json-compact"])
.help("Return information in specified output format"),
)
.arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
.global(true)
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
)
.arg(
Arg::with_name("rpc_timeout")
.long("rpc-timeout")
.value_name("SECONDS")
.takes_value(true)
.default_value(DEFAULT_RPC_TIMEOUT_SECONDS)
.global(true)
.hidden(true)
.help("Timeout value for RPC requests"),
)
.subcommand(
SubCommand::with_name("config")
.about("Solana command-line tool configuration settings")
.aliases(&["get", "set"])
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
SubCommand::with_name("get")
.about("Get current config settings")
.arg(
Arg::with_name("specific_setting")
.index(1)
.value_name("CONFIG_FIELD")
.takes_value(true)
.possible_values(&[
"json_rpc_url",
"websocket_url",
"keypair",
"commitment",
])
.help("Return a specific config setting"),
),
)
.subcommand(
SubCommand::with_name("set")
.about("Set a config setting")
.group(
ArgGroup::with_name("config_settings")
.args(&["json_rpc_url", "websocket_url", "keypair", "commitment"])
.multiple(true)
.required(true),
),
)
.subcommand(
SubCommand::with_name("import-address-labels")
.about("Import a list of address labels")
.arg(
Arg::with_name("filename")
.index(1)
.value_name("FILENAME")
.takes_value(true)
.help("YAML file of address labels"),
),
)
.subcommand(
SubCommand::with_name("export-address-labels")
.about("Export the current address labels")
.arg(
Arg::with_name("filename")
.index(1)
.value_name("FILENAME")
.takes_value(true)
.help("YAML file to receive the current address labels"),
),
),
)
.get_matches();
do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into())
}
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
if parse_settings(&matches)? {
if parse_settings(matches)? {
let mut wallet_manager = None;
let (mut config, signers) = parse_args(&matches, &mut wallet_manager)?;
let (mut config, signers) = parse_args(matches, &mut wallet_manager)?;
config.signers = signers.iter().map(|s| s.as_ref()).collect();
let result = process_command(&config)?;
println!("{}", result);

View File

@ -1,9 +1,10 @@
use crate::{
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
cli::{
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
log_instruction_custom_error, log_instruction_custom_error_ex, CliCommand, CliCommandInfo,
CliConfig, CliError, ProcessResult,
},
feature::get_feature_is_active,
memo::WithMemo,
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
@ -12,7 +13,7 @@ use solana_clap_utils::{
input_parsers::*,
input_validators::*,
keypair::{DefaultSigner, SignerIndex},
memo::MEMO_ARG,
memo::{memo_arg, MEMO_ARG},
nonce::*,
};
use solana_cli_output::CliNonceAccount;
@ -20,16 +21,19 @@ use solana_client::{nonce_utils::*, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account::Account,
feature_set::merge_nonce_error_into_system_error,
hash::Hash,
instruction::InstructionError,
message::Message,
nonce::{self, State},
pubkey::Pubkey,
system_instruction::{
advance_nonce_account, authorize_nonce_account, create_nonce_account,
create_nonce_account_with_seed, withdraw_nonce_account, NonceError, SystemError,
create_nonce_account_with_seed, instruction_to_nonce_error, withdraw_nonce_account,
NonceError, SystemError,
},
system_program,
transaction::Transaction,
transaction::{Transaction, TransactionError},
};
use std::sync::Arc;
@ -56,7 +60,8 @@ impl NonceSubCommands for App<'_, '_> {
.required(true),
"Account to be granted authority of the nonce account. "),
)
.arg(nonce_authority_arg()),
.arg(nonce_authority_arg())
.arg(memo_arg()),
)
.subcommand(
SubCommand::with_name("create-nonce-account")
@ -91,7 +96,8 @@ impl NonceSubCommands for App<'_, '_> {
.value_name("STRING")
.takes_value(true)
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the NONCE_ACCOUNT pubkey")
),
)
.arg(memo_arg()),
)
.subcommand(
SubCommand::with_name("nonce")
@ -115,7 +121,8 @@ impl NonceSubCommands for App<'_, '_> {
.required(true),
"Address of the nonce account. "),
)
.arg(nonce_authority_arg()),
.arg(nonce_authority_arg())
.arg(memo_arg()),
)
.subcommand(
SubCommand::with_name("nonce-account")
@ -161,7 +168,8 @@ impl NonceSubCommands for App<'_, '_> {
.validator(is_amount)
.help("The amount to withdraw from the nonce account, in SOL"),
)
.arg(nonce_authority_arg()),
.arg(nonce_authority_arg())
.arg(memo_arg()),
)
}
}
@ -363,8 +371,21 @@ pub fn process_authorize_nonce_account(
&tx.message,
config.commitment,
)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<NonceError>(result, &config)
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
}
pub fn process_create_nonce_account(
@ -448,8 +469,40 @@ pub fn process_create_nonce_account(
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, recent_blockhash)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<SystemError>(result, &config)
let err_ix_index = if let Err(err) = &result {
err.get_transaction_error().and_then(|tx_err| {
if let TransactionError::InstructionError(ix_index, _) = tx_err {
Some(ix_index)
} else {
None
}
})
} else {
None
};
match err_ix_index {
// SystemInstruction::InitializeNonceAccount failed
Some(1) => {
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
}
// SystemInstruction::CreateAccount{,WithSeed} failed
_ => log_instruction_custom_error::<SystemError>(result, config),
}
}
pub fn process_get_nonce(
@ -474,10 +527,10 @@ pub fn process_new_nonce(
) -> ProcessResult {
check_unique_pubkeys(
(&config.signers[0].pubkey(), "cli keypair".to_string()),
(&nonce_account, "nonce_account_pubkey".to_string()),
(nonce_account, "nonce_account_pubkey".to_string()),
)?;
if let Err(err) = rpc_client.get_account(&nonce_account) {
if let Err(err) = rpc_client.get_account(nonce_account) {
return Err(CliError::BadParameter(format!(
"Unable to advance nonce account {}. error: {}",
nonce_account, err
@ -487,7 +540,7 @@ pub fn process_new_nonce(
let nonce_authority = config.signers[nonce_authority];
let ixs = vec![advance_nonce_account(
&nonce_account,
nonce_account,
&nonce_authority.pubkey(),
)]
.with_memo(memo);
@ -502,8 +555,21 @@ pub fn process_new_nonce(
&tx.message,
config.commitment,
)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<SystemError>(result, &config)
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
}
pub fn process_show_nonce_account(
@ -522,7 +588,7 @@ pub fn process_show_nonce_account(
use_lamports_unit,
..CliNonceAccount::default()
};
if let Some(ref data) = data {
if let Some(data) = data {
nonce_account.nonce = Some(data.blockhash.to_string());
nonce_account.lamports_per_signature = Some(data.fee_calculator.lamports_per_signature);
nonce_account.authority = Some(data.authority.to_string());
@ -565,14 +631,27 @@ pub fn process_withdraw_from_nonce_account(
&tx.message,
config.commitment,
)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<NonceError>(result, &config)
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{app, parse_command};
use crate::{clap_app::get_clap_app, cli::parse_command};
use solana_sdk::{
account::Account,
account_utils::StateMut,
@ -592,11 +671,11 @@ mod tests {
#[test]
fn test_parse_command() {
let test_commands = app("test", "desc", "version");
let test_commands = get_clap_app("test", "desc", "version");
let default_keypair = Keypair::new();
let (default_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
let default_signer = DefaultSigner::new(default_keypair_file.clone());
let default_signer = DefaultSigner::new("", &default_keypair_file);
let (keypair_file, mut tmp_file) = make_tmp_file();
let nonce_account_keypair = Keypair::new();
write_keypair(&nonce_account_keypair, tmp_file.as_file_mut()).unwrap();

File diff suppressed because it is too large Load Diff

View File

@ -92,7 +92,7 @@ where
Ok((message, spend))
} else {
let from_balance = rpc_client
.get_balance_with_commitment(&from_pubkey, commitment)?
.get_balance_with_commitment(from_pubkey, commitment)?
.value;
let (message, SpendAndFee { spend, fee }) = resolve_spend_message(
amount,

File diff suppressed because it is too large Load Diff

View File

@ -119,7 +119,7 @@ fn parse_validator_info(
let key_list: ConfigKeys = deserialize(&account.data)?;
if !key_list.keys.is_empty() {
let (validator_pubkey, _) = key_list.keys[1];
let validator_info_string: String = deserialize(&get_config_data(&account.data)?)?;
let validator_info_string: String = deserialize(get_config_data(&account.data)?)?;
let validator_info: Map<_, _> = serde_json::from_str(&validator_info_string)?;
Ok((validator_pubkey, validator_info))
} else {
@ -246,7 +246,7 @@ pub fn process_set_validator_info(
) -> ProcessResult {
// Validate keybase username
if let Some(string) = validator_info.get("keybaseUsername") {
let result = verify_keybase(&config.signers[0].pubkey(), &string);
let result = verify_keybase(&config.signers[0].pubkey(), string);
if result.is_err() {
if force_keybase {
println!("--force supplied, ignoring: {:?}", result);
@ -272,7 +272,7 @@ pub fn process_set_validator_info(
},
)
.find(|(pubkey, account)| {
let (validator_pubkey, _) = parse_validator_info(&pubkey, &account).unwrap();
let (validator_pubkey, _) = parse_validator_info(pubkey, account).unwrap();
validator_pubkey == config.signers[0].pubkey()
});
@ -393,7 +393,7 @@ pub fn process_get_validator_info(
}
for (validator_info_pubkey, validator_info_account) in validator_info.iter() {
let (validator_pubkey, validator_info) =
parse_validator_info(&validator_info_pubkey, &validator_info_account)?;
parse_validator_info(validator_info_pubkey, validator_info_account)?;
validator_info_list.push(CliValidatorInfo {
identity_pubkey: validator_pubkey.to_string(),
info_pubkey: validator_info_pubkey.to_string(),
@ -408,7 +408,7 @@ pub fn process_get_validator_info(
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::app;
use crate::clap_app::get_clap_app;
use bincode::{serialize, serialized_size};
use serde_json::json;
@ -432,7 +432,7 @@ mod tests {
#[test]
fn test_parse_args() {
let matches = app("test", "desc", "version").get_matches_from(vec![
let matches = get_clap_app("test", "desc", "version").get_matches_from(vec![
"test",
"validator-info",
"publish",
@ -451,7 +451,7 @@ mod tests {
"name": "Alice",
"keybaseUsername": "alice_keybase",
});
assert_eq!(parse_args(&matches), expected);
assert_eq!(parse_args(matches), expected);
}
#[test]

View File

@ -6,6 +6,7 @@ use crate::{
},
memo::WithMemo,
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
stake::check_current_authority,
};
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{
@ -55,6 +56,15 @@ impl VoteSubCommands for App<'_, '_> {
.validator(is_valid_signer)
.help("Keypair of validator that will vote with this account"),
)
.arg(
pubkey!(Arg::with_name("authorized_withdrawer")
.index(3)
.value_name("WITHDRAWER_PUBKEY")
.takes_value(true)
.required(true)
.long("authorized-withdrawer"),
"Public key of the authorized withdrawer")
)
.arg(
Arg::with_name("commission")
.long("commission")
@ -70,10 +80,12 @@ impl VoteSubCommands for App<'_, '_> {
"Public key of the authorized voter [default: validator identity pubkey]. "),
)
.arg(
pubkey!(Arg::with_name("authorized_withdrawer")
.long("authorized-withdrawer")
.value_name("WITHDRAWER_PUBKEY"),
"Public key of the authorized withdrawer [default: validator identity pubkey]. "),
Arg::with_name("allow_unsafe_authorized_withdrawer")
.long("allow-unsafe-authorized-withdrawer")
.takes_value(false)
.help("Allow an authorized withdrawer pubkey to be identical to the validator identity \
account pubkey or vote account pubkey, which is normally an unsafe \
configuration and should be avoided."),
)
.arg(
Arg::with_name("seed")
@ -82,7 +94,7 @@ impl VoteSubCommands for App<'_, '_> {
.takes_value(true)
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the VOTE ACCOUNT pubkey")
)
.arg(memo_arg())
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-authorize-voter")
@ -109,7 +121,7 @@ impl VoteSubCommands for App<'_, '_> {
.required(true),
"New authorized vote signer. "),
)
.arg(memo_arg())
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-authorize-withdrawer")
@ -136,7 +148,65 @@ impl VoteSubCommands for App<'_, '_> {
.required(true),
"New authorized withdrawer. "),
)
.arg(memo_arg())
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-authorize-voter-checked")
.about("Authorize a new vote signing keypair for the given vote account, \
checking the new authority as a signer")
.arg(
pubkey!(Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE_ACCOUNT_ADDRESS")
.required(true),
"Vote account in which to set the authorized voter. "),
)
.arg(
Arg::with_name("authorized")
.index(2)
.value_name("AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("Current authorized vote signer."),
)
.arg(
Arg::with_name("new_authorized")
.index(3)
.value_name("NEW_AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("New authorized vote signer."),
)
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-authorize-withdrawer-checked")
.about("Authorize a new withdraw signing keypair for the given vote account, \
checking the new authority as a signer")
.arg(
pubkey!(Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE_ACCOUNT_ADDRESS")
.required(true),
"Vote account in which to set the authorized withdrawer. "),
)
.arg(
Arg::with_name("authorized")
.index(2)
.value_name("AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("Current authorized withdrawer."),
)
.arg(
Arg::with_name("new_authorized")
.index(3)
.value_name("NEW_AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("New authorized withdrawer."),
)
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-update-validator")
@ -166,7 +236,7 @@ impl VoteSubCommands for App<'_, '_> {
.validator(is_valid_signer)
.help("Authorized withdrawer keypair"),
)
.arg(memo_arg())
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-update-commission")
@ -196,7 +266,7 @@ impl VoteSubCommands for App<'_, '_> {
.validator(is_valid_signer)
.help("Authorized withdrawer keypair"),
)
.arg(memo_arg())
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-account")
@ -266,7 +336,7 @@ impl VoteSubCommands for App<'_, '_> {
.validator(is_valid_signer)
.help("Authorized withdrawer [default: cli config keypair]"),
)
.arg(memo_arg())
.arg(memo_arg())
)
}
}
@ -282,9 +352,28 @@ pub fn parse_create_vote_account(
signer_of(matches, "identity_account", wallet_manager)?;
let commission = value_t_or_exit!(matches, "commission", u8);
let authorized_voter = pubkey_of_signer(matches, "authorized_voter", wallet_manager)?;
let authorized_withdrawer = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?;
let authorized_withdrawer =
pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?.unwrap();
let allow_unsafe = matches.is_present("allow_unsafe_authorized_withdrawer");
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
if !allow_unsafe {
if authorized_withdrawer == vote_account_pubkey.unwrap() {
return Err(CliError::BadParameter(
"Authorized withdrawer pubkey is identical to vote \
account pubkey, an unsafe configuration"
.to_owned(),
));
}
if authorized_withdrawer == identity_pubkey.unwrap() {
return Err(CliError::BadParameter(
"Authorized withdrawer pubkey is identical to identity \
account pubkey, an unsafe configuration"
.to_owned(),
));
}
}
let payer_provided = None;
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, vote_account, identity_account],
@ -311,19 +400,25 @@ pub fn parse_vote_authorize(
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
vote_authorize: VoteAuthorize,
checked: bool,
) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey =
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
let new_authorized_pubkey =
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap();
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
let (authorized, authorized_pubkey) = signer_of(matches, "authorized", wallet_manager)?;
let payer_provided = None;
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, authorized],
matches,
wallet_manager,
)?;
let mut signers = vec![payer_provided, authorized];
let new_authorized_pubkey = if checked {
let (new_authorized_signer, new_authorized_pubkey) =
signer_of(matches, "new_authorized", wallet_manager)?;
signers.push(new_authorized_signer);
new_authorized_pubkey.unwrap()
} else {
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap()
};
let signer_info = default_signer.generate_unique_signers(signers, matches, wallet_manager)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
Ok(CliCommandInfo {
@ -332,6 +427,12 @@ pub fn parse_vote_authorize(
new_authorized_pubkey,
vote_authorize,
memo,
authorized: signer_info.index_of(authorized_pubkey).unwrap(),
new_authorized: if checked {
signer_info.index_of(Some(new_authorized_pubkey))
} else {
None
},
},
signers: signer_info.signers,
})
@ -461,14 +562,14 @@ pub fn process_create_vote_account(
seed: &Option<String>,
identity_account: SignerIndex,
authorized_voter: &Option<Pubkey>,
authorized_withdrawer: &Option<Pubkey>,
authorized_withdrawer: Pubkey,
commission: u8,
memo: Option<&String>,
) -> ProcessResult {
let vote_account = config.signers[vote_account];
let vote_account_pubkey = vote_account.pubkey();
let vote_account_address = if let Some(seed) = seed {
Pubkey::create_with_seed(&vote_account_pubkey, &seed, &solana_vote_program::id())?
Pubkey::create_with_seed(&vote_account_pubkey, seed, &solana_vote_program::id())?
} else {
vote_account_pubkey
};
@ -493,7 +594,7 @@ pub fn process_create_vote_account(
let vote_init = VoteInit {
node_pubkey: identity_pubkey,
authorized_voter: authorized_voter.unwrap_or(identity_pubkey),
authorized_withdrawer: authorized_withdrawer.unwrap_or(identity_pubkey),
authorized_withdrawer,
commission,
};
@ -549,7 +650,7 @@ pub fn process_create_vote_account(
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, recent_blockhash)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<SystemError>(result, &config)
log_instruction_custom_error::<SystemError>(result, config)
}
pub fn process_vote_authorize(
@ -558,28 +659,62 @@ pub fn process_vote_authorize(
vote_account_pubkey: &Pubkey,
new_authorized_pubkey: &Pubkey,
vote_authorize: VoteAuthorize,
authorized: SignerIndex,
new_authorized: Option<SignerIndex>,
memo: Option<&String>,
) -> ProcessResult {
// If the `authorized_account` is also the fee payer, `config.signers` will only have one
// keypair in it
let authorized = if config.signers.len() == 2 {
config.signers[1]
} else {
config.signers[0]
};
let authorized = config.signers[authorized];
let new_authorized_signer = new_authorized.map(|index| config.signers[index]);
check_unique_pubkeys(
(&authorized.pubkey(), "authorized_account".to_string()),
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
)?;
let (_, vote_state) = get_vote_account(rpc_client, vote_account_pubkey, config.commitment)?;
match vote_authorize {
VoteAuthorize::Voter => {
let current_authorized_voter = vote_state
.authorized_voters()
.last()
.ok_or_else(|| {
CliError::RpcRequestError(
"Invalid vote account state; no authorized voters found".to_string(),
)
})?
.1;
check_current_authority(current_authorized_voter, &authorized.pubkey())?;
if let Some(signer) = new_authorized_signer {
if signer.is_interactive() {
return Err(CliError::BadParameter(format!(
"invalid new authorized vote signer {:?}. Interactive vote signers not supported",
new_authorized_pubkey
)).into());
}
}
}
VoteAuthorize::Withdrawer => {
check_current_authority(&vote_state.authorized_withdrawer, &authorized.pubkey())?
}
}
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let ixs = vec![vote_instruction::authorize(
vote_account_pubkey, // vote account to update
&authorized.pubkey(), // current authorized
new_authorized_pubkey, // new vote signer/withdrawer
vote_authorize, // vote or withdraw
)]
.with_memo(memo);
let vote_ix = if new_authorized_signer.is_some() {
vote_instruction::authorize_checked(
vote_account_pubkey, // vote account to update
&authorized.pubkey(), // current authorized
new_authorized_pubkey, // new vote signer/withdrawer
vote_authorize, // vote or withdraw
)
} else {
vote_instruction::authorize(
vote_account_pubkey, // vote account to update
&authorized.pubkey(), // current authorized
new_authorized_pubkey, // new vote signer/withdrawer
vote_authorize, // vote or withdraw
)
};
let ixs = vec![vote_ix].with_memo(memo);
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
@ -592,7 +727,7 @@ pub fn process_vote_authorize(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<VoteError>(result, &config)
log_instruction_custom_error::<VoteError>(result, config)
}
pub fn process_vote_update_validator(
@ -629,7 +764,7 @@ pub fn process_vote_update_validator(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<VoteError>(result, &config)
log_instruction_custom_error::<VoteError>(result, config)
}
pub fn process_vote_update_commission(
@ -660,7 +795,7 @@ pub fn process_vote_update_commission(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<VoteError>(result, &config)
log_instruction_custom_error::<VoteError>(result, config)
}
fn get_vote_account(
@ -763,7 +898,7 @@ pub fn process_withdraw_from_vote_account(
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let withdraw_authority = config.signers[withdraw_authority];
let current_balance = rpc_client.get_balance(&vote_account_pubkey)?;
let current_balance = rpc_client.get_balance(vote_account_pubkey)?;
let minimum_balance = rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?;
let lamports = match withdraw_amount {
@ -798,13 +933,13 @@ pub fn process_withdraw_from_vote_account(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction);
log_instruction_custom_error::<VoteError>(result, &config)
log_instruction_custom_error::<VoteError>(result, config)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{app, parse_command};
use crate::{clap_app::get_clap_app, cli::parse_command};
use solana_sdk::signature::{read_keypair_file, write_keypair, Keypair, Signer};
use tempfile::NamedTempFile;
@ -815,7 +950,7 @@ mod tests {
#[test]
fn test_parse_command() {
let test_commands = app("test", "desc", "version");
let test_commands = get_clap_app("test", "desc", "version");
let keypair = Keypair::new();
let pubkey = keypair.pubkey();
let pubkey_string = pubkey.to_string();
@ -826,7 +961,7 @@ mod tests {
let default_keypair = Keypair::new();
let (default_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
let default_signer = DefaultSigner::new(default_keypair_file.clone());
let default_signer = DefaultSigner::new("", &default_keypair_file);
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
@ -843,6 +978,8 @@ mod tests {
new_authorized_pubkey: pubkey2,
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 0,
new_authorized: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@ -867,6 +1004,8 @@ mod tests {
new_authorized_pubkey: pubkey2,
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 1,
new_authorized: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@ -875,18 +1014,84 @@ mod tests {
}
);
let (voter_keypair_file, mut tmp_file) = make_tmp_file();
let voter_keypair = Keypair::new();
write_keypair(&voter_keypair, tmp_file.as_file_mut()).unwrap();
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
"vote-authorize-voter-checked",
&pubkey_string,
&default_keypair_file,
&voter_keypair_file,
]);
assert_eq!(
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
new_authorized_pubkey: voter_keypair.pubkey(),
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 0,
new_authorized: Some(1),
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
read_keypair_file(&voter_keypair_file).unwrap().into()
],
}
);
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
"vote-authorize-voter-checked",
&pubkey_string,
&authorized_keypair_file,
&voter_keypair_file,
]);
assert_eq!(
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
new_authorized_pubkey: voter_keypair.pubkey(),
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 1,
new_authorized: Some(2),
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
read_keypair_file(&authorized_keypair_file).unwrap().into(),
read_keypair_file(&voter_keypair_file).unwrap().into(),
],
}
);
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
"vote-authorize-voter-checked",
&pubkey_string,
&authorized_keypair_file,
&pubkey2_string,
]);
assert!(parse_command(&test_authorize_voter, &default_signer, &mut None).is_err());
let (keypair_file, mut tmp_file) = make_tmp_file();
let keypair = Keypair::new();
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
// Test CreateVoteAccount SubCommand
let (identity_keypair_file, mut tmp_file) = make_tmp_file();
let identity_keypair = Keypair::new();
let authorized_withdrawer = Keypair::new().pubkey();
write_keypair(&identity_keypair, tmp_file.as_file_mut()).unwrap();
let test_create_vote_account = test_commands.clone().get_matches_from(vec![
"test",
"create-vote-account",
&keypair_file,
&identity_keypair_file,
&authorized_withdrawer.to_string(),
"--commission",
"10",
]);
@ -898,7 +1103,7 @@ mod tests {
seed: None,
identity_account: 2,
authorized_voter: None,
authorized_withdrawer: None,
authorized_withdrawer,
commission: 10,
memo: None,
},
@ -919,6 +1124,7 @@ mod tests {
"create-vote-account",
&keypair_file,
&identity_keypair_file,
&authorized_withdrawer.to_string(),
]);
assert_eq!(
parse_command(&test_create_vote_account2, &default_signer, &mut None).unwrap(),
@ -928,7 +1134,7 @@ mod tests {
seed: None,
identity_account: 2,
authorized_voter: None,
authorized_withdrawer: None,
authorized_withdrawer,
commission: 100,
memo: None,
},
@ -951,6 +1157,7 @@ mod tests {
"create-vote-account",
&keypair_file,
&identity_keypair_file,
&authorized_withdrawer.to_string(),
"--authorized-voter",
&authed.to_string(),
]);
@ -962,7 +1169,7 @@ mod tests {
seed: None,
identity_account: 2,
authorized_voter: Some(authed),
authorized_withdrawer: None,
authorized_withdrawer,
commission: 100,
memo: None,
},
@ -977,14 +1184,14 @@ mod tests {
let (keypair_file, mut tmp_file) = make_tmp_file();
let keypair = Keypair::new();
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
// test init with an authed withdrawer
// succeed even though withdrawer unsafe (because forcefully allowed)
let test_create_vote_account4 = test_commands.clone().get_matches_from(vec![
"test",
"create-vote-account",
&keypair_file,
&identity_keypair_file,
"--authorized-withdrawer",
&authed.to_string(),
&identity_keypair_file,
"--allow-unsafe-authorized-withdrawer",
]);
assert_eq!(
parse_command(&test_create_vote_account4, &default_signer, &mut None).unwrap(),
@ -994,7 +1201,7 @@ mod tests {
seed: None,
identity_account: 2,
authorized_voter: None,
authorized_withdrawer: Some(authed),
authorized_withdrawer: identity_keypair.pubkey(),
commission: 100,
memo: None,
},

744
cli/src/wallet.rs Normal file
View File

@ -0,0 +1,744 @@
use crate::{
cli::{
log_instruction_custom_error, request_and_confirm_airdrop, CliCommand, CliCommandInfo,
CliConfig, CliError, ProcessResult,
},
memo::WithMemo,
nonce::check_nonce_account,
spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount},
};
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_account_decoder::{UiAccount, UiAccountEncoding};
use solana_clap_utils::{
fee_payer::*,
input_parsers::*,
input_validators::*,
keypair::{DefaultSigner, SignerIndex},
memo::*,
nonce::*,
offline::*,
};
use solana_cli_output::{
display::build_balance_message, return_signers_with_config, CliAccount,
CliSignatureVerificationStatus, CliTransaction, CliTransactionConfirmation, OutputFormat,
ReturnSignersConfig,
};
use solana_client::{
blockhash_query::BlockhashQuery, nonce_utils, rpc_client::RpcClient,
rpc_config::RpcTransactionConfig, rpc_response::RpcKeyedAccount,
};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
commitment_config::CommitmentConfig,
message::Message,
pubkey::Pubkey,
signature::Signature,
stake,
system_instruction::{self, SystemError},
system_program,
transaction::Transaction,
};
use solana_transaction_status::{EncodedTransaction, UiTransactionEncoding};
use std::{fmt::Write as FmtWrite, fs::File, io::Write, sync::Arc};
pub trait WalletSubCommands {
fn wallet_subcommands(self) -> Self;
}
impl WalletSubCommands for App<'_, '_> {
fn wallet_subcommands(self) -> Self {
self.subcommand(
SubCommand::with_name("account")
.about("Show the contents of an account")
.alias("account")
.arg(
pubkey!(Arg::with_name("account_pubkey")
.index(1)
.value_name("ACCOUNT_ADDRESS")
.required(true),
"Account key URI. ")
)
.arg(
Arg::with_name("output_file")
.long("output-file")
.short("o")
.value_name("FILEPATH")
.takes_value(true)
.help("Write the account data to this file"),
)
.arg(
Arg::with_name("lamports")
.long("lamports")
.takes_value(false)
.help("Display balance in lamports instead of SOL"),
),
)
.subcommand(
SubCommand::with_name("address")
.about("Get your public key")
.arg(
Arg::with_name("confirm_key")
.long("confirm-key")
.takes_value(false)
.help("Confirm key on device; only relevant if using remote wallet"),
),
)
.subcommand(
SubCommand::with_name("airdrop")
.about("Request SOL from a faucet")
.arg(
Arg::with_name("amount")
.index(1)
.value_name("AMOUNT")
.takes_value(true)
.validator(is_amount)
.required(true)
.help("The airdrop amount to request, in SOL"),
)
.arg(
pubkey!(Arg::with_name("to")
.index(2)
.value_name("RECIPIENT_ADDRESS"),
"The account address of airdrop recipient. "),
),
)
.subcommand(
SubCommand::with_name("balance")
.about("Get your balance")
.arg(
pubkey!(Arg::with_name("pubkey")
.index(1)
.value_name("ACCOUNT_ADDRESS"),
"The account address of the balance to check. ")
)
.arg(
Arg::with_name("lamports")
.long("lamports")
.takes_value(false)
.help("Display balance in lamports instead of SOL"),
),
)
.subcommand(
SubCommand::with_name("confirm")
.about("Confirm transaction by signature")
.arg(
Arg::with_name("signature")
.index(1)
.value_name("TRANSACTION_SIGNATURE")
.takes_value(true)
.required(true)
.help("The transaction signature to confirm"),
)
.after_help(// Formatted specifically for the manually-indented heredoc string
"Note: This will show more detailed information for finalized transactions with verbose mode (-v/--verbose).\
\n\
\nAccount modes:\
\n |srwx|\
\n s: signed\
\n r: readable (always true)\
\n w: writable\
\n x: program account (inner instructions excluded)\
"
),
)
.subcommand(
SubCommand::with_name("create-address-with-seed")
.about("Generate a derived account address with a seed")
.arg(
Arg::with_name("seed")
.index(1)
.value_name("SEED_STRING")
.takes_value(true)
.required(true)
.validator(is_derived_address_seed)
.help("The seed. Must not take more than 32 bytes to encode as utf-8"),
)
.arg(
Arg::with_name("program_id")
.index(2)
.value_name("PROGRAM_ID")
.takes_value(true)
.required(true)
.help(
"The program_id that the address will ultimately be used for, \n\
or one of NONCE, STAKE, and VOTE keywords",
),
)
.arg(
pubkey!(Arg::with_name("from")
.long("from")
.value_name("FROM_PUBKEY")
.required(false),
"From (base) key, [default: cli config keypair]. "),
),
)
.subcommand(
SubCommand::with_name("decode-transaction")
.about("Decode a serialized transaction")
.arg(
Arg::with_name("transaction")
.index(1)
.value_name("TRANSACTION")
.takes_value(true)
.required(true)
.help("transaction to decode"),
)
.arg(
Arg::with_name("encoding")
.index(2)
.value_name("ENCODING")
.possible_values(&["base58", "base64"]) // Subset of `UiTransactionEncoding` enum
.default_value("base58")
.takes_value(true)
.required(true)
.help("transaction encoding"),
),
)
.subcommand(
SubCommand::with_name("resolve-signer")
.about("Checks that a signer is valid, and returns its specific path; useful for signers that may be specified generally, eg. usb://ledger")
.arg(
Arg::with_name("signer")
.index(1)
.value_name("SIGNER_KEYPAIR")
.takes_value(true)
.required(true)
.validator(is_valid_signer)
.help("The signer path to resolve")
)
)
.subcommand(
SubCommand::with_name("transfer")
.about("Transfer funds between system accounts")
.alias("pay")
.arg(
pubkey!(Arg::with_name("to")
.index(1)
.value_name("RECIPIENT_ADDRESS")
.required(true),
"The account address of recipient. "),
)
.arg(
Arg::with_name("amount")
.index(2)
.value_name("AMOUNT")
.takes_value(true)
.validator(is_amount_or_all)
.required(true)
.help("The amount to send, in SOL; accepts keyword ALL"),
)
.arg(
pubkey!(Arg::with_name("from")
.long("from")
.value_name("FROM_ADDRESS"),
"Source account of funds (if different from client local account). "),
)
.arg(
Arg::with_name("no_wait")
.long("no-wait")
.takes_value(false)
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
)
.arg(
Arg::with_name("derived_address_seed")
.long("derived-address-seed")
.takes_value(true)
.value_name("SEED_STRING")
.requires("derived_address_program_id")
.validator(is_derived_address_seed)
.hidden(true)
)
.arg(
Arg::with_name("derived_address_program_id")
.long("derived-address-program-id")
.takes_value(true)
.value_name("PROGRAM_ID")
.requires("derived_address_seed")
.hidden(true)
)
.arg(
Arg::with_name("allow_unfunded_recipient")
.long("allow-unfunded-recipient")
.takes_value(false)
.help("Complete the transfer even if the recipient address is not funded")
)
.offline_args()
.nonce_args(false)
.arg(memo_arg())
.arg(fee_payer_arg()),
)
}
}
fn resolve_derived_address_program_id(matches: &ArgMatches<'_>, arg_name: &str) -> Option<Pubkey> {
matches.value_of(arg_name).and_then(|v| match v {
"NONCE" => Some(system_program::id()),
"STAKE" => Some(stake::program::id()),
"VOTE" => Some(solana_vote_program::id()),
_ => pubkey_of(matches, arg_name),
})
}
pub fn parse_account(
matches: &ArgMatches<'_>,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let account_pubkey = pubkey_of_signer(matches, "account_pubkey", wallet_manager)?.unwrap();
let output_file = matches.value_of("output_file");
let use_lamports_unit = matches.is_present("lamports");
Ok(CliCommandInfo {
command: CliCommand::ShowAccount {
pubkey: account_pubkey,
output_file: output_file.map(ToString::to_string),
use_lamports_unit,
},
signers: vec![],
})
}
pub fn parse_airdrop(
matches: &ArgMatches<'_>,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let pubkey = pubkey_of_signer(matches, "to", wallet_manager)?;
let signers = if pubkey.is_some() {
vec![]
} else {
vec![default_signer.signer_from_path(matches, wallet_manager)?]
};
let lamports = lamports_of_sol(matches, "amount").unwrap();
Ok(CliCommandInfo {
command: CliCommand::Airdrop { pubkey, lamports },
signers,
})
}
pub fn parse_balance(
matches: &ArgMatches<'_>,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let pubkey = pubkey_of_signer(matches, "pubkey", wallet_manager)?;
let signers = if pubkey.is_some() {
vec![]
} else {
vec![default_signer.signer_from_path(matches, wallet_manager)?]
};
Ok(CliCommandInfo {
command: CliCommand::Balance {
pubkey,
use_lamports_unit: matches.is_present("lamports"),
},
signers,
})
}
pub fn parse_decode_transaction(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let blob = value_t_or_exit!(matches, "transaction", String);
let encoding = match matches.value_of("encoding").unwrap() {
"base58" => UiTransactionEncoding::Base58,
"base64" => UiTransactionEncoding::Base64,
_ => unreachable!(),
};
let encoded_transaction = EncodedTransaction::Binary(blob, encoding);
if let Some(transaction) = encoded_transaction.decode() {
Ok(CliCommandInfo {
command: CliCommand::DecodeTransaction(transaction),
signers: vec![],
})
} else {
Err(CliError::BadParameter(
"Unable to decode transaction".to_string(),
))
}
}
pub fn parse_create_address_with_seed(
matches: &ArgMatches<'_>,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let from_pubkey = pubkey_of_signer(matches, "from", wallet_manager)?;
let signers = if from_pubkey.is_some() {
vec![]
} else {
vec![default_signer.signer_from_path(matches, wallet_manager)?]
};
let program_id = resolve_derived_address_program_id(matches, "program_id").unwrap();
let seed = matches.value_of("seed").unwrap().to_string();
Ok(CliCommandInfo {
command: CliCommand::CreateAddressWithSeed {
from_pubkey,
seed,
program_id,
},
signers,
})
}
pub fn parse_transfer(
matches: &ArgMatches<'_>,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let amount = SpendAmount::new_from_matches(matches, "amount");
let to = pubkey_of_signer(matches, "to", wallet_manager)?.unwrap();
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let dump_transaction_message = matches.is_present(DUMP_TRANSACTION_MESSAGE.name);
let no_wait = matches.is_present("no_wait");
let blockhash_query = BlockhashQuery::new_from_matches(matches);
let nonce_account = pubkey_of_signer(matches, NONCE_ARG.name, wallet_manager)?;
let (nonce_authority, nonce_authority_pubkey) =
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
let (fee_payer, fee_payer_pubkey) = signer_of(matches, FEE_PAYER_ARG.name, wallet_manager)?;
let (from, from_pubkey) = signer_of(matches, "from", wallet_manager)?;
let allow_unfunded_recipient = matches.is_present("allow_unfunded_recipient");
let mut bulk_signers = vec![fee_payer, from];
if nonce_account.is_some() {
bulk_signers.push(nonce_authority);
}
let signer_info =
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
let derived_address_seed = matches
.value_of("derived_address_seed")
.map(|s| s.to_string());
let derived_address_program_id =
resolve_derived_address_program_id(matches, "derived_address_program_id");
Ok(CliCommandInfo {
command: CliCommand::Transfer {
amount,
to,
sign_only,
dump_transaction_message,
allow_unfunded_recipient,
no_wait,
blockhash_query,
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
memo,
fee_payer: signer_info.index_of(fee_payer_pubkey).unwrap(),
from: signer_info.index_of(from_pubkey).unwrap(),
derived_address_seed,
derived_address_program_id,
},
signers: signer_info.signers,
})
}
pub fn process_show_account(
rpc_client: &RpcClient,
config: &CliConfig,
account_pubkey: &Pubkey,
output_file: &Option<String>,
use_lamports_unit: bool,
) -> ProcessResult {
let account = rpc_client.get_account(account_pubkey)?;
let data = account.data.clone();
let cli_account = CliAccount {
keyed_account: RpcKeyedAccount {
pubkey: account_pubkey.to_string(),
account: UiAccount::encode(
account_pubkey,
&account,
UiAccountEncoding::Base64,
None,
None,
),
},
use_lamports_unit,
};
let mut account_string = config.output_format.formatted_string(&cli_account);
if config.output_format == OutputFormat::Display
|| config.output_format == OutputFormat::DisplayVerbose
{
if let Some(output_file) = output_file {
let mut f = File::create(output_file)?;
f.write_all(&data)?;
writeln!(&mut account_string)?;
writeln!(&mut account_string, "Wrote account data to {}", output_file)?;
} else if !data.is_empty() {
use pretty_hex::*;
writeln!(&mut account_string, "{:?}", data.hex_dump())?;
}
}
Ok(account_string)
}
pub fn process_airdrop(
rpc_client: &RpcClient,
config: &CliConfig,
pubkey: &Option<Pubkey>,
lamports: u64,
) -> ProcessResult {
let pubkey = if let Some(pubkey) = pubkey {
*pubkey
} else {
config.pubkey()?
};
println!(
"Requesting airdrop of {}",
build_balance_message(lamports, false, true),
);
let pre_balance = rpc_client.get_balance(&pubkey)?;
let result = request_and_confirm_airdrop(rpc_client, config, &pubkey, lamports);
if let Ok(signature) = result {
let signature_cli_message = log_instruction_custom_error::<SystemError>(result, config)?;
println!("{}", signature_cli_message);
let current_balance = rpc_client.get_balance(&pubkey)?;
if current_balance < pre_balance.saturating_add(lamports) {
println!("Balance unchanged");
println!("Run `solana confirm -v {:?}` for more info", signature);
Ok("".to_string())
} else {
Ok(build_balance_message(current_balance, false, true))
}
} else {
log_instruction_custom_error::<SystemError>(result, config)
}
}
pub fn process_balance(
rpc_client: &RpcClient,
config: &CliConfig,
pubkey: &Option<Pubkey>,
use_lamports_unit: bool,
) -> ProcessResult {
let pubkey = if let Some(pubkey) = pubkey {
*pubkey
} else {
config.pubkey()?
};
let balance = rpc_client.get_balance(&pubkey)?;
Ok(build_balance_message(balance, use_lamports_unit, true))
}
pub fn process_confirm(
rpc_client: &RpcClient,
config: &CliConfig,
signature: &Signature,
) -> ProcessResult {
match rpc_client.get_signature_statuses_with_history(&[*signature]) {
Ok(status) => {
let cli_transaction = if let Some(transaction_status) = &status.value[0] {
let mut transaction = None;
let mut get_transaction_error = None;
if config.verbose {
match rpc_client.get_transaction_with_config(
signature,
RpcTransactionConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(CommitmentConfig::confirmed()),
},
) {
Ok(confirmed_transaction) => {
let decoded_transaction = confirmed_transaction
.transaction
.transaction
.decode()
.expect("Successful decode");
let json_transaction = EncodedTransaction::encode(
decoded_transaction.clone(),
UiTransactionEncoding::Json,
);
transaction = Some(CliTransaction {
transaction: json_transaction,
meta: confirmed_transaction.transaction.meta,
block_time: confirmed_transaction.block_time,
slot: Some(confirmed_transaction.slot),
decoded_transaction,
prefix: " ".to_string(),
sigverify_status: vec![],
});
}
Err(err) => {
get_transaction_error = Some(format!("{:?}", err));
}
}
}
CliTransactionConfirmation {
confirmation_status: Some(transaction_status.confirmation_status()),
transaction,
get_transaction_error,
err: transaction_status.err.clone(),
}
} else {
CliTransactionConfirmation {
confirmation_status: None,
transaction: None,
get_transaction_error: None,
err: None,
}
};
Ok(config.output_format.formatted_string(&cli_transaction))
}
Err(err) => Err(CliError::RpcRequestError(format!("Unable to confirm: {}", err)).into()),
}
}
#[allow(clippy::unnecessary_wraps)]
pub fn process_decode_transaction(config: &CliConfig, transaction: &Transaction) -> ProcessResult {
let sigverify_status = CliSignatureVerificationStatus::verify_transaction(transaction);
let decode_transaction = CliTransaction {
decoded_transaction: transaction.clone(),
transaction: EncodedTransaction::encode(transaction.clone(), UiTransactionEncoding::Json),
meta: None,
block_time: None,
slot: None,
prefix: "".to_string(),
sigverify_status,
};
Ok(config.output_format.formatted_string(&decode_transaction))
}
pub fn process_create_address_with_seed(
config: &CliConfig,
from_pubkey: Option<&Pubkey>,
seed: &str,
program_id: &Pubkey,
) -> ProcessResult {
let from_pubkey = if let Some(pubkey) = from_pubkey {
*pubkey
} else {
config.pubkey()?
};
let address = Pubkey::create_with_seed(&from_pubkey, seed, program_id)?;
Ok(address.to_string())
}
#[allow(clippy::too_many_arguments)]
pub fn process_transfer(
rpc_client: &RpcClient,
config: &CliConfig,
amount: SpendAmount,
to: &Pubkey,
from: SignerIndex,
sign_only: bool,
dump_transaction_message: bool,
allow_unfunded_recipient: bool,
no_wait: bool,
blockhash_query: &BlockhashQuery,
nonce_account: Option<&Pubkey>,
nonce_authority: SignerIndex,
memo: Option<&String>,
fee_payer: SignerIndex,
derived_address_seed: Option<String>,
derived_address_program_id: Option<&Pubkey>,
) -> ProcessResult {
let from = config.signers[from];
let mut from_pubkey = from.pubkey();
let (recent_blockhash, fee_calculator) =
blockhash_query.get_blockhash_and_fee_calculator(rpc_client, config.commitment)?;
if !sign_only && !allow_unfunded_recipient {
let recipient_balance = rpc_client
.get_balance_with_commitment(to, config.commitment)?
.value;
if recipient_balance == 0 {
return Err(format!(
"The recipient address ({}) is not funded. \
Add `--allow-unfunded-recipient` to complete the transfer \
",
to
)
.into());
}
}
let nonce_authority = config.signers[nonce_authority];
let fee_payer = config.signers[fee_payer];
let derived_parts = derived_address_seed.zip(derived_address_program_id);
let with_seed = if let Some((seed, program_id)) = derived_parts {
let base_pubkey = from_pubkey;
from_pubkey = Pubkey::create_with_seed(&base_pubkey, &seed, program_id)?;
Some((base_pubkey, seed, program_id, from_pubkey))
} else {
None
};
let build_message = |lamports| {
let ixs = if let Some((base_pubkey, seed, program_id, from_pubkey)) = with_seed.as_ref() {
vec![system_instruction::transfer_with_seed(
from_pubkey,
base_pubkey,
seed.clone(),
program_id,
to,
lamports,
)]
.with_memo(memo)
} else {
vec![system_instruction::transfer(&from_pubkey, to, lamports)].with_memo(memo)
};
if let Some(nonce_account) = &nonce_account {
Message::new_with_nonce(
ixs,
Some(&fee_payer.pubkey()),
nonce_account,
&nonce_authority.pubkey(),
)
} else {
Message::new(&ixs, Some(&fee_payer.pubkey()))
}
};
let (message, _) = resolve_spend_tx_and_check_account_balances(
rpc_client,
sign_only,
amount,
&fee_calculator,
&from_pubkey,
&fee_payer.pubkey(),
build_message,
config.commitment,
)?;
let mut tx = Transaction::new_unsigned(message);
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers_with_config(
&tx,
&config.output_format,
&ReturnSignersConfig {
dump_transaction_message,
},
)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
tx.try_sign(&config.signers, recent_blockhash)?;
let result = if no_wait {
rpc_client.send_transaction(&tx)
} else {
rpc_client.send_and_confirm_transaction_with_spinner(&tx)
};
log_instruction_custom_error::<SystemError>(result, config)
}
}

View File

@ -5,3 +5,4 @@ cd "$(dirname "$0")"
make -C ../../../programs/bpf/c/
cp ../../../programs/bpf/c/out/noop.so .
cat noop.so noop.so noop.so > noop_large.so

BIN
cli/tests/fixtures/noop_large.so vendored Normal file

Binary file not shown.

View File

@ -18,13 +18,15 @@ use solana_sdk::{
signature::{keypair_from_seed, Keypair, Signer},
system_program,
};
use solana_streamer::socket::SocketAddrSpace;
#[test]
fn test_nonce() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
full_battery_tests(test_validator, None, false);
}
@ -34,7 +36,8 @@ fn test_nonce_with_seed() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
full_battery_tests(test_validator, Some(String::from("seed")), false);
}
@ -44,7 +47,8 @@ fn test_nonce_with_authority() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
full_battery_tests(test_validator, None, true);
}
@ -216,7 +220,12 @@ fn test_create_account_with_seed() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let offline_nonce_authority_signer = keypair_from_seed(&[1u8; 32]).unwrap();
let online_nonce_creator_signer = keypair_from_seed(&[2u8; 32]).unwrap();

View File

@ -15,27 +15,29 @@ use solana_sdk::{
pubkey::Pubkey,
signature::{Keypair, Signer},
};
use solana_streamer::socket::SocketAddrSpace;
use std::{env, fs::File, io::Read, path::PathBuf, str::FromStr};
#[test]
fn test_cli_program_deploy_non_upgradeable() {
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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.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
@ -53,7 +55,7 @@ fn test_cli_program_deploy_non_upgradeable() {
process_command(&config).unwrap();
config.command = CliCommand::Deploy {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
address: None,
use_deprecated_loader: false,
allow_excessive_balance: false,
@ -68,12 +70,12 @@ fn test_cli_program_deploy_non_upgradeable() {
.unwrap()
.as_str()
.unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap();
let program_id = Pubkey::from_str(program_id_str).unwrap();
let account0 = rpc_client.get_account(&program_id).unwrap();
assert_eq!(account0.lamports, minimum_balance_for_rent_exemption);
assert_eq!(account0.owner, bpf_loader::id());
assert!(account0.executable);
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap().to_string()).unwrap();
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
assert_eq!(account0.data, elf);
@ -82,7 +84,7 @@ fn test_cli_program_deploy_non_upgradeable() {
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(),
program_location: noop_path.to_str().unwrap().to_string(),
address: Some(1),
use_deprecated_loader: false,
allow_excessive_balance: false,
@ -109,7 +111,7 @@ fn test_cli_program_deploy_non_upgradeable() {
process_command(&config).unwrap();
config.signers = vec![&keypair, &custom_address_keypair];
config.command = CliCommand::Deploy {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
address: Some(1),
use_deprecated_loader: false,
allow_excessive_balance: false,
@ -118,7 +120,7 @@ fn test_cli_program_deploy_non_upgradeable() {
// Use forcing parameter to deploy to account with excess balance
config.command = CliCommand::Deploy {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
address: Some(1),
use_deprecated_loader: false,
allow_excessive_balance: true,
@ -137,21 +139,22 @@ fn test_cli_program_deploy_non_upgradeable() {
fn test_cli_program_deploy_no_authority() {
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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
@ -178,7 +181,7 @@ fn test_cli_program_deploy_no_authority() {
// Deploy a program
config.signers = vec![&keypair, &upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: None,
buffer_signer_index: None,
@ -198,12 +201,12 @@ fn test_cli_program_deploy_no_authority() {
.unwrap()
.as_str()
.unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap();
let program_id = Pubkey::from_str(program_id_str).unwrap();
// Attempt to upgrade the program
config.signers = vec![&keypair, &upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: Some(program_id),
buffer_signer_index: None,
@ -220,21 +223,22 @@ fn test_cli_program_deploy_no_authority() {
fn test_cli_program_deploy_with_authority() {
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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
@ -262,7 +266,7 @@ fn test_cli_program_deploy_with_authority() {
let program_keypair = Keypair::new();
config.signers = vec![&keypair, &upgrade_authority, &program_keypair];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: Some(2),
program_pubkey: Some(program_keypair.pubkey()),
buffer_signer_index: None,
@ -284,7 +288,7 @@ fn test_cli_program_deploy_with_authority() {
.unwrap();
assert_eq!(
program_keypair.pubkey(),
Pubkey::from_str(&program_pubkey_str).unwrap()
Pubkey::from_str(program_pubkey_str).unwrap()
);
let program_account = rpc_client.get_account(&program_keypair.pubkey()).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
@ -309,7 +313,7 @@ fn test_cli_program_deploy_with_authority() {
// Deploy the upgradeable program
config.signers = vec![&keypair, &upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: None,
buffer_signer_index: None,
@ -328,7 +332,7 @@ fn test_cli_program_deploy_with_authority() {
.unwrap()
.as_str()
.unwrap();
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
let program_pubkey = Pubkey::from_str(program_pubkey_str).unwrap();
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
@ -350,7 +354,7 @@ fn test_cli_program_deploy_with_authority() {
// Upgrade the program
config.signers = vec![&keypair, &upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: Some(program_pubkey),
buffer_signer_index: None,
@ -397,14 +401,14 @@ fn test_cli_program_deploy_with_authority() {
.as_str()
.unwrap();
assert_eq!(
Pubkey::from_str(&new_upgrade_authority_str).unwrap(),
Pubkey::from_str(new_upgrade_authority_str).unwrap(),
new_upgrade_authority.pubkey()
);
// Upgrade with new authority
config.signers = vec![&keypair, &new_upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: Some(program_pubkey),
buffer_signer_index: None,
@ -438,6 +442,8 @@ fn test_cli_program_deploy_with_authority() {
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(program_pubkey),
authority_pubkey: keypair.pubkey(),
get_programs: false,
get_buffers: false,
all: false,
use_lamports_unit: false,
});
@ -452,7 +458,7 @@ fn test_cli_program_deploy_with_authority() {
.unwrap();
assert_eq!(
new_upgrade_authority.pubkey(),
Pubkey::from_str(&authority_pubkey_str).unwrap()
Pubkey::from_str(authority_pubkey_str).unwrap()
);
// Set no authority
@ -476,7 +482,7 @@ fn test_cli_program_deploy_with_authority() {
// Upgrade with no authority
config.signers = vec![&keypair, &new_upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: Some(program_pubkey),
buffer_signer_index: None,
@ -491,7 +497,7 @@ fn test_cli_program_deploy_with_authority() {
// deploy with finality
config.signers = vec![&keypair, &new_upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: None,
buffer_signer_index: None,
@ -510,7 +516,7 @@ fn test_cli_program_deploy_with_authority() {
.unwrap()
.as_str()
.unwrap();
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
let program_pubkey = Pubkey::from_str(program_pubkey_str).unwrap();
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@ -521,7 +527,7 @@ fn test_cli_program_deploy_with_authority() {
{
assert_eq!(upgrade_authority_address, None);
} else {
panic!("not a buffer account");
panic!("not a ProgramData account");
}
// Get buffer authority
@ -529,6 +535,8 @@ fn test_cli_program_deploy_with_authority() {
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(program_pubkey),
authority_pubkey: keypair.pubkey(),
get_programs: false,
get_buffers: false,
all: false,
use_lamports_unit: false,
});
@ -545,24 +553,113 @@ fn test_cli_program_deploy_with_authority() {
}
#[test]
fn test_cli_program_write_buffer() {
fn test_cli_program_close_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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
let minimum_balance_for_programdata = rpc_client
.get_minimum_balance_for_rent_exemption(
UpgradeableLoaderState::programdata_len(max_len).unwrap(),
)
.unwrap();
let minimum_balance_for_program = rpc_client
.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::program_len().unwrap())
.unwrap();
let upgrade_authority = Keypair::new();
let mut config = CliConfig::recent_for_tests();
let keypair = Keypair::new();
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
pubkey: None,
lamports: 100 * minimum_balance_for_programdata + minimum_balance_for_program,
};
process_command(&config).unwrap();
// Deploy the upgradeable program
let program_keypair = Keypair::new();
config.signers = vec![&keypair, &upgrade_authority, &program_keypair];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: Some(2),
program_pubkey: Some(program_keypair.pubkey()),
buffer_signer_index: None,
buffer_pubkey: None,
allow_excessive_balance: false,
upgrade_authority_signer_index: 1,
is_final: false,
max_len: Some(max_len),
});
config.output_format = OutputFormat::JsonCompact;
process_command(&config).unwrap();
let (programdata_pubkey, _) = Pubkey::find_program_address(
&[program_keypair.pubkey().as_ref()],
&bpf_loader_upgradeable::id(),
);
// Close program
let close_account = rpc_client.get_account(&programdata_pubkey).unwrap();
let programdata_lamports = close_account.lamports;
let recipient_pubkey = Pubkey::new_unique();
config.signers = vec![&keypair, &upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Close {
account_pubkey: Some(program_keypair.pubkey()),
recipient_pubkey,
authority_index: 1,
use_lamports_unit: false,
});
process_command(&config).unwrap();
rpc_client.get_account(&programdata_pubkey).unwrap_err();
let recipient_account = rpc_client.get_account(&recipient_pubkey).unwrap();
assert_eq!(programdata_lamports, recipient_account.lamports);
}
#[test]
fn test_cli_program_write_buffer() {
solana_logger::setup();
let mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mut noop_large_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_large_path.push("tests");
noop_large_path.push("fixtures");
noop_large_path.push("noop_large");
noop_large_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
@ -590,7 +687,7 @@ fn test_cli_program_write_buffer() {
// Write a buffer with default params
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: None,
buffer_pubkey: None,
buffer_authority_signer_index: None,
@ -606,7 +703,7 @@ fn test_cli_program_write_buffer() {
.unwrap()
.as_str()
.unwrap();
let new_buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
let new_buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
let buffer_account = rpc_client.get_account(&new_buffer_pubkey).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
@ -624,7 +721,7 @@ fn test_cli_program_write_buffer() {
let buffer_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
buffer_authority_signer_index: None,
@ -641,7 +738,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
buffer_keypair.pubkey(),
Pubkey::from_str(&buffer_pubkey_str).unwrap()
Pubkey::from_str(buffer_pubkey_str).unwrap()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer);
@ -661,6 +758,8 @@ fn test_cli_program_write_buffer() {
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(buffer_keypair.pubkey()),
authority_pubkey: keypair.pubkey(),
get_programs: false,
get_buffers: false,
all: false,
use_lamports_unit: false,
});
@ -675,7 +774,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
keypair.pubkey(),
Pubkey::from_str(&authority_pubkey_str).unwrap()
Pubkey::from_str(authority_pubkey_str).unwrap()
);
// Specify buffer authority
@ -683,7 +782,7 @@ fn test_cli_program_write_buffer() {
let authority_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair, &authority_keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
buffer_authority_signer_index: Some(2),
@ -700,7 +799,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
buffer_keypair.pubkey(),
Pubkey::from_str(&buffer_pubkey_str).unwrap()
Pubkey::from_str(buffer_pubkey_str).unwrap()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
@ -720,7 +819,7 @@ fn test_cli_program_write_buffer() {
let authority_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair, &authority_keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: None,
buffer_pubkey: None,
buffer_authority_signer_index: Some(2),
@ -735,7 +834,7 @@ fn test_cli_program_write_buffer() {
.unwrap()
.as_str()
.unwrap();
let buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
let buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
let buffer_account = rpc_client.get_account(&buffer_pubkey).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
@ -754,6 +853,8 @@ fn test_cli_program_write_buffer() {
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(buffer_pubkey),
authority_pubkey: keypair.pubkey(),
get_programs: false,
get_buffers: false,
all: false,
use_lamports_unit: false,
});
@ -768,7 +869,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
authority_keypair.pubkey(),
Pubkey::from_str(&authority_pubkey_str).unwrap()
Pubkey::from_str(authority_pubkey_str).unwrap()
);
// Close buffer
@ -790,7 +891,7 @@ fn test_cli_program_write_buffer() {
// Write a buffer with default params
config.signers = vec![&keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: None,
buffer_pubkey: None,
buffer_authority_signer_index: None,
@ -806,7 +907,7 @@ fn test_cli_program_write_buffer() {
.unwrap()
.as_str()
.unwrap();
let new_buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
let new_buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
// Close buffers and deposit default keypair
let pre_lamports = rpc_client.get_account(&keypair.pubkey()).unwrap().lamports;
@ -824,27 +925,58 @@ fn test_cli_program_write_buffer() {
pre_lamports + minimum_balance_for_buffer,
recipient_account.lamports
);
// write small buffer then attempt to deploy larger program
let buffer_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
buffer_authority_signer_index: None,
max_len: None, //Some(max_len),
});
process_command(&config).unwrap();
config.signers = vec![&keypair, &buffer_keypair];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(noop_large_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: None,
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
allow_excessive_balance: false,
upgrade_authority_signer_index: 1,
is_final: true,
max_len: None,
});
config.output_format = OutputFormat::JsonCompact;
let error = process_command(&config).unwrap_err();
assert_eq!(
error.to_string(),
"Buffer account passed is not large enough, may have been for a different deploy?"
);
}
#[test]
fn test_cli_program_set_buffer_authority() {
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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
@ -868,7 +1000,7 @@ fn test_cli_program_set_buffer_authority() {
let buffer_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
buffer_authority_signer_index: None,
@ -901,7 +1033,7 @@ fn test_cli_program_set_buffer_authority() {
.as_str()
.unwrap();
assert_eq!(
Pubkey::from_str(&new_buffer_authority_str).unwrap(),
Pubkey::from_str(new_buffer_authority_str).unwrap(),
new_buffer_authority.pubkey()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
@ -928,7 +1060,7 @@ fn test_cli_program_set_buffer_authority() {
.as_str()
.unwrap();
assert_eq!(
Pubkey::from_str(&buffer_authority_str).unwrap(),
Pubkey::from_str(buffer_authority_str).unwrap(),
buffer_keypair.pubkey()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
@ -943,21 +1075,22 @@ fn test_cli_program_set_buffer_authority() {
fn test_cli_program_mismatch_buffer_authority() {
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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
@ -982,7 +1115,7 @@ fn test_cli_program_mismatch_buffer_authority() {
let buffer_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair, &buffer_authority];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
buffer_authority_signer_index: Some(2),
@ -1000,7 +1133,7 @@ fn test_cli_program_mismatch_buffer_authority() {
let upgrade_authority = Keypair::new();
config.signers = vec![&keypair, &upgrade_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: None,
buffer_signer_index: None,
@ -1015,7 +1148,7 @@ fn test_cli_program_mismatch_buffer_authority() {
// Attempt to deploy matched authority
config.signers = vec![&keypair, &buffer_authority];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: None,
program_pubkey: None,
buffer_signer_index: None,
@ -1032,21 +1165,22 @@ fn test_cli_program_mismatch_buffer_authority() {
fn test_cli_program_show() {
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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
@ -1074,7 +1208,7 @@ fn test_cli_program_show() {
let authority_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair, &authority_keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
buffer_authority_signer_index: Some(2),
@ -1087,6 +1221,8 @@ fn test_cli_program_show() {
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(buffer_keypair.pubkey()),
authority_pubkey: keypair.pubkey(),
get_programs: false,
get_buffers: false,
all: false,
use_lamports_unit: false,
});
@ -1101,7 +1237,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
buffer_keypair.pubkey(),
Pubkey::from_str(&address_str).unwrap()
Pubkey::from_str(address_str).unwrap()
);
let authority_str = json
.as_object()
@ -1112,7 +1248,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
authority_keypair.pubkey(),
Pubkey::from_str(&authority_str).unwrap()
Pubkey::from_str(authority_str).unwrap()
);
let data_len = json
.as_object()
@ -1127,7 +1263,7 @@ fn test_cli_program_show() {
let program_keypair = Keypair::new();
config.signers = vec![&keypair, &authority_keypair, &program_keypair];
config.command = CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(pathbuf.to_str().unwrap().to_string()),
program_location: Some(noop_path.to_str().unwrap().to_string()),
program_signer_index: Some(2),
program_pubkey: Some(program_keypair.pubkey()),
buffer_signer_index: None,
@ -1147,6 +1283,8 @@ fn test_cli_program_show() {
config.command = CliCommand::Program(ProgramCliCommand::Show {
account_pubkey: Some(program_keypair.pubkey()),
authority_pubkey: keypair.pubkey(),
get_programs: false,
get_buffers: false,
all: false,
use_lamports_unit: false,
});
@ -1161,7 +1299,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
program_keypair.pubkey(),
Pubkey::from_str(&address_str).unwrap()
Pubkey::from_str(address_str).unwrap()
);
let programdata_address_str = json
.as_object()
@ -1176,7 +1314,7 @@ fn test_cli_program_show() {
);
assert_eq!(
programdata_pubkey,
Pubkey::from_str(&programdata_address_str).unwrap()
Pubkey::from_str(programdata_address_str).unwrap()
);
let authority_str = json
.as_object()
@ -1187,7 +1325,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
authority_keypair.pubkey(),
Pubkey::from_str(&authority_str).unwrap()
Pubkey::from_str(authority_str).unwrap()
);
let deployed_slot = json
.as_object()
@ -1212,21 +1350,22 @@ fn test_cli_program_show() {
fn test_cli_program_dump() {
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 mut noop_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
noop_path.push("tests");
noop_path.push("fixtures");
noop_path.push("noop");
noop_path.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let mut file = File::open(pathbuf.to_str().unwrap()).unwrap();
let mut file = File::open(noop_path.to_str().unwrap()).unwrap();
let mut program_data = Vec::new();
file.read_to_end(&mut program_data).unwrap();
let max_len = program_data.len();
@ -1254,7 +1393,7 @@ fn test_cli_program_dump() {
let authority_keypair = Keypair::new();
config.signers = vec![&keypair, &buffer_keypair, &authority_keypair];
config.command = CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: pathbuf.to_str().unwrap().to_string(),
program_location: noop_path.to_str().unwrap().to_string(),
buffer_signer_index: Some(1),
buffer_pubkey: Some(buffer_keypair.pubkey()),
buffer_authority_signer_index: Some(2),

View File

@ -6,13 +6,15 @@ use solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
};
use solana_streamer::socket::SocketAddrSpace;
#[test]
fn test_cli_request_airdrop() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let mut bob_config = CliConfig::recent_for_tests();
bob_config.json_rpc_url = test_validator.rpc_url();

View File

@ -1,6 +1,7 @@
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
spend_utils::SpendAmount,
stake::StakeAuthorizationIndexed,
test_utils::{check_ready, check_recent_balance},
};
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
@ -17,18 +18,22 @@ use solana_sdk::{
nonce::State as NonceState,
pubkey::Pubkey,
signature::{keypair_from_seed, Keypair, Signer},
stake::{
self,
instruction::LockupArgs,
state::{Lockup, StakeAuthorize, StakeState},
},
};
use solana_stake_program::{
stake_instruction::LockupArgs,
stake_state::{Lockup, StakeAuthorize, StakeState},
};
use solana_streamer::socket::SocketAddrSpace;
#[test]
fn test_stake_delegation_force() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let authorized_withdrawer = Keypair::new().pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -49,7 +54,7 @@ fn test_stake_delegation_force() {
seed: None,
identity_account: 0,
authorized_voter: None,
authorized_withdrawer: None,
authorized_withdrawer,
commission: 0,
memo: None,
};
@ -63,6 +68,7 @@ fn test_stake_delegation_force() {
seed: None,
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -117,7 +123,8 @@ fn test_seed_stake_delegation_and_deactivation() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -139,7 +146,7 @@ fn test_seed_stake_delegation_and_deactivation() {
let stake_address = Pubkey::create_with_seed(
&config_validator.signers[0].pubkey(),
"hi there",
&solana_stake_program::id(),
&stake::program::id(),
)
.expect("bad seed");
@ -150,6 +157,7 @@ fn test_seed_stake_delegation_and_deactivation() {
seed: Some("hi there".to_string()),
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -202,7 +210,8 @@ fn test_stake_delegation_and_deactivation() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -230,6 +239,7 @@ fn test_stake_delegation_and_deactivation() {
seed: None,
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -283,7 +293,8 @@ fn test_offline_stake_delegation_and_deactivation() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -331,6 +342,7 @@ fn test_offline_stake_delegation_and_deactivation() {
seed: None,
staker: Some(config_offline.signers[0].pubkey()),
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -425,7 +437,8 @@ fn test_nonced_stake_delegation_and_deactivation() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -450,6 +463,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
seed: None,
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -541,7 +555,8 @@ fn test_stake_authorize() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -580,6 +595,7 @@ fn test_stake_authorize() {
seed: None,
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -599,7 +615,12 @@ fn test_stake_authorize() {
config.signers.pop();
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 0)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: online_authority_pubkey,
authority: 0,
new_authority_signer: None,
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
@ -628,8 +649,18 @@ fn test_stake_authorize() {
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![
(StakeAuthorize::Staker, online_authority2_pubkey, 1),
(StakeAuthorize::Withdrawer, withdraw_authority_pubkey, 0),
StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: online_authority2_pubkey,
authority: 1,
new_authority_signer: None,
},
StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Withdrawer,
new_authority_pubkey: withdraw_authority_pubkey,
authority: 0,
new_authority_signer: None,
},
],
sign_only: false,
dump_transaction_message: false,
@ -656,7 +687,12 @@ fn test_stake_authorize() {
config.signers.push(&online_authority2);
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, offline_authority_pubkey, 1)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: offline_authority_pubkey,
authority: 1,
new_authority_signer: None,
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
@ -682,7 +718,12 @@ fn test_stake_authorize() {
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_offline.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: nonced_authority_pubkey,
authority: 0,
new_authority_signer: None,
}],
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
@ -701,7 +742,12 @@ fn test_stake_authorize() {
config.signers = vec![&offline_presigner];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: nonced_authority_pubkey,
authority: 0,
new_authority_signer: None,
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
@ -752,7 +798,12 @@ fn test_stake_authorize() {
config_offline.signers.push(&nonced_authority);
config_offline.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: online_authority_pubkey,
authority: 1,
new_authority_signer: None,
}],
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
@ -772,7 +823,12 @@ fn test_stake_authorize() {
config.signers = vec![&offline_presigner, &nonced_authority_presigner];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: online_authority_pubkey,
authority: 1,
new_authority_signer: None,
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(
@ -814,7 +870,12 @@ fn test_stake_authorize_with_fee_payer() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, SIG_FEE, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
SIG_FEE,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -860,6 +921,7 @@ fn test_stake_authorize_with_fee_payer() {
seed: None,
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -879,7 +941,12 @@ fn test_stake_authorize_with_fee_payer() {
config.signers = vec![&default_signer, &payer_keypair];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, offline_pubkey, 0)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: offline_pubkey,
authority: 0,
new_authority_signer: None,
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
@ -901,7 +968,12 @@ fn test_stake_authorize_with_fee_payer() {
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_offline.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: payer_pubkey,
authority: 0,
new_authority_signer: None,
}],
sign_only: true,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::None(blockhash),
@ -920,7 +992,12 @@ fn test_stake_authorize_with_fee_payer() {
config.signers = vec![&offline_presigner];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: payer_pubkey,
authority: 0,
new_authority_signer: None,
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
@ -946,7 +1023,12 @@ fn test_stake_split() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -984,6 +1066,7 @@ fn test_stake_split() {
seed: None,
staker: Some(offline_pubkey),
withdrawer: Some(offline_pubkey),
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(10 * minimum_stake_balance),
sign_only: false,
@ -1089,7 +1172,12 @@ fn test_stake_set_lockup() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -1134,6 +1222,7 @@ fn test_stake_set_lockup() {
seed: None,
staker: Some(offline_pubkey),
withdrawer: Some(config.signers[0].pubkey()),
withdrawer_signer: None,
lockup,
amount: SpendAmount::Some(10 * minimum_stake_balance),
sign_only: false,
@ -1162,6 +1251,7 @@ fn test_stake_set_lockup() {
config.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: None,
custodian: 0,
sign_only: false,
dump_transaction_message: false,
@ -1197,6 +1287,7 @@ fn test_stake_set_lockup() {
config.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: None,
custodian: 0,
sign_only: false,
dump_transaction_message: false,
@ -1217,6 +1308,7 @@ fn test_stake_set_lockup() {
config.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: None,
custodian: 1,
sign_only: false,
dump_transaction_message: false,
@ -1249,6 +1341,7 @@ fn test_stake_set_lockup() {
config.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: None,
custodian: 1,
sign_only: false,
dump_transaction_message: false,
@ -1296,6 +1389,7 @@ fn test_stake_set_lockup() {
config_offline.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: None,
custodian: 0,
sign_only: true,
dump_transaction_message: false,
@ -1314,6 +1408,7 @@ fn test_stake_set_lockup() {
config.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: None,
custodian: 0,
sign_only: false,
dump_transaction_message: false,
@ -1348,7 +1443,8 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -1408,6 +1504,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
seed: None,
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: true,
@ -1431,6 +1528,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
seed: None,
staker: Some(offline_pubkey),
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -1520,6 +1618,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
seed: Some(seed.to_string()),
staker: None,
withdrawer: None,
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: true,
@ -1541,6 +1640,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
seed: Some(seed.to_string()),
staker: Some(offline_pubkey),
withdrawer: Some(offline_pubkey),
withdrawer_signer: None,
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
@ -1557,6 +1657,232 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
};
process_command(&config).unwrap();
let seed_address =
Pubkey::create_with_seed(&stake_pubkey, seed, &solana_stake_program::id()).unwrap();
Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap();
check_recent_balance(50_000, &rpc_client, &seed_address);
}
#[test]
fn test_stake_checked_instructions() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let default_signer = Keypair::new();
let mut config = CliConfig::recent_for_tests();
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&default_signer];
request_and_confirm_airdrop(&rpc_client, &config, &config.signers[0].pubkey(), 100_000)
.unwrap();
// Create stake account with withdrawer
let stake_keypair = Keypair::new();
let stake_account_pubkey = stake_keypair.pubkey();
let withdrawer_keypair = Keypair::new();
let withdrawer_pubkey = withdrawer_keypair.pubkey();
config.signers.push(&stake_keypair);
config.command = CliCommand::CreateStakeAccount {
stake_account: 1,
seed: None,
staker: None,
withdrawer: Some(withdrawer_pubkey),
withdrawer_signer: Some(1),
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
from: 0,
};
process_command(&config).unwrap_err(); // unsigned authority should fail
config.signers = vec![&default_signer, &stake_keypair, &withdrawer_keypair];
config.command = CliCommand::CreateStakeAccount {
stake_account: 1,
seed: None,
staker: None,
withdrawer: Some(withdrawer_pubkey),
withdrawer_signer: Some(1),
lockup: Lockup::default(),
amount: SpendAmount::Some(50_000),
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
from: 0,
};
process_command(&config).unwrap();
// Re-authorize account, checking new authority
let staker_keypair = Keypair::new();
let staker_pubkey = staker_keypair.pubkey();
config.signers = vec![&default_signer];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: staker_pubkey,
authority: 0,
new_authority_signer: Some(0),
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
custodian: None,
no_wait: false,
};
process_command(&config).unwrap_err(); // unsigned authority should fail
config.signers = vec![&default_signer, &staker_keypair];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Staker,
new_authority_pubkey: staker_pubkey,
authority: 0,
new_authority_signer: Some(1),
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
custodian: None,
no_wait: false,
};
process_command(&config).unwrap();
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
let stake_state: StakeState = stake_account.state().unwrap();
let current_authority = match stake_state {
StakeState::Initialized(meta) => meta.authorized.staker,
_ => panic!("Unexpected stake state!"),
};
assert_eq!(current_authority, staker_pubkey);
let new_withdrawer_keypair = Keypair::new();
let new_withdrawer_pubkey = new_withdrawer_keypair.pubkey();
config.signers = vec![&default_signer, &withdrawer_keypair];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Withdrawer,
new_authority_pubkey: new_withdrawer_pubkey,
authority: 1,
new_authority_signer: Some(1),
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
custodian: None,
no_wait: false,
};
process_command(&config).unwrap_err(); // unsigned authority should fail
config.signers = vec![
&default_signer,
&withdrawer_keypair,
&new_withdrawer_keypair,
];
config.command = CliCommand::StakeAuthorize {
stake_account_pubkey,
new_authorizations: vec![StakeAuthorizationIndexed {
authorization_type: StakeAuthorize::Withdrawer,
new_authority_pubkey: new_withdrawer_pubkey,
authority: 1,
new_authority_signer: Some(2),
}],
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
custodian: None,
no_wait: false,
};
process_command(&config).unwrap();
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
let stake_state: StakeState = stake_account.state().unwrap();
let current_authority = match stake_state {
StakeState::Initialized(meta) => meta.authorized.withdrawer,
_ => panic!("Unexpected stake state!"),
};
assert_eq!(current_authority, new_withdrawer_pubkey);
// Set lockup, checking new custodian
let custodian = Keypair::new();
let custodian_pubkey = custodian.pubkey();
let lockup = LockupArgs {
unix_timestamp: Some(1_581_534_570),
epoch: Some(200),
custodian: Some(custodian_pubkey),
};
config.signers = vec![&default_signer, &new_withdrawer_keypair];
config.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: Some(1),
custodian: 1,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
};
process_command(&config).unwrap_err(); // unsigned new custodian should fail
config.signers = vec![&default_signer, &new_withdrawer_keypair, &custodian];
config.command = CliCommand::StakeSetLockup {
stake_account_pubkey,
lockup,
new_custodian_signer: Some(2),
custodian: 1,
sign_only: false,
dump_transaction_message: false,
blockhash_query: BlockhashQuery::default(),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
};
process_command(&config).unwrap();
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
let stake_state: StakeState = stake_account.state().unwrap();
let current_lockup = match stake_state {
StakeState::Initialized(meta) => meta.lockup,
_ => panic!("Unexpected stake state!"),
};
assert_eq!(
current_lockup.unix_timestamp,
lockup.unix_timestamp.unwrap()
);
assert_eq!(current_lockup.epoch, lockup.epoch.unwrap());
assert_eq!(current_lockup.custodian, custodian_pubkey);
}

View File

@ -16,7 +16,9 @@ use solana_sdk::{
nonce::State as NonceState,
pubkey::Pubkey,
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
stake,
};
use solana_streamer::socket::SocketAddrSpace;
#[test]
fn test_transfer() {
@ -24,7 +26,12 @@ fn test_transfer() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -276,7 +283,12 @@ fn test_transfer_multisession_signing() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let to_pubkey = Pubkey::new(&[1u8; 32]);
let offline_from_signer = keypair_from_seed(&[2u8; 32]).unwrap();
@ -403,7 +415,12 @@ fn test_transfer_all() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -451,7 +468,12 @@ fn test_transfer_unfunded_recipient() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -499,7 +521,12 @@ fn test_transfer_with_seed() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let test_validator = TestValidator::with_custom_fees(
mint_pubkey,
1,
Some(faucet_addr),
SocketAddrSpace::Unspecified,
);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -513,7 +540,7 @@ fn test_transfer_with_seed() {
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
let derived_address_seed = "seed".to_string();
let derived_address_program_id = solana_stake_program::id();
let derived_address_program_id = stake::program::id();
let derived_address = Pubkey::create_with_seed(
&sender_pubkey,
&derived_address_seed,

View File

@ -14,6 +14,7 @@ use solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
};
use solana_streamer::socket::SocketAddrSpace;
use solana_vote_program::vote_state::{VoteAuthorize, VoteState, VoteStateVersions};
#[test]
@ -21,7 +22,8 @@ fn test_vote_authorize_and_withdraw() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let test_validator =
TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr), SocketAddrSpace::Unspecified);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@ -43,7 +45,7 @@ fn test_vote_authorize_and_withdraw() {
seed: None,
identity_account: 0,
authorized_voter: None,
authorized_withdrawer: Some(config.signers[0].pubkey()),
authorized_withdrawer: config.signers[0].pubkey(),
commission: 0,
memo: None,
};
@ -83,13 +85,48 @@ fn test_vote_authorize_and_withdraw() {
check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey);
// Authorize vote account withdrawal to another signer
let withdraw_authority = Keypair::new();
let first_withdraw_authority = Keypair::new();
config.signers = vec![&default_signer];
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey: first_withdraw_authority.pubkey(),
vote_authorize: VoteAuthorize::Withdrawer,
memo: None,
authorized: 0,
new_authorized: None,
};
process_command(&config).unwrap();
let vote_account = rpc_client
.get_account(&vote_account_keypair.pubkey())
.unwrap();
let vote_state: VoteStateVersions = vote_account.state().unwrap();
let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer;
assert_eq!(authorized_withdrawer, first_withdraw_authority.pubkey());
// Authorize vote account withdrawal to another signer with checked instruction
let withdraw_authority = Keypair::new();
config.signers = vec![&default_signer, &first_withdraw_authority];
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey: withdraw_authority.pubkey(),
vote_authorize: VoteAuthorize::Withdrawer,
memo: None,
authorized: 1,
new_authorized: Some(1),
};
process_command(&config).unwrap_err(); // unsigned by new authority should fail
config.signers = vec![
&default_signer,
&first_withdraw_authority,
&withdraw_authority,
];
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey: withdraw_authority.pubkey(),
vote_authorize: VoteAuthorize::Withdrawer,
memo: None,
authorized: 1,
new_authorized: Some(2),
};
process_command(&config).unwrap();
let vote_account = rpc_client

View File

@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "1.7.0"
version = "1.8.3"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@ -15,7 +15,7 @@ bincode = "1.3.1"
bs58 = "0.3.1"
clap = "2.33.0"
indicatif = "0.15.0"
jsonrpc-core = "17.0.0"
jsonrpc-core = "18.0.0"
log = "0.4.11"
net2 = "0.2.37"
rayon = "1.5.0"
@ -24,14 +24,14 @@ semver = "0.11.0"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.0" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.0" }
solana-faucet = { path = "../faucet", version = "=1.7.0" }
solana-net-utils = { path = "../net-utils", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.0" }
solana-version = { path = "../version", version = "=1.7.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.0" }
solana-account-decoder = { path = "../account-decoder", version = "=1.8.3" }
solana-clap-utils = { path = "../clap-utils", version = "=1.8.3" }
solana-faucet = { path = "../faucet", version = "=1.8.3" }
solana-net-utils = { path = "../net-utils", version = "=1.8.3" }
solana-sdk = { path = "../sdk", version = "=1.8.3" }
solana-transaction-status = { path = "../transaction-status", version = "=1.8.3" }
solana-version = { path = "../version", version = "=1.8.3" }
solana-vote-program = { path = "../programs/vote", version = "=1.8.3" }
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
tungstenite = "0.10.1"
@ -39,8 +39,8 @@ url = "2.1.1"
[dev-dependencies]
assert_matches = "1.3.0"
jsonrpc-http-server = "17.0.0"
solana-logger = { path = "../logger", version = "=1.7.0" }
jsonrpc-http-server = "18.0.0"
solana-logger = { path = "../logger", version = "=1.8.3" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -122,10 +122,10 @@ mod tests {
use crate::{
blockhash_query,
rpc_request::RpcRequest,
rpc_response::{Response, RpcFeeCalculator, RpcResponseContext},
rpc_response::{Response, RpcFeeCalculator, RpcFees, RpcResponseContext},
};
use clap::App;
use serde_json::{self, json, Value};
use serde_json::{self, json};
use solana_account_decoder::{UiAccount, UiAccountEncoding};
use solana_sdk::{account::Account, hash::hash, nonce, system_program};
use std::collections::HashMap;
@ -288,10 +288,12 @@ mod tests {
let rpc_fee_calc = FeeCalculator::new(42);
let get_recent_blockhash_response = json!(Response {
context: RpcResponseContext { slot: 1 },
value: json!((
Value::String(rpc_blockhash.to_string()),
serde_json::to_value(rpc_fee_calc.clone()).unwrap()
)),
value: json!(RpcFees {
blockhash: rpc_blockhash.to_string(),
fee_calculator: rpc_fee_calc.clone(),
last_valid_slot: 42,
last_valid_block_height: 42,
}),
});
let get_fee_calculator_for_blockhash_response = json!(Response {
context: RpcResponseContext { slot: 1 },
@ -300,10 +302,7 @@ mod tests {
}),
});
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
mocks.insert(RpcRequest::GetFees, get_recent_blockhash_response.clone());
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::default()
@ -312,10 +311,7 @@ mod tests {
(rpc_blockhash, rpc_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
mocks.insert(RpcRequest::GetFees, get_recent_blockhash_response.clone());
mocks.insert(
RpcRequest::GetFeeCalculatorForBlockhash,
get_fee_calculator_for_blockhash_response,
@ -328,10 +324,7 @@ mod tests {
(test_blockhash, rpc_fee_calc),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response,
);
mocks.insert(RpcRequest::GetFees, get_recent_blockhash_response);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::None(test_blockhash)

View File

@ -1,5 +1,5 @@
use {
crate::rpc_request,
crate::{rpc_request, rpc_response},
solana_faucet::faucet::FaucetError,
solana_sdk::{
signature::SignerError, transaction::TransactionError, transport::TransportError,
@ -30,6 +30,24 @@ pub enum ClientErrorKind {
Custom(String),
}
impl ClientErrorKind {
pub fn get_transaction_error(&self) -> Option<TransactionError> {
match self {
Self::RpcError(rpc_request::RpcError::RpcResponseError {
data:
rpc_request::RpcResponseErrorData::SendTransactionPreflightFailure(
rpc_response::RpcSimulateTransactionResult {
err: Some(tx_err), ..
},
),
..
}) => Some(tx_err.clone()),
Self::TransactionError(tx_err) => Some(tx_err.clone()),
_ => None,
}
}
}
impl From<TransportError> for ClientErrorKind {
fn from(err: TransportError) -> Self {
match err {
@ -86,6 +104,10 @@ impl ClientError {
pub fn kind(&self) -> &ClientErrorKind {
&self.kind
}
pub fn get_transaction_error(&self) -> Option<TransactionError> {
self.kind.get_transaction_error()
}
}
impl From<ClientErrorKind> for ClientError {

View File

@ -1,10 +1,12 @@
//! The standard [`RpcSender`] over HTTP.
use {
crate::{
client_error::Result,
rpc_custom_error,
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
rpc_response::RpcSimulateTransactionResult,
rpc_sender::RpcSender,
rpc_sender::*,
},
log::*,
reqwest::{
@ -15,10 +17,10 @@ use {
std::{
sync::{
atomic::{AtomicU64, Ordering},
Arc,
Arc, RwLock,
},
thread::sleep,
time::Duration,
time::{Duration, Instant},
},
};
@ -26,13 +28,22 @@ pub struct HttpSender {
client: Arc<reqwest::blocking::Client>,
url: String,
request_id: AtomicU64,
stats: RwLock<RpcTransportStats>,
}
/// The standard [`RpcSender`] over HTTP.
impl HttpSender {
/// Create an HTTP RPC sender.
///
/// The URL is an HTTP URL, usually for port 8899, as in
/// "http://localhost:8899". The sender has a default timeout of 30 seconds.
pub fn new(url: String) -> Self {
Self::new_with_timeout(url, Duration::from_secs(30))
}
/// Create an HTTP RPC sender.
///
/// The URL is an HTTP URL, usually for port 8899.
pub fn new_with_timeout(url: String, timeout: Duration) -> Self {
// `reqwest::blocking::Client` panics if run in a tokio async context. Shuttle the
// request to a different tokio thread to avoid this
@ -49,6 +60,7 @@ impl HttpSender {
client,
url,
request_id: AtomicU64::new(0),
stats: RwLock::new(RpcTransportStats::default()),
}
}
}
@ -57,11 +69,45 @@ impl HttpSender {
struct RpcErrorObject {
code: i64,
message: String,
data: serde_json::Value,
}
struct StatsUpdater<'a> {
stats: &'a RwLock<RpcTransportStats>,
request_start_time: Instant,
rate_limited_time: Duration,
}
impl<'a> StatsUpdater<'a> {
fn new(stats: &'a RwLock<RpcTransportStats>) -> Self {
Self {
stats,
request_start_time: Instant::now(),
rate_limited_time: Duration::default(),
}
}
fn add_rate_limited_time(&mut self, duration: Duration) {
self.rate_limited_time += duration;
}
}
impl<'a> Drop for StatsUpdater<'a> {
fn drop(&mut self) {
let mut stats = self.stats.write().unwrap();
stats.request_count += 1;
stats.elapsed_time += Instant::now().duration_since(self.request_start_time);
stats.rate_limited_time += self.rate_limited_time;
}
}
impl RpcSender for HttpSender {
fn get_transport_stats(&self) -> RpcTransportStats {
self.stats.read().unwrap().clone()
}
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value> {
let mut stats_updater = StatsUpdater::new(&self.stats);
let request_id = self.request_id.fetch_add(1, Ordering::Relaxed);
let request_json = request.build_request_json(request_id, params).to_string();
@ -79,45 +125,42 @@ impl RpcSender for HttpSender {
.body(request_json)
.send()
})
};
}?;
match response {
Ok(response) => {
if !response.status().is_success() {
if response.status() == StatusCode::TOO_MANY_REQUESTS
&& too_many_requests_retries > 0
{
let mut duration = Duration::from_millis(500);
if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
if let Ok(retry_after) = retry_after.to_str() {
if let Ok(retry_after) = retry_after.parse::<u64>() {
if retry_after < 120 {
duration = Duration::from_secs(retry_after);
}
}
if !response.status().is_success() {
if response.status() == StatusCode::TOO_MANY_REQUESTS
&& too_many_requests_retries > 0
{
let mut duration = Duration::from_millis(500);
if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
if let Ok(retry_after) = retry_after.to_str() {
if let Ok(retry_after) = retry_after.parse::<u64>() {
if retry_after < 120 {
duration = Duration::from_secs(retry_after);
}
}
}
}
too_many_requests_retries -= 1;
debug!(
too_many_requests_retries -= 1;
debug!(
"Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
response, too_many_requests_retries, duration
);
sleep(duration);
continue;
}
return Err(response.error_for_status().unwrap_err().into());
}
sleep(duration);
stats_updater.add_rate_limited_time(duration);
continue;
}
return Err(response.error_for_status().unwrap_err().into());
}
let response_text = tokio::task::block_in_place(move || response.text())?;
let json: serde_json::Value = serde_json::from_str(&response_text)?;
if json["error"].is_object() {
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone())
{
Ok(rpc_error_object) => {
let data = match rpc_error_object.code {
let mut json =
tokio::task::block_in_place(move || response.json::<serde_json::Value>())?;
if json["error"].is_object() {
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone()) {
Ok(rpc_error_object) => {
let data = match rpc_error_object.code {
rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
match serde_json::from_value::<RpcSimulateTransactionResult>(json["error"]["data"].clone()) {
Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
@ -138,27 +181,22 @@ impl RpcSender for HttpSender {
_ => RpcResponseErrorData::Empty
};
Err(RpcError::RpcResponseError {
code: rpc_error_object.code,
message: rpc_error_object.message,
data,
}
.into())
}
Err(err) => Err(RpcError::RpcRequestError(format!(
"Failed to deserialize RPC error response: {} [{}]",
serde_json::to_string(&json["error"]).unwrap(),
err
))
.into()),
};
Err(RpcError::RpcResponseError {
code: rpc_error_object.code,
message: rpc_error_object.message,
data,
}
.into())
}
return Ok(json["result"].clone());
}
Err(err) => {
return Err(err.into());
}
Err(err) => Err(RpcError::RpcRequestError(format!(
"Failed to deserialize RPC error response: {} [{}]",
serde_json::to_string(&json["error"]).unwrap(),
err
))
.into()),
};
}
return Ok(json["result"].take());
}
}
}

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