Compare commits

...

791 Commits

Author SHA1 Message Date
86419dfd3c Bump version to 1.1.24 2020-07-30 10:55:12 -06:00
263fc25992 Reject TXs sent via RPC with no signatures
(cherry picked from commit a888f2f516)
2020-07-30 07:44:18 -06:00
f6b669eabc Add new RPC error for TXs with no signatures
(cherry picked from commit 9778fedd7a)
2020-07-30 07:44:18 -06:00
1b2fdcd3a2 Dereplicode send_transaction and request_airdrop RPC handlers
(cherry picked from commit a7079e4dde)
2020-07-30 07:44:18 -06:00
e8e74ee009 Add failing test for TX sent via RPC with no signatures
(cherry picked from commit b962b2ce2d)
2020-07-30 07:44:18 -06:00
227a13f2d2 Fill out missing RPC request received debug logging 2020-07-29 22:58:30 -06:00
6842e37780 Fix race condition between shrinking and cleaning (for 1.1) (#11234)
* Fix race condition between shrinking and cleaning

* Fix compile error...

* fix ci

* Update comments
2020-07-29 06:06:34 +09:00
035bd7db4e Bump version to 1.1.23 2020-07-27 16:26:44 -06:00
14c2e2af13 Designate mainnet-beta epoch 61 as an upgrade epoch
(cherry picked from commit ed01591be6)
2020-07-27 14:48:42 -06:00
a5b915263b Rpc: Add getStakeActivation endpoint (bp #10902) (#11185)
* Rpc: Add getStakeActivation endpoint (#10902)

* Add getStakeActivation endpoint

* Add docs

* Update docs/src/apps/jsonrpc-api.md

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

* Rework return type

* Update docs

* Rebase

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

# Conflicts:
#	core/src/rpc.rs
#	docs/src/apps/jsonrpc-api.md

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-07-23 14:50:59 -06:00
b87ac392e8 Bump version to v1.1.22 2020-07-22 16:17:14 -06:00
f6f4e6062a Use OrderedIterator in collect_balances (#11167) 2020-07-22 13:02:23 -06:00
42c027a7e6 Bump version to 1.1.21 2020-07-21 23:33:01 -06:00
6fbad24477 getEpochInfo RPC endpoint now includes the current block height 2020-07-21 20:21:39 -07:00
4bd018e68b Use OrderedIterator in TransactionStatusService (#11149) (#11150)
* Split out get-first-err for unit testing

* Add failing test

* Add missing ordering

(cherry picked from commit 6c38369042)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-07-21 17:49:38 -06:00
c73e40a351 Add Bank support for "upgrade epochs" where all non-vote transactions will be rejected (bp #11082) (#11109)
* Add Bank support for "upgrade epochs" where all non-vote transactions will be rejected

(cherry picked from commit e5d8c4383f)

# Conflicts:
#	runtime/src/bank.rs

* Fix merge conflict

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-07-17 12:34:19 -07:00
8f790e3153 Add --expected-bank-hash stub for v1.2 command-line compatibility 2020-07-16 13:18:34 -07:00
1972d8b5c0 Update CRATES_IO_TOKEN 2020-07-15 17:55:13 -07:00
bc2fd56516 Gate nonce-overwrite change (#11081) (#11086)
(cherry picked from commit 1da9f9f05a)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-07-15 18:22:33 -06:00
00916b2ca6 CLI: Fix explicitly plumb vote_account through create-vote-account
(cherry picked from commit 14ac233d01)
2020-07-14 10:28:59 -06:00
006a5c5c88 CLI: Fix explicitly plumb withdraw_authority through vote-update-validator
(cherry picked from commit 2284699889)
2020-07-14 10:28:59 -06:00
6666e54a1f CLI: Fix explicitly plumb withdraw_authority through vote-update-commission
(cherry picked from commit 3392ecc310)
2020-07-14 10:28:59 -06:00
d6ea4f50c9 Mode gate RecentBlockhashes/BlockhashQueue sync
(cherry picked from commit 5741002a32)
2020-07-13 22:47:39 -06:00
a0965e1eba Synchronize BlockhashQueue and RecentBlockhashes sysvar update
(cherry picked from commit 5357ff6d60)
2020-07-13 22:47:39 -06:00
7ca65341e6 Factor locked portion of Bank::update_recent_blockhashes() out to helper
(cherry picked from commit 9cc379af6c)
2020-07-13 22:47:39 -06:00
141a5928c4 Add failing test
(cherry picked from commit 942c019d50)
2020-07-13 22:47:39 -06:00
5f0584b6e8 Add vote-update-commission subcommand 2020-07-13 11:45:33 -06:00
b7fb739cd9 Revert "Add EncodedTransaction::Raw"
This reverts commit 60b1bcddb5.
2020-07-12 08:56:36 -07:00
5a4a238029 rebase 2020-07-10 22:52:51 -07:00
01987f8f89 getConfirmedBlocks now has an upper limit on slot range
(cherry picked from commit aef6bf272e)

# Conflicts:
#	core/src/rpc.rs
2020-07-10 22:52:51 -07:00
82caa50781 Add fee-calculator logging (#11001) 2020-07-10 18:04:49 -06:00
60b1bcddb5 Add EncodedTransaction::Raw 2020-07-10 14:55:07 -07:00
dce7739b75 Add block time placeholder to getConfirmedBlock (#10989)
(cherry picked from commit 491f5ae61a)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-07-10 11:02:43 -07:00
1c703af6a2 Fix nonce fee_calculator overwrite (bp #10973) (#10975)
* Fix nonce fee_calculator overwrite (#10973)

* Add failing test

* Pass fee_calculator to prepare_if_nonce_account; only overwrite in error case

(cherry picked from commit 25228ca957)

* v1.1 transaction  builder

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-07-09 16:57:18 -06:00
f49de3b1ad Add --snapshot-version stub to ease migration to 1.2.0 (#10921) 2020-07-05 21:22:31 -07:00
5c1b79f500 net.sh: Refactor node initialization wait (#10819) (#10823)
* remote-node.sh: Factor out init wait to own script

* remote-node.sh: Allow nodes to initialize asynchronously

* testnet-automation: Plumb --async-node-init

(cherry picked from commit 7021e1c584)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-06-26 16:28:55 +00:00
da04616fd4 Fix race in ci/run-sanity.sh (#10796) (#10801)
(cherry picked from commit 4dc9f378b8)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-06-25 05:54:08 +00:00
8653c86284 Fix broken image link (#10496) (#10794)
automerge

(cherry picked from commit 75b8c2c4e3)

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-06-25 01:41:35 +00:00
809e4cbf25 Remote Wallet: Stricter derivation path component parsing (#10725) (#10739)
(cherry picked from commit 842cab2739)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-06-22 18:27:46 +00:00
1aef482972 ledger-tool: Ignore SIGUSR1 (#10730) (#10731)
Prevents warehouse archive calls getting KO'd by logrotate

(cherry picked from commit d42247c652)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-06-21 19:31:25 +00:00
248ab3a6ec Don't bother api.github.com on pull requests to avoid getting rate limited (#10709)
(cherry picked from commit c0389ef82f)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-06-18 23:55:09 +00:00
ec1f2b4f90 Bump version to v1.1.20 (#10705) 2020-06-18 23:29:23 +00:00
c853632fc4 Add stub address_labels field for 1.3 compatibility (#10696) 2020-06-18 11:05:48 -07:00
e651209f73 Update testnet shred version (#10684) (#10685)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit 9c22a6007d)

Co-authored-by: carllin <wumu727@gmail.com>
2020-06-18 07:59:20 +00:00
641f439a45 Update testnet shred version (#10681) (#10682)
Co-authored-by: Carl <carl@solana.com>
(cherry picked from commit dae8bc477b)

Co-authored-by: carllin <wumu727@gmail.com>
2020-06-18 07:44:58 +00:00
a2486f8094 Remove strict from automerge, add rebase opt in 2020-06-17 20:53:55 -07:00
d48bd80619 Plumb --warp-slot through net scripts (bp #10639) (#10642)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>

Co-authored-by: Trent Nelson <trent@solana.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2020-06-18 01:44:58 +00:00
4ff70a05f1 ignore break (#10666) (#10668)
(cherry picked from commit a5f82c995e)

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
2020-06-17 22:46:24 +00:00
7831cef9a7 Wait until bank is frozen before sending RPC notifications (bp #10654) (#10662)
* Wait until bank is frozen before sending RPC notifications (#10654)

(cherry picked from commit 39984cdcc3)

# Conflicts:
#	core/src/replay_stage.rs

* Update replay_stage.rs

Co-authored-by: Justin Starry <justin@solana.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2020-06-17 20:35:16 +00:00
7dd22d6601 Factor out testnet automation SW version resolution (#10659)
(cherry picked from commit a15f60a291)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-06-17 17:19:02 +00:00
3bb0388299 Add address to non-circulating supply (#10647)
(cherry picked from commit 5673343f49)

Co-authored-by: publish-docs.sh <maintainers@solana.com>
2020-06-17 05:43:23 +00:00
a0a2c61856 Allow pre-existing stake accounts in multinode-demo/delegate-stake.sh (#10635)
(cherry picked from commit ae0d5ba201)

Co-authored-by: Trent Nelson <trent@solana.com>
2020-06-16 22:53:52 +00:00
4afa64c20d Plumb --wait-for-supermajority through scripts (#10611) (#10613)
(cherry picked from commit 348bf78cd1)

Co-authored-by: Trent Nelson <trent@solana.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2020-06-16 17:55:16 +00:00
be6edb950c Add generic is_parsable() input validator (bp #10599) (#10620)
* Add generic is_parsable() input validator.
Allow input validators to accept &str, &String and String parameters.

(cherry picked from commit daa2e6363f)

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

* Fix conflict

Co-authored-by: Kristofer Peterson <kris@tranception.com>
Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2020-06-16 11:15:29 +00:00
62bc83ef39 Add mergify automerge rules 2020-06-15 09:14:39 -07:00
f26824f2b5 Bump version to v1.1.19 2020-06-14 20:18:45 -07:00
bc808d785b Fix udp port check retry and check all udp ports (bp #10385) (#10576)
automerge
2020-06-14 17:36:17 -07:00
a5e91f8b14 Fix perf-libs version detection (#10571) (#10573)
automerge
2020-06-14 13:50:10 -07:00
79b1d49e42 Fix fannout gossip bench (bp #10509) (#10555)
* Fix fannout gossip bench (#10509)

* Gossip benchmark

* Rayon tweaking

* push pulls

* fanout to max nodes

* fixup! fanout to max nodes

* fixup! fixup! fanout to max nodes

* update

* multi vote test

* fixup prune

* fast propagation

* fixups

* compute up to 95%

* test for specific tx

* stats

* stats

* fixed tests

* rename

* track a lagging view of which nodes have the local node in their active set in the local received_cache

* test fixups

* dups are old now

* dont prune your own origin

* send vote to tpu

* tests

* fixed tests

* fixed test

* update

* ignore scale

* lint

* fixup

* fixup

* fixup

* cleanup

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

* Merge fixes

Co-authored-by: anatoly yakovenko <anatoly@solana.com>
2020-06-14 06:28:43 -07:00
5c5207b7c4 Use git diff instead of git show for --check (#10566) (#10567)
automerge
2020-06-14 06:28:33 -07:00
6280ea1b6e Check the whole range of commits in the topic branch (bp #10560) (#10563)
automerge
2020-06-14 04:46:09 -07:00
f016ccdbb5 Dial down gossip threadpool (#10540) 2020-06-13 22:48:32 -07:00
a528e966e6 Add Trust Wallet security info (#10516)
automerge

(cherry picked from commit 914f285914)
2020-06-12 22:14:34 -07:00
4be9d926c8 Add FdGYQ... to non-circulation withdrawer authority list (#10542) (#10545)
automerge
2020-06-12 18:14:27 -07:00
94e162b0f0 Refine build condition 2020-06-12 17:03:48 -07:00
26ca3c6d6d Update non-circulating pubkeys (#10524) (#10526)
automerge

(cherry picked from commit fb8612be49)

Co-authored-by: Greg Fitzgerald <greg@solana.com>
2020-06-11 16:58:28 -07:00
729b997392 Improve BPF SDK dependency caching (#10434) (#10517)
automerge
2020-06-11 14:12:16 -07:00
37b381f47f Force CI_REPO_SLUG 2020-06-11 13:14:42 -07:00
0115bfa2ea Bump version to v1.1.18 2020-06-10 22:42:05 -07:00
3f60fe62c2 Add StakeInstruction::Merge (#10503) (#10506)
automerge
2020-06-10 20:04:03 -07:00
ea44e64d21 Add VoteInstruction::UpdateCommission (#10497)
automerge
2020-06-10 12:54:09 -07:00
8e1c2d2df4 Add back missing pull_response success counter (#10491) (#10500)
automerge
2020-06-10 10:45:27 -07:00
a79702c62c Optimize process pull responses (#10460) (#10484)
* Batch process pull responses

* Generate pull requests at 1/2 rate

* Do filtering work of process_pull_response in read lock

Only take write lock to insert if needed.
2020-06-09 20:02:46 -07:00
3c94084177 Add SendTransactionService (#10470)
automerge
2020-06-09 18:13:50 -07:00
7d448eb1a9 Add --warp-slot argument to |solana-ledger-tool create-snapshot| (#10473)
automerge
2020-06-09 11:09:32 -07:00
a705764ca7 v1.1 gossip lock optimizations (#10459)
* Skip gossip requests with different shred version and split lock (#10240)


(cherry picked from commit 3f508b37fd)

* More cluster stats and add epoch stakes cache in retransmit stage (#10345)

* More cluster info metrics for push request/response counts

* Cache staked peers for the epoch

(cherry picked from commit ef37b82ffa)

* Cache tvu peers for broadcast (#10373)


(cherry picked from commit 2cf719ac2c)

* Add pull request count metrics (#10421)


(cherry picked from commit 3d2230f1a9)
2020-06-08 17:05:55 -07:00
3110def6c3 Remove lock around JsonRpcRequestProcessor (bp #10417) (#10450)
automerge
2020-06-08 16:45:49 -07:00
afc89beefa Bump version to v1.1.17 2020-06-08 10:32:26 -07:00
d5d5e8797b Bump new_system_program_activation_epoch by 2 2020-06-08 09:40:39 -07:00
09f0624887 Adjust RPC simulateTransaction endpoint to match v1.2 (#10443)
automerge
2020-06-06 21:08:27 -07:00
52c20a5c38 Add Certus One as a trusted validator for testnet (#10433) (#10437)
automerge
2020-06-05 16:49:21 -07:00
3c38df9be0 Avoid AccountInUse errors when simulating transactions (#10391) (#10419)
automerge
2020-06-04 20:41:12 -07:00
da038e626a v1.1: ledger_cleanup_service: compact at a slower rate than purging (#10415)
automerge
2020-06-04 20:30:31 -07:00
9cfbf8a94d Deactivate legacy_system_instruction_processor at epoch 58/38 (preview/stable) (#10406) (#10407)
automerge
2020-06-04 01:21:43 -07:00
fbcbd37650 v1.1: Enable rolling update of "Permit paying oneself" / "No longer allow create-account to add funds to an existing account" (#10394)
automerge
2020-06-03 16:34:59 -07:00
dca932fe45 Don't share same snapshot dir for secondary access (bp #10384) (#10386)
automerge
2020-06-03 06:34:19 -07:00
8d89eac32f Support opening an in-use rocksdb as secondary (bp #10209) (#10381)
automerge
2020-06-02 23:51:43 -07:00
862fd63bb4 Update system_instruction_processor.rs 2020-06-02 23:35:31 -07:00
578d77495a No longer allow create-account to add funds to an existing account (#10192) 2020-06-02 23:35:31 -07:00
537d135005 Add --max-genesis-archive-unpacked-size to capitalization (#10380)
automerge
2020-06-02 21:39:14 -07:00
5ade9b9f02 Revert "Reduce UNLOCK_NONCE_SLOT to ensure it is active on all three clusters (#10223)" (#10370)
automerge
2020-06-02 12:42:03 -07:00
e023719c58 Add preflight checks to sendTransaction RPC method (bp #10338) (#10362)
automerge
2020-06-01 22:45:51 -07:00
a278f745f8 Reduce stable jobs (#10344) (#10346)
automerge
2020-05-31 22:40:51 -07:00
640bb9cb95 Permit paying oneself (#10337) (#10341)
automerge
2020-05-31 13:18:34 -07:00
c344a878b6 validator: Added --health-check-slot-distance (bp #10324) (#10330)
automerge
2020-05-29 17:49:09 -07:00
9b63f7a50f Improve Rpc inflation tooling (bp #10309) (#10321)
automerge
2020-05-29 17:35:10 -07:00
b128087445 Backport of #9161 to v1.1 branch (#10327)
automerge
2020-05-29 16:34:36 -07:00
72755fcd19 Add mechanism to get blockhash's last valid slot (#10239) (#10318)
automerge
2020-05-29 11:27:45 -07:00
24937e63d4 verify_reachable_ports: Handle errors without expect() (#10298) (#10304)
automerge
2020-05-28 16:12:08 -07:00
995759faf5 Add commitment parameter to getFeeCalculatorForBlockhash (#10255) (#10296) (#10302)
automerge
2020-05-28 15:26:39 -07:00
db60bd30dc Feign RPC health while in a --wait-for-supermajority holding pattern (#10295) (#10300)
automerge
2020-05-28 13:53:05 -07:00
bc86ee8d13 Fix run_orphan DOS (#10290)
Co-authored-by: Carl <carl@solana.com>
2020-05-28 11:29:13 -07:00
93506b22e7 Include GenesisConfig inflation in Display (#10282) (#10288)
automerge
2020-05-28 00:54:13 -07:00
1e53760a65 Use correct --url (#10284) (#10286)
automerge
2020-05-27 22:15:47 -07:00
24c796b434 Bump version to 1.1.16 2020-05-27 18:13:17 -07:00
2cdd3f835f log leader (#10280)
Co-authored-by: Carl <carl@solana.com>
2020-05-27 18:07:31 -07:00
c4e04f70d0 Adjust mainnet-beta shred version 2020-05-27 17:10:53 -07:00
5d971472b2 Purge next slots to avoid a blockstore_processor panic on restart (#10277) 2020-05-27 17:10:27 -07:00
f1201502d4 Bump version to 1.1.15 2020-05-26 21:22:34 -07:00
fd5222ad21 V1.1 single gossip commitment (#10263)
automerge
2020-05-26 21:16:46 -07:00
768a5f2b40 Cluster info metrics (#10215) (#10235)
automerge
2020-05-26 17:28:14 -07:00
87b57b53f9 Wait for one slot to be produced (#10257) (#10258)
automerge
2020-05-26 17:27:36 -07:00
55a64c8945 Activate eager rent collection and BPF loader on mainnet-beta epoch 34 (#10231) 2020-05-26 10:28:29 -07:00
e8c6233c6e Adjust owner hashing activation slot (#10243)
automerge
2020-05-26 01:21:22 -07:00
f51b214449 Adjust include_owner_in_hash to match mainet-beta v1.0 activation (#10230)
automerge
2020-05-25 12:31:15 -07:00
8fe8a5717e Clean up RPCClient retry handling: only retry on 429, after a little sleep (#10182) (#10184)
automerge
2020-05-25 11:41:46 -07:00
9adf8b4fc8 Reduce UNLOCK_NONCE_SLOT to ensure it is active on all three clusters (#10223)
automerge
2020-05-25 01:08:30 -07:00
82772f95a1 LedgerCleanupService no longer causes an OOM and actually purges (bp #10199) (#10221)
automerge
2020-05-24 23:24:45 -07:00
0b5d3df251 Optimize banking processing of AccountInUse (#10154) (#10193)
automerge
2020-05-24 11:46:10 -07:00
e63fdba252 Test ledger-tool commands in run-sanity.sh (#10211)
automerge
2020-05-24 06:07:24 -07:00
5e65b7cbd9 Retry a couple times before declaring a UDP port unreachable (#10181) (#10191)
automerge
2020-05-22 15:57:18 -07:00
68d0fe2dbc Update another non-circulating account 2020-05-22 15:11:19 -07:00
3aad5f563e Add another non-circulating account (#10186) (#10190)
automerge
2020-05-22 14:59:21 -07:00
ccfe09e460 Fixup deserialize_bs58_transaction, and make a few error types more targeted (#10171) (#10177)
automerge
2020-05-21 19:09:24 -07:00
6fd57fafc8 REST API now returns supply in SOL rather than lamports (#10170) (#10174)
automerge

(cherry picked from commit 18be7a7966)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-05-21 16:54:12 -07:00
c7d857583f Revert "Add AVX2 runtime checks (#10033)" (#10167) (#10169)
This reverts commit cf8eb7700b.

(cherry picked from commit 486168b796)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-05-21 13:19:47 -07:00
e29b7876ad Add v0 REST APIs for circulating and total supply (bp #10102) (#10160)
automerge
2020-05-20 21:51:25 -07:00
de479ebda9 transaction-history now searches over the entire history by default (#10145) (#10153)
automerge
2020-05-20 15:32:21 -07:00
d3447f2f41 Fixup subscription docs (#10146) (#10148)
automerge
2020-05-20 12:23:07 -07:00
d9e14b4a82 Fix another unstable test after eager rent (#10120) (#10143)
automerge
2020-05-20 10:22:11 -07:00
94b97e4b56 Ignore test_tvu_exit (#10134) (#10138)
automerge
2020-05-20 00:57:34 -07:00
abd977b819 Fix erasure (bp #10095) (#10127)
automerge
2020-05-19 22:21:35 -07:00
36eafa56a3 Rename getCirculatingSuppy to getSupply in JSON API doc (#10121) (#10123)
automerge
2020-05-19 15:47:39 -07:00
06a63549c1 Add SimulateTransaction RPC endpoint (#10106) (#10116)
automerge
2020-05-19 14:25:06 -07:00
a4047bb9c8 Fix deserialize reference tick (#10111)
Co-authored-by: Carl <carl@solana.com>
2020-05-19 13:55:37 -07:00
a235423000 Cargo.lock 2020-05-19 08:14:29 -07:00
726eadc64b Bump version to 1.1.14 2020-05-18 15:15:26 -07:00
4d18144232 Update accounts whitelist (#10100) (#10104)
automerge
2020-05-18 14:42:02 -07:00
342cf90ce1 Trigger RPC notifications after block commitment cache update (#10077) (#10101)
automerge
2020-05-18 13:34:18 -07:00
3ec109a0e4 Bump solana-rbpf to v0.1.28 (#9976) (#9983)
automerge
2020-05-18 00:10:05 -07:00
2634402fef Bump version to 1.1.13 2020-05-17 16:35:36 -07:00
997f317c23 v1.1: Add nonce to shreds repairs, add shred data size to header (#10076)
* Add nonce to shreds/repairs

* Add data shred size to header

* Align nonce unlock with epoch 47

Co-authored-by: Carl <carl@solana.com>
2020-05-17 13:36:15 -07:00
7bc915c0d1 Abort if the open fd limit cannot be increased (bp #10064) (#10074)
automerge
2020-05-15 14:35:29 -07:00
8651f058eb Add docs section to upgrade Solana App on Ledger Live (#10070) (#10072)
automerge
2020-05-15 11:30:32 -07:00
b6d6ff786a Forge a confirmed root before halting for RPC inspection (#10061) (#10067)
automerge
2020-05-15 10:30:02 -07:00
b9a80152df Fix unstable test after eager rent collection (#10031) (#10060)
automerge
2020-05-15 01:25:48 -07:00
e9dda5ebd7 v1.1: Eager rent collection (#10028)
* Introduce eager rent collection (#9527)

* Switch AccountsIndex.account_maps from HashMap to BTreeMap

* Introduce eager rent collection

* Start to add tests

* Avoid too short eager rent collection cycles

* Add more tests

* Add more tests...

* Refacotr!!!!!!

* Refactoring follow up

* More tiny cleanups

* Don't rewrite 0-lamport accounts to be deterministic

* Refactor a bit

* Do hard fork, restore tests, and perf. mitigation

* Fix build...

* Refactor and add switch over for testnet (TdS)

* Use to_be_bytes

* cleanup

* More tiny cleanup

* Rebase cleanup

* Set Bank::genesis_hash when resuming from snapshot

* Reorder fns and clean ups

* Better naming and commenting

* Yet more naming clarifications

* Make prefix width strictly uniform for 2-base partition_count

* Fix typo...

* Revert cluster-dependent gate

* kick ci?

* kick ci?

* kick ci?

(cherry picked from commit 1eb40c3fe0)

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

* Fix merge conflicts

* Add gating

* Add Danger comment...

* Delay activation epoch

* Add gating for stable as well

* fmt...

* fmt!!!!
2020-05-15 15:38:31 +09:00
5f0be1793c Add Ledger error codes (#10056) (#10059)
automerge
2020-05-14 23:13:18 -07:00
2d8533075d Base58 (#10052) (#10055)
automerge
2020-05-14 18:06:27 -07:00
bf382c6069 Remove inline from all BPF C functions (bp #10038) (#10039)
automerge
2020-05-14 14:47:04 -07:00
366e426f2b Clean up Ledger instructions (#10047) (#10049)
automerge
2020-05-14 13:08:34 -07:00
fa34e6e419 solana-gossip spy can now specify a shred version (#10040) (#10042)
automerge
2020-05-13 21:17:12 -07:00
ab9fe5e9ad Add AVX2 runtime checks (#10033) (#10035)
automerge
2020-05-13 13:43:06 -07:00
3474419111 Revert "[NO-MERGE; needs gating logic] Introduce eager rent collection (bp #9527) (#10022)" (#10026)
This reverts commit ff21251416.
2020-05-13 22:51:59 +09:00
ff21251416 [NO-MERGE; needs gating logic] Introduce eager rent collection (bp #9527) (#10022)
automerge
2020-05-13 06:12:45 -07:00
7e6bbc7b77 Introduce type alias Ancestors (#9699) (#10018)
automerge
2020-05-13 01:46:38 -07:00
82783b18ea Rpc: optionally filter getLargestAccounts by circulating/nonCirculating (#10007) (#10014)
automerge
2020-05-12 21:54:44 -07:00
b7c6f38665 Enable disk metrics (#10009) (#10010)
automerge
2020-05-12 16:45:26 -07:00
11da07eca7 Update testnet shred version (#10000) (#10002)
automerge
2020-05-11 23:35:14 -07:00
b6b779d2c4 Use CommitmentConfig::root() when checking accounts, CommitmentConfig::max() may not be available yet 2020-05-11 22:55:04 -07:00
1c85d62fe4 Fix crash when CI_COMMIT=HEAD (#9994) (#9998)
automerge

(cherry picked from commit 28d1f7c5e7)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-05-11 22:53:48 -07:00
867a213cd3 Bump version to v1.1.12 2020-05-11 22:10:03 -07:00
c51a18a887 getClusterNodes RPC API now includes the node software version (#9993) 2020-05-11 21:38:19 -07:00
206ff02be9 Fix up a couple cli commands that fail when a node is in the --wait-for-supermajority state (#9985) (#9991)
automerge

(cherry picked from commit 3b9dc50541)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-05-11 19:48:59 -07:00
8d7e90e9b8 Advertise node version in gossip (#9986)
automerge
2020-05-11 17:45:19 -07:00
eb11db3e3e Check slot cleaned up for RPC blockstore/slot queries (#9982) (#9989)
automerge
2020-05-11 16:49:22 -07:00
8d8ad84527 Add retransmit packets_by_slot metrics (#9975) (#9984)
automerge
2020-05-11 15:25:40 -07:00
fa059bb3c3 Add windows instructions to CLI install docs (#9987)
automerge
2020-05-11 14:50:26 -07:00
9652e832c2 Write non-error output to stdout (#9960) (#9972)
automerge
2020-05-11 10:18:15 -07:00
52e27712e1 Retransmit and shred fetch metrics (#9965) (#9969)
automerge
2020-05-10 23:15:15 -07:00
c00ec26a3b Cli: Add solana supply command; hide total-supply (bp #9956) (#9963)
automerge
2020-05-10 18:04:46 -07:00
50eba96b58 More logging around failure (#9967) (#9968)
automerge
2020-05-10 17:23:30 -07:00
e7c0629951 Remove RpcClient code duplication (#9952) (#9961)
automerge
2020-05-10 10:36:56 -07:00
a08235da9a send_and_confirm_transaction() no longer needs a keypair (#9950) (#9962)
automerge
2020-05-10 10:14:31 -07:00
b213004157 Rpc: Add getCirculatingSupply endpoint, redux (#9953) (#9955)
automerge
2020-05-09 12:32:08 -07:00
92562b4349 Pull in hardened BPF virtual machine (#9931) 2020-05-08 16:06:22 -07:00
01c490d354 Rename BPF helper to syscall (#9819)
automerge
2020-05-08 16:06:22 -07:00
cfdc0eb99e Maintain sysvar balances for consistent market cap. (#9942)
automerge
2020-05-08 12:15:37 -07:00
0b7b3c9f20 Support ad-hoc genesis args in run.sh (#9697) (#9940)
automerge
2020-05-08 08:29:29 -07:00
5cd685ed3a Bump version to v1.1.11 2020-05-07 16:57:43 -07:00
9498f11d46 v1.1: Include account.owner into account hash (#9918)
automerge
2020-05-07 13:00:52 -07:00
558324b861 Refactor RPC subscriptions account handling (#9888) (#9912)
automerge
2020-05-07 01:14:58 -07:00
9a5fc3513a Add using OutputFormat enum to --sign-only transactions (#9650) (#9911)
automerge
2020-05-06 23:19:36 -07:00
b7c6e139e6 Revert (#9908)
automerge
2020-05-06 22:28:19 -07:00
a9d2fa6aad Cli: Update OutputFormat method to return a String to restore consistency (#9904) (#9905)
automerge
2020-05-06 20:51:45 -07:00
056a9952c3 Cargo.lock 2020-05-06 16:35:26 -07:00
fc21c857a3 Bump version to v1.1.10 2020-05-06 16:04:41 -07:00
614ad64ec1 Fix (#9896) (#9901)
automerge
2020-05-06 13:31:02 -07:00
f72c186004 Correct method name 2020-05-06 11:28:16 -07:00
59a2b05b44 Gossip no longer pushes/pulls from nodes with a different shred version (#9868) (#9894)
automerge
2020-05-05 23:06:36 -07:00
bed6e566ef Display transaction fee in SOL (#9892) (#9898)
automerge

(cherry picked from commit e078ba1dde)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-05-05 22:44:36 -07:00
e85f9fcb73 Repair alternate versions of dead slots (bp #9805) (#9886)
automerge
2020-05-05 19:22:16 -07:00
8cb3953c9a Cli: add cluster-date subcommand, and make block-time slot optional (#9878) (#9883)
automerge
2020-05-05 10:19:10 -07:00
d8e885f425 Enable inflation on testnet effective epoch 44 (#9879) 2020-05-05 08:29:24 -07:00
28fa5149b7 Rpc: Filter blockstore data by cluster-confirmed root (#9873) (#9881)
automerge
2020-05-04 22:34:37 -07:00
190acd7d15 Rpc: add getLargestAccounts endpoint (#9869) (#9877)
automerge
2020-05-04 18:54:21 -07:00
909316bd53 Avoid panic caused by converting non-positive / non-normal floating points values to duration (#9867) (#9872)
(cherry picked from commit 3aedb81d48)

Co-authored-by: Kristofer Peterson <svenski123@users.noreply.github.com>
2020-05-04 14:27:40 -07:00
000b763e95 Add clap.rs default for --commitment (#9859) (#9861)
automerge
2020-05-02 14:47:30 -07:00
9d00ff6624 Bump to 1.1.9 2020-05-02 11:41:51 -07:00
fa254ff18f Fuzzer test and fixes (#9853) (#9858) 2020-05-02 10:05:13 -07:00
f78df36363 Put empty accounts in the accounts list on load (#9840) (#9854)
Indexing into accounts array does not match account_keys otherwise.
Also enforce program accounts not at index 0
Enforce at least 1 Read-write signing fee-payer account.
2020-05-01 21:37:13 -07:00
bae6fe17e9 Watchtower can now emit a notifiation on all non-vote transactions (#9845) (#9852)
automerge
2020-05-01 19:45:32 -07:00
4b1d338e04 Add delay to keep RPC traffic down on error 2020-05-01 10:39:11 -07:00
8079359420 Add incinerator sysvar (#9815) (#9836)
(cherry picked from commit 8dfe0affd4)
2020-05-01 09:02:59 -07:00
3aa52f95a2 v1.1 backport custom error rename (#9826)
* Add program_error conversions (#9203)

* Rename CustomError to Custom (#9207)

* More custom error rename (#9227)

automerge

* Remove librapay conflicts

* Fix rebase

Co-authored-by: Jack May <jack@solana.com>
2020-04-30 23:54:11 -06:00
3d88b9ac22 Cleanup BPF helper symbols (bp #9804) (#9825)
automerge
2020-04-30 13:10:13 -07:00
948487d9a7 Bump Ledger Beta app version (#9822) (#9824)
automerge
2020-04-30 11:21:08 -07:00
d775855a23 Clarify Ledger security implications (#9820) (#9823)
automerge
2020-04-30 11:18:58 -07:00
3f41d60793 Add commitment Root variant, and add fleshed out --commitment arg to Cli (#9806) (#9813)
automerge
2020-04-30 10:40:07 -07:00
7a6543eb5b thiserror, docs, remove general Failure case (#9741) (#9810)
automerge
2020-04-30 10:23:54 -07:00
892abd2a24 Make default programs static (bp #9717) (#9814)
automerge
2020-04-30 02:50:34 -07:00
8fef8eaed9 Remove old logging enabler artifacts (bp #9777) (#9818)
automerge
2020-04-30 01:52:01 -07:00
b7bd9d9fbb Nit: More informative error message (#9616) (#9816)
automerge
2020-04-30 00:54:47 -07:00
a8eb9357cb Upgrade to Rust 1.43.0 (#9754) (#9808)
automerge
2020-04-29 19:50:13 -07:00
87601facf1 Bump Rust-BPF version to be interoperable with latest Rust (#9783) (#9802)
automerge
2020-04-29 16:53:43 -07:00
4facdb25d0 Rpc Client: Prevent error out on get_num_blocks_since_signature_confirmation (#9792) (#9800)
automerge
2020-04-29 16:25:25 -07:00
bef59c3bd7 Rpc: remove unwraps (#9793) (#9797)
automerge
2020-04-29 15:03:05 -07:00
307064949a Fix BPF tool caching (#9781) (#9795)
automerge
2020-04-29 13:35:58 -07:00
40cb8d857b Don't divide by zero 2020-04-29 11:04:08 -07:00
972381efff catchup now estimates the time remaining (#9782) (#9785)
automerge
2020-04-29 01:26:20 -07:00
a2098c9ea9 Update dalek (v1.1 bp) (#9765)
* Disable Move/Libra components

* Update dalek version

Co-authored-by: Trent Nelson <trent@solana.com>
2020-04-28 18:37:20 -06:00
5af9963ea9 Docs: Fix linkcheck errors (#9743)
automerge
2020-04-28 18:37:20 -06:00
69736a792c Remove commented code 2020-04-28 15:49:07 -06:00
59446d5c50 v1.1: backport commitment max changes (#9775)
* Add largest_confirmed_root to BlockCommitmentCache (#9640)

* Add largest_confirmed_root to BlockCommitmentCache

* clippy

* Add blockstore to BlockCommitmentCache to check root

* Add rooted_stake helper fn and test

* Nodes that are behind should correctly id confirmed roots

* Simplify rooted_stake collector

* Cache banks in BankForks until optional largest_confirmed_root (#9678)

automerge

* Rpc: Use cluster largest_confirmed_root as commitment max (#9750)

automerge
2020-04-28 15:04:41 -06:00
ac538d0395 Don't --use-move 2020-04-28 12:47:23 -07:00
e79c910c41 Reorder steps by relative priority for when there aren't enough agents 2020-04-28 12:46:06 -07:00
0a7ef32ec7 Disable move more 2020-04-28 12:39:16 -07:00
1f6a7c174a Report duration of last alarm in the All Clear message (#9766) (#9771)
automerge

(cherry picked from commit 6e42989309)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-04-28 12:30:54 -07:00
109bfc3e7a Use Blockstore lowest_slot to start root iterator (#9738) (#9768)
automerge
2020-04-28 11:36:17 -07:00
682b700ec8 Set HOME correctly (#9757) (#9762)
automerge
2020-04-28 03:07:16 -07:00
89bfe5fab0 sanitize lowest slots (#9747) (#9752)
automerge
2020-04-27 22:01:41 -07:00
fbcc107086 Clean up use to keep rust 1.43.0 from complaining (#9740) (#9749)
automerge
2020-04-27 18:49:58 -07:00
9c6f613f8c Input values are not sanitized after they are deserialized, making it far too easy for Leo to earn SOL (bp #9706) (#9736)
automerge
2020-04-27 16:23:59 -07:00
34f5f48e43 Fix broken doc link to anatomy of transaction (#9728) (#9730)
automerge
2020-04-27 01:28:00 -07:00
09cd6197c2 Update metrics dashboard 2020-04-26 09:53:38 -07:00
4a86a794ed Filter program ids to store (bp #9721) (#9724)
automerge
2020-04-26 01:49:15 -07:00
7cd1c06a50 validator: Add support for log rotation, sending SIGUSR1 will cause the log file to be re-opened (bp #9713) (#9716)
automerge
2020-04-24 16:22:03 -07:00
240433ef25 Add missing slash 2020-04-23 21:36:40 -07:00
0afb058616 Bump version to 1.1.8 2020-04-23 20:40:29 -07:00
f1cda98aeb Update testnet expected shred version 2020-04-23 20:37:17 -07:00
d5cbac41cb Fix vote listener passing bad transactions (#9694) (#9696)
automerge
2020-04-23 18:43:07 -07:00
f19209b23d Update solana-user-authorized_keys.sh 2020-04-23 16:32:05 -06:00
fd670d0ae0 Exit cleanly on panic! so the process don't limp along in a half-dead state (#9690) (#9693)
automerge
2020-04-23 13:52:34 -07:00
948d869c49 Update to rocksdb 0.14 and set max wal size (#9668) (#9688) 2020-04-23 10:42:31 -07:00
2bab4ace8b Remove stray 'v' (#9679) (#9681)
automerge
2020-04-23 01:04:26 -07:00
1ddff68642 Bump version to 1.1.7 2020-04-22 22:13:46 -07:00
c0b250285a Add custodian option to withdraw-stake command (bp #9662) (#9675)
* Merge stake::withdraw instructions (#9617)

* Add custodian option to withdraw-stake command (#9662)

automerge

Co-authored-by: Greg Fitzgerald <greg@solana.com>
2020-04-22 20:30:46 -07:00
4509579e10 Clean up wallet doc URLs and validator/TdS docs (#9676) 2020-04-22 20:30:27 -07:00
9b8d59cc2b Add docs for installing the beta Ledger app (#9641) (#9677)
automerge
2020-04-22 19:38:11 -07:00
bd91fc2985 Don't attempt to rebase or move empty accounts (#9651) (#9674)
automerge
2020-04-22 19:35:20 -07:00
9a3ebe0b20 Remove validator-info publish command from net scripts 2020-04-22 18:05:32 -06:00
6c08dc9c9d Add getLowestNonpurgedBlock rpc; use blockstore api in getConfirmedBlocks (#9656) (#9664)
automerge
2020-04-22 15:13:23 -07:00
740c1df045 Extend snapshot interval in multinode demo (#9657) (#9661)
automerge
2020-04-22 14:39:25 -07:00
0a5905a02c Add single region TPS report testcases (#9609) (#9659) 2020-04-22 12:43:53 -06:00
237eceb6c1 Relax setting withdraw authority during lockup (#9644) (#9646)
automerge
2020-04-21 22:50:18 -07:00
dabbdcf988 Push down cluster_info lock (bp #9594) (#9637)
automerge
2020-04-21 16:42:07 -07:00
3fceaf694c Flag test_tvu_exit as serial to hopefully reduce CI flakiness (#9509) (#9639)
automerge
2020-04-21 14:43:29 -07:00
34df5ad364 cli: Add transaction-history (bp #9614) (#9623)
automerge
2020-04-21 10:49:24 -07:00
573aed2b4b RPC: Allow single slot address history queries (#9630) (#9635)
(cherry picked from commit 3023691487)

Co-authored-by: Justin Starry <justin@solana.com>
2020-04-21 10:23:34 -07:00
6ef65d8513 Document potential null responses in RPC API docs (#9629) (#9634)
automerge
2020-04-21 10:11:55 -07:00
7c6fb3d554 Wait for supermajority of cluster to have rooted a transaction to consider it finalized (#9618) (#9627)
automerge
2020-04-21 00:59:37 -07:00
886eaac211 Handle outdated and current ledger-solana-apps (#9605) (#9612)
automerge
2020-04-20 16:14:06 -07:00
6ca69a1525 Add decode-transaction (#9608)
automerge
2020-04-20 14:20:09 -07:00
1cc2f67391 test (#9601)
automerge
2020-04-20 10:09:49 -07:00
5d547130f0 Calculate distance between u64 without overflow (#9592) (#9599)
automerge
2020-04-20 01:25:41 -07:00
facb209720 Error for invalid shred. (#9588) (#9597)
automerge
2020-04-19 22:50:08 -07:00
5e215ac854 log proper slot (#9576) (#9589)
automerge
2020-04-19 15:52:03 -07:00
d3dd9ec6e2 Fix local-cluster test - archiver should wait for itself + 1 validator (#9577) (#9585)
automerge
2020-04-19 01:44:46 -07:00
12ed7c6845 Bump version to 1.1.6 2020-04-18 23:37:34 -07:00
f9d68b5d86 Budget for gossip traffic (#9550)
(cherry picked from commit 65a9658b13)
2020-04-18 23:09:16 -07:00
8f9f11e37f Tame wallet manager better (#9567) (#9575)
automerge
2020-04-18 13:37:40 -07:00
6a5f67f78c validator: Consider the activated stake of this node to be online again (#9573) (#9574)
automerge
2020-04-18 11:54:42 -07:00
a505e92487 Remove wait_for_majority (#9572)
automerge
2020-04-18 09:54:34 -07:00
701300334a Reduce metrics log output
(cherry picked from commit f142451a33)
2020-04-18 08:40:01 -07:00
b9cf02fd6a Report offline/wrong-shred nodes while waiting for a super majority in gossip
(cherry picked from commit 8509dcb8a0)
2020-04-17 16:21:43 -07:00
71cb8de0dd Reduce ReceiveUpdates log spam
(cherry picked from commit 7b5cdf6adf)
2020-04-17 16:21:43 -07:00
13e5b479eb confirm --verbose now displays failed transactions (#9562)
automerge
2020-04-17 14:56:58 -07:00
2ad435587a Increase the number of JSON RPC service threads (#9551) (#9561)
automerge
2020-04-17 14:48:32 -07:00
8f54d409e2 Consider config in check_for_usb (#9555) (#9557)
automerge
2020-04-17 13:03:45 -07:00
b4345c039a Make rpc_subscriptions.rs tests serial (#9556)
automerge

(cherry picked from commit b58338b066)
2020-04-17 11:40:12 -07:00
e61545ad18 Make rpc tests serial (#9537) (#9553)
automerge
2020-04-16 23:34:26 -07:00
961d1f0ee5 Simplify EpochSlots update (#9545) (#9548)
automerge
2020-04-16 21:02:28 -07:00
b260f686a3 Only build x86_64-unknown-linux-gnu on docs.rs 2020-04-16 19:07:08 -07:00
3cfc38850b Don't upload tarballs to buildkite to speed up build 2020-04-16 13:54:59 -07:00
f12a933a54 Write wallet key to explicit file
(cherry picked from commit 93669ab1fc)
2020-04-16 13:41:33 -07:00
135763e019 Bump version to 1.1.5 2020-04-16 13:23:21 -07:00
aaec7de881 Fix broadcast metrics (#9461)
* Rework broadcast metrics to support multiple threads

* Update dashboards

Co-authored-by: Carl <carl@solana.com>
2020-04-16 13:02:02 -07:00
420ea2f143 Reduce cluster-info metrics. (#9465) 2020-04-16 13:02:02 -07:00
cb2dd56317 Passing -v/--verbose to solana confirm now displays the full transaction (#9530)
automerge
2020-04-16 10:01:42 -07:00
a420d1e91e Don't unwrap on session new
(cherry picked from commit 30b3862770)
2020-04-16 09:46:05 -07:00
0073448afc Default to RUST_BACKTRACE=1 for more informative validator logs
(cherry picked from commit 4ac15e68cf)
2020-04-15 22:46:45 -07:00
086cdd8ef7 Rpc: Speed up getBlockTime (#9510) (#9514)
automerge
2020-04-15 19:12:09 -07:00
dd57cbd6a4 Pacify shellcheck
(cherry picked from commit a7ed33b552)
2020-04-15 17:50:53 -07:00
8937a1db3b Always run shellcheck
(cherry picked from commit 9cc7265b05)
2020-04-15 17:50:53 -07:00
89a914f7c1 Use $rust_stable (#9516)
automerge
2020-04-15 17:22:02 -07:00
cf9936a314 RPC: Add health check URI (bp #9499) (#9505)
automerge
2020-04-15 11:33:20 -07:00
6f95524be3 Fix race in multi_bind_in_range (#9493)
(cherry picked from commit ee72714c08)
2020-04-14 17:52:30 -07:00
8021d368fe limit test jobs to 16 to prevent OOM (#9500)
(cherry picked from commit 2b2b2cac1f)
2020-04-14 17:51:57 -07:00
d7c43f0c0b Cli: enable json output (#9478) (#9495)
automerge
2020-04-14 14:22:23 -07:00
6765453f8a validator: Improve --dynamic-port-range and sys-tuner error messages (bp #9494) (#9496)
automerge
2020-04-14 13:54:29 -07:00
adb0824da5 Use same max_age regardless of leader/not-leader (#9423) (#9487)
automerge
2020-04-14 02:50:42 -07:00
f86dcec94b Print signature as part of progress spinner (#9484) (#9485)
automerge
2020-04-14 01:06:22 -07:00
8f28989520 Fail coverage faster in CI 2020-04-13 21:09:55 -07:00
1823d7bdec Assume json_rpc_url can be upgrade to a websocket if no port is supplied
(cherry picked from commit bcfadd6085)
2020-04-13 20:32:49 -07:00
892a3b6dc4 Rename UpdateNode to UpdateValidatorIdentity (#9475)
automerge
2020-04-13 19:09:42 -07:00
cc987b8884 Unfold coverage test failures
(cherry picked from commit d4ea1ec6ad)
2020-04-13 18:08:37 -07:00
32d616da1e Reorder CI jobs to allow for more concurrent PRs
(cherry picked from commit ce027da236)
2020-04-13 13:00:43 -07:00
6d62d0cd42 Improve address in use error message for RPC pubsub
(cherry picked from commit 37b048effb)
2020-04-13 12:33:17 -07:00
c7d6e2b4a5 Update buildkite-tests.yml
(cherry picked from commit 92a5a51632)
2020-04-13 11:01:16 -07:00
d6f1e4b10a Bump version to v1.1.4 2020-04-12 18:00:06 -07:00
73dad25d74 Sort the output of solana validators by active stake (#9459)
automerge

(cherry picked from commit 3f33f4d3a9)
2020-04-12 17:54:13 -07:00
a895ce51ee Fix flaky new_archiver_external_ip_test (#9457) (#9458)
automerge
2020-04-12 12:48:49 -07:00
3f95e7f055 accounts subcommand now prints account balances in SOL instead of lamports
(cherry picked from commit 3f1399cb0d)
2020-04-12 10:40:06 -07:00
a54042fc11 Don't subject authorizing a new stake authority to lockup (#9434)
(cherry picked from commit 31ebdbc77f)
2020-04-12 10:09:31 -07:00
68525a961f Remove slot field, add test (#9444) (#9449)
automerge
2020-04-11 15:33:12 -07:00
45093c8092 Calculate account refs fix (#9447) (#9450)
automerge
2020-04-11 13:48:11 -07:00
c3227ab671 Simplify vote simulation (#9435) (#9439)
automerge
2020-04-10 18:50:11 -07:00
967c178f5d Safer cargo command (#9437) (#9440)
automerge
2020-04-10 16:54:33 -07:00
310aa1a63f ReceiveUpdates spams the log, adjust the threshold higher (#9429) (#9430)
automerge
2020-04-10 11:24:00 -07:00
d5ae850169 Search for ports sequentially instead of at random for more predictable port selection (bp #9411) (#9419)
automerge
2020-04-09 21:43:29 -07:00
89f5153316 Rpc: Add getConfirmedSignaturesForAddress (#9407) (#9418)
automerge
2020-04-09 21:15:33 -07:00
677008b6cc Allow lower shred count (#9410) (#9412)
automerge
2020-04-09 18:20:28 -07:00
7936f34df8 Use consistent vote account filename (#9414) (#9415)
automerge
2020-04-09 18:00:31 -07:00
65f0187324 Remove dead code (#9404) (#9409)
automerge
2020-04-09 14:08:15 -07:00
8dc5d10f9c Rpc: Add getConfirmedTransaction (#9381) (#9393)
automerge
2020-04-09 09:44:24 -07:00
58d8c3ad70 Remove Trust Wallet Beta install instructions (#9396) (#9398)
automerge
2020-04-09 08:56:50 -07:00
7df45cf58a Fix partition setup (#9386) (#9394)
automerge
2020-04-09 02:55:26 -07:00
3379a8470d Add --no-wait arg to transfer (#9388) (#9391)
automerge
2020-04-09 00:05:06 -07:00
0969e87b08 Moar vm.max_map_count (#9385)
automerge
2020-04-08 19:14:15 -07:00
7a0dcdd1a4 Add Metrics/Dashboards tracking block production (#9342) (#9380)
automerge
2020-04-08 15:54:04 -07:00
34893d2449 Add blockstore address-to-signature index (#9367) (#9379)
automerge
2020-04-08 14:05:54 -07:00
ec8d1c5e2b Improve ledger-tool/accounts for easier debuging (#9370) (#9372)
automerge
2020-04-08 11:43:00 -07:00
e1dbed25b6 Default to mainnet-beta (#9326) (#9368)
automerge
2020-04-07 21:40:04 -07:00
3b08a2a116 Add 1 SOL grace, to allow for a complaint system account to fund a reasonable number of transactions. (#9359) (#9364)
automerge
2020-04-07 14:39:16 -07:00
7e42eca4b0 Cache solana-perf.tgz to speed up CI (#9360)
automerge

(cherry picked from commit dc91698b3a)
2020-04-07 13:31:57 -07:00
580304add4 Bump version to 1.1.3 2020-04-07 09:33:26 -07:00
b58ce6c740 Cache downloads to speed up CI (#9355)
automerge
2020-04-06 23:40:30 -07:00
0b27d0b363 Add support for monitoring system account balances (#9345)
automerge

(cherry picked from commit 03978ac5a5)
2020-04-06 22:58:10 -07:00
6ea74c3d29 RpcClient: include signature check in send_transaction, bump send retries in get_num_blocks_since_signature_confirmation (#9341) (#9346)
automerge
2020-04-06 20:24:27 -07:00
15631f8194 Fix docs (#9349) (#9350)
automerge
2020-04-06 20:22:11 -07:00
b87a1d2bc5 Optimize broadcast cluster_info critical section (#9327) (#9344)
automerge
2020-04-06 19:11:23 -07:00
eae98ad8ab Clean up paper/file system wallet docs (#9340) (#9347)
* Add filesystem wallet page

* Move validator paper wallet instructions to validator page

* Remove paper wallet staking section

* Add steps for multiple fs and paper wallets

* Add keypair convention page and better multi-wallet example
2020-04-06 19:33:59 -06:00
3a6c23e995 Make TestValidator mint_lamports configurable (#9337) (#9339)
automerge
2020-04-06 17:32:49 -07:00
2e3db6aba8 Add instructions for multiple trust wallet addresses (#9335) (#9336)
automerge
2020-04-06 15:04:57 -07:00
f1e635d088 Update choose cluster docs (#9328) (#9331)
automerge
2020-04-06 12:21:31 -07:00
cc07c86aab Reinstate commitment param to support old clients (#9324)
automerge
2020-04-06 11:10:06 -07:00
543b6016ea Remove write lock (#9311) (#9315)
automerge
2020-04-06 09:22:42 -07:00
f4e05909f7 Update getSignatureStatuses to return historical statuses (#9314) (#9322)
automerge
2020-04-06 04:54:12 -07:00
5da1466d08 Introduce background stale AppendVec shrink mechanism (#9219) (#9318)
automerge
2020-04-06 02:31:12 -07:00
7a8528793e Deprecate confirmTransaction, getSignatureStatus, and getSignatureConfirmation (#9298) (#9309)
automerge
2020-04-05 00:51:44 -07:00
4a0338c902 Rework TransactionStatus index in blockstore (#9281) (#9304)
automerge
2020-04-04 23:09:06 -07:00
11b4da4146 RPC: add err field to TransactionStatus, alongside the now deprecated status field (#9296) (#9303)
automerge
2020-04-04 21:58:44 -07:00
33c19130b5 Add log before opening database
(cherry picked from commit b557b3170e)
2020-04-03 15:02:16 -07:00
0c7689206c Advance if no blocks are available in the given range 2020-04-03 14:56:22 -07:00
756bc3b5bb vote-authorize-voter no longer fails if the current authorized voter is not the fee payer (#9288)
automerge
2020-04-03 13:57:15 -07:00
571b2eb807 Update set-solana-release-tag.sh 2020-04-03 11:21:54 -06:00
9819fe6684 Fix sed command for mac and linux (#9287) 2020-04-03 10:44:03 -06:00
ec7e44659d Minor doc fixup (#9285)
automerge
2020-04-03 09:32:57 -07:00
40d0f8da2d Bump version to 1.1.2 2020-04-02 22:35:56 -07:00
47ddb84078 cli: Add --follow option to catchup command to allow for easy ongoing monitoring between two nodes (bp #9260) (#9278)
automerge
2020-04-02 20:43:19 -07:00
4649378f95 ReplayStage fixes (#9271)
Co-authored-by: Carl <carl@solana.com>
2020-04-02 18:12:59 -07:00
3f6027055c Tame overeager wallet manager (#9262) (#9272)
automerge
2020-04-02 16:54:14 -07:00
d61a46476a Backport wallet doc changes to v1.1 (#9266)
* Add ledger live screenshots and reduce duplicate instructions (#9258)

automerge

* Add instructions for Trust Wallet Beta for Android (#9261)

automerge
2020-04-02 15:36:50 -06:00
c112f51f97 Add instructions for Trust Wallet Beta for Android (#9261) (#9265)
automerge
2020-04-02 12:25:46 -07:00
c1351d6b12 Set checks timeout to 20 minutes 2020-04-02 13:11:22 -06:00
c1acfe4843 Add epoch subcommand (#9249) (#9255)
automerge
2020-04-01 21:41:22 -07:00
68a4288078 Place AccountsHashes in same enum ordinal position as the v1.0 version (#9251) (#9253)
automerge

(cherry picked from commit 8b14eb9020)

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-04-01 19:29:55 -07:00
c4c96e1460 Undo breaking rpc removal of getSignatureConfirmation (#9245) (#9250)
automerge
2020-04-01 17:57:41 -07:00
32ab57fa83 Do not trigger tests if only docs were modified (#9240) (#9242)
automerge
2020-04-01 14:30:36 -07:00
a33e8cc164 Do not trigger tests if only docs were modified (#9240) (#9243) 2020-04-01 14:46:38 -06:00
c8b4f616b0 Undo getSignatureStatus breaking change, add getSignatureStatuses (#9232)
automerge
2020-04-01 11:53:55 -07:00
380c3b0080 Add fee-payer option to docs (#9230) (#9237)
automerge
2020-04-01 11:29:39 -07:00
2d6847c27b Add a support page for wallet docs (#9229) (#9235)
automerge
2020-04-01 11:26:36 -07:00
d5b9899ac9 Clean up solana-stake-accounts (#9211) (#9213)
automerge
2020-04-01 10:37:27 -07:00
9817cd769a Fix solana-stake-accounts rebase/move (#9199) (#9210)
automerge
2020-04-01 09:11:54 -07:00
ec3d2fdbdc Fix repair dos (#9056) (#9221)
automerge
2020-04-01 07:47:15 -07:00
1f794fb1da Tune udp buffers and vmmap immediately (#9194) (#9217)
automerge
2020-04-01 01:19:19 -07:00
89e1d7300d Fix error with account hash list getting too big for gossip (#9197) (#9215)
automerge
2020-03-31 23:44:58 -07:00
d239550e68 Fix panic (#9195) (#9209)
automerge
2020-03-31 21:35:12 -07:00
3dc336e1f1 Remove unecessary exception and add a new one (#9200) (#9206)
(cherry picked from commit 62e12e3af5)

Co-authored-by: sakridge <sakridge@gmail.com>
2020-03-31 19:38:37 -07:00
220a369efa Enforce an executable's rent exemption in the runtime (#9134) (#9191)
(cherry picked from commit 130c0b484d)

Co-authored-by: Jack May <jack@solana.com>
2020-03-31 11:57:19 -07:00
b079564a13 Add more Ledger wallet documentation (#9182) (#9190)
automerge
2020-03-31 10:08:02 -07:00
e8935aa99e Fix links (#9184) (#9188)
automerge
2020-03-31 09:57:43 -07:00
016a342de0 solana-validator now supports multiple --authorized-voter arguments (#9174) (#9181)
automerge
2020-03-31 09:21:47 -07:00
47c6dfe1aa Bump version to v1.1.1 2020-03-30 23:15:07 -07:00
c66d528e85 Check ClusterSlots for confirmation of block propagation (#9115) (#9178)
(cherry picked from commit 66946a4680)

Co-authored-by: carllin <wumu727@gmail.com>
2020-03-30 23:09:00 -07:00
8ba8deb933 Ledger cleanup fixes (#9131) (#9176)
automerge
2020-03-30 20:41:48 -07:00
587342d5e3 Install solana-stake-accounts (#9169) (#9173)
automerge
2020-03-30 19:53:39 -07:00
f31d2d9cc4 Use cluster confirmations in rpc and pubsub (#9138) (#9170)
automerge
2020-03-30 18:11:45 -07:00
bc761c2c02 Add solana-stake-accounts CLI tool (bp #9164) (#9168)
automerge
2020-03-30 17:25:07 -07:00
6f4bc3aaff Store BlockCommitmentCache slot and root metadata (#9154) (#9162)
automerge
2020-03-30 11:40:11 -07:00
070664ff94 Make repair metrics less chatty (#9094) (#9156)
automerge
2020-03-29 16:18:48 -07:00
61c2883de6 Calculate ref counts earlier to prevent bad clean (#9147) (#9155)
automerge
2020-03-29 15:53:56 -07:00
e32f7dbe49 catchup now retries when the desired node is not yet online (#9148) (#9152)
automerge
2020-03-29 10:39:56 -07:00
c0b178db45 Sanitize zero lamport accounts in append vecs (#9083) (#9149)
automerge
2020-03-29 00:39:28 -07:00
1027b0681b Fix race in RPC subscriptions test (#9142) (#9145)
automerge
2020-03-28 12:00:20 -07:00
3ae6e0b8ab Add solana-stake-monitor program (#9081) 2020-03-27 22:55:55 -07:00
4b7da6e60d Bump rBPF version to v0.1.25: Fix Windows build (#9136)
automerge
2020-03-27 19:07:58 -07:00
2863f8ec65 Use 1gb as genesis limit to fix bench-tps ledger from not starting (#9133)
automerge
2020-03-27 16:50:19 -07:00
e2491c6322 Prevent add/subtract from executable account (#9132) 2020-03-27 16:43:25 -07:00
4a8b1d9b2c RpcClient now returns Signatures instead of Strings (#9129) 2020-03-27 15:46:00 -07:00
74aed5cb58 Fix offline stake ops test script (#9130) 2020-03-27 12:20:32 -06:00
b130c298df Remove chatty 'setting snapshot root:' info log (#9122) 2020-03-27 10:24:59 -07:00
e5a6f8c2de fix links (#9125)
automerge
2020-03-27 10:21:34 -07:00
87e5f8acbf Add mdbook-linkcheck to docker (#9123)
automerge
2020-03-27 10:18:01 -07:00
c1a3b6ecc2 Add RPC subscription api for rooted slots (#9118)
automerge
2020-03-27 09:33:40 -07:00
c242d66130 Document transaction field in getConfirmedBlock responses (#9121)
automerge
2020-03-27 09:08:18 -07:00
864d212c64 solana account now displays the account's rent epoch (#9114) 2020-03-27 08:58:21 -07:00
a9564d207b Bump assert_cmd from 0.12.1 to 1.0.0 (#9104)
Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 0.12.1 to 1.0.0.
- [Release notes](https://github.com/assert-rs/assert_cmd/releases)
- [Changelog](https://github.com/assert-rs/assert_cmd/blob/master/CHANGELOG.md)
- [Commits](https://github.com/assert-rs/assert_cmd/compare/v0.12.1...v1.0.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-27 09:57:01 -06:00
b82a9c832b Fix links in docs (#9119) 2020-03-27 09:36:55 -06:00
5d9298543f Exclude all executable accounts from rent collection (#9116)
* Whitelist executable accounts for rent exemption

* nudge
2020-03-27 23:28:18 +08:00
4e9ae61044 Add "transaction confirmations" term to docs (#9087)
* Add transaction confirmations term to docs

* feedback
2020-03-27 21:08:36 +08:00
d47262d233 Reduce transmit frequency (#9113)
Co-authored-by: Carl <carl@solana.com>
2020-03-26 23:33:28 -07:00
8fdcf9f968 Make colo.sh support Bash 5 (#9112) 2020-03-27 15:01:42 +09:00
c82d37f6c3 Fix broken gitbook links (#9107) 2020-03-26 21:10:09 -06:00
5a8658283a Add check for propagation of leader block before generating further blocks (#8758)
Co-authored-by: Carl <carl@solana.com>
2020-03-26 19:57:27 -07:00
4b97e58cba Consolidate signature-status rpcs (#9069)
* getSignatureStatus: return confirmations for non-rooted transactions

* Remove getNumConfirmations.. rpc

* Remove getSignatureConfirmation

* Review comments

* More review comments
2020-03-26 19:21:01 -06:00
48031651a0 Add docs for app wallets (#9098) 2020-03-26 19:09:39 -06:00
f3d556e3f9 Refactor VoteTracker (#9084)
* Refactor VoteTracker

Co-authored-by: Carl <carl@solana.com>
2020-03-26 17:55:17 -07:00
8d4cecdb77 Account data may not change once the executable bit is set (#9099)
automerge
2020-03-26 17:10:11 -07:00
39a622f66e Revert setting the default toolchain (#9093)
automerge
2020-03-26 14:21:22 -07:00
dae28b9cfe Bump rBPF to v0.1.24, update rBPF/BPF Loader error handling (#9089) 2020-03-26 14:00:26 -07:00
b7b4aa5d4d move rpc types from client to client-types crate (#9039)
* Separate client types into own crate, so ledger does not need it

Removes about 50 crates of dependency from ledger

* Drop Rpc name from transaction-status types
2020-03-26 13:29:30 -07:00
ed036b978d Accumulate blockstore metrics and submit every 2s (#9075) 2020-03-26 12:51:41 -07:00
284920433f Restructure wallet docs to prep for app wallet content (#9088)
automerge
2020-03-26 12:42:05 -07:00
30bed18b77 Install xargo using CI dictated cargo version if available (#9068) 2020-03-26 11:47:41 -07:00
6678dd10a5 Remove command-line install instructions of Solana's Ledger wallet app (#9085) 2020-03-26 10:37:48 -06:00
296d740f83 Remove contractions in intro doc (#9086) 2020-03-26 09:54:47 -06:00
b8fda9d730 Log how much data the ledger holds before processing it (#9079) 2020-03-25 21:41:50 -07:00
2623c71ed3 Use type aliases/resulting var names consistently (#9060) 2020-03-26 13:08:56 +09:00
e4472db33f Unflake rpc subscriptions test by reducing sub count (#9078)
automerge
2020-03-25 20:43:38 -07:00
076fef5e57 Update Cluster Slots to support multiple threads (#9071)
Co-authored-by: Carl <carl@solana.com>
2020-03-25 18:09:19 -07:00
40eba48109 Bump assert_cmd from 0.12.0 to 0.12.1 (#9074)
Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 0.12.0 to 0.12.1.
- [Release notes](https://github.com/assert-rs/assert_cmd/releases)
- [Changelog](https://github.com/assert-rs/assert_cmd/blob/master/CHANGELOG.md)
- [Commits](https://github.com/assert-rs/assert_cmd/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-25 17:38:13 -07:00
095c79e863 Bump regex from 1.3.5 to 1.3.6 (#9055)
Bumps [regex](https://github.com/rust-lang/regex) from 1.3.5 to 1.3.6.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.3.5...1.3.6)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-25 17:24:14 -07:00
959c1ea857 Cargo update bumpalo (#9067)
* Cargo update bumpalo

* Remove ignore warning
2020-03-25 18:11:08 -06:00
ef3af104ae Return appropriate error for invalid program account (#9047)
automerge
2020-03-25 13:23:05 -07:00
9dc69d9843 Store and compute node/stake state in EpochStakes struct (#8958)
* Store and compute needed bank state in EpochStakes struct
2020-03-25 12:19:15 -07:00
45348b2c83 Remove accounts unwrap (#9062)
automerge
2020-03-25 10:21:30 -07:00
c558db2a48 Fix xargo to version 0.3.19 to avoid unstable feature (#9065)
automerge
2020-03-25 08:43:36 -07:00
f987c18a7e Strictly validate the contents of snapshot/genesis (#8959)
automerge
2020-03-25 02:46:41 -07:00
5d3f43c10b Ignore RUSTSEC-2020-0006 for the moment (#9057)
automerge
2020-03-24 20:10:20 -07:00
216b01b224 Improve coverage.sh usability when used locally (#9054)
automerge
2020-03-24 13:47:16 -07:00
35dd52e9ba Remove SLP from grafana 2020-03-24 12:23:30 -07:00
b0c83921be Move streamer test to integration test (#9050)
Failing in the coverage build.
2020-03-24 11:39:36 -07:00
e744b15ad2 Bump thiserror from 1.0.12 to 1.0.13 (#9017)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.12 to 1.0.13.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.12...1.0.13)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-24 10:51:24 -07:00
1fd695d337 Use all cores (#8908) 2020-03-24 10:33:53 -07:00
8f38bc7dc0 Refactor how pubsub subscriptions are added (#9042) 2020-03-25 00:53:32 +08:00
7d6ea6c17e ledger-tool can now decode stake instructions (#9045)
automerge
2020-03-24 05:23:29 -07:00
56dc958116 Add get_confirmed_block_with_encoding() (#9046)
automerge
2020-03-24 05:05:38 -07:00
19dfb87b1f Fix timeout for subscriptions test (#9043)
automerge
2020-03-24 01:57:28 -07:00
a5287f56fc Remove , 2020-03-23 22:12:16 -07:00
eed8087d87 Respect confirmations param for signature subscription notifications (#9019)
automerge
2020-03-23 17:00:34 -07:00
4115d73b9a Remove Ledger-specific analysis of hardware wallets (#9028)
automerge
2020-03-23 14:05:38 -07:00
064b95c16a Fix link in gitbook (#9027)
automerge
2020-03-23 14:05:27 -07:00
70c167182a ledger tool now outputs transaction status information if available (#9024)
automerge
2020-03-23 12:49:21 -07:00
fee002382e Program address generator (#8995) 2020-03-23 12:38:56 -07:00
d75a470ffa Ledger processing speed tracking (#9005) 2020-03-23 12:19:11 -07:00
c530fbd22b Remove thread-priority crate which is not cross-platform (#9023) 2020-03-23 12:18:52 -07:00
1b8f9e75dd Update getSignatureStatus: support multiple signatures, include slot in each response item (#9022)
* Rename enable-rpc-get-confirmed-block

* Rename RpcTransactionStatus -> RpcTransactionStatusMeta

* Return simplified RpcTransactionStatus; Add support for multiple transactions

* Update docs

* typo
2020-03-23 11:25:39 -06:00
1a5b01676d Remove equal sign separators from CLI options (#9021)
automerge
2020-03-23 09:27:43 -07:00
4b397d15b3 Accounts cleanup service and perf improvements (#8799)
* Use atomic for ref count instead of taking rwlock

* Accounts cleanup service

* Review comments
2020-03-23 08:50:23 -07:00
4d2b83d01f Add option to disable rocks compaction (#9011) 2020-03-23 08:42:32 -07:00
87096f13d2 Update outdated solana-genesis cli help text (#9020)
automerge
2020-03-23 08:16:31 -07:00
a0ffcc61ae Add slot info to Bank::get_signature_confirmation_status (#9018) 2020-03-23 21:55:15 +08:00
4b4819cd07 Add slot context to rpc pubsub notifications (#9001)
automerge
2020-03-23 05:34:42 -07:00
ca791a0378 Ensure --identity is provided when --vote-account is provided (#9014)
automerge
2020-03-22 22:21:00 -07:00
b08f8d3103 Add stake-account to docs (#9010) 2020-03-22 12:20:24 -06:00
88ba8439fc Add frozen account support (#8989)
automerge
2020-03-22 11:10:04 -07:00
4dd0367136 Rwlock storage opt (#9006)
* Remove unecessary account paths rwlock

* Remove path rwlock in accounts_db and optimize storage critical section
2020-03-22 10:04:03 -07:00
ff2c183ac1 Add set-dead-slot command (#9008) 2020-03-21 21:43:33 -07:00
aa24181a53 Remove blockstream unix socket support. RPC or bust (#9004)
automerge
2020-03-21 20:17:11 -07:00
1f83c56e05 Add staking docs (#8988)
automerge
2020-03-21 19:50:09 -07:00
2592894958 CLI: Support setting both stake authorities at once (#8976)
automerge
2020-03-21 18:56:17 -07:00
85027caf42 Bump thiserror from 1.0.11 to 1.0.12 (#9000)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.11...1.0.12)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-21 14:52:25 -06:00
3ea556bc24 Drop storage lock (#8997) 2020-03-21 13:37:52 -07:00
ca4a22d4ba Distinguish account addresses from public keys (#8998) 2020-03-21 13:30:01 -06:00
18c1f0dfe9 Remove stub core/src/genesis_utils.rs (#8999) 2020-03-21 10:54:40 -07:00
734afee5e0 Bump cbindgen from 0.13.1 to 0.13.2 (#8996)
Bumps [cbindgen](https://github.com/eqrion/cbindgen) from 0.13.1 to 0.13.2.
- [Release notes](https://github.com/eqrion/cbindgen/releases)
- [Changelog](https://github.com/eqrion/cbindgen/blob/master/CHANGES)
- [Commits](https://github.com/eqrion/cbindgen/compare/v0.13.1...v0.13.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-20 21:51:28 -06:00
271e17547a Nit thiserror for pubkey (#8994)
automerge
2020-03-20 18:07:37 -07:00
e28368ff1b Move address creation with seed into pubkey (#8991) 2020-03-20 15:20:48 -07:00
1aab959d4e Revert "Move Install Solana doc into the Command-line Guide (#8982)" (#8992)
This reverts commit 5fa36bbab3.
2020-03-20 15:52:20 -06:00
bca769111f Dos all the things (#8914)
* Dos all the things

* Use solana-dos for gossip dos test
2020-03-20 12:55:38 -07:00
909321928c Shred fetch comment and debug message tweak (#8980)
automerge
2020-03-20 11:00:48 -07:00
8b0a7f6838 Update value names in docs (#8983)
automerge
2020-03-20 09:22:02 -07:00
5fa36bbab3 Move Install Solana doc into the Command-line Guide (#8982)
automerge
2020-03-20 09:19:18 -07:00
d65a7a3c30 Fix versioning script on MacOS (#8981)
automerge
2020-03-20 09:16:48 -07:00
453f5ce8f2 Shred filter (#8975)
Thread bank_forks into shred fetch
2020-03-20 07:49:48 -07:00
dc1db33ec9 Add Capabilities to Signal BroadcastStage to Retransmit (#8899) 2020-03-19 23:35:01 -07:00
c68e80c93b Improve CLI usage messages (#8972)
* Improve CLI usage messages

* stragglers

* Apply review feedback

Co-authored-by: Trent Nelson <trent@solana.com>
2020-03-19 21:43:11 -06:00
6b9a0935c1 Some Cli polish (#8966)
automerge
2020-03-19 12:03:36 -07:00
b84468ecd3 Cli: polish transaction progress bar (#8963)
automerge
2020-03-19 11:10:35 -07:00
ff4ba54553 CLI: Fix create-nonce-account with seed (#8929)
* CLI: Fix `create-nonce-account --seed ...`

* CLI: Add test another for `create-nonce-account --seed...`

Explicitly demonstrates a partner workflow with the following
requirements:
1) Nonce account address derived from an offline nonce
authority address
2) Fully online account creation
3) Account creation in a single signing session

* alphabetize
2020-03-19 10:36:53 -06:00
f78a90bce2 Vote InitializeAccount and UpdateNode instructions now need a signature from the validator identity (#8947)
automerge
2020-03-19 01:58:52 -07:00
24d871b529 Bump serde from 1.0.104 to 1.0.105 (#8954)
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.104 to 1.0.105.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.104...v1.0.105)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-18 22:35:30 -07:00
e547f38589 Docs: Fix error during CLI usage build (#8956)
automerge
2020-03-18 22:24:42 -07:00
6fb16f9879 Bump flate2 from 1.0.13 to 1.0.14 (#8901)
Bumps [flate2](https://github.com/alexcrichton/flate2-rs) from 1.0.13 to 1.0.14.
- [Release notes](https://github.com/alexcrichton/flate2-rs/releases)
- [Commits](https://github.com/alexcrichton/flate2-rs/compare/1.0.13...1.0.14)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-18 21:37:41 -07:00
2dc50cff5b Bump bv from 0.11.0 to 0.11.1 (#8952)
automerge
2020-03-18 21:37:21 -07:00
98228c392e CLI: Add multi-session signing support (#8927)
* SDK: Add `NullSigner` implementation

* SDK: Split `Transaction::verify()` to gain access to results

* CLI: Minor refactor of --sign_only result parsing

* CLI: Enable paritial signing

Signers specified by pubkey, but without a matching --signer arg
supplied fall back to a `NullSigner` when --sign-only is in effect.
This allows their pubkey to be used for TX construction as usual,
but leaves their `sign_message()` a NOP. As such, with --sign-only
in effect, signing and verification must be done separately, with
the latter's per-signature results considered

* CLI: Surface/report missing/bad signers to user

* CLI: Suppress --sign-only JSON output

* nits

* Docs for multi-session offline signing
2020-03-18 20:49:38 -07:00
aeb7278b00 Delete broken link (#8950)
automerge
2020-03-18 17:49:21 -07:00
42d7609d54 Fix links for gitbook (#8948)
automerge
2020-03-18 16:45:15 -07:00
a70008cc5c Increase vmap count in sys-tuner (#8940) 2020-03-18 16:24:39 -07:00
306a5c849e Use into_iter() 2020-03-18 16:11:57 -07:00
bb92184085 Refactor distribute_rent_to_validators() for clarity 2020-03-18 16:11:57 -07:00
90c9462dd4 Automated test framework can run scripts on launched clusters. Add offline stake operations test case and script. (#8510)
automerge
2020-03-18 14:57:19 -07:00
21b287ef0b Add docs on wallets and generating keys (#8905)
* Add docs on wallets and generating keys

* Directory wallet -> FS wallet

* New section

* Add instructions for receiving tokens

* Add missing file

* Reorg

* Polish

* Polish

* Prefer solana-keygen

* Polish

* on -> in

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* wallets -> wallet

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* compare -> contrast

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* de-hyphenate

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* Update docs/src/cli/choose-a-wallet.md

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* typo

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* Update docs/src/cli/generate-keys.md

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* proof -> prove

Co-Authored-By: Tyera Eulberg <teulberg@gmail.com>

* Apply review feedback

* Apply more review feedback

* More review feedback

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2020-03-18 15:21:48 -06:00
b0c524765e Update gce-5-node-3-partition.yml 2020-03-18 14:07:09 -07:00
6d0318cbe6 Remove product string from device keypair URL (#8942)
* Remove product string from device url

* Update docs
2020-03-18 13:36:48 -06:00
8f5ee6832f Bump libc from 0.2.67 to 0.2.68 (#8915)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.67 to 0.2.68.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.67...0.2.68)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-18 13:27:08 -06:00
38fe766fa7 Bump crossbeam-channel from 0.3.9 to 0.4.2 (#8930)
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.3.9 to 0.4.2.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/v0.4.2/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.3.9...v0.4.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-18 13:26:42 -06:00
74866882f2 Document account/signer requirements for vote instructions 2020-03-18 11:11:48 -07:00
c638e83bf5 Add --no-untrusted-rpc to docs (#8935)
automerge
2020-03-18 09:40:51 -07:00
de6ef68571 Add BPF virtual address translate helpers (#8919) 2020-03-18 08:39:55 -07:00
c51049a59b Add counter for accounts hash verification. (#8928) 2020-03-18 08:39:09 -07:00
9cedeb0a8d Pull streamer out into its own module. (#8917)
automerge
2020-03-17 23:30:23 -07:00
e37a4823f1 Remove appveyor config, Travis CI for windows now seems to work 2020-03-17 23:14:24 -07:00
bf60345b7a Remove all snapshots not matching the desired hash 2020-03-17 22:58:01 -07:00
cb29b8dd2a Travis CI builds windows-gnu instead of windows-msvc 2020-03-17 22:37:57 -07:00
3a501ad69e Remove all snapshot not matching the desired hash 2020-03-17 22:18:25 -07:00
e6e43d236f Remove unused default update manifest pubkeys 2020-03-17 21:46:39 -07:00
142601d4b6 solana-install-init: --pubkey is no longer required on platforms without a default update manifest 2020-03-17 21:46:39 -07:00
f192e4f08f Nit: Align Rust and C names (#8918) 2020-03-17 19:37:16 -07:00
f020370ae7 Add docs for --trusted-validator options (#8911)
and --halt-on-trusted-validator-hash-mismatch
2020-03-17 18:57:33 -07:00
24935af867 Extend local-cluster CI timeout (#8921)
automerge
2020-03-17 18:23:22 -07:00
6a213bc8f5 Build less for windows 2020-03-17 17:03:56 -07:00
f0414711b7 Cli: add spinner progress bar when waiting for transaction confirmation (#8916)
* Add _with_spinner method

* Use _with_spinner method in cli
2020-03-17 17:58:02 -06:00
d087ed5bf6 Remove copypasta (#8912) 2020-03-17 15:59:09 -07:00
d14dea4660 Restore solana-install for non-windows 2020-03-17 13:47:53 -07:00
29abfebb68 Limit windows to end-user command-line tools 2020-03-17 13:11:00 -07:00
668dfc40c7 Align C and Rust handling of AccountInfos (#8906) 2020-03-17 12:34:14 -07:00
61514e3b0e Allow program accounts to be passed as program and parameter (#8907) 2020-03-17 12:06:15 -07:00
46fcab14dd Try enabling windows build again, maybe it's more stable now 2020-03-17 11:14:08 -07:00
2435c3ce0c Add accounts-bench, a benchmark to test the accounts store speed (#8866) 2020-03-17 11:02:07 -07:00
55907b2167 code layout changes only for ci tests 2020-03-17 10:18:04 -07:00
a03eff51af code layout changes only 2020-03-17 10:18:04 -07:00
10175618d2 solana-keygen grind: do not ignore case (as default) 2020-03-17 10:18:04 -07:00
4ff033852d Increase buffer on low SOL fault to over a week (#8903)
automerge
2020-03-17 09:18:13 -07:00
2237f47b90 Sort device paths for select (#8896) 2020-03-16 18:23:21 -06:00
bfca226964 Hoist USB URL docs (#8894) 2020-03-16 17:07:39 -06:00
6077458ad8 Cli: enable flexible flexible signer paths for pubkey args (#8892)
automerge
2020-03-16 15:17:13 -07:00
7079559c2d Fix windows build by removing sys-info (#8860)
Doesn't build for windows.
2020-03-16 12:53:13 -07:00
0641244378 Add genesis token counter test to system test (#8824)
automerge
2020-03-16 12:09:18 -07:00
563da2bb18 Cleanup CLI types (#8888) 2020-03-16 12:27:09 -06:00
dc347dd3d7 Add Accounts hash consistency halting (#8772)
* Accounts hash consistency halting

* Add option to inject account hash faults for testing.

Enable option in local cluster test to see that node halts.
2020-03-16 08:37:31 -07:00
eab4fe50a3 Use types for CLI value names (#8878)
* Use types for CLI value names

* keygen too

* More cleanup

* nonce keypair -> pubkey
2020-03-16 09:24:59 -06:00
ead6dc553a If let 2020-03-16 07:57:07 -07:00
009c124fac Remove generic 2020-03-16 07:57:07 -07:00
7029c88305 use matches macro 2020-03-16 07:57:07 -07:00
9411fc00b8 Lower error level 2020-03-16 07:57:07 -07:00
5a93a4c466 Fix faucet command in run.sh (#8883)
automerge
2020-03-16 04:44:54 -07:00
9afc5da2e1 Fix vote polling (#8829)
Co-authored-by: Carl <carl@solana.com>
2020-03-15 20:31:05 -07:00
49706172f3 Quietly re-introduce legacy --voting-keypair/--identity-keypair args for v1.0.6 compatibility 2020-03-15 20:00:58 -07:00
b2a0cdaa38 Rename leader to validator, drop _keypair/-keypair suffix (#8876)
automerge
2020-03-15 13:19:55 -07:00
5481d1a039 Validators now run a full gossip node while looking for a snapshot 2020-03-15 09:31:55 -07:00
dd5e320aa1 TdS registration
Updated some outdated information re TdS registration.
2020-03-15 18:45:29 +11:00
3c2aff2b5b Cli: Add resolve-signer subcommand (#8859)
* Expose remote-wallet device pretty path

* Add resolve-signer helpers

* Add cli resolve-signer subcommand

* Print pretty-path in waiting msg
2020-03-14 20:48:41 -07:00
c3c4c9326b Refactor system tests dir structure (#8865)
automerge
2020-03-14 18:37:37 -07:00
ae70f4ea92 Apply s/faucet-keypair/faucet renaming to net scripts (#8867) 2020-03-14 16:49:28 -07:00
29fb79382c Rework validator vote account defaults to half voting fees 2020-03-13 20:13:33 -07:00
5c2cf04e10 Enable any signer in various cli subcommands (#8844)
automerge
2020-03-13 16:06:33 -07:00
9e0a26628b Drop :8899 port from http://devnet.solana.com references 2020-03-13 16:00:54 -07:00
ce88602ced Surface the missing pubkey 2020-03-13 15:57:41 -07:00
53b8d0d528 Remove holding Poh lock (#8838)
automerge
2020-03-13 15:15:13 -07:00
96a61cc4e4 Cli: add subcommand to withdraw from vote account (#8550)
* feat: cli command for vote account withdraw

* Rework names

* Update to flexible signer, and make consistent with other cli apis

* Add integration test

* Clean up default help msg

Co-authored-by: Michael Vines <mvines@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2020-03-13 14:30:04 -06:00
b7b36bb0a4 Upgrade to Rust 1.42 (#8836)
* Upgrade to Rust 1.42

* deref

* parens

Co-authored-by: Trent Nelson <trent@solana.com>
2020-03-13 14:15:22 -06:00
52b254071c Bump regex from 1.3.4 to 1.3.5 (#8830)
Bumps [regex](https://github.com/rust-lang/regex) from 1.3.4 to 1.3.5.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.3.4...1.3.5)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-13 07:43:07 -06:00
fbf2dd1672 CLI: Error message cleanup (#8804)
automerge
2020-03-12 23:20:49 -07:00
4bbf09f582 Enable conservative out-of-bound snapshot cleaning (#8811)
* Enable conservative out-of-bound snapshot cleaning

* Add tests
2020-03-13 14:44:00 +09:00
952cd38b7b Avoid early clean and bad snapshot by ref-counting (#8724)
* Avoid early clean and bad snapshot by ref-counting

* Add measure

* Clean ups

* clean ups
2020-03-13 14:14:37 +09:00
9a79be5ca0 Use cluster information about slots to prioritize repair (#8820)
automerge
2020-03-12 17:34:46 -07:00
2182521a8b Move history out of intro (#8825)
automerge
2020-03-12 16:36:05 -07:00
fe65c2ae02 Add all of docs/src 2020-03-12 14:45:54 -07:00
554d36c74b Update source markdown in CI 2020-03-12 14:34:28 -07:00
29ef0916db Update keys (#8821)
automerge
2020-03-12 13:22:12 -07:00
f93c8290f4 Bump sys-info from 0.5.9 to 0.5.10 (#8810)
Bumps [sys-info](https://github.com/FillZpp/sys-info-rs) from 0.5.9 to 0.5.10.
- [Release notes](https://github.com/FillZpp/sys-info-rs/releases)
- [Changelog](https://github.com/FillZpp/sys-info-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/FillZpp/sys-info-rs/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-12 13:42:31 -06:00
a69293df24 Bump base64 from 0.11.0 to 0.12.0 (#8809)
Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.11.0 to 0.12.0.
- [Release notes](https://github.com/marshallpierce/rust-base64/releases)
- [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md)
- [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.11.0...v0.12.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-12 11:32:56 -06:00
48ac038f7a Bump serial_test from 0.3.2 to 0.4.0 (#8808)
Bumps [serial_test](https://github.com/palfrey/serial_test) from 0.3.2 to 0.4.0.
- [Release notes](https://github.com/palfrey/serial_test/releases)
- [Commits](https://github.com/palfrey/serial_test/compare/v0.3.2...v0.4.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-12 11:14:37 -06:00
5a7d2560c9 Don't tell users to install unreleased software versions 2020-03-12 10:01:25 -07:00
d91027f771 Fix malformed doc link (#8817)
automerge
2020-03-12 09:25:15 -07:00
deaf3cb416 Instruction member function (#8801) 2020-03-12 09:08:39 -07:00
f95e1ea40f Update keys (#8814)
automerge
2020-03-12 08:30:24 -07:00
f64ab49307 Cluster has no way to know which slots are available (#8732)
automerge
2020-03-11 21:31:50 -07:00
fe1c99c0cf Update keys (#8800)
automerge
2020-03-11 17:18:14 -07:00
bdb7b73b8a Add longer running performance tests and new partition testcase (#8773)
* Add 1 hour perf stability tests to colo and GCE

* Add GCE full loss partition testcase to automation
2020-03-11 16:42:52 -07:00
293fff90d3 Restrict which nodes can run stable and coverage
Band-aid fix until https://github.com/solana-labs/solana/issues/8798 is resolved
2020-03-11 14:46:17 -07:00
6eb4973780 Don't use move semantics if not needed (#8793) 2020-03-11 14:37:23 -07:00
5f5824d78d Rework cluster metrics dashboard to support the modern clusters 2020-03-11 14:14:56 -07:00
0ef9d79056 Collapse verbose buildkite logging (#8794)
automerge
2020-03-11 11:54:49 -07:00
215650f6e7 Bump console from 0.9.2 to 0.10.0 (#8786)
Bumps [console](https://github.com/mitsuhiko/console) from 0.9.2 to 0.10.0.
- [Release notes](https://github.com/mitsuhiko/console/releases)
- [Commits](https://github.com/mitsuhiko/console/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-11 12:30:15 -06:00
a0d0d4c0e9 Update keys (#8791) 2020-03-11 12:29:50 -06:00
0422af2aae CLI: Plumb nonce-stored fees (#8750)
automerge
2020-03-11 11:14:15 -07:00
cef8e42938 Notify when validator balance goes below 1 SOL 2020-03-11 10:30:51 -07:00
0eeeec38fa Bump winreg from 0.6.2 to 0.7.0 (#8788)
automerge
2020-03-11 08:59:26 -07:00
75a84ecdae Bump reqwest from 0.10.1 to 0.10.4 (#8787)
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.10.1 to 0.10.4.
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.10.1...v0.10.4)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-11 09:02:40 -06:00
87c507fdbe Refactor system test automation (#8780) 2020-03-10 23:38:50 -07:00
3783ae823d Update keys (#8783)
automerge
2020-03-10 19:08:02 -07:00
f3ed00e28e Add checkmark (#8781)
automerge
2020-03-10 17:28:50 -07:00
307d023b2e Bump hidapi from 1.2.0 to 1.2.1 (#8770)
Bumps [hidapi](https://github.com/ruabmbua/hidapi-rs) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/ruabmbua/hidapi-rs/releases)
- [Commits](https://github.com/ruabmbua/hidapi-rs/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-10 18:07:14 -06:00
775ce3a03f Permit fee-payer/split-stake accounts to be the same when using --seed 2020-03-10 16:12:02 -07:00
f655372b08 Revert to a computed websocket_url value when json_rpc_url is changed 2020-03-10 15:55:13 -07:00
2c4079f4c8 Print approved msg after Ledger interaction (#8771)
automerge
2020-03-10 14:08:51 -07:00
ac1f90f1a9 clippy 2020-03-10 12:31:00 -07:00
4bb55b1622 Add --monitor-active-stake flag 2020-03-10 12:31:00 -07:00
23c5bb17c7 Refactor 2020-03-10 12:31:00 -07:00
a0ed3261c9 Automated tests should use dedicated colo nodes (#8766)
automerge
2020-03-10 12:25:16 -07:00
261732f140 CLI Nonce account access dereplicode (#8743)
* Spruce up CliNonceError

* Add nonce account access helpers

* Use helpers throughout
2020-03-10 13:00:15 -06:00
595c96b262 Plumb pre-emptibility and associated overrides into colo allocation and automated testing (#8754)
automerge
2020-03-10 11:25:44 -07:00
496999beba Configure the cluster right after installing it (#8761) 2020-03-10 10:23:58 -06:00
bb50881346 Fix Gitbook's markdown rendering (#8759)
automerge
2020-03-10 08:05:30 -07:00
948902eae0 Better titles (#8752)
automerge
2020-03-10 07:43:38 -07:00
e41ff2df66 Bump chrono from 0.4.10 to 0.4.11 (#8755)
Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.10 to 0.4.11.
- [Release notes](https://github.com/chronotope/chrono/releases)
- [Changelog](https://github.com/chronotope/chrono/blob/master/CHANGELOG.md)
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.10...v0.4.11)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-10 08:43:18 -06:00
f88b79d42b Bump itertools from 0.8.2 to 0.9.0 (#8756)
Bumps [itertools](https://github.com/bluss/rust-itertools) from 0.8.2 to 0.9.0.
- [Release notes](https://github.com/bluss/rust-itertools/releases)
- [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bluss/rust-itertools/commits)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-10 08:42:11 -06:00
1a0dd53450 Bump rayon from 1.2.0 to 1.3.0 (#8757)
Bumps [rayon](https://github.com/rayon-rs/rayon) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/rayon-rs/rayon/releases)
- [Changelog](https://github.com/rayon-rs/rayon/blob/master/RELEASES.md)
- [Commits](https://github.com/rayon-rs/rayon/compare/v1.2.0...rayon-core-v1.3.0)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-10 08:40:02 -06:00
9872430bd2 Add VoteTracker for tracking cluster's votes in gossip (#8327)
Track votes by slot in cluster_vote_listener
2020-03-09 22:03:09 -07:00
ae8badb141 Support monitoring multiple validators 2020-03-09 20:40:23 -07:00
36fa3a1a0a Wait for 80% of the active stake instead of 75% 2020-03-09 20:31:09 -07:00
df8a69d15f Less links to docs (#8748)
automerge
2020-03-09 19:55:17 -07:00
fad08a19cc Bump serde_json from 1.0.46 to 1.0.48 (#8260)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.46 to 1.0.48.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.46...v1.0.48)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-09 20:20:19 -06:00
6527d05d77 Docs: Fix missing CLI usage.md (#8745)
automerge
2020-03-09 19:11:58 -07:00
d303e6b94e Override GCE self-destruct timer in automation (#8728) 2020-03-09 18:02:07 -07:00
5fa397ceed Remove --derivation-path option (#8741)
automerge
2020-03-09 17:49:01 -07:00
c0fd017906 Move intro out of README (#8735)
automerge
2020-03-09 16:39:57 -07:00
74e7da214a watchtower now uses cli-config/ 2020-03-09 15:43:14 -07:00
756ba07b16 Move cli-config default out of cli/ into cli-config/ 2020-03-09 15:43:14 -07:00
5c236fd06c Rename 'url' to 'json_rpc_url' 2020-03-09 15:43:14 -07:00
f671be814e Move bench-tps instructions (#8734)
automerge
2020-03-09 15:26:03 -07:00
e277437bd2 Limit waiting-message to single- or last-chunk apdus (#8730) 2020-03-09 15:22:50 -06:00
beead7e54d Bump hidapi from 1.1.1 to 1.2.0 (#8588)
automerge
2020-03-09 11:53:47 -07:00
ea010be5cb Wait for stake distribution before starting clients (#8692) 2020-03-09 10:57:51 -07:00
97b6c41d42 Fix typos in error messages (#8726)
automerge
2020-03-09 10:12:42 -07:00
6d0f3762b2 Bump hex from 0.4.1 to 0.4.2 (#8725)
Bumps [hex](https://github.com/KokaKiwi/rust-hex) from 0.4.1 to 0.4.2.
- [Release notes](https://github.com/KokaKiwi/rust-hex/releases)
- [Commits](https://github.com/KokaKiwi/rust-hex/compare/v0.4.1...v0.4.2)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-09 09:23:54 -06:00
132a2a73af Add total-supply command (#8722)
automerge
2020-03-09 01:28:44 -07:00
eab80d0aea Cli: Fix create-with-seed (#8706)
* Add failing test

* Fix create-address-with-seed regression

* Add apis to enable generating a pubkey from all various signers

* Enable other signers as --from in create-with-seed
2020-03-09 00:02:24 -06:00
88b1383eed Permit --no-untrusted-rpc without any --trusted-validators 2020-03-08 22:34:04 -07:00
ff74452ef3 Bump libc from 0.2.66 to 0.2.67 (#8680)
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.66 to 0.2.67.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.66...0.2.67)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-08 21:38:58 -07:00
bf8e9b3d71 Better error message for cli (#8702) 2020-03-08 19:19:34 -07:00
de34187db0 Add purge function to ledger-tool (#8719) 2020-03-08 12:40:56 -07:00
acb23e8ef0 Groom ledger-tool bounds output (#8710) 2020-03-07 09:05:15 -07:00
f992ee3140 Remove unnecessary snapshot hash verification (#8711) 2020-03-07 09:04:52 -07:00
97986a5241 Move download code to download-utils crate (#8704) 2020-03-07 07:08:01 -08:00
a7d1346d51 Remove ask-seed-phrase arg from validator, archiver (#8697)
* Remove ask-seed-phrase from validator

* Update paper-wallet docs

* Remove ask-seed-phrase from archiver

* Remove unused structs, methods
2020-03-06 22:22:23 -07:00
983ec5debc Docs version bump (#8709)
automerge
2020-03-06 21:06:41 -08:00
cb28ac3aed Fix Ledger docs (#8705)
automerge
2020-03-06 20:05:34 -08:00
a817a7c889 Call usage when getting incorrect arguments (#8703)
automerge
2020-03-06 19:08:20 -08:00
a5f2444ad2 Remove copypasta (#8700)
automerge
2020-03-06 18:18:01 -08:00
cea8067219 Disable setLogFilter RPC API by default (#8693)
automerge
2020-03-06 16:03:10 -08:00
4db074a5aa RPC: Add getFeeCalculatorForBlockhash method call (#8687)
Returns the `FeeCalculator` associated with the given blockhash, or
`null` if said blockhash has expired
2020-03-06 17:01:31 -07:00
3eb00ef60f Add ability to start clients separately from validators (#8690)
automerge
2020-03-06 15:32:27 -08:00
ca8bf8f964 Ledger: return specific error if ledger-app-solana is not running (#8684)
* Specific error if ledger-app-solana is not running

* Return helpful error

* Include signer name in multiple-device prompt
2020-03-06 16:03:23 -07:00
39b3ce9bd3 Add shred version support to net/ (#8689)
* Add shred version support to net/

* Update remote-node.sh
2020-03-06 15:49:04 -07:00
4caa313aef Remove releases from readme (#8685)
automerge
2020-03-06 14:03:10 -08:00
a78a339407 Properly escape current version (#8686) 2020-03-06 14:36:01 -07:00
0919b13c87 Split staker infos (#8682) 2020-03-06 13:49:23 -07:00
f2b0e2f418 Add slot rate check to automation framework (#8676) 2020-03-05 23:58:31 -08:00
cb6848aa80 Publish initial snapshot hash in gossip on validator startup (#8679)
automerge
2020-03-05 22:52:31 -08:00
542691c4e4 Docs: Use correct flag in keypair verification instructions (#8677)
automerge
2020-03-05 16:32:17 -08:00
8ad6a8767f Simplify runtime account handling (#8674) 2020-03-05 16:17:31 -08:00
2242b1b4a5 Bump byteorder from 1.3.2 to 1.3.4 (#8159)
Bumps [byteorder](https://github.com/BurntSushi/byteorder) from 1.3.2 to 1.3.4.
- [Release notes](https://github.com/BurntSushi/byteorder/releases)
- [Changelog](https://github.com/BurntSushi/byteorder/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/byteorder/compare/1.3.2...1.3.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-05 17:07:18 -07:00
8df4d8b905 Update to rbpf v0.1.23 - Use trait objects to convey helper context (#8648) 2020-03-05 14:14:21 -08:00
7fad53b112 Use iterated account (#8673)
automerge
2020-03-05 13:10:20 -08:00
9d667db634 SDK: Allow RecentBlockhashes to hold the entire BlockhashQueue (#8632)
automerge
2020-03-05 11:03:21 -08:00
f47a789b15 Add find_incomplete_slots (#8654)
* Add find_incomplete_slots

* Add live slots iterator
2020-03-05 10:58:00 -08:00
5e3ce30d02 Pass the correct program_id to programs (#8630) 2020-03-05 10:57:35 -08:00
97c5fb8141 Allow passing of program_ids to programs (#8639) 2020-03-05 10:57:12 -08:00
0e3a8fa6d9 Add retransmit_stage diagram (#8645) 2020-03-05 10:12:02 -08:00
5eae76c66e Remove solana-archiver from release artifacts 2020-03-05 11:01:53 -07:00
849f79e4ed Delete Archiver installation docs (#8665) 2020-03-05 11:00:00 -07:00
ff7cf839d8 Choose a cluster before checking balances (#8666)
automerge
2020-03-05 09:37:16 -08:00
f3cbd243cc Fix docs build (#8663)
automerge
2020-03-05 09:33:46 -08:00
f146c92e88 Always and fully normalize stored 0-lamport accts. (#8657) 2020-03-05 09:14:40 -07:00
fb2620b3a5 Set ignore_conflicts, the new mergify behaviour is worse 2020-03-05 08:44:20 -07:00
fd00e5cb35 Store FeeCalculator with blockhash in nonce accounts (#8650)
* Copy current state version to v0

* Add `FeeCalculator` to nonce state

* fixup compile

* Dump v0 handling...

Since we new account data is all zeros, new `Current` versioned accounts
look like v0. We could hack around this with some data size checks, but
the `account_utils::*State` traits are applied to `Account`, not the
state data, so we're kind SOL...

* Create more representative test `RecentBlockhashes`

* Improve CLI nonce account display

Co-Authored-By: Michael Vines <mvines@gmail.com>

* Fix that last bank test...

* clippy/fmt

Co-authored-by: Michael Vines <mvines@gmail.com>
2020-03-05 07:40:26 -07:00
44fde2d964 genesis: Add support for multiple bootstrap validators (#8656)
automerge
2020-03-04 23:42:01 -08:00
448b957a13 Add --bind-address and --rpc-bind-address validator arguments (#8628) 2020-03-04 22:46:43 -07:00
01607b9860 Add NextSlotsIterator (#8652)
automerge
2020-03-04 20:46:58 -08:00
23d8c7ff0e Generate a snapshot at synchronized points (#8532)
Co-authored-by: anatoly yakovenko <anatoly@solana.com>
2020-03-04 19:23:40 -08:00
b321da00b4 Nit: Use accessor function (#8647)
automerge
2020-03-04 18:26:58 -08:00
dec3da8f9d Add orphan iterator (#8636) 2020-03-04 18:10:30 -08:00
80aae18794 Nit: Update native loader to iterate accounts (#8640)
automerge
2020-03-04 17:10:22 -08:00
1f2aaf3f98 Generate CLI usage (#8637)
* Generate CLI usage

* Apply review feedback
2020-03-04 17:44:30 -07:00
2534a028c0 Move docs to imperative mood (#8643)
* Move docs to imperative tone

* Apply review feedback
2020-03-04 17:42:22 -07:00
fc409d9262 Consistency nits and spelling (#8642)
automerge
2020-03-04 16:26:32 -08:00
b70d195473 Connect partition flag to validators (#8622) 2020-03-04 16:18:45 -08:00
7eedff2714 Install Solana before using it (#8638)
automerge
2020-03-04 15:21:42 -08:00
6d9185d121 Update TVU drawing (#8611) 2020-03-04 15:16:35 -08:00
f89c22b5ee solana catchup now detects when you try to catchup to yourself (#8635)
automerge
2020-03-04 14:44:21 -08:00
f23dc11a86 compute_bank_stats needs to return newly computed ForkStats (#8608)
* Fix broken confirmation, add test
2020-03-04 11:49:56 -08:00
09a0325534 catchup now supports an optional RPC URL argument for validators with private RPC (#8629)
automerge
2020-03-04 11:44:13 -08:00
408d5da50f Add test for program_ids passed in metas (#8618) 2020-03-04 11:13:33 -08:00
561808cf90 SDK: Store FeeCalculator in recent_blockhashes sysvar (#8609)
* SDK: Store FeeCalculators in recent_blockhashes sysvar

* nits
2020-03-04 12:01:32 -07:00
25df95be6f Expose executable and rent_epoch in AccountInfo (#8619) 2020-03-04 10:52:09 -08:00
b85d7c1f70 Fix account tests (#8615) 2020-03-04 10:40:41 -08:00
642720a2fe nit: describe the root program id (#8621) 2020-03-04 08:55:01 -08:00
1cc7131bb7 Consolidate Nonce state under one struct (#8624)
automerge
2020-03-04 08:51:48 -08:00
8f60f1093a Fix sendTransaction doc (#8625)
automerge
2020-03-04 08:23:29 -08:00
d3b458dd9b Keep GenesisConfig binary compatible with v0.23 (#8617)
automerge
2020-03-04 00:04:44 -08:00
a08e2cc434 nit: clean up MessageHeader output 2020-03-04 00:16:19 -07:00
b83a0434a4 Prepare for multiple nonce account state versions (#8612)
automerge
2020-03-03 21:19:09 -08:00
b68b74ac32 Check transaction signatures in entry verify (#8596) 2020-03-03 20:49:51 -08:00
b084c1d437 Remove accounts hack and correctly restore accounts store counts (#8569)
* Remove accounts hack and correctly restore append-vec counts

* Add test
2020-03-03 20:48:55 -08:00
63ed892502 Remove flaky merkle timing test (#8602) 2020-03-03 19:26:38 -08:00
1cb6101c6a SDK: Add versioning to nonce state (#8607) 2020-03-03 19:39:09 -07:00
be0cc0273f SDK: Re-org nonce state module to facilitate versioning (#8603)
automerge
2020-03-03 17:00:39 -08:00
abf33b3b3b Add commitment flag to vote-account and validators commands (#8597) 2020-03-03 17:53:30 -07:00
d9b0490f72 Update rust-bpf to include matching cargo (#8598) 2020-03-03 14:14:31 -08:00
caa70d2bca Remove v0.23 as a backport target 2020-03-03 15:10:06 -07:00
4f05f08f5d Use fs::rename which is much faster than move_items (#8579) 2020-03-03 10:03:17 -08:00
0c76b89e55 Fix c/p error. We want a rent sysvar account here (#8559) 2020-03-03 09:49:02 -07:00
08ab4b93ea Add Ledger wallet installation instructions (#8581)
automerge
2020-03-03 08:12:29 -08:00
f0028b6972 Remove trailing white space 2020-03-03 18:27:07 +09:00
HM
b6553357f9 watchtower: flag to suppress duplicate notifications (#8549)
* watchtower: send error message as notification

* watchtower: send all clear notification when ok again

* watchtower: add twilio sms notifications

* watchtower: flag to suppress duplicate notifications

* remove trailing space character

* changes as per suggestion on PR

* all changes together

* cargo fmt
2020-03-02 23:37:57 -07:00
d86103383a Do periodic inbound cleaning for rooted slots (#8436)
* Do periodic inbound compaction for rooted slots

* Add comment

* nits

* Consider not_compacted_roots in cleanup_dead_slot

* Renames in AccountsIndex

* Rename to reflect expansion of removed accounts

* Fix a comment

* rename

* Parallelize clean over AccountsIndex

* Some niceties

* Reduce locks and real chunked parallelism

* Measure each step for sampling opportunities

* Just noticed par iter is maybe lazy

* Replace storage scan with optimized index scan

* Various clean-ups

* Clear uncleared_roots even if no updates
2020-03-03 14:57:25 +09:00
1265afebbb SDK: Return a full RecentBlockhashes for tests (#8580)
automerge
2020-03-02 18:44:29 -08:00
306783c661 Don't advertise the snapshot that the node was loaded from
snapshot_packager_service will remove this snapshot hash from gossip
when it starts
2020-03-02 18:58:53 -07:00
8ec8204a30 Run pubsub test poller in tokio runtime (#8494) 2020-03-03 09:44:39 +08:00
8cf3ef895d Prevent trailing space in CLI usage docs generation (#8578)
automerge
2020-03-02 16:37:38 -08:00
e4498adb1f Make block-time more human-readable (#8575) 2020-03-02 14:58:15 -08:00
42c5c59800 Only gossip packaged snapshots 2020-03-02 14:17:17 -07:00
8ef8c9094a Add ReplayStage changes for checking switch threshold (#8504)
* Refactor for supporting switch threshold check
2020-03-02 12:43:43 -08:00
8dc4724340 Allow stake lockup fields to be updated independently (#8568)
* Make Lockup fields optional for SetLockup instruction

* Use LockupArgs in cli

* Include lockup timestamp in stake-account print
2020-03-02 12:28:43 -08:00
13551885c2 --wait-for-supermajority now requires a SLOT 2020-03-02 12:59:35 -07:00
d677e83ed4 Add ---no-untrusted-rpc flag 2020-03-02 11:49:38 -07:00
5d9130a3c4 Hack to skip cleanup_dead_slots upon snapshot load 2020-03-02 10:24:12 -07:00
1ca4913328 Avoid is_x86_feature_detected when not building for x86 2020-03-01 18:10:43 -07:00
b7614abb9e Docs: Update CLI offline cmds (#8548)
* Docs: Update CLI usage

* Docs: Add script to generate offline command links

* Docs: Update list of commands supporting offline signing

* Docs: Omit deprecated `pay` command from offline command list
2020-03-01 17:20:37 -07:00
862a4a243f Demote gossip responder error log messages to info! 2020-03-01 10:43:20 -07:00
db291234ed feat: implement websocket_url as a get/set-able global parameter w/ value computation 2020-03-01 01:07:45 -07:00
2a5605db24 Reduce max snapshot hashes to stay under MTU 2020-02-29 09:21:52 -07:00
b4362cc18b Log RPC node root slot 2020-02-29 09:21:52 -07:00
6a5a6387e2 Fix skipping own leader slots (#8533)
automerge
2020-02-29 00:05:35 -08:00
0f31adeafb GET for /snapshot.tar.bz2 now redirects to the latest snapshot 2020-02-28 23:23:59 -07:00
ae817722d8 Include validator version in log 2020-02-28 23:23:59 -07:00
90bedd7e06 Split signature throughput tracking out of FeeCalculator (#8447)
* SDK: Split new `FeeRateGovernor` out of `FeeCalculator`

Leaving `FeeCalculator` to *only* calculate transaction fees

* Replace `FeeCalculator` with `FeeRateGovernor` as appropriate

* Expose recent `FeeRateGovernor` to clients

* Move `burn()` back into `FeeCalculator`

Appease BPF tests

* Revert "Move `burn()` back into `FeeCalculator`"

This reverts commit f3035624307196722b62ff8b74c12cfcc13b1941.

* Adjust BPF `Fee` sysvar test to reflect removal of `burn()` from `FeeCalculator`

* Make `FeeRateGovernor`'s `lamports_per_signature` private

* rebase artifacts

* fmt

* Drop 'Recent'

* Drop _with_commitment variant

* Use a more portable integer for `target_signatures_per_slot`

* Add docs for `getReeRateCalculator` JSON RPC method

* Don't return `lamports_per_signature` in `getFeeRateGovernor` JSONRPC reply
2020-02-28 13:27:01 -07:00
7d27be2a73 Upgrade to Rust 1.41.1 2020-02-28 10:10:42 -07:00
74da2de3b7 Ensure the validator's identity pubkey is not provided as a --trusted-validator (#8525)
automerge
2020-02-27 20:26:53 -08:00
35db70a56c Use legit solana message in verify (#8513) 2020-02-27 19:23:28 -07:00
7dac8e2dde Reorder InstructionError to remain compatible with v0.23 2020-02-27 18:05:12 -07:00
82c6992d6f Import Tour de SOL docs (#8516)
* Import Tour de SOL docs

* Fix checks

* Fix docs/build.sh
2020-02-28 09:03:14 +08:00
4831c7b9af Remove granularity from genesis (#8514) 2020-02-27 17:45:10 -07:00
113db8d656 Improve net/README.md a bit (#8503) 2020-02-28 08:00:54 +09:00
de6679ea95 Improve install messaging (#8477) 2020-02-27 14:07:36 -08:00
0b66ae5c53 Ledger messaging cleanup (#8506) 2020-02-27 12:23:13 -07:00
61a20febb9 Set withdrawer keys (#8499) 2020-02-27 07:32:35 -07:00
29f81577e9 Fix cluster economics figures and spelling in docs (#8502) 2020-02-27 18:15:17 +08:00
3acf956f6f Fix test_concurrent_snapshot_packaging 2020-02-26 23:32:53 -07:00
87b13bef8e Remove bank_slot_from_archive 2020-02-26 23:32:53 -07:00
0d4cb252c4 Adapt local-cluster/ 2020-02-26 23:32:53 -07:00
fcabc6f799 Rename snapshot.tar.bz2 to snapshot-<slot>-<hash>.tar.bz2 2020-02-26 23:32:53 -07:00
848c43a9ab Peg snapshot version to 1.0.0 2020-02-26 22:44:39 -07:00
5f766cd20b Remove loop (#8493) 2020-02-26 19:59:28 -08:00
8c07ba635e Cargo.lock 2020-02-26 20:47:43 -07:00
bb07aecfec Cargo.lock 2020-02-26 20:47:43 -07:00
27c5ec0149 Use the same reqwest features across the repo 2020-02-26 20:47:43 -07:00
4f01db0482 fix reqwest json issue 2020-02-26 20:47:43 -07:00
f2f8a7a90e Reference the v1.0.0 installer 2020-02-26 19:20:42 -07:00
e743414908 Choose more appropriate options for pubsub websocket server (#8354)
* Choose more sensible options for pubsub websocket server

* Increase max payload size for pubsub service
2020-02-27 08:54:53 +08:00
f6f0f94e17 Add flag to confirm key on device (#8478) 2020-02-26 15:24:44 -07:00
d47a47924a Update voting simulation (#8460) 2020-02-26 14:09:07 -08:00
7a2bf7e7eb Limit leader schedule search space (#8468)
* Limit leader schedule search space

* Fix and add test

* Rename
2020-02-26 13:35:50 -08:00
d5a7867087 Validate the genesis config downloaded over RPC before accepting it 2020-02-26 14:21:37 -07:00
fbf78b83c4 Add retry mechanism when downloading genesis and snapshots 2020-02-26 14:21:37 -07:00
2c63cf3cbd Add curie pubkey to authorized keys (#8473)
automerge
2020-02-26 10:27:37 -08:00
3b648e71e6 Ledger hardware wallet docs (#8472)
* Update protocol documentation

* Correct app-version command const

* Rough initial Ledger docs

* Add more docs

* Cleanup

* Add remote-wallet to docs TOC

Co-authored-by: Greg Fitzgerald <greg@solana.com>
2020-02-26 11:04:28 -07:00
021d0a46f8 Move docs from book/ to docs/ (#8469)
automerge
2020-02-26 07:11:38 -08:00
8839dbfe5b Use runtime executor to send pubsub notifications (#8353)
automerge
2020-02-25 20:23:54 -08:00
407d058611 live-slots now displays the rate the root slot is advancing 2020-02-25 20:59:05 -07:00
c6a7f499ce Allow withdrawer to change the authorized stake key (#8456) 2020-02-25 19:03:26 -07:00
d821fd29d6 Add versioning (#8348)
automerge
2020-02-25 17:12:01 -08:00
6b99ab3a57 Ledger key path rework (#8453)
automerge
2020-02-25 16:41:21 -08:00
004f1d5aed Combine replay stage memory reporting (#8455)
automerge
2020-02-25 16:04:27 -08:00
1caeea8bc2 Refactor new bank paths into common function (#8454) 2020-02-25 15:49:59 -08:00
6ce4a1a18d Update README.md 2020-02-25 14:41:14 -08:00
0b48c8eb35 Promote dangerous cond. from just warning to panic (#8439) 2020-02-26 05:09:57 +09:00
fef913085e 🐌🐌 Publish crates for even longer longer 2020-02-25 09:23:04 -07:00
2059af822d Remove unnecessary new_banks_from_blockstore() argument (#8433)
automerge
2020-02-24 23:27:19 -08:00
0fe74e95fe Add --no-check-vote-account argument (#8430)
automerge
2020-02-24 22:54:51 -08:00
b7755123c1 Make solana root key accessible on Ledger (#8421)
* Use 44/501 key as ledger id

* Add error codes
2020-02-24 22:38:06 -07:00
39282be486 Determine vote_state ahead of time (#8303)
automerge
2020-02-24 19:27:04 -08:00
b18e4057bb Fix SDK deps 2020-02-24 17:25:48 -07:00
12a9b5f35e CLI: collect and deduplicate signers (#8398)
* Rename (keypair util is not a thing)

* Add method to generate_unique_signers

* Cli: refactor signer handling and remote-wallet init

* Fixup unit tests

* Fixup intergation tests

* Update keypair path print statement

* Remove &None

* Use deterministic key in test

* Retain storage-account as index

* Make signer index-handling less brittle

* Cache pubkey on RemoteKeypair::new

* Make signer_of consistent + return pubkey

* Remove &matches double references

* Nonce authorities need special handling
2020-02-24 17:03:30 -07:00
89baa94002 Drop print- prefix from slot/accounts command 2020-02-24 14:46:12 -07:00
1ef3478709 Add genesis subcommand 2020-02-24 14:46:12 -07:00
73063544bd Move shred_version module to sdk/ 2020-02-24 14:46:12 -07:00
90240bf11d r 2020-02-24 14:45:32 -07:00
5c5a06198c Refactor 2020-02-24 14:45:32 -07:00
394933e53c Fix up trusted validator snapshot selection 2020-02-24 14:45:32 -07:00
b106d3ba60 Fix local cluster test, check for accounts hash (#8411) 2020-02-24 10:23:47 -08:00
947a339714 Add snapshot hash of full accounts state (#8295)
* Add snapshot hash of full accounts state

* Use normal hashing for the accounts delta state

* Add merkle
2020-02-22 13:46:40 -08:00
edb18349c9 Improve merkle-tree nodes capacity computing (#8273)
* Improve merkle-tree nodes capacity computing

* Add test cases for math compute of merkle-tree nodes capacity
2020-02-22 11:12:37 -07:00
9dcb965959 Reinstate create-stale-account w/ seed test (#8401)
automerge
2020-02-22 08:54:29 -08:00
72ae82fe47 Bump crossbeam-channel from 0.3.9 to 0.4.2 (#8400)
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.3.9 to 0.4.2.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/v0.4.2/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.3.9...v0.4.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-22 09:53:38 -07:00
2d9d2f1e99 Update cargo versions from 1.0 to 1.1 (#8397) 2020-02-21 23:09:45 -08:00
691 changed files with 63538 additions and 32906 deletions

View File

@ -1,42 +0,0 @@
version: '{build}'
branches:
only:
- master
- /^v[0-9.]+\.[0-9.]+/
cache:
- '%USERPROFILE%\.cargo'
- '%APPVEYOR_BUILD_FOLDER%\target'
clone_folder: d:\projects\solana
build_script:
- bash ci/publish-tarball.sh
notifications:
- provider: Slack
incoming_webhook:
secure: GJsBey+F5apAtUm86MHVJ68Uqa6WN1SImcuIc4TsTZrDhA8K1QWUNw9FFQPybUWDyOcS5dly3kubnUqlGt9ux6Ad2efsfRIQYWv0tOVXKeY=
channel: ci-status
on_build_success: false
on_build_failure: true
on_build_status_changed: true
deploy:
- provider: S3
access_key_id:
secure: fTbJl6JpFebR40J7cOWZ2mXBa3kIvEiXgzxAj6L3N7A=
secret_access_key:
secure: vItsBXb2rEFLvkWtVn/Rcxu5a5+2EwC+b7GsA0waJy9hXh6XuBAD0lnHd9re3g/4
bucket: release.solana.com
region: us-west-1
set_public: true
- provider: GitHub
auth_token:
secure: 81fEmPZ0cV1wLtNuUrcmtgxKF6ROQF1+/ft5m+fHX21z6PoeCbaNo8cTyLioWBj7
draft: false
prerelease: false
on:
appveyor_repo_tag: true

View File

@ -1,15 +1,12 @@
{
"_public_key": "ae29f4f7ad2fc92de70d470e411c8426d5d48db8817c9e3dae574b122192335f",
"environment": {
"CODECOV_TOKEN": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:JnxhrIxh09AvqdJgrVSYmb7PxSrh19aE:07WzVExCHEd1lJ1m8QizRRthGri+WBNeZRKjjEvsy5eo4gv3HD7zVEm42tVTGkqITKkBNQ==]",
"CRATES_IO_TOKEN": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:d0jJqC32/axwzq/N7kMRmpxKhnRrhtpt:zvcPHwkOzGnjhNkAQSejwdy1Jkr9wR1qXFFCnfIjyt/XQYubzB1tLkoly/qdmeb5]",
"GEOLOCATION_API_KEY": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:R4gfB6Ey4i50HyfLt4UZDLBqg3qHEUye:UfZCOgt8XI6Y2g+ivCRVoS1fjFycFs7/GSevvCqh1B50mG0+hzpEyzXQLuKG5OeI]",
"GITHUB_TOKEN": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:Vq2dkGTOzfEpRht0BAGHFp/hDogMvXJe:tFXHg1epVt2mq9hkuc5sRHe+KAnVREi/p8S+IZu67XRyzdiA/nGak1k860FXYuuzuaE0QWekaEc=]",
"INFLUX_DATABASE": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:5KI9WBkXx3R/W4m256mU5MJOE7N8aAT9:Cb8QFELZ9I60t5zhJ9h55Kcs]",
"INFLUX_PASSWORD": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:hQRMpLCrav+OYkNphkeM4hagdVoZv5Iw:AUO76rr6+gF1OLJA8ZLSG8wHKXgYCPNk6gRCV8rBhZBJ4KwDaxpvOhMl7bxxXG6jol7v4aRa/Lk=]",
"INFLUX_USERNAME": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:R7BNmQjfeqoGDAFTJu9bYTGHol2NgnYN:Q2tOT/EBcFvhFk+DKLKmVU7tLCpVC3Ui]",
"SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_unknown_linux_gnu": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:Egc2dMrHDU0NcZ71LwGv/V66shUhwYUE:04VoIb8CKy7KYhQ5W4cEW9SDKZltxWBL5Hob106lMBbUOD/yUvKYcG3Ep8JfTMwO3K8zowW5HpU/IdGoilX0XWLiJJ6t+p05WWK0TA16nOEtwrEG+UK8wm3sN+xCO20i4jDhpNpgg3FYFHT5rKTHW8+zaBTNUX/SFxkN67Lm+92IM28CXYE43SU1WV6H99hGFFVpTK5JVM3JuYU1ex/dHRE+xCzTr4MYUB/F+nGoNFW8HUDV/y0e1jxT9to3x0SmnytEEuk+5RUzFuEt9cKNFeNml3fOCi4qL+sfj/Y5pjH9xDiUxsvH/8NL35jbLP244aFHgWcp]",
"SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_apple_darwin": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:NeOxSoWCvXB9AL4H6OK26l/7bmsKd/oz:Ijfoxtvk2CHlN1ZXHup3Gg/914kbbAkEGWJfvozA8UIe+aUzUObMyTrKkVOeNAH8Q8YH9tNzk7RRnrTcpnzeCCBLlWcVEeruMxHox3mPRzmSeDLxtbzCl9VePlRO3T7jg90K5hW+ZAkd5J/WJNzpAcmr93ts/of3MbvGHSujId/efCTzJEcP6JInnBb8Vrj7TlgKbzUlnqpq1+NjYPSXN3maKa9pKeo2JWxZlGBMoy6QWUUY5GbYEylw9smwh1LJcHZjlaZNMuOl4gNKtaSr38IXQkAXaRUJDPAmPras00YObKzXU8RkTrP4EoP/jx5LPR7f]",
"SOLANA_INSTALL_UPDATE_MANIFEST_KEYPAIR_x86_64_pc_windows_msvc": "EJ[1:yGpTmjdbyjW2kjgIHkFoJv7Ue7EbUvUbqHyw6anGgWg=:7t+56twjW+jR7fpFNNeRFLPd7E4lbmyN:JuviDpkQrfVcNUGRGsa2e/UhvH6tTYyk1s4cHHE5xZH1NByL7Kpqx36VG/+o1AUGEeSQdsBnKgzYdMoFYbO8o50DoRPc86QIEVXCupD6J9avxLFtQgOWgJp+/mCdUVXlqXiFs/vQgS/L4psrcKdF6WHd77BeUr6ll8DjH+9m5FC9Rcai2pXno6VbPpunHQ0oUdYzhFR64+LiRacBaefQ9igZ+nSEWDLqbaZSyfm9viWkijoVFTq8gAgdXXEh7g0QdxVE5T6bPristJhT6jWBhWunPUCDNFFErWIsbRGctepl4pbCWqh2hNTw9btSgVfeY6uGCOsdy9E=]"
"CODECOV_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:3K68mE38LJ2RB98VWmjuNLFBNn1XTGR4:cR4r05/TOZQKmEZp1v4CSgUJtC6QJiOaL85QjXW0qZ061fMnsBA8AtAPMDoDq4WCGOZM1A==]",
"CRATES_IO_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:GGRTYDjMXksevzR6kq4Jx+FaIQZz50RU:xkbwDxcgoCyU+aT2tiI9mymigrEl6YiOr3axe3aX70ELIBKbCdPGilXP/wixvKi94g2u]",
"GEOLOCATION_API_KEY": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:U2PZLi5MU3Ru/zK1SilianEeizcMvxml:AJKf2OAtDHmJh0KyXrBnNnistItZvVVP3cZ7ZLtrVupjmWN/PzmKwSsXeCNObWS+]",
"GITHUB_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:0NJNlpD/O19mvOakCGBYDhIDfySxWFSC:Dz4NXv9x6ncRQ1u9sVoWOcqmkg0sI09qmefghB0GXZgPcFGgn6T0mw7ynNnbUvjyH8dLruKHauk=]",
"INFLUX_DATABASE": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:SzwHIeOVpmbTcGQOGngoFgYumsLZJUGq:t7Rpk49njsWvoM+ztv5Uwuiz]",
"INFLUX_PASSWORD": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:/MUs+q7pdGrUjzwcq+6pgIFxur4hxdqu:am22z2E2dtmw1f1J1Mq5JLcUHZsrEjQAJ0pp21M4AZeJbNO6bVb44d9zSkHj7xdN6U+GNlCk+wU=]",
"INFLUX_USERNAME": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:XjghH20xGVWro9B+epGlJaJcW8Wze0Bi:ZIdOtXudTY5TqKseDU7gVvQXfmXV99Xh]"
}
}

View File

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

7
.gitignore vendored
View File

@ -1,6 +1,7 @@
/book/html/
/book/src/tests.ok
/book/src/.gitbook/assets/*.svg
/docs/html/
/docs/src/tests.ok
/docs/src/cli/usage.md
/docs/src/.gitbook/assets/*.svg
/farf/
/solana-release/
/solana-release.tar.bz2

View File

@ -1,9 +1,40 @@
# Validate your changes with:
#
# $ curl -F 'data=@.mergify.yml' https://gh.mergify.io/validate
# $ curl -F 'data=@.mergify.yml' https://gh.mergify.io/validate/
#
# https://doc.mergify.io/
pull_request_rules:
- name: automatic merge (squash) on CI success
conditions:
- status-success=buildkite/solana
#- status-success=Travis CI - Pull Request
- status-success=ci-gate
- label=automerge
- author≠@dont-squash-my-commits
actions:
merge:
method: squash
# Join the dont-squash-my-commits group if you won't like your commits squashed
- name: automatic merge (rebase) on CI success
conditions:
- status-success=buildkite/solana
#- status-success=Travis CI - Pull Request
- status-success=ci-gate
- label=automerge
- author=@dont-squash-my-commits
actions:
merge:
method: rebase
- name: remove automerge label on CI failure
conditions:
- label=automerge
- "#status-failure!=0"
actions:
label:
remove:
- automerge
comment:
message: automerge label removed due to a CI failure
- name: remove outdated reviews
conditions:
- base=master
@ -19,20 +50,13 @@ pull_request_rules:
label:
add:
- automerge
- name: v0.23 backport
conditions:
- base=master
- label=v0.23
actions:
backport:
branches:
- v0.23
- name: v1.0 backport
conditions:
- base=master
- label=v1.0
actions:
backport:
ignore_conflicts: true
branches:
- v1.0
- name: v1.1 backport
@ -41,6 +65,7 @@ pull_request_rules:
- label=v1.1
actions:
backport:
ignore_conflicts: true
branches:
- v1.1
- name: v1.2 backport
@ -49,5 +74,6 @@ pull_request_rules:
- label=v1.2
actions:
backport:
ignore_conflicts: true
branches:
- v1.2

View File

@ -1,5 +1,6 @@
os:
- osx
- windows
language: rust
rust:
@ -17,6 +18,8 @@ branches:
- master
- /^v\d+\.\d+/
if: type IN (api, cron) OR tag IS present
notifications:
slack:
on_success: change

View File

@ -224,21 +224,20 @@ Inventing new terms is allowed, but should only be done when the term is widely
used and understood. Avoid introducing new 3-letter terms, which can be
confused with 3-letter acronyms.
[Terms currently in use](book/src/terminology.md)
[Terms currently in use](docs/src/terminology.md)
## Design Proposals
Solana's architecture is described by a book generated from markdown files in
the `book/src/` directory, maintained by an *editor* (currently @garious). To
add a design proposal, you'll need to at least propose a change the content
under the [Accepted Design
Proposals](https://docs.solana.com/book/v/master/proposals) chapter. Here's
the full process:
Solana's architecture is described by docs generated from markdown files in
the `docs/src/` directory, maintained by an *editor* (currently @garious). To
add a design proposal, you'll need to include it in the
[Accepted Design Proposals](https://docs.solana.com/proposals)
section of the Solana docs. Here's the full process:
1. Propose a design by creating a PR that adds a markdown document to the
directory `book/src/` and references it from the [table of
contents](book/src/SUMMARY.md). Add any relevant *maintainers* to the PR
`docs/src/proposals` directory and references it from the [table of
contents](docs/src/SUMMARY.md). Add any relevant *maintainers* to the PR
review.
2. The PR being merged indicates your proposed change was accepted and that the
maintainers support your plan of attack.

6845
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ members = [
"bench-exchange",
"bench-streamer",
"bench-tps",
"accounts-bench",
"banking-bench",
"chacha",
"chacha-cuda",
@ -10,6 +11,8 @@ members = [
"cli-config",
"client",
"core",
"dos",
"download-utils",
"faucet",
"perf",
"validator",
@ -24,6 +27,7 @@ members = [
"logger",
"log-analyzer",
"merkle-tree",
"streamer",
"measure",
"metrics",
"net-shaper",
@ -48,9 +52,13 @@ members = [
"sdk",
"sdk-c",
"scripts",
"stake-accounts",
"stake-monitor",
"sys-tuner",
"transaction-status",
"upload-perf",
"net-utils",
"version",
"vote-signer",
"cli",
"rayon-threadlimit",

View File

@ -9,60 +9,7 @@ Blockchain Rebuilt for Scale
Solana&trade; is a new blockchain architecture built from the ground up for scale. The architecture supports
up to 710 thousand transactions per second on a gigabit network.
Disclaimer
===
All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment.
Introduction
===
It's possible for a centralized database to process 710,000 transactions per second on a standard gigabit network if the transactions are, on average, no more than 176 bytes. A centralized database can also replicate itself and maintain high availability without significantly compromising that transaction rate using the distributed system technique known as Optimistic Concurrency Control [\[H.T.Kung, J.T.Robinson (1981)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.65.4735). At Solana, we're demonstrating that these same theoretical limits apply just as well to blockchain on an adversarial network. The key ingredient? Finding a way to share time when nodes can't trust one-another. Once nodes can trust time, suddenly ~40 years of distributed systems research becomes applicable to blockchain!
> Perhaps the most striking difference between algorithms obtained by our method and ones based upon timeout is that using timeout produces a traditional distributed algorithm in which the processes operate asynchronously, while our method produces a globally synchronous one in which every process does the same thing at (approximately) the same time. Our method seems to contradict the whole purpose of distributed processing, which is to permit different processes to operate independently and perform different functions. However, if a distributed system is really a single system, then the processes must be synchronized in some way. Conceptually, the easiest way to synchronize processes is to get them all to do the same thing at the same time. Therefore, our method is used to implement a kernel that performs the necessary synchronization--for example, making sure that two different processes do not try to modify a file at the same time. Processes might spend only a small fraction of their time executing the synchronizing kernel; the rest of the time, they can operate independently--e.g., accessing different files. This is an approach we have advocated even when fault-tolerance is not required. The method's basic simplicity makes it easier to understand the precise properties of a system, which is crucial if one is to know just how fault-tolerant the system is. [\[L.Lamport (1984)\]](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.71.1078)
Furthermore, and much to our surprise, it can be implemented using a mechanism that has existed in Bitcoin since day one. The Bitcoin feature is called nLocktime and it can be used to postdate transactions using block height instead of a timestamp. As a Bitcoin client, you'd use block height instead of a timestamp if you don't trust the network. Block height turns out to be an instance of what's being called a Verifiable Delay Function in cryptography circles. It's a cryptographically secure way to say time has passed. In Solana, we use a far more granular verifiable delay function, a SHA 256 hash chain, to checkpoint the ledger and coordinate consensus. With it, we implement Optimistic Concurrency Control and are now well en route towards that theoretical limit of 710,000 transactions per second.
Architecture
===
Before you jump into the code, review the online book [Solana: Blockchain Rebuilt for Scale](https://docs.solana.com/book/).
(The _latest_ development version of the online book is also [available here](https://docs.solana.com/book/v/master/).)
Release Binaries
===
Official release binaries are available at [Github Releases](https://github.com/solana-labs/solana/releases).
Additionally we provide pre-release binaries for the latest code on the edge and
beta channels. Note that these pre-release binaries may be less stable than an
official release.
### Edge channel
#### Linux (x86_64-unknown-linux-gnu)
* [solana.tar.bz2](http://release.solana.com/edge/solana-release-x86_64-unknown-linux-gnu.tar.bz2)
* [solana-install-init](http://release.solana.com/edge/solana-install-init-x86_64-unknown-linux-gnu) as a stand-alone executable
#### mac OS (x86_64-apple-darwin)
* [solana.tar.bz2](http://release.solana.com/edge/solana-release-x86_64-apple-darwin.tar.bz2)
* [solana-install-init](http://release.solana.com/edge/solana-install-init-x86_64-apple-darwin) as a stand-alone executable
#### Windows (x86_64-pc-windows-msvc)
* [solana.tar.bz2](http://release.solana.com/edge/solana-release-x86_64-pc-windows-msvc.tar.bz2)
* [solana-install-init.exe](http://release.solana.com/edge/solana-install-init-x86_64-pc-windows-msvc.exe) as a stand-alone executable
#### All platforms
* [solana-metrics.tar.bz2](http://release.solana.com.s3.amazonaws.com/edge/solana-metrics.tar.bz2)
### Beta channel
#### Linux (x86_64-unknown-linux-gnu)
* [solana.tar.bz2](http://release.solana.com/beta/solana-release-x86_64-unknown-linux-gnu.tar.bz2)
* [solana-install-init](http://release.solana.com/beta/solana-install-init-x86_64-unknown-linux-gnu) as a stand-alone executable
#### mac OS (x86_64-apple-darwin)
* [solana.tar.bz2](http://release.solana.com/beta/solana-release-x86_64-apple-darwin.tar.bz2)
* [solana-install-init](http://release.solana.com/beta/solana-install-init-x86_64-apple-darwin) as a stand-alone executable
#### Windows (x86_64-pc-windows-msvc)
* [solana.tar.bz2](http://release.solana.com/beta/solana-release-x86_64-pc-windows-msvc.tar.bz2)
* [solana-install-init.exe](http://release.solana.com/beta/solana-install-init-x86_64-pc-windows-msvc.exe) as a stand-alone executable
#### All platforms
* [solana-metrics.tar.bz2](http://release.solana.com.s3.amazonaws.com/beta/solana-metrics.tar.bz2)
Read all about it at [Solana: Blockchain Rebuilt for Scale](https://docs.solana.com/v/master).
Developing
===
@ -121,7 +68,7 @@ $ cargo test
Local Testnet
---
Start your own testnet locally, instructions are in the book [Solana: Blockchain Rebuild for Scale: Getting Started](https://docs.solana.com/book/building-from-source).
Start your own testnet locally, instructions are in the online docs [Solana: Blockchain Rebuild for Scale: Getting Started](https://docs.solana.com/building-from-source).
Remote Testnets
---
@ -238,3 +185,8 @@ problem is solved by this code?" On the other hand, if a test does fail and you
better way to solve the same problem, a Pull Request with your solution would most certainly be
welcome! Likewise, if rewriting a test can better communicate what code it's protecting, please
send us that patch!
Disclaimer
===
All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore nothing in this project constitutes a solicitation for investment.

View File

@ -138,7 +138,7 @@ There are three release channels that map to branches as follows:
### Update documentation
TODO: Documentation update procedure is WIP as we move to gitbook
Document the new recommended version by updating `book/src/running-archiver.md` and `book/src/validator-testnet.md` on the release (beta) branch to point at the `solana-install` for the upcoming release version.
Document the new recommended version by updating `docs/src/running-archiver.md` and `docs/src/validator-testnet.md` on the release (beta) branch to point at the `solana-install` for the upcoming release version.
### Update software on devnet.solana.com

22
accounts-bench/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-accounts-bench"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
log = "0.4.6"
rayon = "1.3.0"
solana-logger = { path = "../logger", version = "1.1.24" }
solana-runtime = { path = "../runtime", version = "1.1.24" }
solana-measure = { path = "../measure", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
rand = "0.7.0"
clap = "2.33.0"
crossbeam-channel = "0.4"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

105
accounts-bench/src/main.rs Normal file
View File

@ -0,0 +1,105 @@
use clap::{value_t, App, Arg};
use rayon::prelude::*;
use solana_measure::measure::Measure;
use solana_runtime::{
accounts::{create_test_accounts, update_accounts, Accounts},
accounts_index::Ancestors,
};
use solana_sdk::pubkey::Pubkey;
use std::fs;
use std::path::PathBuf;
fn main() {
solana_logger::setup();
let matches = App::new("crate")
.about("about")
.version("version")
.arg(
Arg::with_name("num_slots")
.long("num_slots")
.takes_value(true)
.value_name("SLOTS")
.help("Number of slots to store to."),
)
.arg(
Arg::with_name("num_accounts")
.long("num_accounts")
.takes_value(true)
.value_name("NUM_ACCOUNTS")
.help("Total number of accounts"),
)
.arg(
Arg::with_name("iterations")
.long("iterations")
.takes_value(true)
.value_name("ITERATIONS")
.help("Number of bench iterations"),
)
.arg(
Arg::with_name("clean")
.long("clean")
.takes_value(false)
.help("Run clean"),
)
.get_matches();
let num_slots = value_t!(matches, "num_slots", usize).unwrap_or(4);
let num_accounts = value_t!(matches, "num_accounts", usize).unwrap_or(10_000);
let iterations = value_t!(matches, "iterations", usize).unwrap_or(20);
let clean = matches.is_present("clean");
println!("clean: {:?}", clean);
let path = PathBuf::from("farf/accounts-bench");
if fs::remove_dir_all(path.clone()).is_err() {
println!("Warning: Couldn't remove {:?}", path);
}
let accounts = Accounts::new(vec![path]);
println!("Creating {} accounts", num_accounts);
let mut create_time = Measure::start("create accounts");
let pubkeys: Vec<_> = (0..num_slots)
.into_par_iter()
.map(|slot| {
let mut pubkeys: Vec<Pubkey> = vec![];
create_test_accounts(
&accounts,
&mut pubkeys,
num_accounts / num_slots,
slot as u64,
);
pubkeys
})
.collect();
let pubkeys: Vec<_> = pubkeys.into_iter().flatten().collect();
create_time.stop();
println!(
"created {} accounts in {} slots {}",
(num_accounts / num_slots) * num_slots,
num_slots,
create_time
);
let mut ancestors: Ancestors = vec![(0, 0)].into_iter().collect();
for i in 1..num_slots {
ancestors.insert(i as u64, i - 1);
accounts.add_root(i as u64);
}
for x in 0..iterations {
if clean {
let mut time = Measure::start("clean");
accounts.accounts_db.clean_accounts();
time.stop();
println!("{}", time);
for slot in 0..num_slots {
update_accounts(&accounts, &pubkeys, ((x + 1) * num_slots + slot) as u64);
accounts.add_root((x * num_slots + slot) as u64);
}
} else {
let mut pubkeys: Vec<Pubkey> = vec![];
let mut time = Measure::start("hash");
let hash = accounts.accounts_db.update_accounts_hash(0, &ancestors);
time.stop();
println!("hash: {} {}", hash, time);
create_test_accounts(&accounts, &mut pubkeys, 1, 0);
}
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-archiver-lib"
version = "1.0.0"
version = "1.1.24"
description = "Solana Archiver Library"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,30 +10,34 @@ edition = "2018"
[dependencies]
bincode = "1.2.1"
crossbeam-channel = "0.3"
ed25519-dalek = "=1.0.0-pre.1"
crossbeam-channel = "0.4"
ed25519-dalek = "=1.0.0-pre.3"
log = "0.4.8"
rand = "0.6.5"
rand_chacha = "0.1.1"
solana-client = { path = "../client", version = "1.0.0" }
solana-storage-program = { path = "../programs/storage", version = "1.0.0" }
rand = "0.7.0"
rand_chacha = "0.2.2"
solana-client = { path = "../client", version = "1.1.24" }
solana-storage-program = { path = "../programs/storage", version = "1.1.24" }
thiserror = "1.0"
serde = "1.0.104"
serde_json = "1.0.46"
serde = "1.0.105"
serde_json = "1.0.48"
serde_derive = "1.0.103"
solana-net-utils = { path = "../net-utils", version = "1.0.0" }
solana-chacha = { path = "../chacha", version = "1.0.0" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.0" }
solana-ledger = { path = "../ledger", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-perf = { path = "../perf", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
solana-core = { path = "../core", version = "1.0.0" }
solana-archiver-utils = { path = "../archiver-utils", version = "1.0.0" }
solana-metrics = { path = "../metrics", version = "1.0.0" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-chacha = { path = "../chacha", version = "1.1.24" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.24" }
solana-ledger = { path = "../ledger", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-perf = { path = "../perf", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
solana-core = { path = "../core", version = "1.1.24" }
solana-streamer = { path = "../streamer", version = "1.1.24" }
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.24" }
solana-metrics = { path = "../metrics", version = "1.1.24" }
[dev-dependencies]
hex = "0.4.0"
hex = "0.4.2"
[lib]
name = "solana_archiver_lib"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,7 +1,7 @@
use crate::result::ArchiverError;
use crossbeam_channel::unbounded;
use rand::{thread_rng, Rng, SeedableRng};
use rand_chacha::ChaChaRng;
use rand::{thread_rng, Rng};
use rand_chacha::{rand_core::SeedableRng, ChaChaRng};
use solana_archiver_utils::sample_file;
use solana_chacha::chacha::{chacha_cbc_encrypt_ledger, CHACHA_BLOCK_SIZE};
use solana_client::{
@ -10,16 +10,14 @@ use solana_client::{
};
use solana_core::{
cluster_info::{ClusterInfo, Node, VALIDATOR_PORT_RANGE},
cluster_slots::ClusterSlots,
contact_info::ContactInfo,
gossip_service::GossipService,
packet::{limited_deserialize, PACKET_DATA_SIZE},
repair_service,
repair_service::{RepairService, RepairSlotRange, RepairStrategy},
repair_service::{self, RepairService, RepairSlotRange, RepairStats, RepairStrategy},
serve_repair::ServeRepair,
shred_fetch_stage::ShredFetchStage,
sigverify_stage::{DisabledSigVerifier, SigVerifyStage},
storage_stage::NUM_STORAGE_SAMPLES,
streamer::{receiver, responder, PacketReceiver},
window_service::WindowService,
};
use solana_ledger::{
@ -27,6 +25,7 @@ use solana_ledger::{
};
use solana_net_utils::bind_in_range;
use solana_perf::packet::Packets;
use solana_perf::packet::{limited_deserialize, PACKET_DATA_SIZE};
use solana_perf::recycler::Recycler;
use solana_sdk::packet::Packet;
use solana_sdk::{
@ -45,14 +44,15 @@ use solana_storage_program::{
storage_contract::StorageContract,
storage_instruction::{self, StorageAccountType},
};
use solana_streamer::streamer::{receiver, responder, PacketReceiver};
use std::{
io::{self, ErrorKind},
net::{SocketAddr, UdpSocket},
net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
path::{Path, PathBuf},
result,
sync::atomic::{AtomicBool, Ordering},
sync::mpsc::{channel, Receiver, Sender},
sync::{Arc, RwLock},
sync::Arc,
thread::{sleep, spawn, JoinHandle},
time::Duration,
};
@ -184,10 +184,10 @@ impl Archiver {
info!("Archiver: id: {}", keypair.pubkey());
info!("Creating cluster info....");
let mut cluster_info = ClusterInfo::new(node.info.clone(), keypair.clone());
let cluster_info = ClusterInfo::new(node.info.clone(), keypair.clone());
cluster_info.set_entrypoint(cluster_entrypoint.clone());
let cluster_info = Arc::new(RwLock::new(cluster_info));
let cluster_info = Arc::new(cluster_info);
let cluster_slots = Arc::new(ClusterSlots::default());
// Note for now, this ledger will not contain any of the existing entries
// in the ledger located at ledger_path, and will only append on newly received
// entries after being passed to window_service
@ -199,7 +199,7 @@ impl Archiver {
info!("Connecting to the cluster via {:?}", cluster_entrypoint);
let (nodes, _) =
match solana_core::gossip_service::discover_cluster(&cluster_entrypoint.gossip, 1) {
match solana_core::gossip_service::discover_cluster(&cluster_entrypoint.gossip, 2) {
Ok(nodes_and_archivers) => nodes_and_archivers,
Err(e) => {
//shutdown services before exiting
@ -211,12 +211,9 @@ impl Archiver {
let client = solana_core::gossip_service::get_client(&nodes);
info!("Setting up mining account...");
if let Err(e) = Self::setup_mining_account(
&client,
&keypair,
&storage_keypair,
client_commitment.clone(),
) {
if let Err(e) =
Self::setup_mining_account(&client, &keypair, &storage_keypair, client_commitment)
{
//shutdown services before exiting
exit.store(true, Ordering::Relaxed);
gossip_service.join()?;
@ -238,6 +235,7 @@ impl Archiver {
shred_forward_sockets,
repair_socket.clone(),
&shred_fetch_sender,
None,
&exit,
);
let (slot_sender, slot_receiver) = channel();
@ -264,6 +262,7 @@ impl Archiver {
repair_socket,
shred_fetch_receiver,
slot_sender,
cluster_slots,
) {
Ok(window_service) => window_service,
Err(e) => {
@ -308,7 +307,7 @@ impl Archiver {
fn run(
meta: &mut ArchiverMeta,
blockstore: &Arc<Blockstore>,
cluster_info: Arc<RwLock<ClusterInfo>>,
cluster_info: Arc<ClusterInfo>,
archiver_keypair: &Arc<Keypair>,
storage_keypair: &Arc<Keypair>,
exit: &Arc<AtomicBool>,
@ -358,23 +357,23 @@ impl Archiver {
&cluster_info,
archiver_keypair,
storage_keypair,
meta.client_commitment.clone(),
meta.client_commitment,
);
}
exit.store(true, Ordering::Relaxed);
}
fn redeem_rewards(
cluster_info: &Arc<RwLock<ClusterInfo>>,
cluster_info: &ClusterInfo,
archiver_keypair: &Arc<Keypair>,
storage_keypair: &Arc<Keypair>,
client_commitment: CommitmentConfig,
) {
let nodes = cluster_info.read().unwrap().tvu_peers();
let nodes = cluster_info.tvu_peers();
let client = solana_core::gossip_service::get_client(&nodes);
if let Ok(Some(account)) =
client.get_account_with_commitment(&storage_keypair.pubkey(), client_commitment.clone())
client.get_account_with_commitment(&storage_keypair.pubkey(), client_commitment)
{
if let Ok(StorageContract::ArchiverStorage { validations, .. }) = account.state() {
if !validations.is_empty() {
@ -382,8 +381,7 @@ impl Archiver {
&archiver_keypair.pubkey(),
&storage_keypair.pubkey(),
);
let message =
Message::new_with_payer(vec![ix], Some(&archiver_keypair.pubkey()));
let message = Message::new_with_payer(&[ix], Some(&archiver_keypair.pubkey()));
if let Err(e) = client.send_message(&[archiver_keypair.as_ref()], message) {
error!("unable to redeem reward, tx failed: {:?}", e);
} else {
@ -403,9 +401,10 @@ impl Archiver {
}
// Find a segment to replicate and download it.
#[allow(clippy::too_many_arguments)]
fn setup(
meta: &mut ArchiverMeta,
cluster_info: Arc<RwLock<ClusterInfo>>,
cluster_info: Arc<ClusterInfo>,
blockstore: &Arc<Blockstore>,
exit: &Arc<AtomicBool>,
node_info: &ContactInfo,
@ -413,9 +412,10 @@ impl Archiver {
repair_socket: Arc<UdpSocket>,
shred_fetch_receiver: PacketReceiver,
slot_sender: Sender<u64>,
cluster_slots: Arc<ClusterSlots>,
) -> Result<WindowService> {
let slots_per_segment =
match Self::get_segment_config(&cluster_info, meta.client_commitment.clone()) {
match Self::get_segment_config(&cluster_info, meta.client_commitment) {
Ok(slots_per_segment) => slots_per_segment,
Err(e) => {
error!("unable to get segment size configuration, exiting...");
@ -470,6 +470,7 @@ impl Archiver {
RepairStrategy::RepairRange(repair_slot_range),
&Arc::new(LeaderScheduleCache::default()),
|_, _, _, _| true,
cluster_slots,
);
info!("waiting for ledger download");
Self::wait_for_segment_download(
@ -489,7 +490,7 @@ impl Archiver {
blockstore: &Arc<Blockstore>,
exit: &Arc<AtomicBool>,
node_info: &ContactInfo,
cluster_info: Arc<RwLock<ClusterInfo>>,
cluster_info: Arc<ClusterInfo>,
) {
info!(
"window created, waiting for ledger download starting at slot {:?}",
@ -517,11 +518,8 @@ impl Archiver {
contact_info.tvu = "0.0.0.0:0".parse().unwrap();
contact_info.wallclock = timestamp();
// copy over the adopted shred_version from the entrypoint
contact_info.shred_version = cluster_info.read().unwrap().my_data().shred_version;
{
let mut cluster_info_w = cluster_info.write().unwrap();
cluster_info_w.insert_self(contact_info);
}
contact_info.shred_version = cluster_info.my_shred_version();
cluster_info.update_contact_info(|current| *current = contact_info);
}
fn encrypt_ledger(meta: &mut ArchiverMeta, blockstore: &Arc<Blockstore>) -> Result<()> {
@ -581,7 +579,7 @@ impl Archiver {
&keypair.pubkey(),
&Duration::from_millis(100),
&Duration::from_secs(5),
client_commitment.clone(),
client_commitment,
)? == 0
{
return Err(ArchiverError::EmptyStorageAccountBalance);
@ -589,16 +587,15 @@ impl Archiver {
info!("checking storage account keypair...");
// check if the storage account exists
let balance = client
.poll_get_balance_with_commitment(&storage_keypair.pubkey(), client_commitment.clone());
let balance =
client.poll_get_balance_with_commitment(&storage_keypair.pubkey(), client_commitment);
if balance.is_err() || balance.unwrap() == 0 {
let blockhash =
match client.get_recent_blockhash_with_commitment(client_commitment.clone()) {
Ok((blockhash, _)) => blockhash,
Err(e) => {
return Err(ArchiverError::TransportError(e));
}
};
let blockhash = match client.get_recent_blockhash_with_commitment(client_commitment) {
Ok((blockhash, _)) => blockhash,
Err(e) => {
return Err(ArchiverError::TransportError(e));
}
};
let ix = storage_instruction::create_storage_account(
&keypair.pubkey(),
@ -617,6 +614,7 @@ impl Archiver {
ErrorKind::Other,
"setup_mining_account: signature not found",
),
TransportError::Custom(e) => io::Error::new(ErrorKind::Other, e),
})?;
}
Ok(())
@ -624,39 +622,34 @@ impl Archiver {
fn submit_mining_proof(
meta: &ArchiverMeta,
cluster_info: &Arc<RwLock<ClusterInfo>>,
cluster_info: &ClusterInfo,
archiver_keypair: &Arc<Keypair>,
storage_keypair: &Arc<Keypair>,
) {
// No point if we've got no storage account...
let nodes = cluster_info.read().unwrap().tvu_peers();
let nodes = cluster_info.tvu_peers();
let client = solana_core::gossip_service::get_client(&nodes);
let storage_balance = client.poll_get_balance_with_commitment(
&storage_keypair.pubkey(),
meta.client_commitment.clone(),
);
let storage_balance = client
.poll_get_balance_with_commitment(&storage_keypair.pubkey(), meta.client_commitment);
if storage_balance.is_err() || storage_balance.unwrap() == 0 {
error!("Unable to submit mining proof, no storage account");
return;
}
// ...or no lamports for fees
let balance = client.poll_get_balance_with_commitment(
&archiver_keypair.pubkey(),
meta.client_commitment.clone(),
);
let balance = client
.poll_get_balance_with_commitment(&archiver_keypair.pubkey(), meta.client_commitment);
if balance.is_err() || balance.unwrap() == 0 {
error!("Unable to submit mining proof, insufficient Archiver Account balance");
return;
}
let blockhash =
match client.get_recent_blockhash_with_commitment(meta.client_commitment.clone()) {
Ok((blockhash, _)) => blockhash,
Err(_) => {
error!("unable to get recent blockhash, can't submit proof");
return;
}
};
let blockhash = match client.get_recent_blockhash_with_commitment(meta.client_commitment) {
Ok((blockhash, _)) => blockhash,
Err(_) => {
error!("unable to get recent blockhash, can't submit proof");
return;
}
};
let instruction = storage_instruction::mining_proof(
&storage_keypair.pubkey(),
meta.sha_state,
@ -664,7 +657,7 @@ impl Archiver {
Signature::new(&meta.signature.as_ref()),
meta.blockhash,
);
let message = Message::new_with_payer(vec![instruction], Some(&archiver_keypair.pubkey()));
let message = Message::new_with_payer(&[instruction], Some(&archiver_keypair.pubkey()));
let mut transaction = Transaction::new(
&[archiver_keypair.as_ref(), storage_keypair.as_ref()],
message,
@ -692,13 +685,10 @@ impl Archiver {
}
fn get_segment_config(
cluster_info: &Arc<RwLock<ClusterInfo>>,
cluster_info: &ClusterInfo,
client_commitment: CommitmentConfig,
) -> Result<u64> {
let rpc_peers = {
let cluster_info = cluster_info.read().unwrap();
cluster_info.all_rpc_peers()
};
let rpc_peers = cluster_info.all_rpc_peers();
debug!("rpc peers: {:?}", rpc_peers);
if !rpc_peers.is_empty() {
let rpc_client = {
@ -706,16 +696,10 @@ impl Archiver {
RpcClient::new_socket(rpc_peers[node_index].rpc)
};
Ok(rpc_client
.send(
&RpcRequest::GetSlotsPerSegment,
.send::<u64>(
RpcRequest::GetSlotsPerSegment,
serde_json::json!([client_commitment]),
0,
)
.map_err(|err| {
warn!("Error while making rpc request {:?}", err);
ArchiverError::ClientError(err)
})?
.as_u64()
.unwrap())
} else {
Err(ArchiverError::NoRpcPeers)
@ -724,7 +708,7 @@ impl Archiver {
/// Waits until the first segment is ready, and returns the current segment
fn poll_for_segment(
cluster_info: &Arc<RwLock<ClusterInfo>>,
cluster_info: &ClusterInfo,
slots_per_segment: u64,
previous_blockhash: &Hash,
exit: &Arc<AtomicBool>,
@ -744,38 +728,24 @@ impl Archiver {
/// Poll for a different blockhash and associated max_slot than `previous_blockhash`
fn poll_for_blockhash_and_slot(
cluster_info: &Arc<RwLock<ClusterInfo>>,
cluster_info: &ClusterInfo,
slots_per_segment: u64,
previous_blockhash: &Hash,
exit: &Arc<AtomicBool>,
) -> Result<(Hash, u64)> {
info!("waiting for the next turn...");
loop {
let rpc_peers = {
let cluster_info = cluster_info.read().unwrap();
cluster_info.all_rpc_peers()
};
let rpc_peers = cluster_info.all_rpc_peers();
debug!("rpc peers: {:?}", rpc_peers);
if !rpc_peers.is_empty() {
let rpc_client = {
let node_index = thread_rng().gen_range(0, rpc_peers.len());
RpcClient::new_socket(rpc_peers[node_index].rpc)
};
let response = rpc_client
.send(
&RpcRequest::GetStorageTurn,
serde_json::value::Value::Null,
0,
)
.map_err(|err| {
warn!("Error while making rpc request {:?}", err);
ArchiverError::ClientError(err)
})?;
let RpcStorageTurn {
blockhash: storage_blockhash,
slot: turn_slot,
} = serde_json::from_value::<RpcStorageTurn>(response)
.map_err(ArchiverError::JsonError)?;
} = rpc_client.send(RpcRequest::GetStorageTurn, serde_json::value::Value::Null)?;
let turn_blockhash = storage_blockhash.parse().map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
@ -813,14 +783,15 @@ impl Archiver {
blockstore: &Arc<Blockstore>,
slots_per_segment: u64,
) -> Result<u64> {
let ip_addr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
// Create a client which downloads from the archiver and see that it
// can respond with shreds.
let start_slot = Self::get_archiver_segment_slot(archiver_info.storage_addr);
let start_slot = Self::get_archiver_segment_slot(ip_addr, archiver_info.storage_addr);
info!("Archiver download: start at {}", start_slot);
let exit = Arc::new(AtomicBool::new(false));
let (s_reader, r_reader) = channel();
let repair_socket = Arc::new(bind_in_range(VALIDATOR_PORT_RANGE).unwrap().1);
let repair_socket = Arc::new(bind_in_range(ip_addr, VALIDATOR_PORT_RANGE).unwrap().1);
let t_receiver = receiver(
repair_socket.clone(),
&exit,
@ -846,13 +817,14 @@ impl Archiver {
repair_service::MAX_REPAIR_LENGTH,
&repair_slot_range,
);
let mut repair_stats = RepairStats::default();
//iter over the repairs and send them
if let Ok(repairs) = repairs {
let reqs: Vec<_> = repairs
.into_iter()
.filter_map(|repair_request| {
serve_repair
.map_repair_request(&repair_request)
.map_repair_request(&repair_request, &mut repair_stats, Some(0))
.map(|result| ((archiver_info.gossip, result), repair_request))
.ok()
})
@ -917,8 +889,8 @@ impl Archiver {
true
}
fn get_archiver_segment_slot(to: SocketAddr) -> u64 {
let (_port, socket) = bind_in_range(VALIDATOR_PORT_RANGE).unwrap();
fn get_archiver_segment_slot(bind_ip_addr: IpAddr, to: SocketAddr) -> u64 {
let (_port, socket) = bind_in_range(bind_ip_addr, VALIDATOR_PORT_RANGE).unwrap();
socket
.set_read_timeout(Some(Duration::from_secs(5)))
.unwrap();

View File

@ -1,4 +1,3 @@
use serde_json;
use solana_client::client_error;
use solana_ledger::blockstore;
use solana_sdk::transport;

View File

@ -1,6 +1,6 @@
[package]
name = "solana-archiver-utils"
version = "1.0.0"
version = "1.1.24"
description = "Solana Archiver Utils"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,16 +10,19 @@ edition = "2018"
[dependencies]
log = "0.4.8"
rand = "0.6.5"
solana-chacha = { path = "../chacha", version = "1.0.0" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.0" }
solana-ledger = { path = "../ledger", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-perf = { path = "../perf", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
rand = "0.7.0"
solana-chacha = { path = "../chacha", version = "1.1.24" }
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.24" }
solana-ledger = { path = "../ledger", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-perf = { path = "../perf", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
[dev-dependencies]
hex = "0.4.0"
hex = "0.4.2"
[lib]
name = "solana_archiver_utils"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -2,19 +2,22 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-archiver"
version = "1.0.0"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
clap = "2.33.0"
console = "0.9.2"
solana-clap-utils = { path = "../clap-utils", version = "1.0.0" }
solana-core = { path = "../core", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-metrics = { path = "../metrics", version = "1.0.0" }
solana-archiver-lib = { path = "../archiver-lib", version = "1.0.0" }
solana-net-utils = { path = "../net-utils", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
console = "0.10.0"
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" }
solana-core = { path = "../core", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-metrics = { path = "../metrics", version = "1.1.24" }
solana-archiver-lib = { path = "../archiver-lib", version = "1.1.24" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -2,18 +2,22 @@ use clap::{crate_description, crate_name, App, Arg};
use console::style;
use solana_archiver_lib::archiver::Archiver;
use solana_clap_utils::{
input_validators::is_keypair,
keypair::{
self, keypair_input, KeypairWithSource, ASK_SEED_PHRASE_ARG,
SKIP_SEED_PHRASE_VALIDATION_ARG,
},
input_parsers::keypair_of, input_validators::is_keypair_or_ask_keyword,
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
};
use solana_core::{
cluster_info::{Node, VALIDATOR_PORT_RANGE},
contact_info::ContactInfo,
};
use solana_sdk::{commitment_config::CommitmentConfig, signature::Signer};
use std::{net::SocketAddr, path::PathBuf, process::exit, sync::Arc};
use solana_sdk::{
commitment_config::CommitmentConfig,
signature::{Keypair, Signer},
};
use std::{
net::{IpAddr, Ipv4Addr, SocketAddr},
path::PathBuf,
sync::Arc,
};
fn main() {
solana_logger::setup();
@ -24,10 +28,10 @@ fn main() {
.arg(
Arg::with_name("identity_keypair")
.short("i")
.long("identity-keypair")
.long("identity")
.value_name("PATH")
.takes_value(true)
.validator(is_keypair)
.validator(is_keypair_or_ask_keyword)
.help("File containing an identity (keypair)"),
)
.arg(
@ -55,48 +59,27 @@ fn main() {
.long("storage-keypair")
.value_name("PATH")
.takes_value(true)
.validator(is_keypair)
.validator(is_keypair_or_ask_keyword)
.help("File containing the storage account keypair"),
)
.arg(
Arg::with_name(ASK_SEED_PHRASE_ARG.name)
.long(ASK_SEED_PHRASE_ARG.long)
.value_name("KEYPAIR NAME")
.multiple(true)
.takes_value(true)
.possible_values(&["identity-keypair", "storage-keypair"])
.help(ASK_SEED_PHRASE_ARG.help),
)
.arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
.requires(ASK_SEED_PHRASE_ARG.name)
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
)
.get_matches();
let ledger_path = PathBuf::from(matches.value_of("ledger").unwrap());
let identity_keypair = keypair_input(&matches, "identity_keypair")
.unwrap_or_else(|err| {
eprintln!("Identity keypair input failed: {}", err);
exit(1);
})
.keypair;
let KeypairWithSource {
keypair: storage_keypair,
source: storage_keypair_source,
} = keypair_input(&matches, "storage_keypair").unwrap_or_else(|err| {
eprintln!("Storage keypair input failed: {}", err);
exit(1);
});
if storage_keypair_source == keypair::Source::Generated {
let identity_keypair = keypair_of(&matches, "identity_keypair").unwrap_or_else(Keypair::new);
let storage_keypair = keypair_of(&matches, "storage_keypair").unwrap_or_else(|| {
clap::Error::with_description(
"The `storage-keypair` argument was not found",
clap::ErrorKind::ArgumentNotFound,
)
.exit();
}
});
let entrypoint_addr = matches
.value_of("entrypoint")
@ -116,6 +99,7 @@ fn main() {
&identity_keypair.pubkey(),
&gossip_addr,
VALIDATOR_PORT_RANGE,
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
);
println!(

View File

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

View File

@ -1,30 +1,38 @@
use clap::{crate_description, crate_name, value_t, App, Arg};
use crossbeam_channel::unbounded;
use log::*;
use rand::{thread_rng, Rng};
use rayon::prelude::*;
use solana_core::banking_stage::{create_test_recorder, BankingStage};
use solana_core::cluster_info::ClusterInfo;
use solana_core::cluster_info::Node;
use solana_core::genesis_utils::{create_genesis_config, GenesisConfigInfo};
use solana_core::packet::to_packets_chunked;
use solana_core::poh_recorder::PohRecorder;
use solana_core::poh_recorder::WorkingBankEntry;
use solana_ledger::bank_forks::BankForks;
use solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path};
use solana_core::{
banking_stage::{create_test_recorder, BankingStage},
cluster_info::ClusterInfo,
cluster_info::Node,
poh_recorder::PohRecorder,
poh_recorder::WorkingBankEntry,
};
use solana_ledger::{
bank_forks::BankForks,
blockstore::Blockstore,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
get_tmp_ledger_path,
};
use solana_measure::measure::Measure;
use solana_perf::packet::to_packets_chunked;
use solana_runtime::bank::Bank;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::Keypair;
use solana_sdk::signature::Signature;
use solana_sdk::system_transaction;
use solana_sdk::timing::{duration_as_us, timestamp};
use solana_sdk::transaction::Transaction;
use std::sync::atomic::Ordering;
use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex, RwLock};
use std::thread::sleep;
use std::time::{Duration, Instant};
use solana_sdk::{
hash::Hash,
pubkey::Pubkey,
signature::Keypair,
signature::Signature,
system_transaction,
timing::{duration_as_us, timestamp},
transaction::Transaction,
};
use std::{
sync::{atomic::Ordering, mpsc::Receiver, Arc, Mutex},
thread::sleep,
time::{Duration, Instant},
};
fn check_txs(
receiver: &Arc<Receiver<WorkingBankEntry>>,
@ -57,15 +65,22 @@ fn check_txs(
no_bank
}
fn make_accounts_txs(txes: usize, mint_keypair: &Keypair, hash: Hash) -> Vec<Transaction> {
fn make_accounts_txs(
total_num_transactions: usize,
hash: Hash,
same_payer: bool,
) -> Vec<Transaction> {
let to_pubkey = Pubkey::new_rand();
let dummy = system_transaction::transfer(mint_keypair, &to_pubkey, 1, hash);
(0..txes)
let payer_key = Keypair::new();
let dummy = system_transaction::transfer(&payer_key, &to_pubkey, 1, hash);
(0..total_num_transactions)
.into_par_iter()
.map(|_| {
let mut new = dummy.clone();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
new.message.account_keys[0] = Pubkey::new_rand();
if !same_payer {
new.message.account_keys[0] = Pubkey::new_rand();
}
new.message.account_keys[1] = Pubkey::new_rand();
new.signatures = vec![Signature::new(&sig[0..64])];
new
@ -89,13 +104,61 @@ fn bytes_as_usize(bytes: &[u8]) -> usize {
bytes[0] as usize | (bytes[1] as usize) << 8
}
#[allow(clippy::cognitive_complexity)]
fn main() {
solana_logger::setup();
let num_threads = BankingStage::num_threads() as usize;
let matches = App::new(crate_name!())
.about(crate_description!())
.version(solana_version::version!())
.arg(
Arg::with_name("num_chunks")
.long("num-chunks")
.takes_value(true)
.value_name("SIZE")
.help("Number of transaction chunks."),
)
.arg(
Arg::with_name("packets_per_chunk")
.long("packets-per-chunk")
.takes_value(true)
.value_name("SIZE")
.help("Packets per chunk"),
)
.arg(
Arg::with_name("skip_sanity")
.long("skip-sanity")
.takes_value(false)
.help("Skip transaction sanity execution"),
)
.arg(
Arg::with_name("same_payer")
.long("same-payer")
.takes_value(false)
.help("Use the same payer for transfers"),
)
.arg(
Arg::with_name("iterations")
.long("iterations")
.takes_value(true)
.help("Number of iterations"),
)
.arg(
Arg::with_name("num_threads")
.long("num-threads")
.takes_value(true)
.help("Number of iterations"),
)
.get_matches();
let num_threads =
value_t!(matches, "num_threads", usize).unwrap_or(BankingStage::num_threads() as usize);
// a multiple of packet chunk duplicates to avoid races
const CHUNKS: usize = 8 * 2;
const PACKETS_PER_BATCH: usize = 192;
let txes = PACKETS_PER_BATCH * num_threads * CHUNKS;
let num_chunks = value_t!(matches, "num_chunks", usize).unwrap_or(16);
let packets_per_chunk = value_t!(matches, "packets_per_chunk", usize).unwrap_or(192);
let iterations = value_t!(matches, "iterations", usize).unwrap_or(1000);
let total_num_transactions = num_chunks * num_threads * packets_per_chunk;
let mint_total = 1_000_000_000_000;
let GenesisConfigInfo {
genesis_config,
@ -109,34 +172,44 @@ fn main() {
let mut bank_forks = BankForks::new(0, bank0);
let mut bank = bank_forks.working_bank();
info!("threads: {} txs: {}", num_threads, txes);
info!("threads: {} txs: {}", num_threads, total_num_transactions);
let mut transactions = make_accounts_txs(txes, &mint_keypair, genesis_config.hash());
let same_payer = matches.is_present("same_payer");
let mut transactions =
make_accounts_txs(total_num_transactions, genesis_config.hash(), same_payer);
// fund all the accounts
transactions.iter().for_each(|tx| {
let fund = system_transaction::transfer(
let mut fund = system_transaction::transfer(
&mint_keypair,
&tx.message.account_keys[0],
mint_total / txes as u64,
mint_total / total_num_transactions as u64,
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();
fund.signatures = vec![Signature::new(&sig[0..64])];
let x = bank.process_transaction(&fund);
x.unwrap();
});
//sanity check, make sure all the transactions can execute sequentially
transactions.iter().for_each(|tx| {
let res = bank.process_transaction(&tx);
assert!(res.is_ok(), "sanity test transactions");
});
bank.clear_signatures();
//sanity check, make sure all the transactions can execute in parallel
let res = bank.process_transactions(&transactions);
for r in res {
assert!(r.is_ok(), "sanity parallel execution");
let skip_sanity = matches.is_present("skip_sanity");
if !skip_sanity {
//sanity check, make sure all the transactions can execute sequentially
transactions.iter().for_each(|tx| {
let res = bank.process_transaction(&tx);
assert!(res.is_ok(), "sanity test transactions error: {:?}", res);
});
bank.clear_signatures();
//sanity check, make sure all the transactions can execute in parallel
let res = bank.process_transactions(&transactions);
for r in res {
assert!(r.is_ok(), "sanity parallel execution error: {:?}", r);
}
bank.clear_signatures();
}
bank.clear_signatures();
let mut verified: Vec<_> = to_packets_chunked(&transactions.clone(), PACKETS_PER_BATCH);
let mut verified: Vec<_> = to_packets_chunked(&transactions.clone(), packets_per_chunk);
let ledger_path = get_tmp_ledger_path!();
{
let blockstore = Arc::new(
@ -145,7 +218,7 @@ 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 = Arc::new(RwLock::new(cluster_info));
let cluster_info = Arc::new(cluster_info);
let banking_stage = BankingStage::new(
&cluster_info,
&poh_recorder,
@ -155,7 +228,7 @@ fn main() {
);
poh_recorder.lock().unwrap().set_bank(&bank);
let chunk_len = verified.len() / CHUNKS;
let chunk_len = verified.len() / num_chunks;
let mut start = 0;
// This is so that the signal_receiver does not go out of scope after the closure.
@ -164,17 +237,17 @@ fn main() {
let signal_receiver = Arc::new(signal_receiver);
let mut total_us = 0;
let mut tx_total_us = 0;
let base_tx_count = bank.transaction_count();
let mut txs_processed = 0;
let mut root = 1;
let collector = Pubkey::new_rand();
const ITERS: usize = 1_000;
let config = Config {
packets_per_batch: PACKETS_PER_BATCH,
packets_per_batch: packets_per_chunk,
chunk_len,
num_threads,
};
let mut total_sent = 0;
for _ in 0..ITERS {
for _ in 0..iterations {
let now = Instant::now();
let mut sent = 0;
@ -215,7 +288,11 @@ fn main() {
sleep(Duration::from_millis(5));
}
}
if check_txs(&signal_receiver, txes / CHUNKS, &poh_recorder) {
if check_txs(
&signal_receiver,
total_num_transactions / num_chunks,
&poh_recorder,
) {
debug!(
"resetting bank {} tx count: {} txs_proc: {}",
bank.slot(),
@ -246,7 +323,7 @@ fn main() {
poh_recorder.lock().unwrap().set_bank(&bank);
assert!(poh_recorder.lock().unwrap().bank().is_some());
if bank.slot() > 32 {
bank_forks.set_root(root, &None);
bank_forks.set_root(root, &None, None);
root += 1;
}
debug!(
@ -267,7 +344,7 @@ fn main() {
debug!(
"time: {} us checked: {} sent: {}",
duration_as_us(&now.elapsed()),
txes / CHUNKS,
total_num_transactions / num_chunks,
sent,
);
total_sent += sent;
@ -278,20 +355,26 @@ fn main() {
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
tx.signatures[0] = Signature::new(&sig[0..64]);
}
verified = to_packets_chunked(&transactions.clone(), PACKETS_PER_BATCH);
verified = to_packets_chunked(&transactions.clone(), packets_per_chunk);
}
start += chunk_len;
start %= verified.len();
}
let txs_processed = bank_forks.working_bank().transaction_count();
debug!("processed: {} base: {}", txs_processed, base_tx_count);
eprintln!(
"{{'name': 'banking_bench_total', 'median': '{}'}}",
"{{'name': 'banking_bench_total', 'median': '{:.2}'}}",
(1000.0 * 1000.0 * total_sent as f64) / (total_us as f64),
);
eprintln!(
"{{'name': 'banking_bench_tx_total', 'median': '{}'}}",
"{{'name': 'banking_bench_tx_total', 'median': '{:.2}'}}",
(1000.0 * 1000.0 * total_sent as f64) / (tx_total_us as f64),
);
eprintln!(
"{{'name': 'banking_bench_success_tx_total', 'median': '{:.2}'}}",
(1000.0 * 1000.0 * (txs_processed - base_tx_count) as f64) / (total_us as f64),
);
drop(verified_sender);
drop(vote_sender);

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-exchange"
version = "1.0.0"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -10,25 +10,28 @@ publish = false
[dependencies]
clap = "2.32.0"
itertools = "0.8.2"
itertools = "0.9.0"
log = "0.4.8"
num-derive = "0.3"
num-traits = "0.2"
rand = "0.6.5"
rayon = "1.2.0"
serde_json = "1.0.46"
rand = "0.7.0"
rayon = "1.3.0"
serde_json = "1.0.48"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "1.0.0" }
solana-core = { path = "../core", version = "1.0.0" }
solana-genesis = { path = "../genesis", version = "1.0.0" }
solana-client = { path = "../client", version = "1.0.0" }
solana-faucet = { path = "../faucet", version = "1.0.0" }
solana-exchange-program = { path = "../programs/exchange", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-metrics = { path = "../metrics", version = "1.0.0" }
solana-net-utils = { path = "../net-utils", version = "1.0.0" }
solana-runtime = { path = "../runtime", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" }
solana-core = { path = "../core", version = "1.1.24" }
solana-genesis = { path = "../genesis", version = "1.1.24" }
solana-client = { path = "../client", version = "1.1.24" }
solana-faucet = { path = "../faucet", version = "1.1.24" }
solana-exchange-program = { path = "../programs/exchange", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-metrics = { path = "../metrics", version = "1.1.24" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-runtime = { path = "../runtime", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "1.0.0" }
solana-local-cluster = { path = "../local-cluster", version = "1.1.24" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -86,7 +86,7 @@ fn test_exchange_bank_client() {
solana_logger::setup();
let (genesis_config, identity) = create_genesis_config(100_000_000_000_000);
let mut bank = Bank::new(&genesis_config);
bank.add_instruction_processor(id(), process_instruction);
bank.add_static_program("exchange_program", id(), process_instruction);
let clients = vec![BankClient::new(bank)];
let mut config = Config::default();

View File

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

View File

@ -1,6 +1,6 @@
use clap::{crate_description, crate_name, App, Arg};
use solana_core::packet::{Packet, Packets, PacketsRecycler, PACKET_DATA_SIZE};
use solana_core::streamer::{receiver, PacketReceiver};
use solana_streamer::packet::{Packet, Packets, PacketsRecycler, PACKET_DATA_SIZE};
use solana_streamer::streamer::{receiver, PacketReceiver};
use std::cmp::max;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
@ -67,7 +67,8 @@ fn main() -> Result<()> {
}
let mut port = 0;
let mut addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
let ip_addr = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
let mut addr = SocketAddr::new(ip_addr, 0);
let exit = Arc::new(AtomicBool::new(false));
@ -75,7 +76,7 @@ fn main() -> Result<()> {
let mut read_threads = Vec::new();
let recycler = PacketsRecycler::default();
for _ in 0..num_sockets {
let read = solana_net_utils::bind_to(port, false).unwrap();
let read = solana_net_utils::bind_to(ip_addr, port, false).unwrap();
read.set_read_timeout(Some(Duration::new(1, 0))).unwrap();
addr = read.local_addr().unwrap();

View File

@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-bench-tps"
version = "1.0.0"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -11,27 +11,30 @@ homepage = "https://solana.com/"
bincode = "1.2.1"
clap = "2.33.0"
log = "0.4.8"
rayon = "1.2.0"
serde_json = "1.0.46"
rayon = "1.3.0"
serde_json = "1.0.48"
serde_yaml = "0.8.11"
solana-clap-utils = { path = "../clap-utils", version = "1.0.0" }
solana-core = { path = "../core", version = "1.0.0" }
solana-genesis = { path = "../genesis", version = "1.0.0" }
solana-client = { path = "../client", version = "1.0.0" }
solana-faucet = { path = "../faucet", version = "1.0.0" }
solana-librapay = { path = "../programs/librapay", version = "1.0.0", optional = true }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-metrics = { path = "../metrics", version = "1.0.0" }
solana-measure = { path = "../measure", version = "1.0.0" }
solana-net-utils = { path = "../net-utils", version = "1.0.0" }
solana-runtime = { path = "../runtime", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
solana-move-loader-program = { path = "../programs/move_loader", version = "1.0.0", optional = true }
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" }
solana-core = { path = "../core", version = "1.1.24" }
solana-genesis = { path = "../genesis", version = "1.1.24" }
solana-client = { path = "../client", version = "1.1.24" }
solana-faucet = { path = "../faucet", version = "1.1.24" }
#solana-librapay = { path = "../programs/librapay", version = "1.1.8", optional = true }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-metrics = { path = "../metrics", version = "1.1.24" }
solana-measure = { path = "../measure", version = "1.1.24" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-runtime = { path = "../runtime", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
#solana-move-loader-program = { path = "../programs/move_loader", version = "1.1.8", optional = true }
[dev-dependencies]
serial_test = "0.3.2"
serial_test = "0.4.0"
serial_test_derive = "0.4.0"
solana-local-cluster = { path = "../local-cluster", version = "1.0.0" }
solana-local-cluster = { path = "../local-cluster", version = "1.1.24" }
[features]
move = ["solana-librapay", "solana-move-loader-program"]
#[features]
#move = ["solana-librapay", "solana-move-loader-program"]
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1059,8 +1059,8 @@ pub fn generate_and_fund_keypairs<T: 'static + Client + Send + Sync>(
// pay for the transaction fees in a new run.
let enough_lamports = 8 * lamports_per_account / 10;
if first_keypair_balance < enough_lamports || last_keypair_balance < enough_lamports {
let (_blockhash, fee_calculator) = get_recent_blockhash(client.as_ref());
let max_fee = fee_calculator.max_lamports_per_signature;
let fee_rate_governor = client.get_fee_rate_governor().unwrap();
let max_fee = fee_rate_governor.max_lamports_per_signature;
let extra_fees = extra * max_fee;
let total_keypairs = keypairs.len() as u64 + 1; // Add one for funding keypair
let mut total = lamports_per_account * total_keypairs + extra_fees;
@ -1134,7 +1134,7 @@ mod tests {
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_sdk::client::SyncClient;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::genesis_config::create_genesis_config;
#[test]
@ -1181,8 +1181,8 @@ mod tests {
#[test]
fn test_bench_tps_fund_keys_with_fees() {
let (mut genesis_config, id) = create_genesis_config(10_000);
let fee_calculator = FeeCalculator::new(11, 0);
genesis_config.fee_calculator = fee_calculator;
let fee_rate_governor = FeeRateGovernor::new(11, 0);
genesis_config.fee_rate_governor = fee_rate_governor;
let bank = Bank::new(&genesis_config);
let client = Arc::new(BankClient::new(bank));
let keypair_count = 20;

View File

@ -1,6 +1,6 @@
use clap::{crate_description, crate_name, App, Arg, ArgMatches};
use solana_faucet::faucet::FAUCET_PORT;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::signature::{read_keypair_file, Keypair};
use std::{net::SocketAddr, process::exit, time::Duration};
@ -43,7 +43,7 @@ impl Default for Config {
client_ids_and_stake_file: String::new(),
write_to_client_file: false,
read_from_client_file: false,
target_lamports_per_signature: FeeCalculator::default().target_lamports_per_signature,
target_lamports_per_signature: FeeRateGovernor::default().target_lamports_per_signature,
multi_client: true,
use_move: false,
num_lamports_per_account: NUM_LAMPORTS_PER_ACCOUNT_DEFAULT,

View File

@ -3,7 +3,7 @@ use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate
use solana_bench_tps::cli;
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client};
use solana_genesis::Base64Account;
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_program;
use std::{collections::HashMap, fs::File, io::prelude::*, path::Path, process::exit, sync::Arc};
@ -41,7 +41,7 @@ fn main() {
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
let num_accounts = keypairs.len() as u64;
let max_fee =
FeeCalculator::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
FeeRateGovernor::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee)
/ num_accounts
+ num_lamports_per_account;

View File

@ -1,26 +0,0 @@
Building the Solana book
---
Install the book's dependencies, build, and test the book:
```bash
$ ./build.sh
```
Run any Rust tests in the markdown:
```bash
$ make test
```
Render markdown as HTML:
```bash
$ make build
```
Render and view the book:
```bash
$ make open
```

View File

@ -1,22 +0,0 @@
.--------.
| Leader |
`--------`
^
|
.------------------------------------|--------------------.
| TVU | |
| | |
| .-------. .------------. .----+---. .---------. |
.------------. | | Shred | | Retransmit | | Replay | | Storage | |
| Upstream +----->| Fetch +-->| Stage +-->| Stage +-->| Stage | |
| Validators | | | Stage | | | | | | | |
`------------` | `-------` `----+-------` `----+---` `---------` |
| ^ | | |
| | | | |
`--------|----------|----------------|--------------------`
| | |
| V v
.+-----------. .------.
| Gossip | | Bank |
| Service | `------`
`------------`

View File

@ -1,5 +0,0 @@
# Using Solana from the Command-line
This chapter describes the command-line tools for interacting with Solana. One
could use these tools to send payments, stake validators, and check account
balances.

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
# Replication-validation Transaction Fees
**Subject to change.**
As previously mentioned, validator-clients will also be responsible for validating PoReps submitted into the PoH stream by archiver-clients. In this case, validators are providing compute \(CPU/GPU\) and light storage resources to confirm that these replication proofs could only be generated by a client that is storing the referenced PoH leger block.
While replication-clients are incentivized and rewarded through protocol-based rewards schedule \(see [Replication-client Economics](../ed_replication_client_economics/)\), validator-clients will be incentivized to include and validate PoReps in PoH through collection of transaction fees associated with the submitted PoReps and distribution of protocol rewards proportional to the validated PoReps. As will be described in detail in the Section 3.1, replication-client rewards are protocol-based and designed to reward based on a global data redundancy factor. I.e. the protocol will incentivize replication-client participation through rewards based on a target ledger redundancy \(e.g. 10x data redundancy\).
The validation of PoReps by validation-clients is computationally more expensive than state-validation \(detail in the [Economic Sustainability](../ed_economic_sustainability.md) chapter\), thus the transaction fees are expected to be proportionally higher.
There are various attack vectors available for colluding validation and replication clients, also described in detail below in [Economic Sustainability](../ed_economic_sustainability/README.md). To protect against various collusion attack vectors, for a given epoch, validator rewards are distributed across participating validation-clients in proportion to the number of validated PoReps in the epoch less the number of PoReps that mismatch the archivers challenge. The PoRep challenge game is described in [Ledger Replication](https://github.com/solana-labs/solana/blob/master/book/src/ledger-replication.md#the-porep-game). This design rewards validators proportional to the number of PoReps they process and validate, while providing negative pressure for validation-clients to submit lazy or malicious invalid votes on submitted PoReps \(note that it is computationally prohibitive to determine whether a validator-client has marked a valid PoRep as invalid\).

View File

@ -1,37 +0,0 @@
# Introduction
## What is Solana?
Solana is an open source project implementing a new, high-performance, permissionless blockchain. Solana is also the name of a company headquartered in San Francisco that maintains the open source project.
## About this Book
This book describes the Solana open source project, a blockchain built from the ground up for scale. The book covers why Solana is useful, how to use it, how it works, and why it will continue to work long after the company Solana closes its doors. The goal of the Solana architecture is to demonstrate there exists a set of software algorithms that when used in combination to implement a blockchain, removes software as a performance bottleneck, allowing transaction throughput to scale proportionally with network bandwidth. The architecture goes on to satisfy all three desirable properties of a proper blockchain: it is scalable, secure and decentralized.
The architecture describes a theoretical upper bound of 710 thousand transactions per second \(tps\) on a standard gigabit network and 28.4 million tps on 40 gigabit. Furthermore, the architecture supports safe, concurrent execution of programs authored in general purpose programming languages such as C or Rust.
## Disclaimer
All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort. It is up to the reader to check and validate their accuracy and truthfulness. Furthermore, nothing in this project constitutes a solicitation for investment.
## History of the Solana Codebase
In November of 2017, Anatoly Yakovenko published a whitepaper describing Proof of History, a technique for keeping time between computers that do not trust one another. From Anatoly's previous experience designing distributed systems at Qualcomm, Mesosphere and Dropbox, he knew that a reliable clock makes network synchronization very simple. When synchronization is simple the resulting network can be blazing fast, bound only by network bandwidth.
Anatoly watched as blockchain systems without clocks, such as Bitcoin and Ethereum, struggled to scale beyond 15 transactions per second worldwide when centralized payment systems such as Visa required peaks of 65,000 tps. Without a clock, it was clear they'd never graduate to being the global payment system or global supercomputer most had dreamed them to be. When Anatoly solved the problem of getting computers that dont trust each other to agree on time, he knew he had the key to bring 40 years of distributed systems research to the world of blockchain. The resulting cluster wouldn't be just 10 times faster, or a 100 times, or a 1,000 times, but 10,000 times faster, right out of the gate!
Anatoly's implementation began in a private codebase and was implemented in the C programming language. Greg Fitzgerald, who had previously worked with Anatoly at semiconductor giant Qualcomm Incorporated, encouraged him to reimplement the project in the Rust programming language. Greg had worked on the LLVM compiler infrastructure, which underlies both the Clang C/C++ compiler as well as the Rust compiler. Greg claimed that the language's safety guarantees would improve software productivity and that its lack of a garbage collector would allow programs to perform as well as those written in C. Anatoly gave it a shot and just two weeks later, had migrated his entire codebase to Rust. Sold. With plans to weave all the world's transactions together on a single, scalable blockchain, Anatoly called the project Loom.
On February 13th of 2018, Greg began prototyping the first open source implementation of Anatoly's whitepaper. The project was published to GitHub under the name Silk in the loomprotocol organization. On February 28th, Greg made his first release, demonstrating 10 thousand signed transactions could be verified and processed in just over half a second. Shortly after, another former Qualcomm cohort, Stephen Akridge, demonstrated throughput could be massively improved by offloading signature verification to graphics processors. Anatoly recruited Greg, Stephen and three others to co-found a company, then called Loom.
Around the same time, Ethereum-based project Loom Network sprung up and many people were confused about whether they were the same project. The Loom team decided it would rebrand. They chose the name Solana, a nod to a small beach town North of San Diego called Solana Beach, where Anatoly, Greg and Stephen lived and surfed for three years when they worked for Qualcomm. On March 28th, the team created the Solana Labs GitHub organization and renamed Greg's prototype Silk to Solana.
In June of 2018, the team scaled up the technology to run on cloud-based networks and on July 19th, published a 50-node, permissioned, public testnet consistently supporting bursts of 250,000 transactions per second. In a later release in December, called v0.10 Pillbox, the team published a permissioned testnet running 150 nodes on a gigabit network and demonstrated soak tests processing an _average_ of 200 thousand transactions per second with bursts over 500 thousand. The project was also extended to support on-chain programs written in the C programming language and run concurrently in a safe execution environment called BPF.
## What is a Solana Cluster?
A cluster is a set of computers that work together and can be viewed from the outside as a single system. A Solana cluster is a set of independently owned computers working together \(and sometimes against each other\) to verify the output of untrusted, user-submitted programs. A Solana cluster can be utilized any time a user wants to preserve an immutable record of events in time or programmatic interpretations of those events. One use is to track which of the computers did meaningful work to keep the cluster running. Another use might be to track the possession of real-world assets. In each case, the cluster produces a record of events called the ledger. It will be preserved for the lifetime of the cluster. As long as someone somewhere in the world maintains a copy of the ledger, the output of its programs \(which may contain a record of who possesses what\) will forever be reproducible, independent of the organization that launched it.
## What are SOLs?
A SOL is the name of Solana's native token, which can be passed to nodes in a Solana cluster in exchange for running an on-chain program or validating its output. The system may perform micropayments of fractional SOLs, which are called _lamports_. They are named in honor of Solana's biggest technical influence, [Leslie Lamport](https://en.wikipedia.org/wiki/Leslie_Lamport). A lamport has a value of 0.000000001 SOL.

View File

@ -1,51 +0,0 @@
# Installation Guide
Follow this guide to setup Solana's key generation tool called `solana-keygen`
{% hint style="warn" %}
After installation, ensure your version is `0.23.1` or higher by running `solana-keygen -V`
{% endhint %}
## Download
First, download the latest release tarball from GitHub.
1. Setup download url
```bash
solana_downloads=https://github.com/solana-labs/solana/releases/latest/download
```
2. Specify the download file based on your machine
**MacOS**
```bash
solana_release=solana-release-x86_64-apple-darwin.tar.bz2
```
**Linux**
```bash
solana_release=solana-release-x86_64-unknown-linux-gnu.tar.bz2
```
3. Download
```bash
curl -L -sSf -o solana-release.tar.bz2 $solana_downloads/$solana_release
```
## Extract
Next, extract the tarball
```bash
tar xf solana-release.tar.bz2
```
## Add to "PATH"
Now add the tool to your PATH environment variable with the following command
```bash
export PATH="$(pwd)/solana-release/bin:${PATH}"
```
## Check
Finally, check that `solana-keygen` can be run by running
```bash
solana-keygen -V
```

View File

@ -1,280 +0,0 @@
# Paper Wallet Usage
Solana commands can be run without ever saving a keypair to disk on a machine.
If avoiding writing a private key to disk is a security concern of yours, you've
come to the right place.
{% hint style="warning" %}
Even using this secure input method, it's still possible that a private key gets
written to disk by unencrypted memory swaps. It is the user's responsibility to
protect against this scenario.
{% endhint %}
## Creating a Paper Wallet
Using the `solana-keygen` tool, it is possible to generate new seed phrases as
well as derive a keypair from an existing seed phrase and (optional) passphrase.
The seed phrase and passphrase can be used together as a paper wallet. As long
as you keep your seed phrase and passphrase stored safely, you can use them to
access your account.
{% hint style="info" %}
For more information about how seed phrases work, review this
[Bitcoin Wiki page](https://en.bitcoin.it/wiki/Seed_phrase).
{% endhint %}
### Seed Phrase Generation
Generating a new keypair can be done using the `solana-keygen new` command. The
command will generate a random seed phrase, ask you to enter an optional
passphrase, and then will display the derived public key and the generated seed
phrase for your paper wallet.
After copying down your seed phrase, you can use the
[public key derivation](#public-key-derivation) instructions to verify that you
have not made any errors.
```bash
solana-keygen new --no-outfile
```
{% hint style="warning" %}
If the `--no-outfile` flag is **omitted**, the default behavior is to write the
keypair to `~/.config/solana/id.json`
{% endhint %}
{% hint style="info" %}
For added security, increase the seed phrase word count using the `--word-count`
argument
{% endhint %}
For full usage details run:
```bash
solana-keygen new --help
```
### Public Key Derivation
Public keys can be derived from a seed phrase and a passphrase if you choose to
use one. This is useful for using an offline-generated seed phrase to
derive a valid public key. The `solana-keygen pubkey` command will walk you
through entering your seed phrase and a passphrase if you chose to use one.
```bash
solana-keygen pubkey ASK
```
{% hint style="info" %}
Note that you could potentially use different passphrases for the same seed
phrase. Each unique passphrase will yield a different keypair.
{% endhint %}
The `solana-keygen` tool uses the same BIP39 standard English word list as it
does to generate seed phrases. If your seed phrase was generated with another
tool that uses a different word list, you can still use `solana-keygen`, but
will need to pass the `--skip-seed-phrase-validation` argument and forego this
validation.
```bash
solana-keygen pubkey ASK --skip-seed-phrase-validation
```
{% hint style="info" %}
Copy the derived public key to a USB stick for easy usage on networked computers
{% endhint %}
{% hint style="info" %}
A common next step is to [check the balance](#checking-account-balance) of the
account associated with a public key
{% endhint %}
For full usage details run:
```bash
solana-keygen pubkey --help
```
## Verifying the Keypair
A keypair can be verified by following a variation on the
[offline signing](../offline-signing/README.md) procedure with a dummy transaction.
### Create and Sign a Dummy Transaction
Use offline signing to acquire the signature of a dummy transaction that can
be verified in the next step. A 0 Lamport [transfer](../cli/usage.md#solana-transfer)
is used to prevent inadvertent loss of funds. Additionally, an improbable _blockhash_
value is specified, as well as using the address of the _system program_ for the `TO`
argument, to ensure the transaction would be rejected by the _cluster_ should
it be submitted in error.
Command
```text
solana transfer 11111111111111111111111111111111 0 --sign-only \
--ask-seed-phrase keypair --blockhash 11111111111111111111111111111111
```
Prompt for seed phrase
```text
[keypair] seed phrase:
[keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
Recovered pubkey `AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi`. Continue? (y/n): y
```
Output
```text
Blockhash: 11111111111111111111111111111111
Signers (Pubkey=Signature):
AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA
{"blockhash":"11111111111111111111111111111111","signers":["AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA"]}
```
### Verify the Signature
Using the _Signers_ output from the [previous step](#create-and-sign-a-dummy-transaction)
to reconstruct the transaction, this time specifying the _pubkey_ and _signature_
as in the submission step of [offline signing](../offline-signing/README.md). That is, the `--from` and
`--fee-payer` are explicitly set to the _pubkey_ rather than being taken from
the keypair (which is not queried this time).
Command
```text
solana transfer 11111111111111111111111111111111 0 --sign-only --from AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi \
--signer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA \
--blockhash 11111111111111111111111111111111 --fee-payer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi
```
Output
```text
Blockhash: 11111111111111111111111111111111
Signers (Pubkey=Signature):
AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA
{"blockhash":"11111111111111111111111111111111","signers":["AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWA"]}
```
### An Example of Failure
To simulate an error the [verification step](#verify-the-signature) is repeated,
but with a corrupted _signature_ (the last letter is changed from "A" to "B").
Command
```text
solana transfer 11111111111111111111111111111111 0 --sign-only --from AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi \
--signer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi=3uZndChSmPoYfaCihC993E7EAHKDsuu53Ge6Dk1K6ULwhJkgcgiHNm9J1Geqq2azW6PKxQTFjC8rMm5bGxRcYWB \
--blockhash 11111111111111111111111111111111 --fee-payer AjTz9EX6vXB6EboKpFm7SwrbDannb6icjvEE632D3rfi
```
Output (Error)
```text
Error: BadParameter("Transaction construction failed, incorrect signature or public key provided")
```
## Checking Account Balance
All that is needed to check an account balance is the public key of an account.
To retrieve public keys securely from a paper wallet, follow the
[Public Key Derivation](#public-key-derivation) instructions on an
[air gapped computer](https://en.wikipedia.org/wiki/Air_gap_\(networking\)).
Public keys can then be typed manually or transferred via a USB stick to a
networked machine.
Next, configure the `solana` CLI tool to connect to a particular cluster:
```bash
solana config set --url <CLUSTER URL> # (i.e. http://devnet.solana.com:8899)
```
Finally, to check the balance, run the following command:
```bash
solana balance <PUBKEY>
```
In order to check a list of public keys quickly, append public keys to a file,
one per line, like so:
`public_keys.txt`
```bash
7hTw3XhprjT2DkVxVixtig9eZwHTZ2rksTSYN7Jh5niZ
9ufAiSyboCZmmEsoStgLYQfnx9KfqP1ZtDK8Wr1j8SJV
# ...
```
And run the following command:
```bash
while read PUBLIC_KEY;
do echo "$PUBLIC_KEY: $(solana balance "$PUBLIC_KEY" | tail -n1)";
done < public_keys.txt
```
## Running a Validator
In order to run a validator, you will need to specify an "identity keypair"
which will be used to fund all of the vote transactions signed by your validator.
Rather than specifying a path with `--identity-keypair <PATH>` you can use the
`--ask-seed-phrase` option.
```bash
solana-validator --ask-seed-phrase identity-keypair --ledger ...
[identity-keypair] seed phrase: 🔒
[identity-keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
```
The `--ask-seed-phrase` option accepts multiple keypairs. If you wish to use this
input method for your voting keypair as well you can do the following:
```bash
solana-validator --ask-seed-phrase identity-keypair voting-keypair --ledger ...
[identity-keypair] seed phrase: 🔒
[identity-keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
[voting-keypair] seed phrase: 🔒
[voting-keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
```
Refer to the following page for a comprehensive guide on running a validator:
{% page-ref page="../running-validator/README.md" %}
## Delegating Stake
Solana CLI tooling supports secure keypair input for stake delegation. To do so,
first create a stake account with some SOL. Use the special `ASK` keyword to
trigger a seed phrase input prompt for the stake account and use
`--keypair ASK` to securely input the funding keypair.
```bash
solana create-stake-account ASK 1 --keypair ASK
[stake_account] seed phrase: 🔒
[stake_account] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
[keypair] seed phrase: 🔒
[keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
```
Then, to delegate that stake to a validator, use `--keypair ASK` to
securely input the funding keypair.
```bash
solana delegate-stake --keypair ASK <STAKE_ACCOUNT_PUBKEY> <VOTE_ACCOUNT_PUBKEY>
[keypair] seed phrase: 🔒
[keypair] If this seed phrase has an associated passphrase, enter it now. Otherwise, press ENTER to continue:
```
Refer to the following page for a comprehensive guide on delegating stake:
{% page-ref page="../running-validator/validator-stake.md" %}
---
{% page-ref page="../api-reference/cli.md" %}

View File

@ -1,156 +0,0 @@
# Running an Archiver
This document describes how to setup an archiver in the testnet
Please note some of the information and instructions described here may change in future releases.
## Overview
Archivers are specialized light clients. They download a part of the ledger \(a.k.a Segment\) and store it. They earn rewards for storing segments.
The testnet features a validator running at devnet.solana.com, which serves as the entrypoint to the cluster for your archiver node.
Additionally there is a blockexplorer available at [http://devnet.solana.com/](http://devnet.solana.com/).
The testnet is configured to reset the ledger daily, or sooner should the hourly automated cluster sanity test fail.
## Machine Requirements
Archivers don't need specialized hardware. Anything with more than 128GB of disk space will be able to participate in the cluster as an archiver node.
Currently the disk space requirements are very low but we expect them to change in the future.
Prebuilt binaries are available for Linux x86\_64 \(Ubuntu 18.04 recommended\), macOS, and Windows.
### Confirm The Testnet Is Reachable
Before starting an archiver node, sanity check that the cluster is accessible to your machine by running some simple commands. If any of the commands fail, please retry 5-10 minutes later to confirm the testnet is not just restarting itself before debugging further.
Fetch the current transaction count over JSON RPC:
```bash
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"getTransactionCount"}' http://devnet.solana.com:8899
```
Inspect the blockexplorer at [http://devnet.solana.com/](http://devnet.solana.com/) for activity.
View the [metrics dashboard](https://metrics.solana.com:3000/d/testnet-beta/testnet-monitor-beta?var-testnet=testnet) for more detail on cluster activity.
## Archiver Setup
#### Obtaining The Software
#### Bootstrap with `solana-install`
The `solana-install` tool can be used to easily install and upgrade the cluster software.
#### Linux and mac OS
```bash
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.18.0/install/solana-install-init.sh | sh -s
```
Alternatively build the `solana-install` program from source and run the following command to obtain the same result:
```bash
solana-install init
```
#### Windows
Download and install **solana-install-init** from [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest)
After a successful install, `solana-install update` may be used to easily update the software to a newer version at any time.
#### Download Prebuilt Binaries
If you would rather not use `solana-install` to manage the install, you can manually download and install the binaries.
#### Linux
Download the binaries by navigating to [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), download **solana-release-x86\_64-unknown-linux-gnu.tar.bz2**, then extract the archive:
```bash
tar jxf solana-release-x86_64-unknown-linux-gnu.tar.bz2
cd solana-release/
export PATH=$PWD/bin:$PATH
```
#### mac OS
Download the binaries by navigating to [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), download **solana-release-x86\_64-apple-darwin.tar.bz2**, then extract the archive:
```bash
tar jxf solana-release-x86_64-apple-darwin.tar.bz2
cd solana-release/
export PATH=$PWD/bin:$PATH
```
#### Windows
Download the binaries by navigating to [https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest), download **solana-release-x86\_64-pc-windows-msvc.tar.bz2**, then extract it into a folder. It is a good idea to add this extracted folder to your windows PATH.
## Starting The Archiver
Try running following command to join the gossip network and view all the other nodes in the cluster:
```bash
solana-gossip spy --entrypoint devnet.solana.com:8001
# Press ^C to exit
```
Now configure the keypairs for your archiver by running:
Navigate to the solana install location and open a cmd prompt
```bash
solana-keygen new -o archiver-keypair.json
solana-keygen new -o storage-keypair.json
```
Use solana-keygen to show the public keys for each of the keypairs, they will be needed in the next step:
* Windows
```bash
# The archiver's identity
solana-keygen pubkey archiver-keypair.json
solana-keygen pubkey storage-keypair.json
```
* Linux and mac OS
\`\`\`bash
export ARCHIVER\_IDENTITY=$\(solana-keygen pubkey archiver-keypair.json\)
export STORAGE\_IDENTITY=$\(solana-keygen pubkey storage-keypair.json\)
```text
Then set up the storage accounts for your archiver by running:
```bash
solana --keypair archiver-keypair.json airdrop .0001
solana --keypair archiver-keypair.json create-archiver-storage-account $ARCHIVER_IDENTITY $STORAGE_IDENTITY
```
Note: Every time the testnet restarts, run the steps to setup the archiver accounts again.
To start the archiver:
```bash
solana-archiver --entrypoint devnet.solana.com:8001 --identity-keypair archiver-keypair.json --storage-keypair storage-keypair.json --ledger archiver-ledger
```
## Verify Archiver Setup
From another console, confirm the IP address and **identity pubkey** of your archiver is visible in the gossip network by running:
```bash
solana-gossip spy --entrypoint devnet.solana.com:8001
```
Provide the **storage account pubkey** to the `solana storage-account` command to view the recent mining activity from your archiver:
```bash
solana --keypair storage-keypair.json storage-account $STORAGE_IDENTITY
```

View File

@ -1,32 +0,0 @@
# Running a Validator
This document describes how to participate in the Solana testnet as a validator
node.
Please note some of the information and instructions described here may change
in future releases, and documentation will be updated for mainnet participation.
## Overview
Solana currently maintains several testnets, each featuring a validator that can
serve as the entrypoint to the cluster for your validator.
Current testnet entrypoints:
* Developer testnet, devnet.solana.com
Solana may launch special testnets for validator participation; we will provide
you with a specific entrypoint URL to use.
Prior to mainnet, the testnets may be running different versions of solana
software, which may feature breaking changes. For information on choosing a
testnet and finding software version info, jump to [Choosing a Testnet](validator-testnet.md).
The testnets are configured to reset the ledger daily, or sooner, should the
hourly automated cluster sanity test fail.
There is a network explorer that shows the status of solana testnets available
at [http://explorer.solana.com/](https://explorer.solana.com/).
Also we'd love it if you choose to register your validator node with us at
[https://forms.gle/LfFscZqJELbuUP139](https://forms.gle/LfFscZqJELbuUP139).

View File

@ -1,79 +0,0 @@
# Installing the Validator Software
Install the Solana release
[v0.23.1](https://github.com/solana-labs/solana/releases/tag/v0.23.1) on your
machine by running:
```bash
curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.23.1/install/solana-install-init.sh | sh -s - 0.23.1
```
If you are connecting to a different testnet, you can replace `0.23.1` with the
release tag matching the software version of your desired testnet, or replace it
with the named channel `stable`, `beta`, or `edge`.
The following output indicates a successful update:
```text
looking for latest release
downloading v0.23.1 installer
Configuration: /home/solana/.config/solana/install/config.yml
Active release directory: /home/solana/.local/share/solana/install/active_release
* Release version: 0.23.1
* Release URL: https://github.com/solana-labs/solana/releases/download/v0.23.1/solana-release-x86_64-unknown-linux-gnu.tar.bz2
Update successful
```
After a successful install, `solana-install update` may be used to easily update
the cluster software to a newer version at any time.
## Download Prebuilt Binaries
If you would rather not use `solana-install` to manage the install, you can
manually download and install the binaries.
### Linux
Download the binaries by navigating to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
download **solana-release-x86\_64-unknown-linux-gnu.tar.bz2**, then extract the
archive:
```bash
tar jxf solana-release-x86_64-unknown-linux-gnu.tar.bz2
cd solana-release/
export PATH=$PWD/bin:$PATH
```
### macOS
Download the binaries by navigating to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
download **solana-release-x86\_64-apple-darwin.tar.bz2**, then extract the
archive:
```bash
tar jxf solana-release-x86_64-apple-darwin.tar.bz2
cd solana-release/
export PATH=$PWD/bin:$PATH
```
## Build From Source
If you are unable to use the prebuilt binaries or prefer to build it yourself
from source, navigate to
[https://github.com/solana-labs/solana/releases/latest](https://github.com/solana-labs/solana/releases/latest),
and download the **Source Code** archive. Extract the code and build the
binaries with:
```bash
./scripts/cargo-install-all.sh .
export PATH=$PWD/bin:$PATH
```
You can then run the following command to obtain the same result as with
prebuilt binaries:
```bash
solana-install init
```

View File

@ -1,39 +0,0 @@
# Choosing a Testnet
Solana maintains several testnets, each featuring a Solana-owned validator
that serves as an entrypoint to the cluster.
Current testnet entrypoints:
* Stable: devnet.solana.com
Application developers should target the Stable testnet. Key differences
between the Stable testnet and what will be mainnet:
* Stable testnet tokens are not real
* Stable testnet includes a token faucet for application testing
* Stable testnet may be subject to ledger resets
* Stable testnet typically runs a newer software version than mainnet
* Stable testnet may be maintained by different validators than mainnet
The Beta testnet is used to showcase and stabilize new features before they
are tagged for release. Application developers are free to target the Beta
testnet, but should expect instability and periodic ledger resets. Regarding
stability, all that can be said is that CI automation was successful.
### Get Testnet Version
You can submit a JSON-RPC request to see the specific software version of the
cluster. Use this to specify [the software version to install](validator-software.md).
```bash
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"getVersion"}' devnet.solana.com:8899
```
Example result:
`{"jsonrpc":"2.0","result":{"solana-core":"0.21.0"},"id":1}`
## Using a Different Testnet
This guide is written in the context of devnet.solana.com, our most stable
cluster. To participate in another testnet, modify the commands in the following
pages, replacing `devnet.solana.com` with your desired testnet.

View File

@ -1,4 +0,0 @@
# TVU
![TVU Block Diagram](../../.gitbook/assets/tvu.svg)

View File

@ -1,6 +1,6 @@
[package]
name = "solana-chacha-cuda"
version = "1.0.0"
version = "1.1.24"
description = "Solana Chacha Cuda APIs"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,15 +10,18 @@ edition = "2018"
[dependencies]
log = "0.4.8"
solana-archiver-utils = { path = "../archiver-utils", version = "1.0.0" }
solana-chacha = { path = "../chacha", version = "1.0.0" }
solana-ledger = { path = "../ledger", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-perf = { path = "../perf", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
solana-archiver-utils = { path = "../archiver-utils", version = "1.1.24" }
solana-chacha = { path = "../chacha", version = "1.1.24" }
solana-ledger = { path = "../ledger", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-perf = { path = "../perf", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
[dev-dependencies]
hex-literal = "0.2.1"
[lib]
name = "solana_chacha_cuda"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-chacha-sys"
version = "1.0.0"
version = "1.1.24"
description = "Solana chacha-sys"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,3 +10,6 @@ edition = "2018"
[build-dependencies]
cc = "1.0.49"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,6 +1,6 @@
[package]
name = "solana-chacha"
version = "1.0.0"
version = "1.1.24"
description = "Solana Chacha APIs"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -10,16 +10,19 @@ edition = "2018"
[dependencies]
log = "0.4.8"
rand = "0.6.5"
rand_chacha = "0.1.1"
solana-chacha-sys = { path = "../chacha-sys", version = "1.0.0" }
solana-ledger = { path = "../ledger", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-perf = { path = "../perf", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
rand = "0.7.0"
rand_chacha = "0.2.2"
solana-chacha-sys = { path = "../chacha-sys", version = "1.1.24" }
solana-ledger = { path = "../ledger", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-perf = { path = "../perf", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
[dev-dependencies]
hex-literal = "0.2.1"
[lib]
name = "solana_chacha"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

8
ci/_
View File

@ -5,7 +5,13 @@
# |source| me
#
base_dir=$(realpath --strip "$(dirname "$0")/..")
_() {
echo "--- $*"
if [[ $(pwd) = $base_dir ]]; then
echo "--- $*"
else
echo "--- $* (wd: $(pwd))"
fi
"$@"
}

View File

@ -9,7 +9,7 @@
# ./affects-files.sh ^snap/ -- anything under the snap/ subdirectory
# ./affects-files.sh snap/ -- also matches foo/snap/
# Any pattern starting with the ! character will be negated:
# ./affects-files.sh !^book/ -- anything *not* under the book/ subdirectory
# ./affects-files.sh !^docs/ -- anything *not* under the docs/ subdirectory
#
set -e
cd "$(dirname "$0")"/..

View File

@ -2,19 +2,23 @@
# Build steps that run after the primary pipeline on pushes and tags.
# Pull requests to not run these steps.
steps:
- command: "ci/publish-tarball.sh"
timeout_in_minutes: 60
name: "publish tarball"
- command: "ci/publish-docs.sh"
timeout_in_minutes: 15
name: "publish docs"
- command: "ci/publish-bpf-sdk.sh"
timeout_in_minutes: 5
name: "publish bpf sdk"
- wait
- command: "sdk/docker-solana/build.sh"
timeout_in_minutes: 60
name: "publish docker"
- command: "ci/publish-crate.sh"
timeout_in_minutes: 120
timeout_in_minutes: 240
name: "publish crate"
branches: "!master"
- command: "ci/publish-bpf-sdk.sh"
timeout_in_minutes: 5
name: "publish bpf sdk"
- command: "ci/publish-tarball.sh"
timeout_in_minutes: 60
name: "publish tarball"
- command: "ci/publish-book.sh"
timeout_in_minutes: 15
name: "publish book"
# - command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-move.sh"
# name: "move"
# timeout_in_minutes: 20

26
ci/buildkite-tests.yml Normal file
View File

@ -0,0 +1,26 @@
# These steps are conditionally triggered by ci/buildkite.yml when files
# other than those in docs/ are modified
steps:
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-coverage.sh"
name: "coverage"
timeout_in_minutes: 30
- wait
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-stable.sh"
name: "stable"
timeout_in_minutes: 60
artifact_paths: "log-*.txt"
- wait
- command: "ci/test-stable-perf.sh"
name: "stable-perf"
timeout_in_minutes: 40
artifact_paths: "log-*.txt"
agents:
- "queue=cuda"
- command: "ci/test-bench.sh"
name: "bench"
timeout_in_minutes: 30
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-local-cluster.sh"
name: "local-cluster"
timeout_in_minutes: 45
artifact_paths: "log-*.txt"

View File

@ -1,38 +1,28 @@
# Build steps that run on pushes and pull requests.
# If files other than those in docs/ were modified, this will be followed up by
# ci/buildkite-tests.yml
#
# Release tags use buildkite-release.yml instead
steps:
- command: "ci/shellcheck.sh"
name: "shellcheck"
- command: "ci/test-sanity.sh"
name: "sanity"
timeout_in_minutes: 5
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-checks.sh"
name: "checks"
timeout_in_minutes: 20
- command: "ci/shellcheck.sh"
name: "shellcheck"
timeout_in_minutes: 5
- wait
- command: "ci/test-stable-perf.sh"
name: "stable-perf"
timeout_in_minutes: 40
artifact_paths: "log-*.txt"
agents:
- "queue=cuda"
- command: "ci/test-bench.sh"
name: "bench"
timeout_in_minutes: 30
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-stable.sh"
name: "stable"
timeout_in_minutes: 60
artifact_paths: "log-*.txt"
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-move.sh"
name: "move"
timeout_in_minutes: 20
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_stable_docker_image ci/test-local-cluster.sh"
name: "local-cluster"
timeout_in_minutes: 30
artifact_paths: "log-*.txt"
- command: ". ci/rust-version.sh; ci/docker-run.sh $$rust_nightly_docker_image ci/test-coverage.sh"
name: "coverage"
timeout_in_minutes: 30
- command: "ci/maybe-trigger-tests.sh"
name: "maybe-trigger-tests"
timeout_in_minutes: 2
- wait
- trigger: "solana-secondary"
branches: "!pull/*"
async: true

View File

@ -49,7 +49,7 @@ else
# ~/.cargo
ARGS+=(--volume "$PWD:/home")
fi
ARGS+=(--env "CARGO_HOME=/home/.cargo")
ARGS+=(--env "HOME=/home" --env "CARGO_HOME=/home/.cargo")
# kcov tries to set the personality of the binary which docker
# doesn't allow by default.
@ -67,6 +67,7 @@ ARGS+=(
--env BUILDKITE_JOB_ID
--env CI
--env CI_BRANCH
--env CI_TAG
--env CI_BUILD_ID
--env CI_COMMIT
--env CI_JOB_ID

View File

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

View File

@ -15,6 +15,8 @@ To update the pinned version:
1. Run `ci/docker-rust-nightly/build.sh` to rebuild the nightly image locally,
or potentially `ci/docker-rust-nightly/build.sh YYYY-MM-DD` if there's a
specific YYYY-MM-DD that is desired (default is today's build).
Check https://rust-lang.github.io/rustup-components-history/ for build
status
1. Update `ci/rust-version.sh` to reflect the new nightly `YYY-MM-DD`
1. Run `SOLANA_DOCKER_RUN_NOSETUID=1 ci/docker-run.sh --nopull solanalabs/rust-nightly:YYYY-MM-DD ci/test-coverage.sh`
to confirm the new nightly image builds. Fix any issues as needed

View File

@ -1,6 +1,6 @@
# Note: when the rust version is changed also modify
# ci/rust-version.sh to pick up the new image tag
FROM rust:1.41.0
FROM rust:1.43.0
# Add Google Protocol Buffers for Libra's metrics library.
ENV PROTOC_VERSION 3.8.0
@ -32,6 +32,7 @@ RUN set -x \
&& cargo install cargo-audit \
&& cargo install svgbob_cli \
&& cargo install mdbook \
&& cargo install mdbook-linkcheck \
&& rustc --version \
&& cargo --version \
&& curl -OL https://github.com/google/protobuf/releases/download/v$PROTOC_VERSION/$PROTOC_ZIP \

View File

@ -178,7 +178,7 @@ startNodes() {
(
set -x
$solana_cli --keypair config/bootstrap-validator/identity-keypair.json \
$solana_cli --keypair config/bootstrap-validator/identity.json \
--url http://127.0.0.1:8899 genesis-hash
) | tee genesis-hash.log
maybeExpectedGenesisHash="--expected-genesis-hash $(tail -n1 genesis-hash.log)"

21
ci/maybe-trigger-tests.sh Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
annotate() {
${BUILDKITE:-false} && {
buildkite-agent annotate "$@"
}
}
# Skip if only the docs have been modified
ci/affects-files.sh \
\!^docs/ \
|| {
annotate --style info \
"Skipping all further tests as only docs/ files were modified"
exit 0
}
annotate --style info "Triggering tests"
buildkite-agent pipeline upload ci/buildkite-tests.yml

View File

@ -11,10 +11,10 @@ if [[ -n $CI_BRANCH ]]; then
set -x
(
. ci/rust-version.sh stable
ci/docker-run.sh "$rust_stable_docker_image" make -Cbook -B svg
ci/docker-run.sh "$rust_stable_docker_image" make -C docs
)
# make a local commit for the svgs
git add -A -f book/src/.gitbook/assets/.
# make a local commit for the svgs and generated/updated markdown
git add -f docs/src
if ! git diff-index --quiet HEAD; then
git config user.email maintainers@solana.com
git config user.name "$me"

View File

@ -45,7 +45,7 @@ linux)
TARGET=x86_64-unknown-linux-gnu
;;
windows)
TARGET=x86_64-pc-windows-msvc
TARGET=x86_64-pc-windows-gnu
;;
*)
echo CI_OS_NAME unset
@ -71,16 +71,7 @@ echo --- Creating release tarball
export CHANNEL
source ci/rust-version.sh stable
scripts/cargo-install-all.sh +"$rust_stable" --use-move solana-release
# Reduce the Windows archive size until
# https://github.com/appveyor/ci/issues/2997 is fixed
if [[ -n $APPVEYOR ]]; then
rm -f \
solana-release/bin/solana-validator.exe \
solana-release/bin/solana-bench-exchange.exe \
fi
scripts/cargo-install-all.sh +"$rust_stable" solana-release
tar cvf solana-release-$TARGET.tar solana-release
bzip2 solana-release-$TARGET.tar
@ -104,9 +95,8 @@ fi
source ci/upload-ci-artifact.sh
for file in solana-release-$TARGET.tar.bz2 solana-release-$TARGET.yml solana-install-init-"$TARGET"* $MAYBE_TARBALLS; do
upload-ci-artifact "$file"
if [[ -n $DO_NOT_PUBLISH_TAR ]]; then
upload-ci-artifact "$file"
echo "Skipped $file due to DO_NOT_PUBLISH_TAR"
continue
fi

View File

@ -2,8 +2,10 @@
set -e
cd "$(dirname "$0")/.."
# shellcheck source=multinode-demo/common.sh
source multinode-demo/common.sh
rm -f config/run/init-completed
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
timeout 15 ./run.sh &
pid=$!
@ -17,6 +19,16 @@ while [[ ! -f config/run/init-completed ]]; do
fi
done
snapshot_slot=1
# wait a bit longer than snapshot_slot
while [[ $($solana_cli --url http://localhost:8899 slot --commitment recent) -le $((snapshot_slot + 1)) ]]; do
sleep 1
done
curl -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":1, "method":"validatorExit"}' http://localhost:8899
wait $pid
$solana_ledger_tool create-snapshot --ledger config/ledger "$snapshot_slot" config/snapshot-ledger
cp config/ledger/genesis.tar.bz2 config/snapshot-ledger
$solana_ledger_tool verify --ledger config/snapshot-ledger

View File

@ -1,28 +1,30 @@
#
# This file maintains the rust versions for use by CI.
#
# Build with stable rust, updating the stable toolchain if necessary:
# $ source ci/rust-version.sh stable
# $ cargo +"$rust_stable" build
#
# Build with nightly rust, updating the nightly toolchain if necessary:
# $ source ci/rust-version.sh nightly
# $ cargo +"$rust_nightly" build
#
# Obtain the environment variables without any automatic toolchain updating:
# $ source ci/rust-version.sh
#
# Obtain the environment variables updating both stable and nightly, only stable, or
# only nightly:
# $ source ci/rust-version.sh all
# $ source ci/rust-version.sh stable
# $ source ci/rust-version.sh nightly
# Then to build with either stable or nightly:
# $ cargo +"$rust_stable" build
# $ cargo +"$rust_nightly" build
#
if [[ -n $RUST_STABLE_VERSION ]]; then
stable_version="$RUST_STABLE_VERSION"
else
stable_version=1.41.0
stable_version=1.43.0
fi
if [[ -n $RUST_NIGHTLY_VERSION ]]; then
nightly_version="$RUST_NIGHTLY_VERSION"
else
nightly_version=2020-02-06
nightly_version=2020-04-23
fi
@ -51,6 +53,10 @@ export rust_nightly_docker_image=solanalabs/rust-nightly:"$nightly_version"
nightly)
rustup_install "$rust_nightly"
;;
all)
rustup_install "$rust_stable"
rustup_install "$rust_nightly"
;;
*)
echo "Note: ignoring unknown argument: $1"
;;

View File

@ -25,7 +25,7 @@ source ci/_
source ci/upload-ci-artifact.sh
eval "$(ci/channel-info.sh)"
source ci/rust-version.sh nightly
source ci/rust-version.sh all
set -o pipefail
export RUST_BACKTRACE=1
@ -67,8 +67,9 @@ _ cargo +$rust_nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
_ cargo +$rust_nightly bench --manifest-path programs/bpf/Cargo.toml ${V:+--verbose} --features=bpf_c \
-- -Z unstable-options --format=json --nocapture | tee -a "$BENCH_FILE"
# Run banking bench. Doesn't require nightly, but use since it is already built.
# Run banking/accounts bench. Doesn't require nightly, but use since it is already built.
_ cargo +$rust_nightly run --release --manifest-path banking-bench/Cargo.toml ${V:+--verbose} | tee -a "$BENCH_FILE"
_ cargo +$rust_nightly run --release --manifest-path accounts-bench/Cargo.toml ${V:+--verbose} -- --num_accounts 10000 --num_slots 4 | tee -a "$BENCH_FILE"
# `solana-upload-perf` disabled as it can take over 30 minutes to complete for some
# reason

View File

@ -10,9 +10,6 @@ source ci/rust-version.sh nightly
export RUST_BACKTRACE=1
export RUSTFLAGS="-D warnings"
# Look for failed mergify.io backports
_ git show HEAD --check --oneline
_ cargo +"$rust_stable" fmt --all -- --check
# Clippy gets stuck for unknown reasons if sdk-c is included in the build, so check it separately.
@ -22,11 +19,9 @@ _ cargo +"$rust_stable" clippy --all --exclude solana-sdk-c -- --deny=warnings
_ cargo +"$rust_stable" clippy --manifest-path sdk-c/Cargo.toml -- --deny=warnings
_ cargo +"$rust_stable" audit --version
_ cargo +"$rust_stable" audit --ignore RUSTSEC-2020-0002
_ ci/nits.sh
_ cargo +"$rust_stable" audit --ignore RUSTSEC-2020-0002 --ignore RUSTSEC-2020-0008
_ ci/order-crates-for-publishing.py
_ book/build.sh
_ ci/check-ssh-keys.sh
_ docs/build.sh
{
cd programs/bpf

27
ci/test-sanity.sh Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
source ci/_
(
echo --- git diff --check
set -x
# Look for failed mergify.io backports by searching leftover conflict markers
# Also check for any trailing whitespaces!
if [[ -n $BUILDKITE_PULL_REQUEST_BASE_BRANCH ]]; then
base_branch=$BUILDKITE_PULL_REQUEST_BASE_BRANCH
else
base_branch=$BUILDKITE_BRANCH
fi
git fetch origin "$base_branch"
git diff "$(git merge-base HEAD "origin/$base_branch")..HEAD" --check --oneline
)
echo
_ ci/nits.sh
_ ci/check-ssh-keys.sh
echo --- ok

View File

@ -13,12 +13,12 @@ annotate() {
# Run the appropriate test based on entrypoint
testName=$(basename "$0" .sh)
# Skip if only the book has been modified
# Skip if only the docs have been modified
ci/affects-files.sh \
\!^book/ \
\!^docs/ \
|| {
annotate --style info \
"Skipped $testName as only book files were modified"
"Skipped $testName as only docs/ files were modified"
exit 0
}
@ -38,11 +38,16 @@ test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
# Clear the BPF sysroot files, they are not automatically rebuilt
rm -rf target/xargo # Issue #3105
# Limit compiler jobs to reduce memory usage
# on machines with 2gb/thread of memory
NPROC=$(nproc)
NPROC=$((NPROC>14 ? 14 : NPROC))
echo "Executing $testName"
case $testName in
test-stable)
_ cargo +"$rust_stable" test --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
_ cargo +"$rust_stable" test --manifest-path bench-tps/Cargo.toml --features=move ${V:+--verbose} test_bench_tps_local_cluster_move -- --nocapture
_ cargo +"$rust_stable" test --jobs "$NPROC" --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
#_ cargo +"$rust_stable" test --manifest-path bench-tps/Cargo.toml --features=move ${V:+--verbose} test_bench_tps_local_cluster_move -- --nocapture
;;
test-stable-perf)
ci/affects-files.sh \

View File

@ -23,10 +23,14 @@ if [[ -z $CI_TAG ]]; then
exit 1
fi
if [[ -z $CI_REPO_SLUG ]]; then
echo Error: CI_REPO_SLUG not defined
exit 1
fi
# Force CI_REPO_SLUG since sometimes
# BUILDKITE_TRIGGERED_FROM_BUILD_PIPELINE_SLUG is not set correctly, causing the
# artifact upload to fail
CI_REPO_SLUG=solana-labs/solana
#if [[ -z $CI_REPO_SLUG ]]; then
# echo Error: CI_REPO_SLUG not defined
# exit 1
#fi
releaseId=$( \
curl -s "https://api.github.com/repos/$CI_REPO_SLUG/releases/tags/$CI_TAG" \

View File

@ -1,6 +1,6 @@
[package]
name = "solana-clap-utils"
version = "1.0.0"
version = "1.1.24"
description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -11,11 +11,15 @@ edition = "2018"
[dependencies]
clap = "2.33.0"
rpassword = "4.0"
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
thiserror = "1.0.11"
tiny-bip39 = "0.7.0"
url = "2.1.0"
chrono = "0.4"
[lib]
name = "solana_clap_utils"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -0,0 +1,22 @@
use crate::ArgConstant;
use clap::Arg;
pub const COMMITMENT_ARG: ArgConstant<'static> = ArgConstant {
name: "commitment",
long: "commitment",
help: "Return information at the selected commitment level",
};
pub fn commitment_arg<'a, 'b>() -> Arg<'a, 'b> {
commitment_arg_with_default("recent")
}
pub fn commitment_arg_with_default<'a, 'b>(default_value: &'static str) -> Arg<'a, 'b> {
Arg::with_name(COMMITMENT_ARG.name)
.long(COMMITMENT_ARG.long)
.takes_value(true)
.possible_values(&["recent", "root", "max"])
.default_value(default_value)
.value_name("COMMITMENT_LEVEL")
.help(COMMITMENT_ARG.help)
}

View File

@ -1,16 +1,18 @@
use crate::keypair::{
keypair_from_seed_phrase, keypair_util_from_path, ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
keypair_from_seed_phrase, pubkey_from_path, resolve_signer_from_path, signer_from_path,
ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
};
use chrono::DateTime;
use clap::ArgMatches;
use solana_remote_wallet::remote_wallet::DerivationPath;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
clock::UnixTimestamp,
commitment_config::CommitmentConfig,
native_token::sol_to_lamports,
pubkey::Pubkey,
signature::{read_keypair_file, Keypair, Signature, Signer},
};
use std::str::FromStr;
use std::{str::FromStr, sync::Arc};
// Return parsed values from matches at `name`
pub fn values_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<T>>
@ -61,6 +63,21 @@ pub fn keypair_of(matches: &ArgMatches<'_>, name: &str) -> Option<Keypair> {
}
}
pub fn keypairs_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<Keypair>> {
matches.values_of(name).map(|values| {
values
.filter_map(|value| {
if value == ASK_KEYWORD {
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
keypair_from_seed_phrase(name, skip_validation, true).ok()
} else {
read_keypair_file(value).ok()
}
})
.collect()
})
}
// Return a pubkey for an argument that can itself be parsed into a pubkey,
// or is a filename that can be read as a keypair
pub fn pubkey_of(matches: &ArgMatches<'_>, name: &str) -> Option<Pubkey> {
@ -96,28 +113,77 @@ pub fn pubkeys_sigs_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<(Pubk
}
// Return a signer from matches at `name`
#[allow(clippy::type_complexity)]
pub fn signer_of(
name: &str,
matches: &ArgMatches<'_>,
) -> Result<Option<Box<dyn Signer>>, Box<dyn std::error::Error>> {
name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<(Option<Box<dyn Signer>>, Option<Pubkey>), Box<dyn std::error::Error>> {
if let Some(location) = matches.value_of(name) {
keypair_util_from_path(matches, location, name).map(Some)
let signer = signer_from_path(matches, location, name, wallet_manager)?;
let signer_pubkey = signer.pubkey();
Ok((Some(signer), Some(signer_pubkey)))
} else {
Ok((None, None))
}
}
pub fn pubkey_of_signer(
matches: &ArgMatches<'_>,
name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Option<Pubkey>, Box<dyn std::error::Error>> {
if let Some(location) = matches.value_of(name) {
Ok(Some(pubkey_from_path(
matches,
location,
name,
wallet_manager,
)?))
} else {
Ok(None)
}
}
pub fn pubkeys_of_multiple_signers(
matches: &ArgMatches<'_>,
name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Option<Vec<Pubkey>>, Box<dyn std::error::Error>> {
if let Some(pubkey_matches) = matches.values_of(name) {
let mut pubkeys: Vec<Pubkey> = vec![];
for signer in pubkey_matches {
pubkeys.push(pubkey_from_path(matches, signer, name, wallet_manager)?);
}
Ok(Some(pubkeys))
} else {
Ok(None)
}
}
pub fn resolve_signer(
matches: &ArgMatches<'_>,
name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Option<String>, Box<dyn std::error::Error>> {
Ok(resolve_signer_from_path(
matches,
matches.value_of(name).unwrap(),
name,
wallet_manager,
)?)
}
pub fn lamports_of_sol(matches: &ArgMatches<'_>, name: &str) -> Option<u64> {
value_of(matches, name).map(sol_to_lamports)
}
pub fn derivation_of(matches: &ArgMatches<'_>, name: &str) -> Option<DerivationPath> {
matches.value_of(name).map(|derivation_str| {
let derivation_str = derivation_str.replace("'", "");
let mut parts = derivation_str.split('/');
let account = parts.next().unwrap().parse::<u16>().unwrap();
let change = parts.next().map(|change| change.parse::<u16>().unwrap());
DerivationPath { account, change }
pub fn commitment_of(matches: &ArgMatches<'_>, name: &str) -> Option<CommitmentConfig> {
matches.value_of(name).map(|value| match value {
"max" => CommitmentConfig::max(),
"recent" => CommitmentConfig::recent(),
"root" => CommitmentConfig::root(),
_ => CommitmentConfig::default(),
})
}
@ -295,40 +361,4 @@ mod tests {
.get_matches_from(vec!["test", "--single", "0.03"]);
assert_eq!(lamports_of_sol(&matches, "single"), Some(30000000));
}
#[test]
fn test_derivation_of() {
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", "2/3"]);
assert_eq!(
derivation_of(&matches, "single"),
Some(DerivationPath {
account: 2,
change: Some(3)
})
);
assert_eq!(derivation_of(&matches, "another"), None);
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", "2"]);
assert_eq!(
derivation_of(&matches, "single"),
Some(DerivationPath {
account: 2,
change: None
})
);
assert_eq!(derivation_of(&matches, "another"), None);
let matches = app()
.clone()
.get_matches_from(vec!["test", "--single", "2'/3'"]);
assert_eq!(
derivation_of(&matches, "single"),
Some(DerivationPath {
account: 2,
change: Some(3)
})
);
}
}

View File

@ -1,69 +1,117 @@
use crate::keypair::{parse_keypair_path, KeypairUrl, ASK_KEYWORD};
use chrono::DateTime;
use solana_remote_wallet::remote_keypair::generate_remote_keypair;
use solana_sdk::{
clock::Slot,
hash::Hash,
pubkey::Pubkey,
signature::{read_keypair_file, Signature},
};
use std::fmt::Display;
use std::str::FromStr;
fn is_parsable_generic<U, T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
U: FromStr,
U::Err: Display,
{
string
.as_ref()
.parse::<U>()
.map(|_| ())
.map_err(|err| format!("error parsing '{}': {}", string, err))
}
// Return an error if string cannot be parsed as type T.
// Takes a String to avoid second type parameter when used as a clap validator
pub fn is_parsable<T>(string: String) -> Result<(), String>
where
T: FromStr,
T::Err: Display,
{
is_parsable_generic::<T, String>(string)
}
// Return an error if a pubkey cannot be parsed.
pub fn is_pubkey(string: String) -> Result<(), String> {
match string.parse::<Pubkey>() {
Ok(_) => Ok(()),
Err(err) => Err(format!("{:?}", err)),
}
pub fn is_pubkey<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
is_parsable_generic::<Pubkey, _>(string)
}
// Return an error if a hash cannot be parsed.
pub fn is_hash(string: String) -> Result<(), String> {
match string.parse::<Hash>() {
Ok(_) => Ok(()),
Err(err) => Err(format!("{:?}", err)),
}
pub fn is_hash<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
is_parsable_generic::<Hash, _>(string)
}
// Return an error if a keypair file cannot be parsed.
pub fn is_keypair(string: String) -> Result<(), String> {
read_keypair_file(&string)
pub fn is_keypair<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
read_keypair_file(string.as_ref())
.map(|_| ())
.map_err(|err| format!("{:?}", err))
.map_err(|err| format!("{}", err))
}
// Return an error if a keypair file cannot be parsed
pub fn is_keypair_or_ask_keyword(string: String) -> Result<(), String> {
if string.as_str() == ASK_KEYWORD {
pub fn is_keypair_or_ask_keyword<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
if string.as_ref() == ASK_KEYWORD {
return Ok(());
}
read_keypair_file(&string)
read_keypair_file(string.as_ref())
.map(|_| ())
.map_err(|err| format!("{:?}", err))
.map_err(|err| format!("{}", err))
}
// Return an error if string cannot be parsed as pubkey string or keypair file location
pub fn is_pubkey_or_keypair(string: String) -> Result<(), String> {
is_pubkey(string.clone()).or_else(|_| is_keypair(string))
pub fn is_pubkey_or_keypair<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
is_pubkey(string.as_ref()).or_else(|_| is_keypair(string))
}
// Return an error if string cannot be parsed as pubkey or keypair file or keypair ask keyword
pub fn is_pubkey_or_keypair_or_ask_keyword(string: String) -> Result<(), String> {
is_pubkey(string.clone()).or_else(|_| is_keypair_or_ask_keyword(string))
}
pub fn is_valid_signer(string: String) -> Result<(), String> {
match parse_keypair_path(&string) {
KeypairUrl::Usb(path) => generate_remote_keypair(path, None)
.map(|_| ())
.map_err(|err| format!("{:?}", err)),
// Return an error if string cannot be parsed as a pubkey string, or a valid Signer that can
// produce a pubkey()
pub fn is_valid_pubkey<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
match parse_keypair_path(string.as_ref()) {
KeypairUrl::Filepath(path) => is_keypair(path),
_ => Ok(()),
}
}
// Return an error if string cannot be parsed as a valid Signer. This is an alias of
// `is_valid_pubkey`, and does accept pubkey strings, even though a Pubkey is not by itself
// sufficient to sign a transaction.
//
// In the current offline-signing implementation, a pubkey is the valid input for a signer field
// when paired with an offline `--signer` argument to provide a Presigner (pubkey + signature).
// Clap validators can't check multiple fields at once, so the verification that a `--signer` is
// also provided and correct happens in parsing, not in validation.
pub fn is_valid_signer<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
is_valid_pubkey(string)
}
// Return an error if string cannot be parsed as pubkey=signature string
pub fn is_pubkey_sig(string: String) -> Result<(), String> {
let mut signer = string.split('=');
pub fn is_pubkey_sig<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
let mut signer = string.as_ref().split('=');
match Pubkey::from_str(
signer
.next()
@ -76,16 +124,19 @@ pub fn is_pubkey_sig(string: String) -> Result<(), String> {
.ok_or_else(|| "Malformed signer string".to_string())?,
) {
Ok(_) => Ok(()),
Err(err) => Err(format!("{:?}", err)),
Err(err) => Err(format!("{}", err)),
}
}
Err(err) => Err(format!("{:?}", err)),
Err(err) => Err(format!("{}", err)),
}
}
// Return an error if a url cannot be parsed.
pub fn is_url(string: String) -> Result<(), String> {
match url::Url::parse(&string) {
pub fn is_url<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
match url::Url::parse(string.as_ref()) {
Ok(url) => {
if url.has_host() {
Ok(())
@ -93,22 +144,34 @@ pub fn is_url(string: String) -> Result<(), String> {
Err("no host provided".to_string())
}
}
Err(err) => Err(format!("{:?}", err)),
Err(err) => Err(format!("{}", err)),
}
}
pub fn is_port(port: String) -> Result<(), String> {
port.parse::<u16>()
.map(|_| ())
.map_err(|e| format!("{:?}", e))
pub fn is_slot<T>(slot: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
is_parsable_generic::<Slot, _>(slot)
}
pub fn is_valid_percentage(percentage: String) -> Result<(), String> {
pub fn is_port<T>(port: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
is_parsable_generic::<u16, _>(port)
}
pub fn is_valid_percentage<T>(percentage: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
percentage
.as_ref()
.parse::<u8>()
.map_err(|e| {
format!(
"Unable to parse input percentage, provided: {}, err: {:?}",
"Unable to parse input percentage, provided: {}, err: {}",
percentage, e
)
})
@ -124,8 +187,11 @@ pub fn is_valid_percentage(percentage: String) -> Result<(), String> {
})
}
pub fn is_amount(amount: String) -> Result<(), String> {
if amount.parse::<u64>().is_ok() || amount.parse::<f64>().is_ok() {
pub fn is_amount<T>(amount: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
if amount.as_ref().parse::<u64>().is_ok() || amount.as_ref().parse::<f64>().is_ok() {
Ok(())
} else {
Err(format!(
@ -135,29 +201,35 @@ pub fn is_amount(amount: String) -> Result<(), String> {
}
}
pub fn is_rfc3339_datetime(value: String) -> Result<(), String> {
DateTime::parse_from_rfc3339(&value)
pub fn is_rfc3339_datetime<T>(value: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
DateTime::parse_from_rfc3339(value.as_ref())
.map(|_| ())
.map_err(|e| format!("{:?}", e))
.map_err(|e| format!("{}", e))
}
pub fn is_derivation(value: String) -> Result<(), String> {
let value = value.replace("'", "");
pub fn is_derivation<T>(value: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
let value = value.as_ref().replace("'", "");
let mut parts = value.split('/');
let account = parts.next().unwrap();
account
.parse::<u16>()
.parse::<u32>()
.map_err(|e| {
format!(
"Unable to parse derivation, provided: {}, err: {:?}",
"Unable to parse derivation, provided: {}, err: {}",
account, e
)
})
.and_then(|_| {
if let Some(change) = parts.next() {
change.parse::<u16>().map_err(|e| {
change.parse::<u32>().map_err(|e| {
format!(
"Unable to parse derivation, provided: {}, err: {:?}",
"Unable to parse derivation, provided: {}, err: {}",
change, e
)
})
@ -174,13 +246,14 @@ mod tests {
#[test]
fn test_is_derivation() {
assert_eq!(is_derivation("2".to_string()), Ok(()));
assert_eq!(is_derivation("0".to_string()), Ok(()));
assert_eq!(is_derivation("0/2".to_string()), Ok(()));
assert_eq!(is_derivation("0'/2'".to_string()), Ok(()));
assert!(is_derivation("a".to_string()).is_err());
assert!(is_derivation("65537".to_string()).is_err());
assert!(is_derivation("a/b".to_string()).is_err());
assert!(is_derivation("0/65537".to_string()).is_err());
assert_eq!(is_derivation("2"), Ok(()));
assert_eq!(is_derivation("0"), Ok(()));
assert_eq!(is_derivation("65537"), Ok(()));
assert_eq!(is_derivation("0/2"), Ok(()));
assert_eq!(is_derivation("0'/2'"), Ok(()));
assert!(is_derivation("a").is_err());
assert!(is_derivation("4294967296").is_err());
assert!(is_derivation("a/b").is_err());
assert!(is_derivation("0/4294967296").is_err());
}
}

View File

@ -1,17 +1,20 @@
use crate::{
input_parsers::{derivation_of, pubkeys_sigs_of},
offline::SIGNER_ARG,
input_parsers::pubkeys_sigs_of,
offline::{SIGNER_ARG, SIGN_ONLY_ARG},
ArgConstant,
};
use bip39::{Language, Mnemonic, Seed};
use clap::{values_t, ArgMatches, Error, ErrorKind};
use clap::ArgMatches;
use rpassword::prompt_password_stderr;
use solana_remote_wallet::remote_keypair::generate_remote_keypair;
use solana_remote_wallet::{
remote_keypair::generate_remote_keypair,
remote_wallet::{maybe_wallet_manager, RemoteWalletError, RemoteWalletManager},
};
use solana_sdk::{
pubkey::Pubkey,
signature::{
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair,
read_keypair_file, Keypair, Presigner, Signature, Signer,
read_keypair_file, Keypair, NullSigner, Presigner, Signature, Signer,
},
};
use std::{
@ -19,6 +22,7 @@ use std::{
io::{stdin, stdout, Write},
process::exit,
str::FromStr,
sync::Arc,
};
pub enum KeypairUrl {
@ -35,7 +39,7 @@ pub fn parse_keypair_path(path: &str) -> KeypairUrl {
} else if path == ASK_KEYWORD {
KeypairUrl::Ask
} else if path.starts_with("usb://") {
KeypairUrl::Usb(path.split_at(6).1.to_string())
KeypairUrl::Usb(path.to_string())
} else if let Ok(pubkey) = Pubkey::from_str(path) {
KeypairUrl::Pubkey(pubkey)
} else {
@ -56,10 +60,11 @@ pub fn presigner_from_pubkey_sigs(
})
}
pub fn keypair_util_from_path(
pub fn signer_from_path(
matches: &ArgMatches,
path: &str,
keypair_name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Box<dyn Signer>, Box<dyn error::Error>> {
match parse_keypair_path(path) {
KeypairUrl::Ask => {
@ -70,25 +75,45 @@ pub fn keypair_util_from_path(
false,
)?))
}
KeypairUrl::Filepath(path) => Ok(Box::new(read_keypair_file(&path)?)),
KeypairUrl::Filepath(path) => match read_keypair_file(&path) {
Err(e) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("could not find keypair file: {} error: {}", path, e),
)
.into()),
Ok(file) => Ok(Box::new(file)),
},
KeypairUrl::Stdin => {
let mut stdin = std::io::stdin();
Ok(Box::new(read_keypair(&mut stdin)?))
}
KeypairUrl::Usb(path) => Ok(Box::new(generate_remote_keypair(
path,
derivation_of(matches, "derivation_path"),
)?)),
KeypairUrl::Usb(path) => {
if wallet_manager.is_none() {
*wallet_manager = maybe_wallet_manager()?;
}
if let Some(wallet_manager) = wallet_manager {
Ok(Box::new(generate_remote_keypair(
path,
wallet_manager,
matches.is_present("confirm_key"),
keypair_name,
)?))
} else {
Err(RemoteWalletError::NoDeviceFound.into())
}
}
KeypairUrl::Pubkey(pubkey) => {
let presigner = pubkeys_sigs_of(matches, SIGNER_ARG.name)
.as_ref()
.and_then(|presigners| presigner_from_pubkey_sigs(&pubkey, presigners));
if let Some(presigner) = presigner {
Ok(Box::new(presigner))
} else if matches.is_present(SIGN_ONLY_ARG.name) {
Ok(Box::new(NullSigner::new(&pubkey)))
} else {
Err(Error::with_description(
"Missing signature for supplied pubkey",
ErrorKind::MissingRequiredArgument,
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("missing signature for supplied pubkey: {}", pubkey),
)
.into())
}
@ -96,39 +121,75 @@ pub fn keypair_util_from_path(
}
}
pub fn pubkey_from_path(
matches: &ArgMatches,
path: &str,
keypair_name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Pubkey, Box<dyn error::Error>> {
match parse_keypair_path(path) {
KeypairUrl::Pubkey(pubkey) => Ok(pubkey),
_ => Ok(signer_from_path(matches, path, keypair_name, wallet_manager)?.pubkey()),
}
}
pub fn resolve_signer_from_path(
matches: &ArgMatches,
path: &str,
keypair_name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Option<String>, Box<dyn error::Error>> {
match parse_keypair_path(path) {
KeypairUrl::Ask => {
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
// This method validates the seed phrase, but returns `None` because there is no path
// on disk or to a device
keypair_from_seed_phrase(keypair_name, skip_validation, false).map(|_| None)
}
KeypairUrl::Filepath(path) => match read_keypair_file(&path) {
Err(e) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("could not find keypair file: {} error: {}", path, e),
)
.into()),
Ok(_) => Ok(Some(path.to_string())),
},
KeypairUrl::Stdin => {
let mut stdin = std::io::stdin();
// This method validates the keypair from stdin, but returns `None` because there is no
// path on disk or to a device
read_keypair(&mut stdin).map(|_| None)
}
KeypairUrl::Usb(path) => {
if wallet_manager.is_none() {
*wallet_manager = maybe_wallet_manager()?;
}
if let Some(wallet_manager) = wallet_manager {
let path = generate_remote_keypair(
path,
wallet_manager,
matches.is_present("confirm_key"),
keypair_name,
)
.map(|keypair| keypair.path)?;
Ok(Some(path))
} else {
Err(RemoteWalletError::NoDeviceFound.into())
}
}
_ => Ok(Some(path.to_string())),
}
}
// Keyword used to indicate that the user should be asked for a keypair seed phrase
pub const ASK_KEYWORD: &str = "ASK";
pub const ASK_SEED_PHRASE_ARG: ArgConstant<'static> = ArgConstant {
long: "ask-seed-phrase",
name: "ask_seed_phrase",
help: "Recover a keypair using a seed phrase and optional passphrase",
};
pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
long: "skip-seed-phrase-validation",
name: "skip_seed_phrase_validation",
help: "Skip validation of seed phrases. Use this if your phrase does not use the BIP39 official English word list",
};
#[derive(Debug, PartialEq)]
pub enum Source {
Generated,
Path,
SeedPhrase,
}
pub struct KeypairWithSource {
pub keypair: Keypair,
pub source: Source,
}
impl KeypairWithSource {
fn new(keypair: Keypair, source: Source) -> Self {
Self { keypair, source }
}
}
/// 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)?;
@ -182,47 +243,6 @@ pub fn keypair_from_seed_phrase(
Ok(keypair)
}
/// Checks CLI arguments to determine whether a keypair should be:
/// - inputted securely via stdin,
/// - read in from a file,
/// - or newly generated
pub fn keypair_input(
matches: &clap::ArgMatches,
keypair_name: &str,
) -> Result<KeypairWithSource, Box<dyn error::Error>> {
let ask_seed_phrase_matches =
values_t!(matches.values_of(ASK_SEED_PHRASE_ARG.name), String).unwrap_or_default();
let keypair_match_name = keypair_name.replace('-', "_");
if ask_seed_phrase_matches
.iter()
.any(|s| s.as_str() == keypair_name)
{
if matches.value_of(keypair_match_name).is_some() {
clap::Error::with_description(
&format!(
"`--{} {}` cannot be used with `{} <PATH>`",
ASK_SEED_PHRASE_ARG.long, keypair_name, keypair_name
),
clap::ErrorKind::ArgumentConflict,
)
.exit();
}
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
keypair_from_seed_phrase(keypair_name, skip_validation, true)
.map(|keypair| KeypairWithSource::new(keypair, Source::SeedPhrase))
} else if let Some(keypair_file) = matches.value_of(keypair_match_name) {
if keypair_file.starts_with("usb://") {
Ok(KeypairWithSource::new(Keypair::new(), Source::Path))
} else {
read_keypair_file(keypair_file)
.map(|keypair| KeypairWithSource::new(keypair, Source::Path))
}
} else {
Ok(KeypairWithSource::new(Keypair::new(), Source::Generated))
}
}
fn sanitize_seed_phrase(seed_phrase: &str) -> String {
seed_phrase
.split_whitespace()
@ -233,14 +253,6 @@ fn sanitize_seed_phrase(seed_phrase: &str) -> String {
#[cfg(test)]
mod tests {
use super::*;
use clap::ArgMatches;
#[test]
fn test_keypair_input() {
let arg_matches = ArgMatches::default();
let KeypairWithSource { source, .. } = keypair_input(&arg_matches, "").unwrap();
assert_eq!(source, Source::Generated);
}
#[test]
fn test_sanitize_seed_phrase() {

View File

@ -1,3 +1,5 @@
use thiserror::Error;
#[macro_export]
macro_rules! version {
() => {
@ -23,6 +25,24 @@ pub struct ArgConstant<'a> {
pub help: &'a str,
}
/// Error type for forwarding Errors out of `main()` of a `clap` app
/// and still using the `Display` formatter
#[derive(Error)]
#[error("{0}")]
pub struct DisplayError(Box<dyn std::error::Error>);
impl DisplayError {
pub fn new_as_boxed(inner: Box<dyn std::error::Error>) -> Box<Self> {
DisplayError(inner).into()
}
}
impl std::fmt::Debug for DisplayError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", self.0)
}
}
pub mod commitment;
pub mod input_parsers;
pub mod input_validators;
pub mod keypair;

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-cli-config"
description = "Blockchain, Rebuilt for Scale"
version = "1.0.0"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -11,6 +11,10 @@ homepage = "https://solana.com/"
[dependencies]
dirs = "2.0.2"
lazy_static = "1.4.0"
serde = "1.0.104"
serde = "1.0.105"
serde_derive = "1.0.103"
serde_yaml = "0.8.11"
url = "2.1.1"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,10 +1,7 @@
// Wallet settings that can be configured for long-term use
use serde_derive::{Deserialize, Serialize};
use std::{
fs::{create_dir_all, File},
io::{self, Write},
path::Path,
};
use std::{collections::HashMap, io};
use url::Url;
lazy_static! {
pub static ref CONFIG_FILE: Option<String> = {
@ -15,37 +12,89 @@ lazy_static! {
};
}
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct Config {
pub url: String,
pub json_rpc_url: String,
pub websocket_url: String,
pub keypair_path: String,
#[serde(default)]
pub address_labels: HashMap<String, String>,
}
impl Default for Config {
fn default() -> Self {
let keypair_path = {
let mut keypair_path = dirs::home_dir().expect("home directory");
keypair_path.extend(&[".config", "solana", "id.json"]);
keypair_path.to_str().unwrap().to_string()
};
let json_rpc_url = "https://api.mainnet-beta.solana.com".to_string();
// Empty websocket_url string indicates the client should
// `Config::compute_websocket_url(&json_rpc_url)`
let websocket_url = "".to_string();
Self {
json_rpc_url,
websocket_url,
keypair_path,
address_labels: HashMap::new(),
}
}
}
impl Config {
pub fn new(url: &str, keypair_path: &str) -> Self {
Self {
url: url.to_string(),
keypair_path: keypair_path.to_string(),
}
}
pub fn load(config_file: &str) -> Result<Self, io::Error> {
let file = File::open(config_file.to_string())?;
let config = serde_yaml::from_reader(file)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
Ok(config)
crate::load_config_file(config_file)
}
pub fn save(&self, config_file: &str) -> Result<(), io::Error> {
let serialized = serde_yaml::to_string(self)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
crate::save_config_file(self, config_file)
}
if let Some(outdir) = Path::new(&config_file).parent() {
create_dir_all(outdir)?;
pub fn compute_websocket_url(json_rpc_url: &str) -> String {
let json_rpc_url: Option<Url> = json_rpc_url.parse().ok();
if json_rpc_url.is_none() {
return "".to_string();
}
let mut file = File::create(config_file)?;
file.write_all(&serialized.into_bytes())?;
Ok(())
let json_rpc_url = json_rpc_url.unwrap();
let is_secure = json_rpc_url.scheme().to_ascii_lowercase() == "https";
let mut ws_url = json_rpc_url.clone();
ws_url
.set_scheme(if is_secure { "wss" } else { "ws" })
.expect("unable to set scheme");
if let Some(port) = json_rpc_url.port() {
ws_url.set_port(Some(port + 1)).expect("unable to set port");
}
ws_url.to_string()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn compute_websocket_url() {
assert_eq!(
Config::compute_websocket_url(&"http://devnet.solana.com"),
"ws://devnet.solana.com/".to_string()
);
assert_eq!(
Config::compute_websocket_url(&"https://devnet.solana.com"),
"wss://devnet.solana.com/".to_string()
);
assert_eq!(
Config::compute_websocket_url(&"http://example.com:8899"),
"ws://example.com:8900/".to_string()
);
assert_eq!(
Config::compute_websocket_url(&"https://example.com:1234"),
"wss://example.com:1235/".to_string()
);
assert_eq!(Config::compute_websocket_url(&"garbage"), String::new());
}
}

View File

@ -1,4 +1,39 @@
#[macro_use]
extern crate lazy_static;
pub mod config;
mod config;
pub use config::{Config, CONFIG_FILE};
use std::{
fs::{create_dir_all, File},
io::{self, Write},
path::Path,
};
pub fn load_config_file<T, P>(config_file: P) -> Result<T, io::Error>
where
T: serde::de::DeserializeOwned,
P: AsRef<Path>,
{
let file = File::open(config_file)?;
let config = serde_yaml::from_reader(file)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
Ok(config)
}
pub fn save_config_file<T, P>(config: &T, config_file: P) -> Result<(), io::Error>
where
T: serde::ser::Serialize,
P: AsRef<Path>,
{
let serialized = serde_yaml::to_string(config)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
if let Some(outdir) = config_file.as_ref().parent() {
create_dir_all(outdir)?;
}
let mut file = File::create(config_file)?;
file.write_all(&serialized.into_bytes())?;
Ok(())
}

View File

@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.com>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "1.0.0"
version = "1.1.24"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@ -11,44 +11,49 @@ homepage = "https://solana.com/"
[dependencies]
bincode = "1.2.1"
bs58 = "0.3.0"
chrono = { version = "0.4.10", features = ["serde"] }
chrono = { version = "0.4.11", features = ["serde"] }
clap = "2.33.0"
criterion-stats = "0.3.0"
ctrlc = { version = "3.1.4", features = ["termination"] }
console = "0.9.2"
console = "0.10.0"
dirs = "2.0.2"
log = "0.4.8"
Inflector = "0.11.4"
indicatif = "0.14.0"
humantime = "2.0.0"
num-traits = "0.2"
pretty-hex = "0.1.1"
reqwest = { version = "0.10.1", default-features = false, features = ["blocking", "rustls-tls"] }
serde = "1.0.104"
reqwest = { version = "0.10.4", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serde = "1.0.105"
serde_derive = "1.0.103"
serde_json = "1.0.46"
solana-budget-program = { path = "../programs/budget", version = "1.0.0" }
solana-clap-utils = { path = "../clap-utils", version = "1.0.0" }
solana-cli-config = { path = "../cli-config", version = "1.0.0" }
solana-client = { path = "../client", version = "1.0.0" }
solana-config-program = { path = "../programs/config", version = "1.0.0" }
solana-faucet = { path = "../faucet", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.0.0" }
solana-net-utils = { path = "../net-utils", version = "1.0.0" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.0.0" }
solana-runtime = { path = "../runtime", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
solana-stake-program = { path = "../programs/stake", version = "1.0.0" }
solana-storage-program = { path = "../programs/storage", version = "1.0.0" }
solana-vote-program = { path = "../programs/vote", version = "1.0.0" }
solana-vote-signer = { path = "../vote-signer", version = "1.0.0" }
titlecase = "1.1.0"
serde_json = "1.0.48"
solana-budget-program = { path = "../programs/budget", version = "1.1.24" }
solana-clap-utils = { path = "../clap-utils", version = "1.1.24" }
solana-cli-config = { path = "../cli-config", version = "1.1.24" }
solana-client = { path = "../client", version = "1.1.24" }
solana-config-program = { path = "../programs/config", version = "1.1.24" }
solana-faucet = { path = "../faucet", version = "1.1.24" }
solana-logger = { path = "../logger", version = "1.1.24" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.24" }
solana-runtime = { path = "../runtime", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
solana-stake-program = { path = "../programs/stake", version = "1.1.24" }
solana-storage-program = { path = "../programs/storage", version = "1.1.24" }
solana-transaction-status = { path = "../transaction-status", version = "1.1.24" }
solana-vote-program = { path = "../programs/vote", version = "1.1.24" }
solana-vote-signer = { path = "../vote-signer", version = "1.1.24" }
thiserror = "1.0.13"
url = "2.1.1"
[dev-dependencies]
solana-core = { path = "../core", version = "1.0.0" }
solana-budget-program = { path = "../programs/budget", version = "1.0.0" }
solana-core = { path = "../core", version = "1.1.24" }
solana-budget-program = { path = "../programs/budget", version = "1.1.24" }
tempfile = "3.1.0"
[[bin]]
name = "solana"
path = "src/main.rs"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

File diff suppressed because it is too large Load Diff

982
cli/src/cli_output.rs Normal file
View File

@ -0,0 +1,982 @@
use crate::{cli::build_balance_message, display::writeln_name_value};
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
use console::{style, Emoji};
use inflector::cases::titlecase::to_title_case;
use serde::Serialize;
use serde_json::{Map, Value};
use solana_client::rpc_response::{
RpcAccountBalance, RpcEpochInfo, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
};
use solana_sdk::{
clock::{self, Epoch, Slot, UnixTimestamp},
native_token::lamports_to_sol,
stake_history::StakeHistoryEntry,
};
use solana_stake_program::stake_state::{Authorized, Lockup};
use solana_vote_program::{
authorized_voters::AuthorizedVoters,
vote_state::{BlockTimestamp, Lockout},
};
use std::{collections::BTreeMap, fmt, time::Duration};
static WARNING: Emoji = Emoji("⚠️", "!");
#[derive(PartialEq)]
pub enum OutputFormat {
Display,
Json,
JsonCompact,
}
impl OutputFormat {
pub fn formatted_string<T>(&self, item: &T) -> String
where
T: Serialize + fmt::Display,
{
match self {
OutputFormat::Display => format!("{}", item),
OutputFormat::Json => serde_json::to_string_pretty(item).unwrap(),
OutputFormat::JsonCompact => serde_json::to_value(item).unwrap().to_string(),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct CliAccount {
#[serde(flatten)]
pub keyed_account: RpcKeyedAccount,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl fmt::Display for CliAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Public Key:", &self.keyed_account.pubkey)?;
writeln_name_value(
f,
"Balance:",
&build_balance_message(
self.keyed_account.account.lamports,
self.use_lamports_unit,
true,
),
)?;
writeln_name_value(f, "Owner:", &self.keyed_account.account.owner)?;
writeln_name_value(
f,
"Executable:",
&self.keyed_account.account.executable.to_string(),
)?;
writeln_name_value(
f,
"Rent Epoch:",
&self.keyed_account.account.rent_epoch.to_string(),
)?;
Ok(())
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct CliBlockProduction {
pub epoch: Epoch,
pub start_slot: Slot,
pub end_slot: Slot,
pub total_slots: usize,
pub total_blocks_produced: usize,
pub total_slots_skipped: usize,
pub leaders: Vec<CliBlockProductionEntry>,
pub individual_slot_status: Vec<CliSlotStatus>,
#[serde(skip_serializing)]
pub verbose: bool,
}
impl fmt::Display for CliBlockProduction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln!(
f,
"{}",
style(format!(
" {:<44} {:>15} {:>15} {:>15} {:>23}",
"Identity Pubkey",
"Leader Slots",
"Blocks Produced",
"Skipped Slots",
"Skipped Slot Percentage",
))
.bold()
)?;
for leader in &self.leaders {
writeln!(
f,
" {:<44} {:>15} {:>15} {:>15} {:>22.2}%",
leader.identity_pubkey,
leader.leader_slots,
leader.blocks_produced,
leader.skipped_slots,
leader.skipped_slots as f64 / leader.leader_slots as f64 * 100.
)?;
}
writeln!(f)?;
writeln!(
f,
" {:<44} {:>15} {:>15} {:>15} {:>22.2}%",
format!("Epoch {} total:", self.epoch),
self.total_slots,
self.total_blocks_produced,
self.total_slots_skipped,
self.total_slots_skipped as f64 / self.total_slots as f64 * 100.
)?;
writeln!(
f,
" (using data from {} slots: {} to {})",
self.total_slots, self.start_slot, self.end_slot
)?;
if self.verbose {
writeln!(f)?;
writeln!(f)?;
writeln!(
f,
"{}",
style(format!(" {:<15} {:<44}", "Slot", "Identity Pubkey")).bold(),
)?;
for status in &self.individual_slot_status {
if status.skipped {
writeln!(
f,
"{}",
style(format!(
" {:<15} {:<44} SKIPPED",
status.slot, status.leader
))
.red()
)?;
} else {
writeln!(
f,
"{}",
style(format!(" {:<15} {:<44}", status.slot, status.leader))
)?;
}
}
}
Ok(())
}
}
#[derive(Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliBlockProductionEntry {
pub identity_pubkey: String,
pub leader_slots: u64,
pub blocks_produced: u64,
pub skipped_slots: u64,
}
#[derive(Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliSlotStatus {
pub slot: Slot,
pub leader: String,
pub skipped: bool,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliEpochInfo {
#[serde(flatten)]
pub epoch_info: RpcEpochInfo,
}
impl From<RpcEpochInfo> for CliEpochInfo {
fn from(epoch_info: RpcEpochInfo) -> Self {
Self { epoch_info }
}
}
impl fmt::Display for CliEpochInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Slot:", &self.epoch_info.absolute_slot.to_string())?;
writeln_name_value(f, "Epoch:", &self.epoch_info.epoch.to_string())?;
let start_slot = self.epoch_info.absolute_slot - self.epoch_info.slot_index;
let end_slot = start_slot + self.epoch_info.slots_in_epoch;
writeln_name_value(
f,
"Epoch Slot Range:",
&format!("[{}..{})", start_slot, end_slot),
)?;
writeln_name_value(
f,
"Epoch Completed Percent:",
&format!(
"{:>3.3}%",
self.epoch_info.slot_index as f64 / self.epoch_info.slots_in_epoch as f64 * 100_f64
),
)?;
let remaining_slots_in_epoch = self.epoch_info.slots_in_epoch - self.epoch_info.slot_index;
writeln_name_value(
f,
"Epoch Completed Slots:",
&format!(
"{}/{} ({} remaining)",
self.epoch_info.slot_index,
self.epoch_info.slots_in_epoch,
remaining_slots_in_epoch
),
)?;
writeln_name_value(
f,
"Epoch Completed Time:",
&format!(
"{}/{} ({} remaining)",
slot_to_human_time(self.epoch_info.slot_index),
slot_to_human_time(self.epoch_info.slots_in_epoch),
slot_to_human_time(remaining_slots_in_epoch)
),
)
}
}
fn slot_to_human_time(slot: Slot) -> String {
humantime::format_duration(Duration::from_secs(
slot * clock::DEFAULT_TICKS_PER_SLOT / clock::DEFAULT_TICKS_PER_SECOND,
))
.to_string()
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliValidators {
pub total_active_stake: u64,
pub total_current_stake: u64,
pub total_deliquent_stake: u64,
pub current_validators: Vec<CliValidator>,
pub delinquent_validators: Vec<CliValidator>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl fmt::Display for CliValidators {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn write_vote_account(
f: &mut fmt::Formatter,
validator: &CliValidator,
total_active_stake: u64,
use_lamports_unit: bool,
delinquent: bool,
) -> fmt::Result {
fn non_zero_or_dash(v: u64) -> String {
if v == 0 {
"-".into()
} else {
format!("{}", v)
}
}
writeln!(
f,
"{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>7} {}",
if delinquent {
WARNING.to_string()
} else {
" ".to_string()
},
validator.identity_pubkey,
validator.vote_account_pubkey,
validator.commission,
non_zero_or_dash(validator.last_vote),
non_zero_or_dash(validator.root_slot),
validator.credits,
if validator.activated_stake > 0 {
format!(
"{} ({:.2}%)",
build_balance_message(validator.activated_stake, use_lamports_unit, true),
100. * validator.activated_stake as f64 / total_active_stake as f64
)
} else {
"-".into()
},
)
}
writeln_name_value(
f,
"Active Stake:",
&build_balance_message(self.total_active_stake, self.use_lamports_unit, true),
)?;
if self.total_deliquent_stake > 0 {
writeln_name_value(
f,
"Current Stake:",
&format!(
"{} ({:0.2}%)",
&build_balance_message(self.total_current_stake, self.use_lamports_unit, true),
100. * self.total_current_stake as f64 / self.total_active_stake as f64
),
)?;
writeln_name_value(
f,
"Delinquent Stake:",
&format!(
"{} ({:0.2}%)",
&build_balance_message(
self.total_deliquent_stake,
self.use_lamports_unit,
true
),
100. * self.total_deliquent_stake as f64 / self.total_active_stake as f64
),
)?;
}
writeln!(f)?;
writeln!(
f,
"{}",
style(format!(
" {:<44} {:<44} {} {} {} {:>7} {}",
"Identity Pubkey",
"Vote Account Pubkey",
"Commission",
"Last Vote",
"Root Block",
"Credits",
"Active Stake",
))
.bold()
)?;
for validator in &self.current_validators {
write_vote_account(
f,
validator,
self.total_active_stake,
self.use_lamports_unit,
false,
)?;
}
for validator in &self.delinquent_validators {
write_vote_account(
f,
validator,
self.total_active_stake,
self.use_lamports_unit,
true,
)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliValidator {
pub identity_pubkey: String,
pub vote_account_pubkey: String,
pub commission: u8,
pub last_vote: u64,
pub root_slot: u64,
pub credits: u64,
pub activated_stake: u64,
}
impl CliValidator {
pub fn new(vote_account: &RpcVoteAccountInfo, current_epoch: Epoch) -> Self {
Self {
identity_pubkey: vote_account.node_pubkey.to_string(),
vote_account_pubkey: vote_account.vote_pubkey.to_string(),
commission: vote_account.commission,
last_vote: vote_account.last_vote,
root_slot: vote_account.root_slot,
credits: vote_account
.epoch_credits
.iter()
.find_map(|(epoch, credits, _)| {
if *epoch == current_epoch {
Some(*credits)
} else {
None
}
})
.unwrap_or(0),
activated_stake: vote_account.activated_stake,
}
}
}
#[derive(Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliNonceAccount {
pub balance: u64,
pub minimum_balance_for_rent_exemption: u64,
pub nonce: Option<String>,
pub lamports_per_signature: Option<u64>,
pub authority: Option<String>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl fmt::Display for CliNonceAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"Balance: {}",
build_balance_message(self.balance, self.use_lamports_unit, true)
)?;
writeln!(
f,
"Minimum Balance Required: {}",
build_balance_message(
self.minimum_balance_for_rent_exemption,
self.use_lamports_unit,
true
)
)?;
let nonce = self.nonce.as_deref().unwrap_or("uninitialized");
writeln!(f, "Nonce: {}", nonce)?;
if let Some(fees) = self.lamports_per_signature {
writeln!(f, "Fee: {} lamports per signature", fees)?;
} else {
writeln!(f, "Fees: uninitialized")?;
}
let authority = self.authority.as_deref().unwrap_or("uninitialized");
writeln!(f, "Authority: {}", authority)
}
}
#[derive(Serialize, Deserialize)]
pub struct CliStakeVec(Vec<CliKeyedStakeState>);
impl CliStakeVec {
pub fn new(list: Vec<CliKeyedStakeState>) -> Self {
Self(list)
}
}
impl fmt::Display for CliStakeVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for state in &self.0 {
writeln!(f)?;
write!(f, "{}", state)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliKeyedStakeState {
pub stake_pubkey: String,
#[serde(flatten)]
pub stake_state: CliStakeState,
}
impl fmt::Display for CliKeyedStakeState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Stake Pubkey: {}", self.stake_pubkey)?;
write!(f, "{}", self.stake_state)
}
}
#[derive(Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliStakeState {
pub stake_type: CliStakeType,
pub total_stake: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub delegated_stake: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub delegated_vote_account_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub activation_epoch: Option<Epoch>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deactivation_epoch: Option<Epoch>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub authorized: Option<CliAuthorized>,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub lockup: Option<CliLockup>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl fmt::Display for CliStakeState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn show_authorized(f: &mut fmt::Formatter, authorized: &CliAuthorized) -> fmt::Result {
writeln!(f, "Stake Authority: {}", authorized.staker)?;
writeln!(f, "Withdraw Authority: {}", authorized.withdrawer)?;
Ok(())
}
fn show_lockup(f: &mut fmt::Formatter, lockup: &CliLockup) -> fmt::Result {
writeln!(
f,
"Lockup Timestamp: {} (UnixTimestamp: {})",
DateTime::<Utc>::from_utc(
NaiveDateTime::from_timestamp(lockup.unix_timestamp, 0),
Utc
)
.to_rfc3339_opts(SecondsFormat::Secs, true),
lockup.unix_timestamp
)?;
writeln!(f, "Lockup Epoch: {}", lockup.epoch)?;
writeln!(f, "Lockup Custodian: {}", lockup.custodian)?;
Ok(())
}
match self.stake_type {
CliStakeType::RewardsPool => writeln!(f, "Stake account is a rewards pool")?,
CliStakeType::Uninitialized => writeln!(f, "Stake account is uninitialized")?,
CliStakeType::Initialized => {
writeln!(
f,
"Total Stake: {}",
build_balance_message(self.total_stake, self.use_lamports_unit, true)
)?;
writeln!(f, "Stake account is undelegated")?;
show_authorized(f, self.authorized.as_ref().unwrap())?;
show_lockup(f, self.lockup.as_ref().unwrap())?;
}
CliStakeType::Stake => {
writeln!(
f,
"Total Stake: {}",
build_balance_message(self.total_stake, self.use_lamports_unit, true)
)?;
writeln!(
f,
"Delegated Stake: {}",
build_balance_message(
self.delegated_stake.unwrap(),
self.use_lamports_unit,
true
)
)?;
if let Some(delegated_vote_account_address) = &self.delegated_vote_account_address {
writeln!(
f,
"Delegated Vote Account Address: {}",
delegated_vote_account_address
)?;
}
writeln!(
f,
"Stake activates starting from epoch: {}",
self.activation_epoch.unwrap()
)?;
if let Some(deactivation_epoch) = self.deactivation_epoch {
writeln!(
f,
"Stake deactivates starting from epoch: {}",
deactivation_epoch
)?;
}
show_authorized(f, self.authorized.as_ref().unwrap())?;
show_lockup(f, self.lockup.as_ref().unwrap())?;
}
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
pub enum CliStakeType {
Stake,
RewardsPool,
Uninitialized,
Initialized,
}
impl Default for CliStakeType {
fn default() -> Self {
Self::Uninitialized
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliStakeHistory {
pub entries: Vec<CliStakeHistoryEntry>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl fmt::Display for CliStakeHistory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln!(
f,
"{}",
style(format!(
" {:<5} {:>20} {:>20} {:>20}",
"Epoch", "Effective Stake", "Activating Stake", "Deactivating Stake",
))
.bold()
)?;
for entry in &self.entries {
writeln!(
f,
" {:>5} {:>20} {:>20} {:>20} {}",
entry.epoch,
build_balance_message(entry.effective_stake, self.use_lamports_unit, false),
build_balance_message(entry.activating_stake, self.use_lamports_unit, false),
build_balance_message(entry.deactivating_stake, self.use_lamports_unit, false),
if self.use_lamports_unit {
"lamports"
} else {
"SOL"
}
)?;
}
Ok(())
}
}
impl From<&(Epoch, StakeHistoryEntry)> for CliStakeHistoryEntry {
fn from((epoch, entry): &(Epoch, StakeHistoryEntry)) -> Self {
Self {
epoch: *epoch,
effective_stake: entry.effective,
activating_stake: entry.activating,
deactivating_stake: entry.deactivating,
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliStakeHistoryEntry {
pub epoch: Epoch,
pub effective_stake: u64,
pub activating_stake: u64,
pub deactivating_stake: u64,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliAuthorized {
pub staker: String,
pub withdrawer: String,
}
impl From<&Authorized> for CliAuthorized {
fn from(authorized: &Authorized) -> Self {
Self {
staker: authorized.staker.to_string(),
withdrawer: authorized.withdrawer.to_string(),
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliLockup {
pub unix_timestamp: UnixTimestamp,
pub epoch: Epoch,
pub custodian: String,
}
impl From<&Lockup> for CliLockup {
fn from(lockup: &Lockup) -> Self {
Self {
unix_timestamp: lockup.unix_timestamp,
epoch: lockup.epoch,
custodian: lockup.custodian.to_string(),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct CliValidatorInfoVec(Vec<CliValidatorInfo>);
impl CliValidatorInfoVec {
pub fn new(list: Vec<CliValidatorInfo>) -> Self {
Self(list)
}
}
impl fmt::Display for CliValidatorInfoVec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.0.is_empty() {
writeln!(f, "No validator info accounts found")?;
}
for validator_info in &self.0 {
writeln!(f)?;
write!(f, "{}", validator_info)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliValidatorInfo {
pub identity_pubkey: String,
pub info_pubkey: String,
pub info: Map<String, Value>,
}
impl fmt::Display for CliValidatorInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Validator Identity Pubkey:", &self.identity_pubkey)?;
writeln_name_value(f, " Info Pubkey:", &self.info_pubkey)?;
for (key, value) in self.info.iter() {
writeln_name_value(
f,
&format!(" {}:", to_title_case(key)),
&value.as_str().unwrap_or("?"),
)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliVoteAccount {
pub account_balance: u64,
pub validator_identity: String,
#[serde(flatten)]
pub authorized_voters: CliAuthorizedVoters,
pub authorized_withdrawer: String,
pub credits: u64,
pub commission: u8,
pub root_slot: Option<Slot>,
pub recent_timestamp: BlockTimestamp,
pub votes: Vec<CliLockout>,
pub epoch_voting_history: Vec<CliEpochVotingHistory>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
}
impl fmt::Display for CliVoteAccount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"Account Balance: {}",
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, "Credits: {}", self.credits)?;
writeln!(f, "Commission: {}%", self.commission)?;
writeln!(
f,
"Root Slot: {}",
match self.root_slot {
Some(slot) => slot.to_string(),
None => "~".to_string(),
}
)?;
writeln!(f, "Recent Timestamp: {:?}", self.recent_timestamp)?;
if !self.votes.is_empty() {
writeln!(f, "Recent Votes:")?;
for vote in &self.votes {
writeln!(
f,
"- slot: {}\n confirmation count: {}",
vote.slot, vote.confirmation_count
)?;
}
writeln!(f, "Epoch Voting History:")?;
for epoch_info in &self.epoch_voting_history {
writeln!(
f,
"- epoch: {}\n slots in epoch: {}\n credits earned: {}",
epoch_info.epoch, epoch_info.slots_in_epoch, epoch_info.credits_earned,
)?;
}
}
Ok(())
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliAuthorizedVoters {
authorized_voters: BTreeMap<Epoch, String>,
}
impl fmt::Display for CliAuthorizedVoters {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.authorized_voters)
}
}
impl From<&AuthorizedVoters> for CliAuthorizedVoters {
fn from(authorized_voters: &AuthorizedVoters) -> Self {
let mut voter_map: BTreeMap<Epoch, String> = BTreeMap::new();
for (epoch, voter) in authorized_voters.iter() {
voter_map.insert(*epoch, voter.to_string());
}
Self {
authorized_voters: voter_map,
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliEpochVotingHistory {
pub epoch: Epoch,
pub slots_in_epoch: u64,
pub credits_earned: u64,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliLockout {
pub slot: Slot,
pub confirmation_count: u32,
}
impl From<&Lockout> for CliLockout {
fn from(lockout: &Lockout) -> Self {
Self {
slot: lockout.slot,
confirmation_count: lockout.confirmation_count,
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliBlockTime {
pub slot: Slot,
pub timestamp: UnixTimestamp,
}
impl fmt::Display for CliBlockTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Block:", &self.slot.to_string())?;
writeln_name_value(
f,
"Date:",
&format!(
"{} (UnixTimestamp: {})",
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(self.timestamp, 0), Utc)
.to_rfc3339_opts(SecondsFormat::Secs, true),
self.timestamp
),
)
}
}
#[derive(Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CliSignOnlyData {
pub blockhash: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub signers: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub absent: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub bad_sig: Vec<String>,
}
impl fmt::Display for CliSignOnlyData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Blockhash:", &self.blockhash)?;
if !self.signers.is_empty() {
writeln!(f, "{}", style("Signers (Pubkey=Signature):").bold())?;
for signer in self.signers.iter() {
writeln!(f, " {}", signer)?;
}
}
if !self.absent.is_empty() {
writeln!(f, "{}", style("Absent Signers (Pubkey):").bold())?;
for pubkey in self.absent.iter() {
writeln!(f, " {}", pubkey)?;
}
}
if !self.bad_sig.is_empty() {
writeln!(f, "{}", style("Bad Signatures (Pubkey):").bold())?;
for pubkey in self.bad_sig.iter() {
writeln!(f, " {}", pubkey)?;
}
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
pub struct CliSignature {
pub signature: String,
}
impl fmt::Display for CliSignature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Signature:", &self.signature)?;
Ok(())
}
}
#[derive(Serialize, Deserialize)]
pub struct CliAccountBalances {
pub accounts: Vec<RpcAccountBalance>,
}
impl fmt::Display for CliAccountBalances {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"{}",
style(format!("{:<44} {}", "Address", "Balance",)).bold()
)?;
for account in &self.accounts {
writeln!(
f,
"{:<44} {}",
account.address,
&format!("{} SOL", lamports_to_sol(account.lamports))
)?;
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
pub struct CliSupply {
pub total: u64,
pub circulating: u64,
pub non_circulating: u64,
pub non_circulating_accounts: Vec<String>,
#[serde(skip_serializing)]
pub print_accounts: bool,
}
impl From<RpcSupply> for CliSupply {
fn from(rpc_supply: RpcSupply) -> Self {
Self {
total: rpc_supply.total,
circulating: rpc_supply.circulating,
non_circulating: rpc_supply.non_circulating,
non_circulating_accounts: rpc_supply.non_circulating_accounts,
print_accounts: false,
}
}
}
impl fmt::Display for CliSupply {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln_name_value(f, "Total:", &format!("{} SOL", lamports_to_sol(self.total)))?;
writeln_name_value(
f,
"Circulating:",
&format!("{} SOL", lamports_to_sol(self.circulating)),
)?;
writeln_name_value(
f,
"Non-Circulating:",
&format!("{} SOL", lamports_to_sol(self.non_circulating)),
)?;
if self.print_accounts {
writeln!(f)?;
writeln_name_value(f, "Non-Circulating Accounts:", " ")?;
for account in &self.non_circulating_accounts {
writeln!(f, " {}", account)?;
}
}
Ok(())
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,12 @@
use crate::cli::SettingType;
use console::style;
use solana_sdk::transaction::Transaction;
use indicatif::{ProgressBar, ProgressStyle};
use solana_sdk::{
hash::Hash, native_token::lamports_to_sol, program_utils::limited_deserialize,
transaction::Transaction,
};
use solana_transaction_status::RpcTransactionStatusMeta;
use std::{fmt, io};
// Pretty print a "name value"
pub fn println_name_value(name: &str, value: &str) {
@ -11,26 +18,195 @@ pub fn println_name_value(name: &str, value: &str) {
println!("{} {}", style(name).bold(), styled_value);
}
pub fn println_name_value_or(name: &str, value: &str, default_value: &str) {
if value == "" {
println!(
"{} {} {}",
style(name).bold(),
style(default_value),
style("(default)").italic()
);
pub fn writeln_name_value(f: &mut fmt::Formatter, name: &str, value: &str) -> fmt::Result {
let styled_value = if value == "" {
style("(not set)").italic()
} else {
println!("{} {}", style(name).bold(), style(value));
style(value)
};
writeln!(f, "{} {}", style(name).bold(), styled_value)
}
pub fn println_signers(tx: &Transaction) {
pub fn println_name_value_or(name: &str, value: &str, setting_type: SettingType) {
let description = match setting_type {
SettingType::Explicit => "",
SettingType::Computed => "(computed)",
SettingType::SystemDefault => "(default)",
};
println!(
"{} {} {}",
style(name).bold(),
style(value),
style(description).italic(),
);
}
pub fn println_signers(
blockhash: &Hash,
signers: &[String],
absent: &[String],
bad_sig: &[String],
) {
println!();
println!("Blockhash: {}", tx.message.recent_blockhash);
println!("Signers (Pubkey=Signature):");
tx.signatures
.iter()
.zip(tx.message.account_keys.clone())
.for_each(|(signature, pubkey)| println!(" {:?}={:?}", pubkey, signature));
println!("Blockhash: {}", blockhash);
if !signers.is_empty() {
println!("Signers (Pubkey=Signature):");
signers.iter().for_each(|signer| println!(" {}", signer))
}
if !absent.is_empty() {
println!("Absent Signers (Pubkey):");
absent.iter().for_each(|pubkey| println!(" {}", pubkey))
}
if !bad_sig.is_empty() {
println!("Bad Signatures (Pubkey):");
bad_sig.iter().for_each(|pubkey| println!(" {}", pubkey))
}
println!();
}
pub fn write_transaction<W: io::Write>(
w: &mut W,
transaction: &Transaction,
transaction_status: &Option<RpcTransactionStatusMeta>,
prefix: &str,
) -> io::Result<()> {
let message = &transaction.message;
writeln!(
w,
"{}Recent Blockhash: {:?}",
prefix, message.recent_blockhash
)?;
for (signature_index, signature) in transaction.signatures.iter().enumerate() {
writeln!(
w,
"{}Signature {}: {:?}",
prefix, signature_index, signature
)?;
}
writeln!(w, "{}{:?}", prefix, message.header)?;
for (account_index, account) in message.account_keys.iter().enumerate() {
writeln!(w, "{}Account {}: {:?}", prefix, account_index, account)?;
}
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
let program_pubkey = message.account_keys[instruction.program_id_index as usize];
writeln!(w, "{}Instruction {}", prefix, instruction_index)?;
writeln!(
w,
"{} Program: {} ({})",
prefix, program_pubkey, instruction.program_id_index
)?;
for (account_index, account) in instruction.accounts.iter().enumerate() {
let account_pubkey = message.account_keys[*account as usize];
writeln!(
w,
"{} Account {}: {} ({})",
prefix, account_index, account_pubkey, account
)?;
}
let mut raw = true;
if program_pubkey == solana_vote_program::id() {
if let Ok(vote_instruction) = limited_deserialize::<
solana_vote_program::vote_instruction::VoteInstruction,
>(&instruction.data)
{
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)
{
writeln!(w, "{} {:?}", prefix, stake_instruction)?;
raw = false;
}
} else if program_pubkey == solana_sdk::system_program::id() {
if let Ok(system_instruction) = limited_deserialize::<
solana_sdk::system_instruction::SystemInstruction,
>(&instruction.data)
{
writeln!(w, "{} {:?}", prefix, system_instruction)?;
raw = false;
}
}
if raw {
writeln!(w, "{} Data: {:?}", prefix, instruction.data)?;
}
}
if let Some(transaction_status) = transaction_status {
writeln!(
w,
"{}Status: {}",
prefix,
match &transaction_status.status {
Ok(_) => "Ok".into(),
Err(err) => err.to_string(),
}
)?;
writeln!(
w,
"{} Fee: {} SOL",
prefix,
lamports_to_sol(transaction_status.fee)
)?;
assert_eq!(
transaction_status.pre_balances.len(),
transaction_status.post_balances.len()
);
for (i, (pre, post)) in transaction_status
.pre_balances
.iter()
.zip(transaction_status.post_balances.iter())
.enumerate()
{
if pre == post {
writeln!(
w,
"{} Account {} balance: {} SOL",
prefix,
i,
lamports_to_sol(*pre)
)?;
} else {
writeln!(
w,
"{} Account {} balance: {} SOL -> {} SOL",
prefix,
i,
lamports_to_sol(*pre),
lamports_to_sol(*post)
)?;
}
}
} else {
writeln!(w, "{}Status: Unavailable", prefix)?;
}
Ok(())
}
pub fn println_transaction(
transaction: &Transaction,
transaction_status: &Option<RpcTransactionStatusMeta>,
prefix: &str,
) {
let mut w = Vec::new();
if write_transaction(&mut w, transaction, transaction_status, prefix).is_ok() {
if let Ok(s) = String::from_utf8(w) {
print!("{}", s);
}
}
}
/// Creates a new process bar for processing that will take an unknown amount of time
pub fn new_spinner_progress_bar() -> ProgressBar {
let progress_bar = ProgressBar::new(42);
progress_bar
.set_style(ProgressStyle::default_spinner().template("{spinner:.green} {wide_msg}"));
progress_bar.enable_steady_tick(100);
progress_bar
}

View File

@ -1,4 +1,8 @@
#[macro_use]
extern crate serde_derive;
pub mod cli;
pub mod cli_output;
pub mod cluster_query;
pub mod display;
pub mod nonce;

View File

@ -2,17 +2,16 @@ use clap::{crate_description, crate_name, AppSettings, Arg, ArgGroup, ArgMatches
use console::style;
use solana_clap_utils::{
input_parsers::derivation_of,
input_validators::{is_derivation, is_url},
keypair::{keypair_util_from_path, SKIP_SEED_PHRASE_VALIDATION_ARG},
input_validators::is_url, keypair::SKIP_SEED_PHRASE_VALIDATION_ARG, DisplayError,
};
use solana_cli::{
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliError},
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliSigners},
cli_output::OutputFormat,
display::{println_name_value, println_name_value_or},
};
use solana_cli_config::config::{Config, CONFIG_FILE};
use std::error;
use solana_cli_config::{Config, CONFIG_FILE};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use std::{error, sync::Arc};
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
let parse_args = match matches.subcommand() {
@ -20,29 +19,31 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
("get", Some(subcommand_matches)) => {
if let Some(config_file) = matches.value_of("config_file") {
let config = Config::load(config_file).unwrap_or_default();
let (url_setting_type, json_rpc_url) =
CliConfig::compute_json_rpc_url_setting("", &config.json_rpc_url);
let (ws_setting_type, websocket_url) = CliConfig::compute_websocket_url_setting(
"",
&config.websocket_url,
"",
&config.json_rpc_url,
);
let (keypair_setting_type, keypair_path) =
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
if let Some(field) = subcommand_matches.value_of("specific_setting") {
let (field_name, value, default_value) = match field {
"url" => ("RPC URL", config.url, CliConfig::default_json_rpc_url()),
"keypair" => (
"Key Path",
config.keypair_path,
CliConfig::default_keypair_path(),
),
let (field_name, value, setting_type) = match field {
"json_rpc_url" => ("RPC URL", json_rpc_url, url_setting_type),
"websocket_url" => ("WebSocket URL", websocket_url, ws_setting_type),
"keypair" => ("Key Path", keypair_path, keypair_setting_type),
_ => unreachable!(),
};
println_name_value_or(&format!("{}:", field_name), &value, &default_value);
println_name_value_or(&format!("{}:", field_name), &value, setting_type);
} else {
println_name_value("Config File:", config_file);
println_name_value_or(
"RPC URL:",
&config.url,
&CliConfig::default_json_rpc_url(),
);
println_name_value_or(
"Keypair Path:",
&config.keypair_path,
&CliConfig::default_keypair_path(),
);
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
}
} else {
println!(
@ -56,15 +57,34 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
if let Some(config_file) = matches.value_of("config_file") {
let mut config = Config::load(config_file).unwrap_or_default();
if let Some(url) = subcommand_matches.value_of("json_rpc_url") {
config.url = url.to_string();
config.json_rpc_url = url.to_string();
// Revert to a computed `websocket_url` value when `json_rpc_url` is
// changed
config.websocket_url = "".to_string();
}
if let Some(url) = subcommand_matches.value_of("websocket_url") {
config.websocket_url = url.to_string();
}
if let Some(keypair) = subcommand_matches.value_of("keypair") {
config.keypair_path = keypair.to_string();
}
config.save(config_file)?;
let (url_setting_type, json_rpc_url) =
CliConfig::compute_json_rpc_url_setting("", &config.json_rpc_url);
let (ws_setting_type, websocket_url) = CliConfig::compute_websocket_url_setting(
"",
&config.websocket_url,
"",
&config.json_rpc_url,
);
let (keypair_setting_type, keypair_path) =
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
println_name_value("Config File:", config_file);
println_name_value("RPC URL:", &config.url);
println_name_value("Keypair Path:", &config.keypair_path);
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
} else {
println!(
"{} Either provide the `--config` arg or ensure home directory exists to use the default config location",
@ -80,59 +100,55 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
Ok(parse_args)
}
pub fn parse_args(matches: &ArgMatches<'_>) -> Result<CliConfig, Box<dyn error::Error>> {
pub fn parse_args<'a>(
matches: &ArgMatches<'_>,
mut wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<(CliConfig<'a>, CliSigners), Box<dyn error::Error>> {
let config = if let Some(config_file) = matches.value_of("config_file") {
Config::load(config_file).unwrap_or_default()
} else {
Config::default()
};
let json_rpc_url = if let Some(url) = matches.value_of("json_rpc_url") {
url.to_string()
} else if config.url != "" {
config.url
} else {
let default = CliConfig::default();
default.json_rpc_url
};
let (_, json_rpc_url) = CliConfig::compute_json_rpc_url_setting(
matches.value_of("json_rpc_url").unwrap_or(""),
&config.json_rpc_url,
);
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_path) = CliConfig::compute_keypair_path_setting(
matches.value_of("keypair").unwrap_or(""),
&config.keypair_path,
);
let CliCommandInfo {
command,
require_keypair,
} = parse_command(&matches)?;
let CliCommandInfo { command, signers } =
parse_command(&matches, &default_signer_path, &mut wallet_manager)?;
let (keypair, keypair_path) = if require_keypair {
let path = if matches.is_present("keypair") {
matches.value_of("keypair").unwrap().to_string()
} else if config.keypair_path != "" {
config.keypair_path
} else {
let default_keypair_path = CliConfig::default_keypair_path();
if !std::path::Path::new(&default_keypair_path).exists() {
return Err(CliError::KeypairFileNotFound(format!(
"Generate a new keypair at {} with `solana-keygen new`",
default_keypair_path
))
.into());
}
default_keypair_path
};
let output_format = matches
.value_of("output_format")
.map(|value| match value {
"json" => OutputFormat::Json,
"json-compact" => OutputFormat::JsonCompact,
_ => unreachable!(),
})
.unwrap_or(OutputFormat::Display);
let keypair = keypair_util_from_path(matches, &path, "keypair")?;
(keypair, Some(path))
} else {
let default = CliConfig::default();
(default.keypair, None)
};
Ok(CliConfig {
command,
json_rpc_url,
keypair,
keypair_path,
derivation_path: derivation_of(matches, "derivation_path"),
rpc_client: None,
verbose: matches.is_present("verbose"),
})
Ok((
CliConfig {
command,
json_rpc_url,
websocket_url,
signers: vec![],
keypair_path: default_signer_path,
rpc_client: None,
verbose: matches.is_present("verbose"),
output_format,
},
signers,
))
}
fn main() -> Result<(), Box<dyn error::Error>> {
@ -146,7 +162,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
let arg = Arg::with_name("config_file")
.short("C")
.long("config")
.value_name("PATH")
.value_name("FILEPATH")
.takes_value(true)
.global(true)
.help("Configuration file to use");
@ -166,30 +182,38 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.validator(is_url)
.help("JSON RPC URL for the solana cluster"),
)
.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("PATH")
.value_name("KEYPAIR")
.global(true)
.takes_value(true)
.help("/path/to/id.json or usb://remote/wallet/path"),
)
.arg(
Arg::with_name("derivation_path")
.long("derivation-path")
.value_name("ACCOUNT or ACCOUNT/CHANGE")
.global(true)
.takes_value(true)
.validator(is_derivation)
.help("Derivation path to use: m/44'/501'/ACCOUNT'/CHANGE'; default key is device base pubkey: m/44'/501'/0'")
.help("Filepath or URL to a keypair"),
)
.arg(
Arg::with_name("verbose")
.long("verbose")
.short("v")
.global(true)
.help("Show extra information header"),
.help("Show additional information"),
)
.arg(
Arg::with_name("output_format")
.long("output")
.global(true)
.takes_value(true)
.possible_values(&["json", "json-compact"])
.help("Return information in specified output format. Supports: json, json-compact"),
)
.arg(
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
@ -210,7 +234,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.index(1)
.value_name("CONFIG_FIELD")
.takes_value(true)
.possible_values(&["url", "keypair"])
.possible_values(&["json_rpc_url", "websocket_url", "keypair"])
.help("Return a specific config setting"),
),
)
@ -219,7 +243,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.about("Set a config setting")
.group(
ArgGroup::with_name("config_settings")
.args(&["json_rpc_url", "keypair"])
.args(&["json_rpc_url", "websocket_url", "keypair"])
.multiple(true)
.required(true),
),
@ -227,10 +251,17 @@ fn main() -> Result<(), Box<dyn error::Error>> {
)
.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)? {
let config = parse_args(&matches)?;
let mut wallet_manager = None;
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);
}
};
Ok(())
}

File diff suppressed because it is too large Load Diff

View File

@ -1,253 +0,0 @@
use clap::{App, Arg, ArgMatches};
use serde_json::Value;
use solana_clap_utils::{
input_parsers::value_of,
input_validators::{is_hash, is_pubkey_sig},
offline::{BLOCKHASH_ARG, SIGNER_ARG, SIGN_ONLY_ARG},
};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::Signature};
use std::str::FromStr;
#[derive(Clone, Debug, PartialEq)]
pub enum BlockhashQuery {
None(Hash, FeeCalculator),
FeeCalculator(Hash),
All,
}
impl BlockhashQuery {
pub fn new(blockhash: Option<Hash>, sign_only: bool) -> Self {
match blockhash {
Some(hash) if sign_only => Self::None(hash, FeeCalculator::default()),
Some(hash) if !sign_only => Self::FeeCalculator(hash),
None if !sign_only => Self::All,
_ => panic!("Cannot resolve blockhash"),
}
}
pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self {
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
BlockhashQuery::new(blockhash, sign_only)
}
pub fn get_blockhash_fee_calculator(
&self,
rpc_client: &RpcClient,
) -> Result<(Hash, FeeCalculator), Box<dyn std::error::Error>> {
let (hash, fee_calc) = match self {
BlockhashQuery::None(hash, fee_calc) => (Some(hash), Some(fee_calc)),
BlockhashQuery::FeeCalculator(hash) => (Some(hash), None),
BlockhashQuery::All => (None, None),
};
if None == fee_calc {
let (cluster_hash, fee_calc) = rpc_client.get_recent_blockhash()?;
Ok((*hash.unwrap_or(&cluster_hash), fee_calc))
} else {
Ok((*hash.unwrap(), fee_calc.unwrap().clone()))
}
}
}
impl Default for BlockhashQuery {
fn default() -> Self {
BlockhashQuery::All
}
}
fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(BLOCKHASH_ARG.name)
.long(BLOCKHASH_ARG.long)
.takes_value(true)
.value_name("BLOCKHASH")
.validator(is_hash)
.help(BLOCKHASH_ARG.help)
}
fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGN_ONLY_ARG.name)
.long(SIGN_ONLY_ARG.long)
.takes_value(false)
.requires(BLOCKHASH_ARG.name)
.help(SIGN_ONLY_ARG.help)
}
fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGNER_ARG.name)
.long(SIGNER_ARG.long)
.takes_value(true)
.value_name("BASE58_PUBKEY=BASE58_SIG")
.validator(is_pubkey_sig)
.requires(BLOCKHASH_ARG.name)
.multiple(true)
.help(SIGNER_ARG.help)
}
pub trait OfflineArgs {
fn offline_args(self) -> Self;
}
impl OfflineArgs for App<'_, '_> {
fn offline_args(self) -> Self {
self.arg(blockhash_arg())
.arg(sign_only_arg())
.arg(signer_arg())
}
}
pub fn parse_sign_only_reply_string(reply: &str) -> (Hash, Vec<(Pubkey, Signature)>) {
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 signer_strings = object.get("signers").unwrap().as_array().unwrap();
let signers = signer_strings
.iter()
.map(|signer_string| {
let mut signer = signer_string.as_str().unwrap().split('=');
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
(key, sig)
})
.collect();
(blockhash, signers)
}
#[cfg(test)]
mod tests {
use super::*;
use clap::App;
use serde_json::{self, json, Value};
use solana_client::{
rpc_request::RpcRequest,
rpc_response::{Response, RpcResponseContext},
};
use solana_sdk::{fee_calculator::FeeCalculator, hash::hash};
use std::collections::HashMap;
#[test]
fn test_blockhashspec_new_ok() {
let blockhash = hash(&[1u8]);
assert_eq!(
BlockhashQuery::new(Some(blockhash), true),
BlockhashQuery::None(blockhash, FeeCalculator::default()),
);
assert_eq!(
BlockhashQuery::new(Some(blockhash), false),
BlockhashQuery::FeeCalculator(blockhash),
);
assert_eq!(BlockhashQuery::new(None, false), BlockhashQuery::All,);
}
#[test]
#[should_panic]
fn test_blockhashspec_new_fail() {
BlockhashQuery::new(None, true);
}
#[test]
fn test_blockhashspec_new_from_matches_ok() {
let test_commands = App::new("blockhashspec_test").offline_args();
let blockhash = hash(&[1u8]);
let blockhash_string = blockhash.to_string();
let matches = test_commands.clone().get_matches_from(vec![
"blockhashspec_test",
"--blockhash",
&blockhash_string,
"--sign-only",
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::None(blockhash, FeeCalculator::default()),
);
let matches = test_commands.clone().get_matches_from(vec![
"blockhashspec_test",
"--blockhash",
&blockhash_string,
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::FeeCalculator(blockhash),
);
let matches = test_commands
.clone()
.get_matches_from(vec!["blockhashspec_test"]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::All,
);
}
#[test]
#[should_panic]
fn test_blockhashspec_new_from_matches_fail() {
let test_commands = App::new("blockhashspec_test")
.arg(blockhash_arg())
// We can really only hit this case unless the arg requirements
// are broken, so unset the requires() to recreate that condition
.arg(sign_only_arg().requires(""));
let matches = test_commands
.clone()
.get_matches_from(vec!["blockhashspec_test", "--sign-only"]);
BlockhashQuery::new_from_matches(&matches);
}
#[test]
fn test_blockhashspec_get_blockhash_fee_calc() {
let test_blockhash = hash(&[0u8]);
let rpc_blockhash = hash(&[1u8]);
let rpc_fee_calc = FeeCalculator::new(42, 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()
)),
});
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::All
.get_blockhash_fee_calculator(&rpc_client)
.unwrap(),
(rpc_blockhash, rpc_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::FeeCalculator(test_blockhash)
.get_blockhash_fee_calculator(&rpc_client)
.unwrap(),
(test_blockhash, rpc_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::None(test_blockhash, FeeCalculator::default())
.get_blockhash_fee_calculator(&rpc_client)
.unwrap(),
(test_blockhash, FeeCalculator::default()),
);
let rpc_client = RpcClient::new_mock("fails".to_string());
assert!(BlockhashQuery::All
.get_blockhash_fee_calculator(&rpc_client)
.is_err());
}
}

View File

@ -0,0 +1,394 @@
use super::*;
#[derive(Debug, PartialEq)]
pub enum Source {
Cluster,
NonceAccount(Pubkey),
}
impl Source {
pub fn get_blockhash_and_fee_calculator(
&self,
rpc_client: &RpcClient,
) -> Result<(Hash, FeeCalculator), Box<dyn std::error::Error>> {
match self {
Self::Cluster => {
let res = rpc_client.get_recent_blockhash()?;
Ok(res)
}
Self::NonceAccount(ref pubkey) => {
let data = nonce::get_account(rpc_client, pubkey)
.and_then(|ref a| nonce::data_from_account(a))?;
Ok((data.blockhash, data.fee_calculator))
}
}
}
pub fn get_fee_calculator(
&self,
rpc_client: &RpcClient,
blockhash: &Hash,
) -> Result<Option<FeeCalculator>, Box<dyn std::error::Error>> {
match self {
Self::Cluster => {
let res = rpc_client.get_fee_calculator_for_blockhash(blockhash)?;
Ok(res)
}
Self::NonceAccount(ref pubkey) => {
let res = nonce::get_account(rpc_client, pubkey)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|d| {
if d.blockhash == *blockhash {
Ok(Some(d.fee_calculator))
} else {
Ok(None)
}
})?;
Ok(res)
}
}
}
}
#[derive(Debug, PartialEq)]
pub enum BlockhashQuery {
None(Hash),
FeeCalculator(Source, Hash),
All(Source),
}
impl BlockhashQuery {
pub fn new(blockhash: Option<Hash>, sign_only: bool, nonce_account: Option<Pubkey>) -> Self {
let source = nonce_account
.map(Source::NonceAccount)
.unwrap_or(Source::Cluster);
match blockhash {
Some(hash) if sign_only => Self::None(hash),
Some(hash) if !sign_only => Self::FeeCalculator(source, hash),
None if !sign_only => Self::All(source),
_ => panic!("Cannot resolve blockhash"),
}
}
pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self {
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let nonce_account = pubkey_of(matches, nonce::NONCE_ARG.name);
BlockhashQuery::new(blockhash, sign_only, nonce_account)
}
pub fn get_blockhash_and_fee_calculator(
&self,
rpc_client: &RpcClient,
) -> Result<(Hash, FeeCalculator), Box<dyn std::error::Error>> {
match self {
BlockhashQuery::None(hash) => Ok((*hash, FeeCalculator::default())),
BlockhashQuery::FeeCalculator(source, hash) => {
let fee_calculator = source
.get_fee_calculator(rpc_client, hash)?
.ok_or(format!("Hash has expired {:?}", hash))?;
Ok((*hash, fee_calculator))
}
BlockhashQuery::All(source) => source.get_blockhash_and_fee_calculator(rpc_client),
}
}
}
impl Default for BlockhashQuery {
fn default() -> Self {
BlockhashQuery::All(Source::Cluster)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{nonce::nonce_arg, offline::blockhash_query::BlockhashQuery};
use clap::App;
use serde_json::{self, json, Value};
use solana_client::{
rpc_request::RpcRequest,
rpc_response::{Response, RpcAccount, RpcFeeCalculator, RpcResponseContext},
};
use solana_sdk::{
account::Account, fee_calculator::FeeCalculator, hash::hash, nonce, system_program,
};
use std::collections::HashMap;
#[test]
fn test_blockhash_query_new_ok() {
let blockhash = hash(&[1u8]);
let nonce_pubkey = Pubkey::new(&[1u8; 32]);
assert_eq!(
BlockhashQuery::new(Some(blockhash), true, None),
BlockhashQuery::None(blockhash),
);
assert_eq!(
BlockhashQuery::new(Some(blockhash), false, None),
BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
);
assert_eq!(
BlockhashQuery::new(None, false, None),
BlockhashQuery::All(blockhash_query::Source::Cluster)
);
assert_eq!(
BlockhashQuery::new(Some(blockhash), true, Some(nonce_pubkey)),
BlockhashQuery::None(blockhash),
);
assert_eq!(
BlockhashQuery::new(Some(blockhash), false, Some(nonce_pubkey)),
BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_pubkey),
blockhash
),
);
assert_eq!(
BlockhashQuery::new(None, false, Some(nonce_pubkey)),
BlockhashQuery::All(blockhash_query::Source::NonceAccount(nonce_pubkey)),
);
}
#[test]
#[should_panic]
fn test_blockhash_query_new_no_nonce_fail() {
BlockhashQuery::new(None, true, None);
}
#[test]
#[should_panic]
fn test_blockhash_query_new_nonce_fail() {
let nonce_pubkey = Pubkey::new(&[1u8; 32]);
BlockhashQuery::new(None, true, Some(nonce_pubkey));
}
#[test]
fn test_blockhash_query_new_from_matches_ok() {
let test_commands = App::new("blockhash_query_test")
.arg(nonce_arg())
.offline_args();
let blockhash = hash(&[1u8]);
let blockhash_string = blockhash.to_string();
let matches = test_commands.clone().get_matches_from(vec![
"blockhash_query_test",
"--blockhash",
&blockhash_string,
"--sign-only",
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::None(blockhash),
);
let matches = test_commands.clone().get_matches_from(vec![
"blockhash_query_test",
"--blockhash",
&blockhash_string,
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
);
let matches = test_commands
.clone()
.get_matches_from(vec!["blockhash_query_test"]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::All(blockhash_query::Source::Cluster),
);
let nonce_pubkey = Pubkey::new(&[1u8; 32]);
let nonce_string = nonce_pubkey.to_string();
let matches = test_commands.clone().get_matches_from(vec![
"blockhash_query_test",
"--blockhash",
&blockhash_string,
"--sign-only",
"--nonce",
&nonce_string,
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::None(blockhash),
);
let matches = test_commands.clone().get_matches_from(vec![
"blockhash_query_test",
"--blockhash",
&blockhash_string,
"--nonce",
&nonce_string,
]);
assert_eq!(
BlockhashQuery::new_from_matches(&matches),
BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_pubkey),
blockhash
),
);
}
#[test]
#[should_panic]
fn test_blockhash_query_new_from_matches_without_nonce_fail() {
let test_commands = App::new("blockhash_query_test")
.arg(blockhash_arg())
// We can really only hit this case if the arg requirements
// are broken, so unset the requires() to recreate that condition
.arg(sign_only_arg().requires(""));
let matches = test_commands
.clone()
.get_matches_from(vec!["blockhash_query_test", "--sign-only"]);
BlockhashQuery::new_from_matches(&matches);
}
#[test]
#[should_panic]
fn test_blockhash_query_new_from_matches_with_nonce_fail() {
let test_commands = App::new("blockhash_query_test")
.arg(blockhash_arg())
// We can really only hit this case if the arg requirements
// are broken, so unset the requires() to recreate that condition
.arg(sign_only_arg().requires(""));
let nonce_pubkey = Pubkey::new(&[1u8; 32]);
let nonce_string = nonce_pubkey.to_string();
let matches = test_commands.clone().get_matches_from(vec![
"blockhash_query_test",
"--sign-only",
"--nonce",
&nonce_string,
]);
BlockhashQuery::new_from_matches(&matches);
}
#[test]
fn test_blockhash_query_get_blockhash_fee_calc() {
let test_blockhash = hash(&[0u8]);
let rpc_blockhash = hash(&[1u8]);
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()
)),
});
let get_fee_calculator_for_blockhash_response = json!(Response {
context: RpcResponseContext { slot: 1 },
value: json!(RpcFeeCalculator {
fee_calculator: rpc_fee_calc.clone()
}),
});
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::default()
.get_blockhash_and_fee_calculator(&rpc_client)
.unwrap(),
(rpc_blockhash, rpc_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
mocks.insert(
RpcRequest::GetFeeCalculatorForBlockhash,
get_fee_calculator_for_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::FeeCalculator(Source::Cluster, test_blockhash)
.get_blockhash_and_fee_calculator(&rpc_client)
.unwrap(),
(test_blockhash, rpc_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(
RpcRequest::GetRecentBlockhash,
get_recent_blockhash_response.clone(),
);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::None(test_blockhash)
.get_blockhash_and_fee_calculator(&rpc_client)
.unwrap(),
(test_blockhash, FeeCalculator::default()),
);
let rpc_client = RpcClient::new_mock("fails".to_string());
assert!(BlockhashQuery::default()
.get_blockhash_and_fee_calculator(&rpc_client)
.is_err());
let nonce_blockhash = Hash::new(&[2u8; 32]);
let nonce_fee_calc = FeeCalculator::new(4242);
let data = nonce::state::Data {
authority: Pubkey::new(&[3u8; 32]),
blockhash: nonce_blockhash,
fee_calculator: nonce_fee_calc.clone(),
};
let nonce_account = Account::new_data_with_space(
42,
&nonce::state::Versions::new_current(nonce::State::Initialized(data)),
nonce::State::size(),
&system_program::id(),
)
.unwrap();
let nonce_pubkey = Pubkey::new(&[4u8; 32]);
let rpc_nonce_account = RpcAccount::encode(nonce_account);
let get_account_response = json!(Response {
context: RpcResponseContext { slot: 1 },
value: json!(Some(rpc_nonce_account.clone())),
});
let mut mocks = HashMap::new();
mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone());
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::All(Source::NonceAccount(nonce_pubkey))
.get_blockhash_and_fee_calculator(&rpc_client)
.unwrap(),
(nonce_blockhash, nonce_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone());
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::FeeCalculator(Source::NonceAccount(nonce_pubkey), nonce_blockhash)
.get_blockhash_and_fee_calculator(&rpc_client)
.unwrap(),
(nonce_blockhash, nonce_fee_calc.clone()),
);
let mut mocks = HashMap::new();
mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone());
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert!(
BlockhashQuery::FeeCalculator(Source::NonceAccount(nonce_pubkey), test_blockhash)
.get_blockhash_and_fee_calculator(&rpc_client)
.is_err()
);
let mut mocks = HashMap::new();
mocks.insert(RpcRequest::GetAccountInfo, get_account_response.clone());
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert_eq!(
BlockhashQuery::None(nonce_blockhash)
.get_blockhash_and_fee_calculator(&rpc_client)
.unwrap(),
(nonce_blockhash, FeeCalculator::default()),
);
let rpc_client = RpcClient::new_mock("fails".to_string());
assert!(BlockhashQuery::All(Source::NonceAccount(nonce_pubkey))
.get_blockhash_and_fee_calculator(&rpc_client)
.is_err());
}
}

129
cli/src/offline/mod.rs Normal file
View File

@ -0,0 +1,129 @@
pub mod blockhash_query;
use crate::nonce;
use clap::{App, Arg, ArgMatches};
use serde_json::Value;
use solana_clap_utils::{
input_parsers::{pubkey_of, value_of},
input_validators::{is_hash, is_pubkey_sig},
keypair::presigner_from_pubkey_sigs,
offline::{BLOCKHASH_ARG, SIGNER_ARG, SIGN_ONLY_ARG},
};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
signature::{Presigner, Signature},
};
use std::str::FromStr;
fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(BLOCKHASH_ARG.name)
.long(BLOCKHASH_ARG.long)
.takes_value(true)
.value_name("BLOCKHASH")
.validator(is_hash)
.help(BLOCKHASH_ARG.help)
}
fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGN_ONLY_ARG.name)
.long(SIGN_ONLY_ARG.long)
.takes_value(false)
.requires(BLOCKHASH_ARG.name)
.help(SIGN_ONLY_ARG.help)
}
fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGNER_ARG.name)
.long(SIGNER_ARG.long)
.takes_value(true)
.value_name("PUBKEY=SIGNATURE")
.validator(is_pubkey_sig)
.requires(BLOCKHASH_ARG.name)
.multiple(true)
.help(SIGNER_ARG.help)
}
pub trait OfflineArgs {
fn offline_args(self) -> Self;
}
impl OfflineArgs for App<'_, '_> {
fn offline_args(self) -> Self {
self.arg(blockhash_arg())
.arg(sign_only_arg())
.arg(signer_arg())
}
}
pub struct SignOnly {
pub blockhash: Hash,
pub present_signers: Vec<(Pubkey, Signature)>,
pub absent_signers: Vec<Pubkey>,
pub bad_signers: Vec<Pubkey>,
}
impl SignOnly {
pub fn has_all_signers(&self) -> bool {
self.absent_signers.is_empty() && self.bad_signers.is_empty()
}
pub fn presigner_of(&self, pubkey: &Pubkey) -> Option<Presigner> {
presigner_from_pubkey_sigs(pubkey, &self.present_signers)
}
}
pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
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();
let signer_strings = object.get("signers");
if let Some(sig_strings) = signer_strings {
present_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|signer_string| {
let mut signer = signer_string.as_str().unwrap().split('=');
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
(key, sig)
})
.collect();
}
let mut absent_signers: Vec<Pubkey> = Vec::new();
let signer_strings = object.get("absent");
if let Some(sig_strings) = signer_strings {
absent_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|val| {
let s = val.as_str().unwrap();
Pubkey::from_str(s).unwrap()
})
.collect();
}
let mut bad_signers: Vec<Pubkey> = Vec::new();
let signer_strings = object.get("badSig");
if let Some(sig_strings) = signer_strings {
bad_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|val| {
let s = val.as_str().unwrap();
Pubkey::from_str(s).unwrap()
})
.collect();
}
SignOnly {
blockhash,
present_signers,
absent_signers,
bad_signers,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,18 @@
use crate::cli::{
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, CliCommand,
CliCommandInfo, CliConfig, CliError, ProcessResult,
check_account_for_fee, check_unique_pubkeys, generate_unique_signers,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
SignerIndex,
};
use clap::{App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{input_parsers::*, input_validators::*};
use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::signer_from_path};
use solana_client::rpc_client::RpcClient;
use solana_sdk::signature::Keypair;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account_utils::StateMut, message::Message, pubkey::Pubkey, signature::Signer,
system_instruction::SystemError, transaction::Transaction,
account_utils::StateMut, message::Message, pubkey::Pubkey, system_instruction::SystemError,
transaction::Transaction,
};
use solana_storage_program::storage_instruction::{self, StorageAccountType};
use std::sync::Arc;
pub trait StorageSubCommands {
fn storage_subcommands(self) -> Self;
@ -24,18 +26,18 @@ impl StorageSubCommands for App<'_, '_> {
.arg(
Arg::with_name("storage_account_owner")
.index(1)
.value_name("STORAGE ACCOUNT OWNER PUBKEY")
.value_name("AUTHORITY_PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair),
.validator(is_valid_pubkey),
)
.arg(
Arg::with_name("storage_account")
.index(2)
.value_name("STORAGE ACCOUNT")
.value_name("ACCOUNT_KEYPAIR")
.takes_value(true)
.required(true)
.validator(is_keypair_or_ask_keyword),
.validator(is_valid_signer),
),
)
.subcommand(
@ -44,18 +46,18 @@ impl StorageSubCommands for App<'_, '_> {
.arg(
Arg::with_name("storage_account_owner")
.index(1)
.value_name("STORAGE ACCOUNT OWNER PUBKEY")
.value_name("AUTHORITY_PUBKEY")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair),
.validator(is_valid_pubkey),
)
.arg(
Arg::with_name("storage_account")
.index(2)
.value_name("STORAGE ACCOUNT")
.value_name("ACCOUNT_KEYPAIR")
.takes_value(true)
.required(true)
.validator(is_keypair_or_ask_keyword),
.validator(is_valid_signer),
),
)
.subcommand(
@ -64,19 +66,19 @@ impl StorageSubCommands for App<'_, '_> {
.arg(
Arg::with_name("node_account_pubkey")
.index(1)
.value_name("NODE PUBKEY")
.value_name("NODE_ACCOUNT_ADDRESS")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.validator(is_valid_pubkey)
.help("The node account to credit the rewards to"),
)
.arg(
Arg::with_name("storage_account_pubkey")
.index(2)
.value_name("STORAGE ACCOUNT PUBKEY")
.value_name("STORAGE_ACCOUNT_ADDRESS")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.validator(is_valid_pubkey)
.help("Storage account address to redeem credits for"),
),
)
@ -87,11 +89,11 @@ impl StorageSubCommands for App<'_, '_> {
.arg(
Arg::with_name("storage_account_pubkey")
.index(1)
.value_name("STORAGE ACCOUNT PUBKEY")
.value_name("STORAGE_ACCOUNT_ADDRESS")
.takes_value(true)
.required(true)
.validator(is_pubkey_or_keypair)
.help("Storage account pubkey"),
.validator(is_valid_pubkey)
.help("Storage account address"),
),
)
}
@ -99,66 +101,106 @@ impl StorageSubCommands for App<'_, '_> {
pub fn parse_storage_create_archiver_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
let storage_account = keypair_of(matches, "storage_account").unwrap();
let account_owner =
pubkey_of_signer(matches, "storage_account_owner", wallet_manager)?.unwrap();
let (storage_account, storage_account_pubkey) =
signer_of(matches, "storage_account", wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
vec![payer_provided, storage_account],
matches,
default_signer_path,
wallet_manager,
)?;
Ok(CliCommandInfo {
command: CliCommand::CreateStorageAccount {
account_owner,
storage_account: storage_account.into(),
storage_account: signer_info.index_of(storage_account_pubkey).unwrap(),
account_type: StorageAccountType::Archiver,
},
require_keypair: true,
signers: signer_info.signers,
})
}
pub fn parse_storage_create_validator_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
let storage_account = keypair_of(matches, "storage_account").unwrap();
let account_owner =
pubkey_of_signer(matches, "storage_account_owner", wallet_manager)?.unwrap();
let (storage_account, storage_account_pubkey) =
signer_of(matches, "storage_account", wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
vec![payer_provided, storage_account],
matches,
default_signer_path,
wallet_manager,
)?;
Ok(CliCommandInfo {
command: CliCommand::CreateStorageAccount {
account_owner,
storage_account: storage_account.into(),
storage_account: signer_info.index_of(storage_account_pubkey).unwrap(),
account_type: StorageAccountType::Validator,
},
require_keypair: true,
signers: signer_info.signers,
})
}
pub fn parse_storage_claim_reward(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let node_account_pubkey = pubkey_of(matches, "node_account_pubkey").unwrap();
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
pub fn parse_storage_claim_reward(
matches: &ArgMatches<'_>,
default_signer_path: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let node_account_pubkey =
pubkey_of_signer(matches, "node_account_pubkey", wallet_manager)?.unwrap();
let storage_account_pubkey =
pubkey_of_signer(matches, "storage_account_pubkey", wallet_manager)?.unwrap();
Ok(CliCommandInfo {
command: CliCommand::ClaimStorageReward {
node_account_pubkey,
storage_account_pubkey,
},
require_keypair: true,
signers: vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?],
})
}
pub fn parse_storage_get_account_command(
matches: &ArgMatches<'_>,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
let storage_account_pubkey =
pubkey_of_signer(matches, "storage_account_pubkey", wallet_manager)?.unwrap();
Ok(CliCommandInfo {
command: CliCommand::ShowStorageAccount(storage_account_pubkey),
require_keypair: false,
signers: vec![],
})
}
pub fn process_create_storage_account(
rpc_client: &RpcClient,
config: &CliConfig,
storage_account: SignerIndex,
account_owner: &Pubkey,
storage_account: &Keypair,
account_type: StorageAccountType,
) -> ProcessResult {
let storage_account = config.signers[storage_account];
let storage_account_pubkey = storage_account.pubkey();
check_unique_pubkeys(
(&config.keypair.pubkey(), "cli keypair".to_string()),
(&config.signers[0].pubkey(), "cli keypair".to_string()),
(
&storage_account_pubkey,
"storage_account_pubkey".to_string(),
@ -183,7 +225,7 @@ pub fn process_create_storage_account(
.max(1);
let ixs = storage_instruction::create_storage_account(
&config.keypair.pubkey(),
&config.signers[0].pubkey(),
&account_owner,
&storage_account_pubkey,
required_balance,
@ -191,21 +233,17 @@ pub fn process_create_storage_account(
);
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let message = Message::new(ixs);
let message = Message::new(&ixs);
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(
&[config.keypair.as_ref(), storage_account],
recent_blockhash,
)?;
tx.try_sign(&config.signers, recent_blockhash)?;
check_account_for_fee(
rpc_client,
&config.keypair.pubkey(),
&config.signers[0].pubkey(),
&fee_calculator,
&tx.message,
)?;
let result = rpc_client
.send_and_confirm_transaction(&mut tx, &[config.keypair.as_ref(), storage_account]);
log_instruction_custom_error::<SystemError>(result)
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<SystemError>(result, &config)
}
pub fn process_claim_storage_reward(
@ -218,18 +256,18 @@ pub fn process_claim_storage_reward(
let instruction =
storage_instruction::claim_reward(node_account_pubkey, storage_account_pubkey);
let signers = [config.keypair.as_ref()];
let message = Message::new_with_payer(vec![instruction], Some(&signers[0].pubkey()));
let signers = [config.signers[0]];
let message = Message::new_with_payer(&[instruction], Some(&signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&signers, recent_blockhash)?;
check_account_for_fee(
rpc_client,
&config.keypair.pubkey(),
&config.signers[0].pubkey(),
&fee_calculator,
&tx.message,
)?;
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &signers)?;
Ok(signature_str)
let signature = rpc_client.send_and_confirm_transaction_with_spinner(&tx)?;
Ok(signature.to_string())
}
pub fn process_show_storage_account(
@ -249,7 +287,7 @@ pub fn process_show_storage_account(
use solana_storage_program::storage_contract::StorageContract;
let storage_contract: StorageContract = account.state().map_err(|err| {
CliError::RpcRequestError(format!("Unable to deserialize storage account: {:?}", err))
CliError::RpcRequestError(format!("Unable to deserialize storage account: {}", err))
})?;
println!("{:#?}", storage_contract);
println!("Account Lamports: {}", account.lamports);
@ -260,7 +298,7 @@ pub fn process_show_storage_account(
mod tests {
use super::*;
use crate::cli::{app, parse_command};
use solana_sdk::signature::write_keypair;
use solana_sdk::signature::{read_keypair_file, write_keypair, Keypair, Signer};
use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) {
@ -274,6 +312,10 @@ mod tests {
let pubkey = Pubkey::new_rand();
let pubkey_string = pubkey.to_string();
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 (keypair_file, mut tmp_file) = make_tmp_file();
let storage_account_keypair = Keypair::new();
write_keypair(&storage_account_keypair, tmp_file.as_file_mut()).unwrap();
@ -285,14 +327,22 @@ mod tests {
&keypair_file,
]);
assert_eq!(
parse_command(&test_create_archiver_storage_account).unwrap(),
parse_command(
&test_create_archiver_storage_account,
&default_keypair_file,
&mut None
)
.unwrap(),
CliCommandInfo {
command: CliCommand::CreateStorageAccount {
account_owner: pubkey,
storage_account: storage_account_keypair.into(),
storage_account: 1,
account_type: StorageAccountType::Archiver,
},
require_keypair: true
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
storage_account_keypair.into()
],
}
);
@ -309,14 +359,22 @@ mod tests {
&keypair_file,
]);
assert_eq!(
parse_command(&test_create_validator_storage_account).unwrap(),
parse_command(
&test_create_validator_storage_account,
&default_keypair_file,
&mut None
)
.unwrap(),
CliCommandInfo {
command: CliCommand::CreateStorageAccount {
account_owner: pubkey,
storage_account: storage_account_keypair.into(),
storage_account: 1,
account_type: StorageAccountType::Validator,
},
require_keypair: true
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
storage_account_keypair.into()
],
}
);
@ -327,13 +385,13 @@ mod tests {
&storage_account_string,
]);
assert_eq!(
parse_command(&test_claim_storage_reward).unwrap(),
parse_command(&test_claim_storage_reward, &default_keypair_file, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::ClaimStorageReward {
node_account_pubkey: pubkey,
storage_account_pubkey,
},
require_keypair: true
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
);
}

View File

@ -1,6 +1,6 @@
use crate::{
cli::{check_account_for_fee, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
display::println_name_value,
cli_output::{CliValidatorInfo, CliValidatorInfoVec},
};
use bincode::deserialize;
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
@ -11,9 +11,11 @@ use serde_json::{Map, Value};
use solana_clap_utils::{
input_parsers::pubkey_of,
input_validators::{is_pubkey, is_url},
keypair::signer_from_path,
};
use solana_client::rpc_client::RpcClient;
use solana_config_program::{config_instruction, get_config_data, ConfigKeys, ConfigState};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account::Account,
commitment_config::CommitmentConfig,
@ -22,8 +24,7 @@ use solana_sdk::{
signature::{Keypair, Signer},
transaction::Transaction,
};
use std::error;
use titlecase::titlecase;
use std::{error, sync::Arc};
pub const MAX_SHORT_FIELD_LENGTH: usize = 70;
pub const MAX_LONG_FIELD_LENGTH: usize = 300;
@ -224,17 +225,26 @@ impl ValidatorInfoSubCommands for App<'_, '_> {
}
}
pub fn parse_validator_info_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
pub fn parse_validator_info_command(
matches: &ArgMatches<'_>,
default_signer_path: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let info_pubkey = pubkey_of(matches, "info_pubkey");
// Prepare validator info
let validator_info = parse_args(&matches);
let validator_info = parse_args(matches);
Ok(CliCommandInfo {
command: CliCommand::SetValidatorInfo {
validator_info,
force_keybase: matches.is_present("force"),
info_pubkey,
},
require_keypair: true,
signers: vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?],
})
}
@ -244,7 +254,7 @@ pub fn parse_get_validator_info_command(
let info_pubkey = pubkey_of(matches, "info_pubkey");
Ok(CliCommandInfo {
command: CliCommand::GetValidatorInfo(info_pubkey),
require_keypair: false,
signers: vec![],
})
}
@ -257,13 +267,13 @@ pub fn process_set_validator_info(
) -> ProcessResult {
// Validate keybase username
if let Some(string) = validator_info.get("keybaseUsername") {
let result = verify_keybase(&config.keypair.pubkey(), &string);
let result = verify_keybase(&config.signers[0].pubkey(), &string);
if result.is_err() {
if force_keybase {
println!("--force supplied, ignoring: {:?}", result);
} else {
result.map_err(|err| {
CliError::BadParameter(format!("Invalid validator keybase username: {:?}", err))
CliError::BadParameter(format!("Invalid validator keybase username: {}", err))
})?;
}
}
@ -282,7 +292,7 @@ pub fn process_set_validator_info(
})
.find(|(pubkey, account)| {
let (validator_pubkey, _) = parse_validator_info(&pubkey, &account).unwrap();
validator_pubkey == config.keypair.pubkey()
validator_pubkey == config.signers[0].pubkey()
});
// Create validator-info keypair to use if info_pubkey not provided or does not exist
@ -300,7 +310,7 @@ pub fn process_set_validator_info(
.poll_get_balance_with_commitment(&info_pubkey, CommitmentConfig::default())
.unwrap_or(0);
let keys = vec![(id(), false), (config.keypair.pubkey(), true)];
let keys = vec![(id(), false), (config.signers[0].pubkey(), true)];
let (message, signers): (Message, Vec<&dyn Signer>) = if balance == 0 {
if info_pubkey != info_keypair.pubkey() {
println!(
@ -311,12 +321,12 @@ pub fn process_set_validator_info(
}
println!(
"Publishing info for Validator {:?}",
config.keypair.pubkey()
config.signers[0].pubkey()
);
let lamports = rpc_client
.get_minimum_balance_for_rent_exemption(ValidatorInfo::max_space() as usize)?;
let mut instructions = config_instruction::create_account::<ValidatorInfo>(
&config.keypair.pubkey(),
&config.signers[0].pubkey(),
&info_keypair.pubkey(),
lamports,
keys.clone(),
@ -327,13 +337,13 @@ pub fn process_set_validator_info(
keys,
&validator_info,
)]);
let signers = vec![config.keypair.as_ref(), &info_keypair];
let message = Message::new(instructions);
let signers = vec![config.signers[0], &info_keypair];
let message = Message::new(&instructions);
(message, signers)
} else {
println!(
"Updating Validator {:?} info at: {:?}",
config.keypair.pubkey(),
config.signers[0].pubkey(),
info_pubkey
);
let instructions = vec![config_instruction::store(
@ -342,8 +352,8 @@ pub fn process_set_validator_info(
keys,
&validator_info,
)];
let message = Message::new_with_payer(instructions, Some(&config.keypair.pubkey()));
let signers = vec![config.keypair.as_ref()];
let message = Message::new_with_payer(&instructions, Some(&config.signers[0].pubkey()));
let signers = vec![config.signers[0]];
(message, signers)
};
@ -353,18 +363,22 @@ pub fn process_set_validator_info(
tx.try_sign(&signers, recent_blockhash)?;
check_account_for_fee(
rpc_client,
&config.keypair.pubkey(),
&config.signers[0].pubkey(),
&fee_calculator,
&tx.message,
)?;
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &signers)?;
let signature_str = rpc_client.send_and_confirm_transaction_with_spinner(&tx)?;
println!("Success! Validator info published at: {:?}", info_pubkey);
println!("{}", signature_str);
Ok("".to_string())
}
pub fn process_get_validator_info(rpc_client: &RpcClient, pubkey: Option<Pubkey>) -> ProcessResult {
pub fn process_get_validator_info(
rpc_client: &RpcClient,
config: &CliConfig,
pubkey: Option<Pubkey>,
) -> ProcessResult {
let validator_info: Vec<(Pubkey, Account)> = if let Some(validator_info_pubkey) = pubkey {
vec![(
validator_info_pubkey,
@ -383,24 +397,22 @@ pub fn process_get_validator_info(rpc_client: &RpcClient, pubkey: Option<Pubkey>
.collect()
};
let mut validator_info_list: Vec<CliValidatorInfo> = vec![];
if validator_info.is_empty() {
println!("No validator info accounts found");
}
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)?;
println!();
println_name_value("Validator Identity Pubkey:", &validator_pubkey.to_string());
println_name_value(" Info Pubkey:", &validator_info_pubkey.to_string());
for (key, value) in validator_info.iter() {
println_name_value(
&format!(" {}:", titlecase(key)),
&value.as_str().unwrap_or("?"),
);
}
validator_info_list.push(CliValidatorInfo {
identity_pubkey: validator_pubkey.to_string(),
info_pubkey: validator_info_pubkey.to_string(),
info: validator_info,
});
}
Ok("".to_string())
Ok(config
.output_format
.formatted_string(&CliValidatorInfoVec::new(validator_info_list)))
}
#[cfg(test)]

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
use serde_json::Value;
use solana_cli::cli::{process_command, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient;
use solana_core::validator::new_validator_for_tests;
use solana_core::validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{bpf_loader, pubkey::Pubkey};
use solana_sdk::{bpf_loader, pubkey::Pubkey, signature::Keypair};
use std::{
fs::{remove_dir_all, File},
io::Read,
@ -22,7 +22,13 @@ fn test_cli_deploy_program() {
pathbuf.push("noop");
pathbuf.set_extension("so");
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
@ -38,6 +44,7 @@ fn test_cli_deploy_program() {
.unwrap();
let mut config = CliConfig::default();
let keypair = Keypair::new();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.command = CliCommand::Airdrop {
faucet_host: None,
@ -45,6 +52,7 @@ fn test_cli_deploy_program() {
pubkey: None,
lamports: minimum_balance_for_rent_exemption + 1, // min balance for rent exemption + leftover for tx processing
};
config.signers = vec![&keypair];
process_command(&config).unwrap();
config.command = CliCommand::Deploy(pathbuf.to_str().unwrap().to_string());

View File

@ -1,28 +1,22 @@
use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig};
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
cli_output::OutputFormat,
nonce,
offline::{
blockhash_query::{self, BlockhashQuery},
parse_sign_only_reply_string,
},
};
use solana_client::rpc_client::RpcClient;
use solana_core::validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
hash::Hash,
pubkey::Pubkey,
signature::{keypair_from_seed, read_keypair_file, write_keypair, Keypair, Signer},
system_instruction::create_address_with_seed,
signature::{keypair_from_seed, Keypair, Signer},
system_program,
};
use std::fs::remove_dir_all;
use std::sync::mpsc::channel;
#[cfg(test)]
use solana_core::validator::new_validator_for_tests;
use std::rc::Rc;
use std::thread::sleep;
use std::time::Duration;
use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) {
let tmp_file = NamedTempFile::new().unwrap();
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
}
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
(0..5).for_each(|tries| {
@ -39,34 +33,21 @@ fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
#[test]
fn test_nonce() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let mut config_payer = CliConfig::default();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let (keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
let mut config_nonce = CliConfig::default();
config_nonce.keypair = keypair.into();
config_nonce.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
full_battery_tests(
&rpc_client,
&faucet_addr,
&mut config_payer,
&mut config_nonce,
&keypair_file,
None,
None,
);
full_battery_tests(&rpc_client, &faucet_addr, json_rpc_url, None, false);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
@ -74,33 +55,26 @@ fn test_nonce() {
#[test]
fn test_nonce_with_seed() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let mut config_payer = CliConfig::default();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let (keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
let mut config_nonce = CliConfig::default();
config_nonce.keypair = keypair.into();
config_nonce.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
full_battery_tests(
&rpc_client,
&faucet_addr,
&mut config_payer,
&mut config_nonce,
&keypair_file,
json_rpc_url,
Some(String::from("seed")),
None,
false,
);
server.close().unwrap();
@ -109,84 +83,86 @@ fn test_nonce_with_seed() {
#[test]
fn test_nonce_with_authority() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let mut config_payer = CliConfig::default();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let nonce_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&nonce_keypair, tmp_file.as_file_mut()).unwrap();
let mut config_nonce = CliConfig::default();
config_nonce.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
let nonce_authority = Keypair::new();
let (authority_keypair_file, mut tmp_file2) = make_tmp_file();
write_keypair(&nonce_authority, tmp_file2.as_file_mut()).unwrap();
full_battery_tests(
&rpc_client,
&faucet_addr,
&mut config_payer,
&mut config_nonce,
&nonce_keypair_file,
None,
Some(&authority_keypair_file),
);
full_battery_tests(&rpc_client, &faucet_addr, json_rpc_url, None, true);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
fn read_keypair_from_option(keypair_file: &Option<&str>) -> Option<Box<dyn Signer>> {
keypair_file.map(|akf| read_keypair_file(&akf).unwrap().into())
}
fn full_battery_tests(
rpc_client: &RpcClient,
faucet_addr: &std::net::SocketAddr,
config_payer: &mut CliConfig,
config_nonce: &mut CliConfig,
nonce_keypair_file: &str,
json_rpc_url: String,
seed: Option<String>,
authority_keypair_file: Option<&str>,
use_nonce_authority: bool,
) {
let mut config_payer = CliConfig::default();
config_payer.json_rpc_url = json_rpc_url.clone();
let payer = Keypair::new();
config_payer.signers = vec![&payer];
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_payer.keypair.pubkey(),
&config_payer.signers[0].pubkey(),
2000,
&config_payer,
)
.unwrap();
check_balance(2000, &rpc_client, &config_payer.keypair.pubkey());
check_balance(2000, &rpc_client, &config_payer.signers[0].pubkey());
let mut config_nonce = CliConfig::default();
config_nonce.json_rpc_url = json_rpc_url;
let nonce_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
config_nonce.signers = vec![&nonce_keypair];
let nonce_account = if let Some(seed) = seed.as_ref() {
create_address_with_seed(&config_nonce.keypair.pubkey(), seed, &system_program::id())
.unwrap()
Pubkey::create_with_seed(
&config_nonce.signers[0].pubkey(),
seed,
&system_program::id(),
)
.unwrap()
} else {
read_keypair_file(&nonce_keypair_file).unwrap().pubkey()
nonce_keypair.pubkey()
};
let nonce_authority = Keypair::new();
let optional_authority = if use_nonce_authority {
Some(nonce_authority.pubkey())
} else {
None
};
// Create nonce account
config_payer.signers.push(&nonce_keypair);
config_payer.command = CliCommand::CreateNonceAccount {
nonce_account: Rc::new(read_keypair_file(&nonce_keypair_file).unwrap().into()),
nonce_account: 1,
seed,
nonce_authority: read_keypair_from_option(&authority_keypair_file).map(|k| k.pubkey()),
nonce_authority: optional_authority,
lamports: 1000,
};
process_command(&config_payer).unwrap();
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
check_balance(1000, &rpc_client, &nonce_account);
// Get nonce
config_payer.signers.pop();
config_payer.command = CliCommand::GetNonce(nonce_account);
let first_nonce_string = process_command(&config_payer).unwrap();
let first_nonce = first_nonce_string.parse::<Hash>().unwrap();
@ -198,14 +174,24 @@ fn full_battery_tests(
assert_eq!(first_nonce, second_nonce);
let mut authorized_signers: Vec<&dyn Signer> = vec![&payer];
let index = if use_nonce_authority {
authorized_signers.push(&nonce_authority);
1
} else {
0
};
// New nonce
config_payer.signers = authorized_signers.clone();
config_payer.command = CliCommand::NewNonce {
nonce_account,
nonce_authority: read_keypair_from_option(&authority_keypair_file),
nonce_authority: index,
};
process_command(&config_payer).unwrap();
// Get nonce
config_payer.signers = vec![&payer];
config_payer.command = CliCommand::GetNonce(nonce_account);
let third_nonce_string = process_command(&config_payer).unwrap();
let third_nonce = third_nonce_string.parse::<Hash>().unwrap();
@ -214,14 +200,15 @@ fn full_battery_tests(
// Withdraw from nonce account
let payee_pubkey = Pubkey::new_rand();
config_payer.signers = authorized_signers;
config_payer.command = CliCommand::WithdrawFromNonceAccount {
nonce_account,
nonce_authority: read_keypair_from_option(&authority_keypair_file),
nonce_authority: index,
destination_account_pubkey: payee_pubkey,
lamports: 100,
};
process_command(&config_payer).unwrap();
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
check_balance(900, &rpc_client, &nonce_account);
check_balance(100, &rpc_client, &payee_pubkey);
@ -234,48 +221,165 @@ fn full_battery_tests(
// Set new authority
let new_authority = Keypair::new();
let (new_authority_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&new_authority, tmp_file.as_file_mut()).unwrap();
config_payer.command = CliCommand::AuthorizeNonceAccount {
nonce_account,
nonce_authority: read_keypair_from_option(&authority_keypair_file),
new_authority: read_keypair_file(&new_authority_keypair_file)
.unwrap()
.pubkey(),
nonce_authority: index,
new_authority: new_authority.pubkey(),
};
process_command(&config_payer).unwrap();
// Old authority fails now
config_payer.command = CliCommand::NewNonce {
nonce_account,
nonce_authority: read_keypair_from_option(&authority_keypair_file),
nonce_authority: index,
};
process_command(&config_payer).unwrap_err();
// New authority can advance nonce
config_payer.signers = vec![&payer, &new_authority];
config_payer.command = CliCommand::NewNonce {
nonce_account,
nonce_authority: Some(
read_keypair_file(&new_authority_keypair_file)
.unwrap()
.into(),
),
nonce_authority: 1,
};
process_command(&config_payer).unwrap();
// New authority can withdraw from nonce account
config_payer.command = CliCommand::WithdrawFromNonceAccount {
nonce_account,
nonce_authority: Some(
read_keypair_file(&new_authority_keypair_file)
.unwrap()
.into(),
),
nonce_authority: 1,
destination_account_pubkey: payee_pubkey,
lamports: 100,
};
process_command(&config_payer).unwrap();
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
check_balance(800, &rpc_client, &nonce_account);
check_balance(200, &rpc_client, &payee_pubkey);
}
#[test]
fn test_create_account_with_seed() {
let TestValidator {
server,
leader_data,
alice: mint_keypair,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
let faucet_addr = receiver.recv().unwrap();
let offline_nonce_authority_signer = keypair_from_seed(&[1u8; 32]).unwrap();
let online_nonce_creator_signer = keypair_from_seed(&[2u8; 32]).unwrap();
let to_address = Pubkey::new(&[3u8; 32]);
let config = CliConfig::default();
// Setup accounts
let rpc_client = RpcClient::new_socket(leader_data.rpc);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&offline_nonce_authority_signer.pubkey(),
42,
&config,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&online_nonce_creator_signer.pubkey(),
4242,
&config,
)
.unwrap();
check_balance(42, &rpc_client, &offline_nonce_authority_signer.pubkey());
check_balance(4242, &rpc_client, &online_nonce_creator_signer.pubkey());
check_balance(0, &rpc_client, &to_address);
// Create nonce account
let creator_pubkey = online_nonce_creator_signer.pubkey();
let authority_pubkey = offline_nonce_authority_signer.pubkey();
let seed = authority_pubkey.to_string()[0..32].to_string();
let nonce_address =
Pubkey::create_with_seed(&creator_pubkey, &seed, &system_program::id()).unwrap();
check_balance(0, &rpc_client, &nonce_address);
let mut creator_config = CliConfig::default();
creator_config.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
creator_config.signers = vec![&online_nonce_creator_signer];
creator_config.command = CliCommand::CreateNonceAccount {
nonce_account: 0,
seed: Some(seed),
nonce_authority: Some(authority_pubkey),
lamports: 241,
};
process_command(&creator_config).unwrap();
check_balance(241, &rpc_client, &nonce_address);
check_balance(42, &rpc_client, &offline_nonce_authority_signer.pubkey());
check_balance(4000, &rpc_client, &online_nonce_creator_signer.pubkey());
check_balance(0, &rpc_client, &to_address);
// Fetch nonce hash
let nonce_hash = nonce::get_account(&rpc_client, &nonce_address)
.and_then(|ref a| nonce::data_from_account(a))
.unwrap()
.blockhash;
// Test by creating transfer TX with nonce, fully offline
let mut authority_config = CliConfig::default();
authority_config.json_rpc_url = String::default();
authority_config.signers = vec![&offline_nonce_authority_signer];
// Verify we cannot contact the cluster
authority_config.command = CliCommand::ClusterVersion;
process_command(&authority_config).unwrap_err();
authority_config.command = CliCommand::Transfer {
lamports: 10,
to: to_address,
from: 0,
sign_only: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_address),
nonce_authority: 0,
fee_payer: 0,
};
authority_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&authority_config).unwrap();
let sign_only = parse_sign_only_reply_string(&sign_only_reply);
let authority_presigner = sign_only.presigner_of(&authority_pubkey).unwrap();
assert_eq!(sign_only.blockhash, nonce_hash);
// And submit it
let mut submit_config = CliConfig::default();
submit_config.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
submit_config.signers = vec![&authority_presigner];
submit_config.command = CliCommand::Transfer {
lamports: 10,
to: to_address,
from: 0,
sign_only: false,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_address),
sign_only.blockhash,
),
nonce_account: Some(nonce_address),
nonce_authority: 0,
fee_payer: 0,
};
process_command(&submit_config).unwrap();
check_balance(241, &rpc_client, &nonce_address);
check_balance(31, &rpc_client, &offline_nonce_authority_signer.pubkey());
check_balance(4000, &rpc_client, &online_nonce_creator_signer.pubkey());
check_balance(10, &rpc_client, &to_address);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@ -1,33 +1,23 @@
use chrono::prelude::*;
use serde_json::Value;
use solana_clap_utils::keypair::presigner_from_pubkey_sigs;
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand},
offline::{parse_sign_only_reply_string, BlockhashQuery},
cli_output::OutputFormat,
nonce,
offline::{
blockhash_query::{self, BlockhashQuery},
parse_sign_only_reply_string,
},
};
use solana_client::rpc_client::RpcClient;
use solana_core::validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
account_utils::StateMut,
fee_calculator::FeeCalculator,
nonce_state::NonceState,
nonce::State as NonceState,
pubkey::Pubkey,
signature::{read_keypair_file, write_keypair, Keypair, Signer},
signature::{Keypair, Signer},
};
use std::fs::remove_dir_all;
use std::sync::mpsc::channel;
#[cfg(test)]
use solana_core::validator::new_validator_for_tests;
use std::rc::Rc;
use std::thread::sleep;
use std::time::Duration;
use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) {
let tmp_file = NamedTempFile::new().unwrap();
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
}
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
(0..5).for_each(|tries| {
@ -44,7 +34,13 @@ fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
#[test]
fn test_cli_timestamp_tx() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
@ -52,33 +48,39 @@ fn test_cli_timestamp_tx() {
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer0 = Keypair::new();
let default_signer1 = Keypair::new();
let mut config_payer = CliConfig::default();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_payer.signers = vec![&default_signer0];
let mut config_witness = CliConfig::default();
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
config_witness.signers = vec![&default_signer1];
assert_ne!(
config_payer.keypair.pubkey(),
config_witness.keypair.pubkey()
config_payer.signers[0].pubkey(),
config_witness.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_payer.keypair.pubkey(),
&config_payer.signers[0].pubkey(),
50,
&config_witness,
)
.unwrap();
check_balance(50, &rpc_client, &config_payer.keypair.pubkey());
check_balance(50, &rpc_client, &config_payer.signers[0].pubkey());
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_witness.keypair.pubkey(),
&config_witness.signers[0].pubkey(),
1,
&config_witness,
)
.unwrap();
@ -89,7 +91,7 @@ fn test_cli_timestamp_tx() {
lamports: 10,
to: bob_pubkey,
timestamp: Some(dt),
timestamp_pubkey: Some(config_witness.keypair.pubkey()),
timestamp_pubkey: Some(config_witness.signers[0].pubkey()),
..PayCommand::default()
});
let sig_response = process_command(&config_payer);
@ -101,7 +103,7 @@ fn test_cli_timestamp_tx() {
.expect("base58-encoded public key");
let process_id = Pubkey::new(&process_id_vec);
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_balance(10, &rpc_client, &process_id); // contract balance
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
@ -109,7 +111,7 @@ fn test_cli_timestamp_tx() {
config_witness.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt);
process_command(&config_witness).unwrap();
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_balance(0, &rpc_client, &process_id); // contract balance
check_balance(10, &rpc_client, &bob_pubkey); // recipient balance
@ -119,7 +121,13 @@ fn test_cli_timestamp_tx() {
#[test]
fn test_cli_witness_tx() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
@ -127,31 +135,37 @@ fn test_cli_witness_tx() {
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer0 = Keypair::new();
let default_signer1 = Keypair::new();
let mut config_payer = CliConfig::default();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_payer.signers = vec![&default_signer0];
let mut config_witness = CliConfig::default();
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
config_witness.signers = vec![&default_signer1];
assert_ne!(
config_payer.keypair.pubkey(),
config_witness.keypair.pubkey()
config_payer.signers[0].pubkey(),
config_witness.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_payer.keypair.pubkey(),
&config_payer.signers[0].pubkey(),
50,
&config_witness,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_witness.keypair.pubkey(),
&config_witness.signers[0].pubkey(),
1,
&config_witness,
)
.unwrap();
@ -159,7 +173,7 @@ fn test_cli_witness_tx() {
config_payer.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
witnesses: Some(vec![config_witness.keypair.pubkey()]),
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
..PayCommand::default()
});
let sig_response = process_command(&config_payer);
@ -171,7 +185,7 @@ fn test_cli_witness_tx() {
.expect("base58-encoded public key");
let process_id = Pubkey::new(&process_id_vec);
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_balance(10, &rpc_client, &process_id); // contract balance
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
@ -179,7 +193,7 @@ fn test_cli_witness_tx() {
config_witness.command = CliCommand::Witness(bob_pubkey, process_id);
process_command(&config_witness).unwrap();
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_balance(0, &rpc_client, &process_id); // contract balance
check_balance(10, &rpc_client, &bob_pubkey); // recipient balance
@ -189,7 +203,13 @@ fn test_cli_witness_tx() {
#[test]
fn test_cli_cancel_tx() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
@ -197,24 +217,29 @@ fn test_cli_cancel_tx() {
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer0 = Keypair::new();
let default_signer1 = Keypair::new();
let mut config_payer = CliConfig::default();
config_payer.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_payer.signers = vec![&default_signer0];
let mut config_witness = CliConfig::default();
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
config_witness.signers = vec![&default_signer1];
assert_ne!(
config_payer.keypair.pubkey(),
config_witness.keypair.pubkey()
config_payer.signers[0].pubkey(),
config_witness.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_payer.keypair.pubkey(),
&config_payer.signers[0].pubkey(),
50,
&config_witness,
)
.unwrap();
@ -222,7 +247,7 @@ fn test_cli_cancel_tx() {
config_payer.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
witnesses: Some(vec![config_witness.keypair.pubkey()]),
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
cancelable: true,
..PayCommand::default()
});
@ -235,7 +260,7 @@ fn test_cli_cancel_tx() {
.expect("base58-encoded public key");
let process_id = Pubkey::new(&process_id_vec);
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_balance(10, &rpc_client, &process_id); // contract balance
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
@ -243,7 +268,7 @@ fn test_cli_cancel_tx() {
config_payer.command = CliCommand::Cancel(process_id);
process_command(&config_payer).unwrap();
check_balance(50, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
check_balance(50, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
check_balance(0, &rpc_client, &process_id); // contract balance
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
@ -253,7 +278,13 @@ fn test_cli_cancel_tx() {
#[test]
fn test_offline_pay_tx() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let bob_pubkey = Pubkey::new_rand();
let (sender, receiver) = channel();
@ -261,64 +292,73 @@ fn test_offline_pay_tx() {
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let default_offline_signer = Keypair::new();
let mut config_offline = CliConfig::default();
config_offline.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_offline.signers = vec![&default_offline_signer];
let mut config_online = CliConfig::default();
config_online.json_rpc_url =
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config_online.signers = vec![&default_signer];
assert_ne!(
config_offline.keypair.pubkey(),
config_online.keypair.pubkey()
config_offline.signers[0].pubkey(),
config_online.signers[0].pubkey()
);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_offline.keypair.pubkey(),
&config_offline.signers[0].pubkey(),
50,
&config_offline,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config_online.keypair.pubkey(),
&config_online.signers[0].pubkey(),
50,
&config_offline,
)
.unwrap();
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
check_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
check_balance(50, &rpc_client, &config_online.signers[0].pubkey());
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
config_offline.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
blockhash_query: BlockhashQuery::None(blockhash),
sign_only: true,
..PayCommand::default()
});
config_offline.output_format = OutputFormat::JsonCompact;
let sig_response = process_command(&config_offline).unwrap();
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
check_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
check_balance(50, &rpc_client, &config_online.signers[0].pubkey());
check_balance(0, &rpc_client, &bob_pubkey);
let (blockhash, signers) = parse_sign_only_reply_string(&sig_response);
let offline_presigner =
presigner_from_pubkey_sigs(&config_offline.keypair.pubkey(), &signers).unwrap();
let online_pubkey = config_online.keypair.pubkey();
config_online.keypair = offline_presigner.into();
let sign_only = parse_sign_only_reply_string(&sig_response);
assert!(sign_only.has_all_signers());
let offline_presigner = sign_only
.presigner_of(&config_offline.signers[0].pubkey())
.unwrap();
let online_pubkey = config_online.signers[0].pubkey();
config_online.signers = vec![&offline_presigner];
config_online.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
..PayCommand::default()
});
process_command(&config_online).unwrap();
check_balance(40, &rpc_client, &config_offline.keypair.pubkey());
check_balance(40, &rpc_client, &config_offline.signers[0].pubkey());
check_balance(50, &rpc_client, &online_pubkey);
check_balance(10, &rpc_client, &bob_pubkey);
@ -330,15 +370,23 @@ fn test_offline_pay_tx() {
fn test_nonced_pay_tx() {
solana_logger::setup();
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let mut config = CliConfig::default();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let minimum_nonce_balance = rpc_client
.get_minimum_balance_for_rent_exemption(NonceState::size())
@ -347,59 +395,60 @@ fn test_nonced_pay_tx() {
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config.keypair.pubkey(),
&config.signers[0].pubkey(),
50 + minimum_nonce_balance,
&config,
)
.unwrap();
check_balance(
50 + minimum_nonce_balance,
&rpc_client,
&config.keypair.pubkey(),
&config.signers[0].pubkey(),
);
// Create nonce account
let nonce_account = Keypair::new();
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
config.command = CliCommand::CreateNonceAccount {
nonce_account: Rc::new(read_keypair_file(&nonce_keypair_file).unwrap().into()),
nonce_account: 1,
seed: None,
nonce_authority: Some(config.keypair.pubkey()),
nonce_authority: Some(config.signers[0].pubkey()),
lamports: minimum_nonce_balance,
};
config.signers.push(&nonce_account);
process_command(&config).unwrap();
check_balance(50, &rpc_client, &config.keypair.pubkey());
check_balance(50, &rpc_client, &config.signers[0].pubkey());
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
// Fetch nonce hash
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
let nonce_hash = match nonce_state {
NonceState::Initialized(_meta, hash) => hash,
_ => panic!("Nonce is not initialized"),
};
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
.and_then(|ref a| nonce::data_from_account(a))
.unwrap()
.blockhash;
let bob_pubkey = Pubkey::new_rand();
config.signers = vec![&default_signer];
config.command = CliCommand::Pay(PayCommand {
lamports: 10,
to: bob_pubkey,
blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
nonce_hash,
),
nonce_account: Some(nonce_account.pubkey()),
..PayCommand::default()
});
process_command(&config).expect("failed to process pay command");
check_balance(40, &rpc_client, &config.keypair.pubkey());
check_balance(40, &rpc_client, &config.signers[0].pubkey());
check_balance(10, &rpc_client, &bob_pubkey);
// Verify that nonce has been used
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
match nonce_state {
NonceState::Initialized(_meta, hash) => assert_ne!(hash, nonce_hash),
_ => assert!(false, "Nonce is not initialized"),
}
let nonce_hash2 = nonce::get_account(&rpc_client, &nonce_account.pubkey())
.and_then(|ref a| nonce::data_from_account(a))
.unwrap()
.blockhash;
assert_ne!(nonce_hash, nonce_hash2);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();

View File

@ -1,13 +1,19 @@
use solana_cli::cli::{process_command, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient;
use solana_core::validator::new_validator_for_tests;
use solana_core::validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use std::fs::remove_dir_all;
use std::sync::mpsc::channel;
use solana_sdk::signature::Keypair;
use std::{fs::remove_dir_all, sync::mpsc::channel};
#[test]
fn test_cli_request_airdrop() {
let (server, leader_data, alice, ledger_path) = new_validator_for_tests();
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
@ -20,6 +26,8 @@ fn test_cli_request_airdrop() {
pubkey: None,
lamports: 50,
};
let keypair = Keypair::new();
bob_config.signers = vec![&keypair];
let sig_response = process_command(&bob_config);
sig_response.unwrap();
@ -27,7 +35,7 @@ fn test_cli_request_airdrop() {
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let balance = rpc_client
.retry_get_balance(&bob_config.keypair.pubkey(), 1)
.retry_get_balance(&bob_config.signers[0].pubkey(), 1)
.unwrap()
.unwrap();
assert_eq!(balance, 50);

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,21 @@
use solana_clap_utils::keypair::presigner_from_pubkey_sigs;
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
offline::{parse_sign_only_reply_string, BlockhashQuery},
cli_output::OutputFormat,
nonce,
offline::{
blockhash_query::{self, BlockhashQuery},
parse_sign_only_reply_string,
},
};
use solana_client::rpc_client::RpcClient;
use solana_core::validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
account_utils::StateMut,
fee_calculator::FeeCalculator,
nonce_state::NonceState,
nonce::State as NonceState,
pubkey::Pubkey,
signature::{keypair_from_seed, read_keypair_file, write_keypair, Signer},
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
};
use std::fs::remove_dir_all;
use std::sync::mpsc::channel;
#[cfg(test)]
use solana_core::validator::new_validator_for_tests_ex;
use std::rc::Rc;
use std::thread::sleep;
use std::time::Duration;
use tempfile::NamedTempFile;
fn make_tmp_file() -> (String, NamedTempFile) {
let tmp_file = NamedTempFile::new().unwrap();
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
}
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
(0..5).for_each(|tries| {
@ -42,7 +32,17 @@ fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
#[test]
fn test_transfer() {
let (server, leader_data, mint_keypair, ledger_path, _) = new_validator_for_tests_ex(1, 42_000);
let TestValidator {
server,
leader_data,
alice: mint_keypair,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
@ -50,15 +50,18 @@ fn test_transfer() {
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let default_offline_signer = Keypair::new();
let mut config = CliConfig::default();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
let sender_pubkey = config.keypair.pubkey();
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
println!("sender: {:?}", sender_pubkey);
println!("recipient: {:?}", recipient_pubkey);
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000, &config)
.unwrap();
check_balance(50_000, &rpc_client, &sender_pubkey);
check_balance(0, &rpc_client, &recipient_pubkey);
@ -66,12 +69,13 @@ fn test_transfer() {
config.command = CliCommand::Transfer {
lamports: 10,
to: recipient_pubkey,
from: None,
from: 0,
sign_only: false,
blockhash_query: BlockhashQuery::All,
no_wait: false,
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: None,
fee_payer: None,
nonce_authority: 0,
fee_payer: 0,
};
process_command(&config).unwrap();
check_balance(49_989, &rpc_client, &sender_pubkey);
@ -79,13 +83,13 @@ fn test_transfer() {
let mut offline = CliConfig::default();
offline.json_rpc_url = String::default();
offline.signers = vec![&default_offline_signer];
// Verify we cannot contact the cluster
offline.command = CliCommand::ClusterVersion;
process_command(&offline).unwrap_err();
let offline_pubkey = offline.keypair.pubkey();
println!("offline: {:?}", offline_pubkey);
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 50).unwrap();
let offline_pubkey = offline.signers[0].pubkey();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 50, &config).unwrap();
check_balance(50, &rpc_client, &offline_pubkey);
// Offline transfer
@ -93,25 +97,30 @@ fn test_transfer() {
offline.command = CliCommand::Transfer {
lamports: 10,
to: recipient_pubkey,
from: None,
from: 0,
sign_only: true,
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
no_wait: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: None,
fee_payer: None,
nonce_authority: 0,
fee_payer: 0,
};
offline.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&offline).unwrap();
let (blockhash, signers) = parse_sign_only_reply_string(&sign_only_reply);
let offline_presigner = presigner_from_pubkey_sigs(&offline_pubkey, &signers).unwrap();
let sign_only = parse_sign_only_reply_string(&sign_only_reply);
assert!(sign_only.has_all_signers());
let offline_presigner = sign_only.presigner_of(&offline_pubkey).unwrap();
config.signers = vec![&offline_presigner];
config.command = CliCommand::Transfer {
lamports: 10,
to: recipient_pubkey,
from: Some(offline_presigner.clone().into()),
from: 0,
sign_only: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: None,
fee_payer: Some(offline_presigner.clone().into()),
nonce_authority: 0,
fee_payer: 0,
};
process_command(&config).unwrap();
check_balance(39, &rpc_client, &offline_pubkey);
@ -119,13 +128,12 @@ fn test_transfer() {
// Create nonce account
let nonce_account = keypair_from_seed(&[3u8; 32]).unwrap();
let (nonce_account_file, mut tmp_file) = make_tmp_file();
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
let minimum_nonce_balance = rpc_client
.get_minimum_balance_for_rent_exemption(NonceState::size())
.unwrap();
config.signers = vec![&default_signer, &nonce_account];
config.command = CliCommand::CreateNonceAccount {
nonce_account: Rc::new(read_keypair_file(&nonce_account_file).unwrap().into()),
nonce_account: 1,
seed: None,
nonce_authority: None,
lamports: minimum_nonce_balance,
@ -134,75 +142,83 @@ fn test_transfer() {
check_balance(49_987 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
// Fetch nonce hash
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
let nonce_hash = match nonce_state {
NonceState::Initialized(_meta, hash) => hash,
_ => panic!("Nonce is not initialized"),
};
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
.and_then(|ref a| nonce::data_from_account(a))
.unwrap()
.blockhash;
// Nonced transfer
config.signers = vec![&default_signer];
config.command = CliCommand::Transfer {
lamports: 10,
to: recipient_pubkey,
from: None,
from: 0,
sign_only: false,
blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
nonce_hash,
),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: None,
fee_payer: None,
nonce_authority: 0,
fee_payer: 0,
};
process_command(&config).unwrap();
check_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
check_balance(30, &rpc_client, &recipient_pubkey);
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
let new_nonce_hash = match nonce_state {
NonceState::Initialized(_meta, hash) => hash,
_ => panic!("Nonce is not initialized"),
};
let new_nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
.and_then(|ref a| nonce::data_from_account(a))
.unwrap()
.blockhash;
assert_ne!(nonce_hash, new_nonce_hash);
// Assign nonce authority to offline
config.signers = vec![&default_signer];
config.command = CliCommand::AuthorizeNonceAccount {
nonce_account: nonce_account.pubkey(),
nonce_authority: None,
nonce_authority: 0,
new_authority: offline_pubkey,
};
process_command(&config).unwrap();
check_balance(49_975 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
// Fetch nonce hash
let account = rpc_client.get_account(&nonce_account.pubkey()).unwrap();
let nonce_state: NonceState = account.state().unwrap();
let nonce_hash = match nonce_state {
NonceState::Initialized(_meta, hash) => hash,
_ => panic!("Nonce is not initialized"),
};
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
.and_then(|ref a| nonce::data_from_account(a))
.unwrap()
.blockhash;
// Offline, nonced transfer
offline.signers = vec![&default_offline_signer];
offline.command = CliCommand::Transfer {
lamports: 10,
to: recipient_pubkey,
from: None,
from: 0,
sign_only: true,
blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()),
no_wait: false,
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: None,
fee_payer: None,
nonce_authority: 0,
fee_payer: 0,
};
let sign_only_reply = process_command(&offline).unwrap();
let (blockhash, signers) = parse_sign_only_reply_string(&sign_only_reply);
let offline_presigner = presigner_from_pubkey_sigs(&offline_pubkey, &signers).unwrap();
let sign_only = parse_sign_only_reply_string(&sign_only_reply);
assert!(sign_only.has_all_signers());
let offline_presigner = sign_only.presigner_of(&offline_pubkey).unwrap();
config.signers = vec![&offline_presigner];
config.command = CliCommand::Transfer {
lamports: 10,
to: recipient_pubkey,
from: Some(offline_presigner.clone().into()),
from: 0,
sign_only: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(
blockhash_query::Source::NonceAccount(nonce_account.pubkey()),
sign_only.blockhash,
),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: Some(offline_presigner.clone().into()),
fee_payer: Some(offline_presigner.clone().into()),
nonce_authority: 0,
fee_payer: 0,
};
process_command(&config).unwrap();
check_balance(28, &rpc_client, &offline_pubkey);
@ -211,3 +227,128 @@ fn test_transfer() {
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}
#[test]
fn test_transfer_multisession_signing() {
let TestValidator {
server,
leader_data,
alice: mint_keypair,
ledger_path,
..
} = TestValidator::run_with_options(TestValidatorOptions {
fees: 1,
bootstrap_validator_lamports: 42_000,
..TestValidatorOptions::default()
});
let (sender, receiver) = channel();
run_local_faucet(mint_keypair, sender, None);
let faucet_addr = receiver.recv().unwrap();
let to_pubkey = Pubkey::new(&[1u8; 32]);
let offline_from_signer = keypair_from_seed(&[2u8; 32]).unwrap();
let offline_fee_payer_signer = keypair_from_seed(&[3u8; 32]).unwrap();
let from_null_signer = NullSigner::new(&offline_from_signer.pubkey());
let config = CliConfig::default();
// Setup accounts
let rpc_client = RpcClient::new_socket(leader_data.rpc);
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&offline_from_signer.pubkey(),
43,
&config,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&offline_fee_payer_signer.pubkey(),
3,
&config,
)
.unwrap();
check_balance(43, &rpc_client, &offline_from_signer.pubkey());
check_balance(3, &rpc_client, &offline_fee_payer_signer.pubkey());
check_balance(0, &rpc_client, &to_pubkey);
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
// Offline fee-payer signs first
let mut fee_payer_config = CliConfig::default();
fee_payer_config.json_rpc_url = String::default();
fee_payer_config.signers = vec![&offline_fee_payer_signer, &from_null_signer];
// Verify we cannot contact the cluster
fee_payer_config.command = CliCommand::ClusterVersion;
process_command(&fee_payer_config).unwrap_err();
fee_payer_config.command = CliCommand::Transfer {
lamports: 42,
to: to_pubkey,
from: 1,
sign_only: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
};
fee_payer_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&fee_payer_config).unwrap();
let sign_only = parse_sign_only_reply_string(&sign_only_reply);
assert!(!sign_only.has_all_signers());
let fee_payer_presigner = sign_only
.presigner_of(&offline_fee_payer_signer.pubkey())
.unwrap();
// Now the offline fund source
let mut from_config = CliConfig::default();
from_config.json_rpc_url = String::default();
from_config.signers = vec![&fee_payer_presigner, &offline_from_signer];
// Verify we cannot contact the cluster
from_config.command = CliCommand::ClusterVersion;
process_command(&from_config).unwrap_err();
from_config.command = CliCommand::Transfer {
lamports: 42,
to: to_pubkey,
from: 1,
sign_only: true,
no_wait: false,
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
};
from_config.output_format = OutputFormat::JsonCompact;
let sign_only_reply = process_command(&from_config).unwrap();
let sign_only = parse_sign_only_reply_string(&sign_only_reply);
assert!(sign_only.has_all_signers());
let from_presigner = sign_only
.presigner_of(&offline_from_signer.pubkey())
.unwrap();
// Finally submit to the cluster
let mut config = CliConfig::default();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&fee_payer_presigner, &from_presigner];
config.command = CliCommand::Transfer {
lamports: 42,
to: to_pubkey,
from: 1,
sign_only: false,
no_wait: false,
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
fee_payer: 0,
};
process_command(&config).unwrap();
check_balance(1, &rpc_client, &offline_from_signer.pubkey());
check_balance(1, &rpc_client, &offline_fee_payer_signer.pubkey());
check_balance(42, &rpc_client, &to_pubkey);
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

121
cli/tests/vote.rs Normal file
View File

@ -0,0 +1,121 @@
use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig};
use solana_client::rpc_client::RpcClient;
use solana_core::validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
account_utils::StateMut,
pubkey::Pubkey,
signature::{Keypair, Signer},
};
use solana_vote_program::vote_state::{VoteAuthorize, VoteState, VoteStateVersions};
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
(0..5).for_each(|tries| {
let balance = client.retry_get_balance(pubkey, 1).unwrap().unwrap();
if balance == expected_balance {
return;
}
if tries == 4 {
assert_eq!(balance, expected_balance);
}
sleep(Duration::from_millis(500));
});
}
#[test]
fn test_vote_authorize_and_withdraw() {
let TestValidator {
server,
leader_data,
alice,
ledger_path,
..
} = TestValidator::run();
let (sender, receiver) = channel();
run_local_faucet(alice, sender, None);
let faucet_addr = receiver.recv().unwrap();
let rpc_client = RpcClient::new_socket(leader_data.rpc);
let default_signer = Keypair::new();
let mut config = CliConfig::default();
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
config.signers = vec![&default_signer];
request_and_confirm_airdrop(
&rpc_client,
&faucet_addr,
&config.signers[0].pubkey(),
100_000,
&config,
)
.unwrap();
// Create vote account
let vote_account_keypair = Keypair::new();
let vote_account_pubkey = vote_account_keypair.pubkey();
config.signers = vec![&default_signer, &vote_account_keypair];
config.command = CliCommand::CreateVoteAccount {
vote_account: 1,
seed: None,
identity_account: 0,
authorized_voter: None,
authorized_withdrawer: Some(config.signers[0].pubkey()),
commission: 0,
};
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, config.signers[0].pubkey());
let expected_balance = rpc_client
.get_minimum_balance_for_rent_exemption(VoteState::size_of())
.unwrap()
.max(1);
check_balance(expected_balance, &rpc_client, &vote_account_pubkey);
// Authorize vote account withdrawal to another signer
let withdraw_authority = Keypair::new();
config.signers = vec![&default_signer];
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey: withdraw_authority.pubkey(),
vote_authorize: VoteAuthorize::Withdrawer,
};
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, withdraw_authority.pubkey());
// Withdraw from vote account
let destination_account = Pubkey::new_rand(); // Send withdrawal to new account to make balance check easy
config.signers = vec![&default_signer, &withdraw_authority];
config.command = CliCommand::WithdrawFromVoteAccount {
vote_account_pubkey,
withdraw_authority: 1,
lamports: 100,
destination_account_pubkey: destination_account,
};
process_command(&config).unwrap();
check_balance(expected_balance - 100, &rpc_client, &vote_account_pubkey);
check_balance(100, &rpc_client, &destination_account);
// Re-assign validator identity
let new_identity_keypair = Keypair::new();
config.signers.push(&new_identity_keypair);
config.command = CliCommand::VoteUpdateValidator {
vote_account_pubkey,
new_identity_account: 2,
withdraw_authority: 1,
};
process_command(&config).unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();
}

View File

@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "1.0.0"
version = "1.1.24"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.com>"]
repository = "https://github.com/solana-labs/solana"
@ -11,15 +11,18 @@ edition = "2018"
[dependencies]
bincode = "1.2.1"
bs58 = "0.3.0"
indicatif = "0.14.0"
jsonrpc-core = "14.0.5"
log = "0.4.8"
rayon = "1.2.0"
reqwest = { version = "0.10.1", default-features = false, features = ["blocking", "rustls-tls"] }
serde = "1.0.104"
rayon = "1.3.0"
reqwest = { version = "0.10.4", default-features = false, features = ["blocking", "rustls-tls", "json"] }
serde = "1.0.105"
serde_derive = "1.0.103"
serde_json = "1.0.46"
solana-net-utils = { path = "../net-utils", version = "1.0.0" }
solana-sdk = { path = "../sdk", version = "1.0.0" }
serde_json = "1.0.48"
solana-transaction-status = { path = "../transaction-status", version = "1.1.24" }
solana-net-utils = { path = "../net-utils", version = "1.1.24" }
solana-sdk = { path = "../sdk", version = "1.1.24" }
solana-vote-program = { path = "../programs/vote", version = "1.1.24" }
thiserror = "1.0"
tungstenite = "0.10.1"
url = "2.1.1"
@ -28,4 +31,7 @@ url = "2.1.1"
assert_matches = "1.3.0"
jsonrpc-core = "14.0.5"
jsonrpc-http-server = "14.0.6"
solana-logger = { path = "../logger", version = "1.0.0" }
solana-logger = { path = "../logger", version = "1.1.24" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,20 +1,161 @@
use crate::rpc_request;
use solana_sdk::{signature::SignerError, transaction::TransactionError};
use std::{fmt, io};
use solana_sdk::{
signature::SignerError, transaction::TransactionError, transport::TransportError,
};
use std::io;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ClientError {
pub enum ClientErrorKind {
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
#[error(transparent)]
RpcError(#[from] rpc_request::RpcError),
#[error(transparent)]
SerdeJson(#[from] serde_json::error::Error),
#[error(transparent)]
SigningError(#[from] SignerError),
#[error(transparent)]
TransactionError(#[from] TransactionError),
#[error("Custom: {0}")]
Custom(String),
}
impl fmt::Display for ClientError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "solana client error")
impl From<TransportError> for ClientErrorKind {
fn from(err: TransportError) -> Self {
match err {
TransportError::IoError(err) => Self::Io(err),
TransportError::TransactionError(err) => Self::TransactionError(err),
TransportError::Custom(err) => Self::Custom(err),
}
}
}
impl Into<TransportError> for ClientErrorKind {
fn into(self) -> TransportError {
match self {
Self::Io(err) => TransportError::IoError(err),
Self::TransactionError(err) => TransportError::TransactionError(err),
Self::Reqwest(err) => TransportError::Custom(format!("{:?}", err)),
Self::RpcError(err) => TransportError::Custom(format!("{:?}", err)),
Self::SerdeJson(err) => TransportError::Custom(format!("{:?}", err)),
Self::SigningError(err) => TransportError::Custom(format!("{:?}", err)),
Self::Custom(err) => TransportError::Custom(format!("{:?}", err)),
}
}
}
#[derive(Error, Debug)]
#[error("{kind}")]
pub struct ClientError {
request: Option<rpc_request::RpcRequest>,
#[source]
kind: ClientErrorKind,
}
impl ClientError {
pub fn new_with_request(kind: ClientErrorKind, request: rpc_request::RpcRequest) -> Self {
Self {
request: Some(request),
kind,
}
}
pub fn into_with_request(self, request: rpc_request::RpcRequest) -> Self {
Self {
request: Some(request),
..self
}
}
pub fn request(&self) -> Option<&rpc_request::RpcRequest> {
self.request.as_ref()
}
pub fn kind(&self) -> &ClientErrorKind {
&self.kind
}
}
impl From<ClientErrorKind> for ClientError {
fn from(kind: ClientErrorKind) -> Self {
Self {
request: None,
kind,
}
}
}
impl From<TransportError> for ClientError {
fn from(err: TransportError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl Into<TransportError> for ClientError {
fn into(self) -> TransportError {
self.kind.into()
}
}
impl From<std::io::Error> for ClientError {
fn from(err: std::io::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<reqwest::Error> for ClientError {
fn from(err: reqwest::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<rpc_request::RpcError> for ClientError {
fn from(err: rpc_request::RpcError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<serde_json::error::Error> for ClientError {
fn from(err: serde_json::error::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<SignerError> for ClientError {
fn from(err: SignerError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<TransactionError> for ClientError {
fn from(err: TransactionError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
pub type Result<T> = std::result::Result<T, ClientError>;

View File

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

View File

@ -8,6 +8,7 @@ pub mod perf_utils;
pub mod pubsub_client;
pub mod rpc_client;
pub mod rpc_client_request;
pub mod rpc_config;
pub mod rpc_request;
pub mod rpc_response;
pub mod thin_client;

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