Compare commits

..

88 Commits

Author SHA1 Message Date
Trent Nelson
03b21f2e9d Bump version to v1.6.2 2021-03-30 00:06:01 -06:00
carllin
cc5565b17e Setup ReplayStage confirmation scaffolding for duplicate slots (#9698)
(cherry picked from commit 52703badfa)
2021-03-29 22:07:14 -06:00
mergify[bot]
50beef0b15 Allow incomplete features in frozen-abi (#16205)
(cherry picked from commit 9ba9d2a8ae)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-03-30 03:46:10 +00:00
mergify[bot]
06a54e1423 remove old code (#15988) (#15993)
(cherry picked from commit 9760fded2d)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-03-30 00:50:27 +00:00
mergify[bot]
4d731ecd08 eliminate lock on record (#15929) (#16073)
* eliminate lock on record

* use same error as MaxHeightReached

* clippy

* review feedback

* refactor should_tick code

* pr feedback

(cherry picked from commit 57ba86c821)

Co-authored-by: Jeff Washington (jwash) <75863576+jeffwashington@users.noreply.github.com>
2021-03-30 00:46:13 +00:00
mergify[bot]
ee06789a66 sdk: Add try_from_slice_unchecked for Borsh (#16098) (#16158)
* sdk: Add try_from_slice_unchecked for Borsh

* Add tests

* Rename + clarify comment

* Rename back to unchecked

(cherry picked from commit cffa851e0f)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-03-29 23:15:34 +00:00
mergify[bot]
2dabe1d706 Add handling to close accounts to many-accounts bench (#16199) (#16201)
* gitignore farf

* Improve cli args

* Use derived addresses for accounts

* Add parameter to close every nth account created

(cherry picked from commit 1d145e1fc2)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-29 22:54:09 +00:00
Tyera Eulberg
3b1279a005 Future-aware enum name 2021-03-29 14:58:35 -06:00
mergify[bot]
5c9f85f28d Rpc: enable getConfirmedBlocks and getConfirmedBlocksWithLimit to return confirmed (not yet finalized) data (#16161) (#16198)
* Add commitment config capabilities

* Use rpc limit if no end_slot provided

* Limit to actually finalized blocks

* Support confirmed blocks in getConfirmedBlocks and getConfirmedBlocksWithLimit

* Update docs

* Add client plumbing

* Rename config enum

(cherry picked from commit 60ed8e2892)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-29 19:53:17 +00:00
mergify[bot]
e12dd46ef3 Derive PartialEq for StakeActivationState (#16196)
(cherry picked from commit 4e7bd45d4c)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-29 18:16:44 +00:00
mergify[bot]
c4fa03b478 Status cache improvements (#16174) (#16178)
(cherry picked from commit 5e5b63712b)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-03-29 10:11:16 -07:00
mergify[bot]
9fb749deb7 Print the rust version when building bpf programs (#16181) (#16183)
(cherry picked from commit abada56ba1)

Co-authored-by: Justin Starry <justin@solana.com>
2021-03-29 07:18:55 +00:00
mergify[bot]
bd48344de2 Fix handling of invoked ix accounts in program-test (#16170) (#16176)
(cherry picked from commit 27ab415ecc)

Co-authored-by: Justin Starry <justin@solana.com>
2021-03-29 01:55:11 +00:00
mergify[bot]
78e54f1d2c Implement mnemonic support for solana-keygen grind (solana-labs#9325) (#16108) (#16173)
* Implement mnemonic support for solana-keygen grind (solana-labs#9325)

* Updated to include feedback from review.

* Renaming as per review feedback

* Fixed an incorrectly transcribed underscore

* Properly re-use string constants.

(cherry picked from commit e50f598449)

Co-authored-by: bji <bryan@ischo.com>
2021-03-28 07:05:17 +00:00
mergify[bot]
76a6576976 sdk: Use u32::MAX from std to unbreak BPF builds (#16171) (#16172)
(cherry picked from commit aabe186e3f)

Co-authored-by: Justin Starry <justin@solana.com>
2021-03-27 17:05:53 +00:00
mergify[bot]
92ec1ae255 Switch to a single use (#16169)
(cherry picked from commit 16e4ccca13)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-27 06:58:31 +00:00
Michael Vines
0d203728cc Add RpcClient::get_stake_activation() 2021-03-26 22:33:06 -07:00
mergify[bot]
625773e5b8 Rpc: enable getConfirmedBlock and getConfirmedTransaction to return confirmed (not yet finalized) data (bp #16142) (#16160)
* Rpc: enable getConfirmedBlock and getConfirmedTransaction to return confirmed (not yet finalized) data (#16142)

* Add Blockstore block and tx apis that allow unrooted responses

* Add TransactionStatusMessage, and send on bank freeze; also refactor TransactionStatusSender

* Track highest slot with tx-status writes complete

* Rename and unpub fn

* Add commitment to GetConfirmed input configs

* Support confirmed blocks in getConfirmedBlock

* Support confirmed txs in getConfirmedTransaction

* Update sigs-for-addr2 comment

* Enable confirmed block in cli

* Enable confirmed transaction in cli

* Review comments

* Rename blockstore method

(cherry picked from commit 433f1ead1c)

# Conflicts:
#	core/src/replay_stage.rs

* Fix conflict

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-03-27 04:51:53 +00:00
mergify[bot]
a4cb1e45ae Only print skipped leader slot message when the node is actually leader (#16156) (#16164)
Also, check vote signature after the vote is signed

(cherry picked from commit 60b4771fc6)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-03-27 02:03:10 +00:00
mergify[bot]
8aded2778e Bump bpf-tools to version v1.4 (#16152) (#16154)
(cherry picked from commit 658ddd1c9c)

Co-authored-by: Dmitri Makarov <dmakarov@users.noreply.github.com>
2021-03-26 20:51:25 +00:00
mergify[bot]
d940c5b1a3 Skip leader slots until a vote lands (#15607) (#16147)
(cherry picked from commit b99ae8f334)

Co-authored-by: sakridge <sakridge@gmail.com>
2021-03-26 19:07:24 +00:00
Trent Nelson
1be045df94 sq: optimize
(cherry picked from commit 482c027d3b)
2021-03-25 21:31:52 -06:00
Trent Nelson
86191911c7 perf: use saturating/checked integer arithmetic
(cherry picked from commit 834fae684b)
2021-03-25 21:31:52 -06:00
mergify[bot]
8f852d8a6b makes test_pull_request_time_pruning smaller (#16128) (#16144)
(cherry picked from commit b041b55028)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-03-26 01:20:26 +00:00
Kristofer Peterson
68a439f8da Refactored ShortU16Visitor::visit_seq() to reject overflows, extra leading zeros and ensure one-to-one encoding. 2021-03-26 01:20:22 +00:00
Trent Nelson
e021832708 sdk: ShortU16 - rename variables for clarity
ShortU16's implementation embeds its usage as the length of a
ShortVec, confusingly referring to both a 'len' and a 'size'
at the same time.
2021-03-26 01:20:22 +00:00
Trent Nelson
87b11aa187 sdk: Add ShortU16 deser test 2021-03-26 01:20:22 +00:00
mergify[bot]
7475a6f444 makes turbine peer computation consistent between broadcast and retransmit (#14910) (#16143)
get_broadcast_peers is using tvu_peers:
https://github.com/solana-labs/solana/blob/84e52b606/core/src/broadcast_stage.rs#L362-L370
which is potentially inconsistent with retransmit_peers:
https://github.com/solana-labs/solana/blob/84e52b606/core/src/cluster_info.rs#L1332-L1345

Also, the leader does not include its own contact-info when broadcasting
shreds:
https://github.com/solana-labs/solana/blob/84e52b606/core/src/cluster_info.rs#L1324
but on the retransmit side, slot leader is removed only _after_ neighbors and
children are computed:
https://github.com/solana-labs/solana/blob/84e52b606/core/src/retransmit_stage.rs#L383-L384
So the turbine broadcast tree is different between the two stages.

This commit:
* Removes retransmit_peers. Broadcast and retransmit stages will use tvu_peers
  consistently.
* Retransmit stage removes slot leader _before_ computing children and
  neighbors.

(cherry picked from commit 570fd3f810)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-03-26 00:16:48 +00:00
mergify[bot]
86ce650661 Add timeout for local cluster partition tests (bp #16123) (#16137)
* Add timeout for local cluster partition tests (#16123)

* Add timeout for local cluster partition tests

* fix optimistic conf test logs

* Bump instruction count assertions

(cherry picked from commit e817a6db00)

# Conflicts:
#	local-cluster/Cargo.toml

* Fix conflict

Co-authored-by: Justin Starry <justin@solana.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
2021-03-25 22:56:05 +00:00
mergify[bot]
4dc5a53014 Show bpf-tools download progress (#16135)
(cherry picked from commit 07273bfa9e)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-25 20:55:11 +00:00
mergify[bot]
5e35cf3536 program: Correct clamp in Message::signer_keys() (#16114)
(cherry picked from commit 8b3de72e2a)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-03-25 17:53:34 +00:00
Trent Nelson
e8a8d1efb3 clap-utils: Allow NullSigners outside sign-only mode
(cherry picked from commit 7f0ac6a67c)
2021-03-25 11:10:53 -06:00
mergify[bot]
defd9238fa Simplify account.rent_epoch handling for sysvar rent (bp #16049) (#16118)
* Simplify account.rent_epoch handling for sysvar rent (#16049)

* Add some code for special local testing

* Add comment to store_account_and_update_capitalization

* Simplify account.rent_epoch handling for sysvar rent

* Introduce *_for_test functions

* Add deprecation messages to existing api

(cherry picked from commit 6d5c6c17c5)

# Conflicts:
#	sdk/src/native_loader.rs

* Fix conflicts

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-03-25 17:17:43 +09:00
mergify[bot]
5f061dcea1 Support getBlockTime for unfinalized blocks (#16103) (#16110)
(cherry picked from commit a8ef29df27)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-25 04:18:00 +00:00
mergify[bot]
e6ee27a738 Add Exodus as Solana Mobile app option (#16100) (#16101)
* Add Exodus as Solana Mobile app option

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

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

Co-authored-by: Davey <35187388+davidzelaya@users.noreply.github.com>
2021-03-24 21:34:58 +00:00
mergify[bot]
dd2d25d698 limits CrdsGossipPull::pull_request_time size (#15793) (#16097)
There is no pruning logic on CrdsGossipPull::pull_request_time
https://github.com/solana-labs/solana/blob/79ac1997d/core/src/crds_gossip_pull.rs#L172-L174
potentially allowing this to take too much memory.

Additionally, CrdsGossipPush::last_pushed_to is pruning recent push
timestamps:
https://github.com/solana-labs/solana/blob/79ac1997d/core/src/crds_gossip_push.rs#L275-L279
instead of the older ones.

Co-authored-by: Nathan Hawkins <utsl@utsl.org>
(cherry picked from commit a6c23648cb)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-03-24 20:05:04 +00:00
Dmitri Makarov
9096c3df02 Adjust BPF test programs instruction counts 2021-03-24 11:59:59 +01:00
Dmitri Makarov
9f94c2a9a0 Bump bpf-tools to version v1.3
This brings in the fix for increased compute budget that wasn't caught
when bpf-tools v1.2 were released.
2021-03-24 11:59:59 +01:00
Dmitri Makarov
34213da9f4 Bump bpf-tools to v1.2 and get rid of xargo 2021-03-24 11:59:59 +01:00
mergify[bot]
c3c4991c44 rpc: add getSlotLeaders method (#16057) (#16079)
(cherry picked from commit e7fd7d46cf)

Co-authored-by: Justin Starry <justin@solana.com>
2021-03-23 19:27:18 +00:00
mergify[bot]
9d37a33dcd buffers data shreds to make larger erasure coded sets (bp #15849) (#16074)
* buffers data shreds to make larger erasure coded sets (#15849)

Broadcast stage batches up to 8 entries:
https://github.com/solana-labs/solana/blob/79280b304/core/src/broadcast_stage/broadcast_utils.rs#L26-L29
which will be serialized into some number of shreds and chunked into FEC
sets of at most 32 shreds each:
https://github.com/solana-labs/solana/blob/79280b304/ledger/src/shred.rs#L576-L597
So depending on the size of entries, FEC sets can be small, which may
aggravate loss rate.
For example 16 FEC sets of 2:2 data/code shreds each have higher loss
rate than one 32:32 set.

This commit broadcasts data shreds immediately, but also buffers them
until it has a batch of 32 data shreds, at which point 32 coding shreds
are generated and broadcasted.

(cherry picked from commit 4f82b897bc)

# Conflicts:
#	ledger/src/shred.rs

* removes backport merge conflicts

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-03-23 18:23:09 +00:00
mergify[bot]
a04ca03fee renames is_last_in_fec_set back to is_last_data (#15848) (#16075)
https://github.com/solana-labs/solana/pull/10095
renamed is_last_data to is_last_in_fec_set. However, the code shows that
this is actually meant to indicate where the serialized data is
complete:
https://github.com/solana-labs/solana/blob/420174d3d/ledger/src/shred.rs#L599-L600
https://github.com/solana-labs/solana/blob/420174d3d/ledger/src/shred.rs#L229-L231

There are multiple FEC sets for each `&[Entry]` serialized and this flag
does not represent shreds last in FEC sets (only the very last one by
overlap). So the name is wrong and confusing

(cherry picked from commit 3b85cbc504)

Co-authored-by: behzad nouri <behzadnouri@gmail.com>
2021-03-23 16:59:47 +00:00
mergify[bot]
64ce4a6203 solana transfer now requires --allow-unfunded-recipient if the recipient doesn't exist (bp #16060) (#16067)
* transfer now requires --allow-unfunded-recipient if the recipient doesn't exist

(cherry picked from commit 3dff5c9dee)

* Avoid RPC in `--sign-only` mode

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

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-23 03:54:42 +00:00
mergify[bot]
7ac3c9ec76 Handle blockstore insert dup checks (#16051) (#16066)
(cherry picked from commit d76ad33597)

Co-authored-by: carllin <carl@solana.com>
2021-03-23 00:49:10 +00:00
mergify[bot]
7d91515e8d Make getStakeActivation response consistent for undelegated accounts (#16038) (#16040)
(cherry picked from commit 2ec24d438f)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-19 22:07:30 +00:00
mergify[bot]
4e3f2c3d2d program-test: Fix warp and staking issue (#16002) (#16031)
Since program-test creates a test genesis and then adds fees and rent,
some of the genesis accounts get rent-collected after warping.  Most
notably, `StakeConfig` gets rent-collected, causing any stake operations
to fail after warp.  This fix creates genesis with the `Rent` and
`FeeRateGovernor` actually used by the bank.

(cherry picked from commit 6cc22e62d4)

Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
2021-03-19 14:54:58 +00:00
mergify[bot]
8b67ba6d3d docs: SIGUSR1 killing wrapper shell scripts (#16009)
(cherry picked from commit 07dc522981)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-03-19 07:45:34 +00:00
mergify[bot]
c2ce68ab90 Santize instruction index when loading instruction from sysvar (#15942) (#16004)
(cherry picked from commit 4c5660ba7a)

Co-authored-by: Justin Starry <justin@solana.com>
2021-03-19 02:48:41 +00:00
mergify[bot]
fe87cb1cd1 Update to reqwest 0.11.2 (#16000)
(cherry picked from commit 02b81dd05d)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-18 22:12:01 +00:00
mergify[bot]
1c8f6a836a cli cleanup (#15990) (#15997)
(cherry picked from commit 067b390194)

Co-authored-by: Jack May <jack@solana.com>
2021-03-18 20:03:04 +00:00
mergify[bot]
3d5ff7968e rpc: Add config options limiting getConfirmedBlock response data (#15970) (#15995)
* Add new confirmed block struct

* Add RpcConfirmedBlockConfig options

* Configure block response based on new options

* Add client api, use in cli fetch_epoch_rewards

* Update docs

* Apply review suggestions

(cherry picked from commit aa54c468ea)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-18 19:33:01 +00:00
Tyera Eulberg
d6160f7744 Avoid panic when validator doesn't have performance samples (#15976)
(cherry picked from commit ba33c9e18e)
2021-03-18 08:28:31 -07:00
mergify[bot]
5e9ce99abf remote-wallet: Expose Ledger app settings (#15978)
(cherry picked from commit 2dabcac0da)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-03-18 09:13:24 +00:00
mergify[bot]
ebd6fe7acb Avoid a panic when --slots-per-epoch is less than MINIMUM_SLOTS_PER_EPOCH (#15975)
(cherry picked from commit 4ab98fff02)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-18 07:17:50 +00:00
mergify[bot]
9e91a2c2fd Add Close instrruction and tooling to upgradeable loader (#15887) (#15972)
(cherry picked from commit 7f500d610c)

Co-authored-by: Jack May <jack@solana.com>
2021-03-18 06:02:57 +00:00
Michael Vines
899f57962a Add --slots-per-epoch argument
(cherry picked from commit 04c99cf7ea)
2021-03-17 17:25:51 -07:00
Michael Vines
3176b00e57 Add --slots-per-epoch validator
(cherry picked from commit c06ff47a90)
2021-03-17 17:25:51 -07:00
Jeff Washington (jwash)
08b9da8397 drop poh lock after record (#15930)
(cherry picked from commit 5460fb10a2)
2021-03-17 17:24:53 -07:00
mergify[bot]
2bc21ecba2 Allow unbounded wallclock processing time in tests (#15961) (#15966)
(cherry picked from commit f548a04fae)

Co-authored-by: carllin <carl@solana.com>
2021-03-18 00:22:06 +00:00
Jeff Washington (jwash)
5b2a65fab3 add metrics for tick producer and poh_recorder (#15931)
(cherry picked from commit 40997d0aef)
2021-03-17 16:36:50 -07:00
mergify[bot]
f5d56eabf3 Build full SPL in CI (bp #15886) (#15964)
* Build full SPL in CI

(cherry picked from commit 82269f1351)

* Avoid changing signature of ProgramTest::add_account

(cherry picked from commit 03180b502d)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-17 22:46:55 +00:00
Michael Vines
af45efb62c Notice the user when the --mint, --bpf-program, or --clone arguments are ignored
(cherry picked from commit 59c19d9fbf)
2021-03-17 14:10:14 -07:00
mergify[bot]
f528cda832 Ignore flaky test_banking_stage_entries_only and test_banking_stage_entryfication (#15959)
(cherry picked from commit 8a9b51952e)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-17 20:34:30 +00:00
mergify[bot]
eeef9f4e59 Separate snapshot location (bp #15840) (#15956)
* Add option for separate snapshot location

(cherry picked from commit 6126878f509c69e23480a5ec22b3271e2b16e072)
(cherry picked from commit 0209d334bd)

* Apply suggestions from code review

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

* add missed suggestion

(cherry picked from commit a43b3674c7)

* Revert to snapshots

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

* Revert to snapshots 2

(cherry picked from commit 20b53eb4b4)

* Revert to removing only tmp-

(cherry picked from commit a5d144b00f)

Co-authored-by: DimAn <diman@diman.io>
Co-authored-by: DimAn <andiman7000@gmail.com>
2021-03-17 20:25:18 +00:00
Michael Vines
32124b59e9 Download snapshot files with a tmp- prefix so they'll automatically be cleaned up if interrupted
(cherry picked from commit 58b980f9cd)
2021-03-17 10:18:18 -07:00
Michael Vines
aa9772f9c0 Replace solana-program-test when building example-helloworld 2021-03-17 09:08:41 -07:00
mergify[bot]
5f183bd773 Add helper for paring down signers to those requried by a tx message (bp #15899) (#15938)
* sdk: Add accessor for signer pubkeys of a tx message

(cherry picked from commit bf33ce8906)

* clap-utils: Add helper to `CliSignerInfo` for getting signers for a message

(cherry picked from commit 4e99f1e634)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-03-17 07:48:47 +00:00
mergify[bot]
2238e5001b solana-install init can now select a pre-release from Github (#15936)
(cherry picked from commit d9176c1903)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-17 04:31:55 +00:00
mergify[bot]
79fa7ef55c CLI: Support dumping the TX message in sign-only mode (#15933)
(cherry picked from commit 672e9c640f)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-03-17 04:13:21 +00:00
mergify[bot]
07df827411 Bump tokio to 1.1 (#15926) (#15928)
(cherry picked from commit 654449ce91)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-16 23:29:55 +00:00
mergify[bot]
a259ff0e72 Wallclock BankingStage Throttle (#15731) (#15890)
(cherry picked from commit c1ba265dd9)

Co-authored-by: carllin <carl@solana.com>
2021-03-16 21:12:59 +00:00
mergify[bot]
d7d3e767e7 fix: compute pre/post token balances on all accounts if token program present (#15900) (#15923)
* fix: compute pre/post token balances on all accounts if token program present

* fix: skip token program in balance query

* fix: prevent program ids from being collected

(cherry picked from commit 61112d4826)

Co-authored-by: Josh <josh.hundley@gmail.com>
2021-03-16 18:23:29 +00:00
mergify[bot]
6e8aa9af17 nit: fix spelling (#15908) (#15911)
(cherry picked from commit 5760cf0f41)

# Conflicts:
#	sdk/src/feature_set.rs

Co-authored-by: Jack May <jack@solana.com>
2021-03-16 10:58:39 -07:00
mergify[bot]
0236de7bc8 Encourage use of the default --ledger location (#15921)
(cherry picked from commit 1c261d293f)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-16 16:58:14 +00:00
mergify[bot]
899bd1572a Show flags for accounts in tx by solana confirm (#15804) (#15906)
* Show flags for accounts in tx by solana confirm

* Address review comments

* Improve comment a bit

* Apply suggestions from code review

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

* Further apply review suggestions

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

Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
2021-03-16 10:43:06 +00:00
mergify[bot]
97ec4cd44e Cli: better estimate of epoch time elapsed/remaining (#15893) (#15918)
* Add rpc_client api for getRecentPerformanceSamples

* Prep fn for variable avg slot time

* Use recent-perf-samples to more-accurately estimate epoch completed times

* Spell out average

(cherry picked from commit 3726358f51)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-16 09:58:51 +00:00
mergify[bot]
5500970a7e Add cargo-bpf-test --no-run flag, matching cargo-test (#15916)
(cherry picked from commit eb19e11688)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-16 09:45:35 +00:00
Michael Vines
caea04d8d5 Pin solana crate versions to prevent downstream users from accidentally mixing crate versions 2021-03-16 08:41:28 +00:00
Michael Vines
b1a90c3580 =1.6.1 2021-03-16 08:41:28 +00:00
mergify[bot]
5bd4e38345 Charge compute budget for bytes passed via cpi (#15874) (#15905)
(cherry picked from commit ad9901d7c6)

Co-authored-by: Jack May <jack@solana.com>
2021-03-16 07:57:32 +00:00
mergify[bot]
fddba08571 Improve Instruction::new deprecation warning (#15896)
(cherry picked from commit 8567b41d5f)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-16 05:18:31 +00:00
Michael Vines
87963764fa Export tokio for program-test clients
(cherry picked from commit 430ed6d774)
2021-03-15 22:14:17 -07:00
mergify[bot]
b691a159dd increment_cargo_version.sh tune ups (bp #15880) (#15892)
* Disallow version bump with dirty working tree

(cherry picked from commit 853e735edf)

* Ignore `not_paths` for `*.md` files when bumping version

(cherry picked from commit 510760d81b)

* Also ignore `*/node_modules/*` paths when bumping version

(cherry picked from commit 2bf46b789f)

Co-authored-by: Trent Nelson <trent@solana.com>
2021-03-16 02:07:46 +00:00
mergify[bot]
5af1d48be8 Display actual account length (#15875) (#15884)
(cherry picked from commit 60e5fd11c9)

Co-authored-by: Jack May <jack@solana.com>
2021-03-16 01:01:25 +00:00
mergify[bot]
3b3ec3313f Fix real_number_string_trimmed zero-decimal behavior (#15873) (#15877)
* Add failing test

* Don't strip zeroes from zero-decimal amounts

* Add zero-case test

(cherry picked from commit c40bd5f394)

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
2021-03-15 21:33:01 +00:00
Michael Vines
be00246fb5 Bump version to v1.6.1 2021-03-15 14:47:58 -06:00
Michael Vines
1d80ba9edf Update cargo lock files on version bump 2021-03-15 14:47:58 -06:00
mergify[bot]
4bcf976ecd Fix delinquent stake display (#15839)
(cherry picked from commit eab182188a)

Co-authored-by: Michael Vines <mvines@gmail.com>
2021-03-13 20:27:25 +00:00
1111 changed files with 56760 additions and 128331 deletions

View File

@@ -2,6 +2,6 @@
"_public_key": "ae29f4f7ad2fc92de70d470e411c8426d5d48db8817c9e3dae574b122192335f",
"_comment": "These credentials are encrypted and pose no risk",
"environment": {
"CODECOV_TOKEN": "EJ[1:KToenD1Sr3w82lHGxz1n+j3hwNlLk/1pYrjZHlvY6kE=:hN1Q25omtJ+4yYVn+qzIsPLKT3O6J9XN:DMLNLXi/pkWgvwF6gNIcNF222sgsRR9LnwLZYj0P0wGj7q6w8YQnd1Rskj+sRroI/z5pQg==]"
"CODECOV_TOKEN": "EJ[1:Z7OneT3RdJJ0DipCHQ7rC84snQ+FPbgHwZADQiz54wk=:3K68mE38LJ2RB98VWmjuNLFBNn1XTGR4:cR4r05/TOZQKmEZp1v4CSgUJtC6QJiOaL85QjXW0qZ061fMnsBA8AtAPMDoDq4WCGOZM1A==]"
}
}

View File

@@ -36,7 +36,4 @@ export CARGO_TARGET_CACHE=$HOME/cargo-target-cache/"$CHANNEL"-"$BUILDKITE_LABEL"
# `std:
# "found possibly newer version of crate `std` which `xyz` depends on
rm -rf target/bpfel-unknown-unknown
if [[ $BUILDKITE_LABEL = "stable-perf" ]]; then
rm -rf target/release
fi
)

View File

@@ -38,7 +38,6 @@ jobs:
- readlink -f .
script:
- source ci/env.sh
- rustup set profile default
- ci/publish-tarball.sh
deploy:
- provider: s3
@@ -74,7 +73,7 @@ jobs:
language: node_js
node_js:
- "lts/*"
- "node"
cache:
directories:

1413
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,6 @@ members = [
"perf",
"validator",
"genesis",
"genesis-utils",
"gossip",
"install",
"keygen",
@@ -32,6 +31,7 @@ members = [
"log-analyzer",
"merkle-root-bench",
"merkle-tree",
"stake-o-matic",
"storage-bigtable",
"storage-proto",
"streamer",
@@ -39,20 +39,21 @@ members = [
"metrics",
"net-shaper",
"notifier",
"poh",
"poh-bench",
"program-test",
"programs/secp256k1",
"programs/bpf_loader",
"programs/budget",
"programs/config",
"programs/exchange",
"programs/failure",
"programs/noop",
"programs/ownable",
"programs/secp256k1",
"programs/stake",
"programs/vest",
"programs/vote",
"remote-wallet",
"rpc",
"ramp-tps",
"runtime",
"runtime/store-tool",
"sdk",
@@ -60,6 +61,7 @@ members = [
"sdk/cargo-test-bpf",
"scripts",
"stake-accounts",
"stake-monitor",
"sys-tuner",
"tokens",
"transaction-status",
@@ -75,6 +77,3 @@ members = [
exclude = [
"programs/bpf",
]
[profile.dev]
split-debuginfo = "unpacked"

View File

@@ -1,6 +1,6 @@
<p align="center">
<a href="https://solana.com">
<img alt="Solana" src="https://i.imgur.com/uBVzyX3.png" width="250" />
<img alt="Solana" src="https://i.imgur.com/OMnvVEz.png" width="250" />
</a>
</p>
@@ -19,7 +19,7 @@ $ source $HOME/.cargo/env
$ rustup component add rustfmt
```
Please make sure you are always using the latest stable rust version by running:
Please sure you are always using the latest stable rust version by running:
```bash
$ rustup update
@@ -32,12 +32,6 @@ $ sudo apt-get update
$ sudo apt-get install libssl-dev libudev-dev pkg-config zlib1g-dev llvm clang make
```
On Mac M1s, make sure you set up your terminal & homebrew [to use](https://5balloons.info/correct-way-to-install-and-use-homebrew-on-m1-macs/) Rosetta. You can install it with:
```bash
$ softwareupdate --install-rosetta
```
## **2. Download the source code.**
```bash

View File

@@ -42,36 +42,14 @@ RPC DoS/Crashes:
$5,000 USD in locked SOL tokens (locked for 12 months)
* RPC attacks
Out of Scope:
The following components are out of scope for the bounty program
* Metrics: `/metrics` in the monorepo as well as https://metrics.solana.com
* Explorer: `/explorer` in the monorepo as well as https://explorer.solana.com
* Any encrypted credentials, auth tokens, etc. checked into the repo
* Bugs in dependencies. Please take them upstream!
* Attacks that require social engineering
Eligibility:
* The participant submitting the bug report shall follow the process outlined within this document
* The participant submitting the bug bounty shall follow the process outlined within this document
* Valid exploits can be eligible even if they are not successfully executed on the cluster
* Multiple submissions for the same class of exploit are still eligible for compensation, though may be compensated at a lower rate, however these will be assessed on a case-by-case basis
* Participants must complete KYC and sign the participation agreement here when the registrations are open https://solana.com/validator-registration. Security exploits will still be assessed and open for submission at all times. This needs only be done prior to distribution of tokens.
Payment of Bug Bounties:
* Payments for eligible bug reports are distributed monthly.
* Bounties for all bug reports submitted in a given month are paid out in the middle of the
following month.
* The SOL/USD conversion rate used for payments is the market price at the end of
the last day of the month for the month in which the bug was submitted.
* The reference for this price is the Closing Price given by Coingecko.com on
that date given here:
https://www.coingecko.com/en/coins/solana/historical_data/usd#panel
* For example, for all bugs submitted in March 2021, the SOL/USD price for bug
payouts is the Close price on 2021-03-31 of $19.49. This applies to all bugs
submitted in March 2021, to be paid in mid-April 2021.
* Bug bounties are paid out in
[stake accounts](https://solana.com/staking) with a
[lockup](https://docs.solana.com/staking/stake-accounts#lockups)
expiring 12 months from the last day of the month in which the bug was submitted.
Notes:
* All locked tokens can be staked during the lockup period
<a name="process"></a>
## Incident Response Process

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-account-decoder"
version = "1.7.8"
version = "1.6.2"
description = "Solana account decoder"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -19,10 +19,11 @@ lazy_static = "1.4.0"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-config-program = { path = "../programs/config", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.8" }
spl-token-v2-0 = { package = "spl-token", version = "=3.2.0", features = ["no-entrypoint"] }
solana-config-program = { path = "../programs/config", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.6.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.2" }
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
thiserror = "1.0"
zstd = "0.5.1"

View File

@@ -48,7 +48,7 @@ pub enum UiAccountData {
Binary(String, UiAccountEncoding),
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum UiAccountEncoding {
Binary, // Legacy. Retained for RPC backwards compatibility
@@ -62,39 +62,39 @@ pub enum UiAccountEncoding {
impl UiAccount {
pub fn encode<T: ReadableAccount>(
pubkey: &Pubkey,
account: &T,
account: T,
encoding: UiAccountEncoding,
additional_data: Option<AccountAdditionalData>,
data_slice_config: Option<UiDataSliceConfig>,
) -> Self {
let data = match encoding {
UiAccountEncoding::Binary => UiAccountData::LegacyBinary(
bs58::encode(slice_data(account.data(), data_slice_config)).into_string(),
bs58::encode(slice_data(&account.data(), data_slice_config)).into_string(),
),
UiAccountEncoding::Base58 => UiAccountData::Binary(
bs58::encode(slice_data(account.data(), data_slice_config)).into_string(),
bs58::encode(slice_data(&account.data(), data_slice_config)).into_string(),
encoding,
),
UiAccountEncoding::Base64 => UiAccountData::Binary(
base64::encode(slice_data(account.data(), data_slice_config)),
base64::encode(slice_data(&account.data(), data_slice_config)),
encoding,
),
UiAccountEncoding::Base64Zstd => {
let mut encoder = zstd::stream::write::Encoder::new(Vec::new(), 0).unwrap();
match encoder
.write_all(slice_data(account.data(), data_slice_config))
.write_all(slice_data(&account.data(), data_slice_config))
.and_then(|()| encoder.finish())
{
Ok(zstd_data) => UiAccountData::Binary(base64::encode(zstd_data), encoding),
Err(_) => UiAccountData::Binary(
base64::encode(slice_data(account.data(), data_slice_config)),
base64::encode(slice_data(&account.data(), data_slice_config)),
UiAccountEncoding::Base64,
),
}
}
UiAccountEncoding::JsonParsed => {
if let Ok(parsed_data) =
parse_account_data(pubkey, account.owner(), account.data(), additional_data)
parse_account_data(pubkey, &account.owner(), &account.data(), additional_data)
{
UiAccountData::Json(parsed_data)
} else {
@@ -224,7 +224,7 @@ mod test {
fn test_base64_zstd() {
let encoded_account = UiAccount::encode(
&Pubkey::default(),
&AccountSharedData::from(Account {
AccountSharedData::from(Account {
data: vec![0; 1024],
..Account::default()
}),

View File

@@ -9,14 +9,14 @@ use crate::{
};
use inflector::Inflector;
use serde_json::Value;
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, stake, system_program, sysvar};
use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program, sysvar};
use std::collections::HashMap;
use thiserror::Error;
lazy_static! {
static ref BPF_UPGRADEABLE_LOADER_PROGRAM_ID: Pubkey = solana_sdk::bpf_loader_upgradeable::id();
static ref CONFIG_PROGRAM_ID: Pubkey = solana_config_program::id();
static ref STAKE_PROGRAM_ID: Pubkey = stake::program::id();
static ref STAKE_PROGRAM_ID: Pubkey = solana_stake_program::id();
static ref SYSTEM_PROGRAM_ID: Pubkey = system_program::id();
static ref SYSVAR_PROGRAM_ID: Pubkey = sysvar::id();
static ref TOKEN_PROGRAM_ID: Pubkey = spl_token_id_v2_0();

View File

@@ -6,10 +6,10 @@ use bincode::deserialize;
use serde_json::Value;
use solana_config_program::{get_config_data, ConfigKeys};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::stake::config::{self as stake_config, Config as StakeConfig};
use solana_stake_program::config::Config as StakeConfig;
pub fn parse_config(data: &[u8], pubkey: &Pubkey) -> Result<ConfigAccountType, ParseAccountError> {
let parsed_account = if pubkey == &stake_config::id() {
let parsed_account = if pubkey == &solana_stake_program::config::id() {
get_config_data(data)
.ok()
.and_then(|data| deserialize::<StakeConfig>(data).ok())
@@ -37,7 +37,7 @@ fn parse_config_data<T>(data: &[u8], keys: Vec<(Pubkey, bool)>) -> Option<UiConf
where
T: serde::de::DeserializeOwned,
{
let config_data: T = deserialize(get_config_data(data).ok()?).ok()?;
let config_data: T = deserialize(&get_config_data(data).ok()?).ok()?;
let keys = keys
.iter()
.map(|key| UiConfigKey {
@@ -101,7 +101,11 @@ mod test {
};
let stake_config_account = create_config_account(vec![], &stake_config, 10);
assert_eq!(
parse_config(stake_config_account.data(), &stake_config::id()).unwrap(),
parse_config(
&stake_config_account.data(),
&solana_stake_program::config::id()
)
.unwrap(),
ConfigAccountType::StakeConfig(UiStakeConfig {
warmup_cooldown_rate: 0.25,
slash_penalty: 50,
@@ -121,7 +125,7 @@ mod test {
10,
);
assert_eq!(
parse_config(validator_info_config_account.data(), &info_pubkey).unwrap(),
parse_config(&validator_info_config_account.data(), &info_pubkey).unwrap(),
ConfigAccountType::ValidatorInfo(UiConfig {
keys: vec![
UiConfigKey {

View File

@@ -9,13 +9,7 @@ pub fn parse_nonce(data: &[u8]) -> Result<UiNonceState, ParseAccountError> {
.map_err(|_| ParseAccountError::from(InstructionError::InvalidAccountData))?;
let nonce_state = nonce_state.convert_to_current();
match nonce_state {
// This prevents parsing an allocated System-owned account with empty data of any non-zero
// length as `uninitialized` nonce. An empty account of the wrong length can never be
// initialized as a nonce account, and an empty account of the correct length may not be an
// uninitialized nonce account, since it can be assigned to another program.
State::Uninitialized => Err(ParseAccountError::from(
InstructionError::InvalidAccountData,
)),
State::Uninitialized => Ok(UiNonceState::Uninitialized),
State::Initialized(data) => Ok(UiNonceState::Initialized(UiNonceData {
authority: data.authority.to_string(),
blockhash: data.blockhash.to_string(),

View File

@@ -4,7 +4,7 @@ use crate::{
};
use bincode::deserialize;
use solana_sdk::clock::{Epoch, UnixTimestamp};
use solana_sdk::stake::state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
use solana_stake_program::stake_state::{Authorized, Delegation, Lockup, Meta, Stake, StakeState};
pub fn parse_stake(data: &[u8]) -> Result<StakeAccountType, ParseAccountError> {
let stake_state: StakeState = deserialize(data)

View File

@@ -14,23 +14,23 @@ use std::str::FromStr;
// A helper function to convert spl_token_v2_0::id() as spl_sdk::pubkey::Pubkey to
// solana_sdk::pubkey::Pubkey
pub fn spl_token_id_v2_0() -> Pubkey {
Pubkey::new_from_array(spl_token_v2_0::id().to_bytes())
Pubkey::from_str(&spl_token_v2_0::id().to_string()).unwrap()
}
// A helper function to convert spl_token_v2_0::native_mint::id() as spl_sdk::pubkey::Pubkey to
// solana_sdk::pubkey::Pubkey
pub fn spl_token_v2_0_native_mint() -> Pubkey {
Pubkey::new_from_array(spl_token_v2_0::native_mint::id().to_bytes())
Pubkey::from_str(&spl_token_v2_0::native_mint::id().to_string()).unwrap()
}
// A helper function to convert a solana_sdk::pubkey::Pubkey to spl_sdk::pubkey::Pubkey
pub fn spl_token_v2_0_pubkey(pubkey: &Pubkey) -> SplTokenPubkey {
SplTokenPubkey::new_from_array(pubkey.to_bytes())
SplTokenPubkey::from_str(&pubkey.to_string()).unwrap()
}
// A helper function to convert a spl_sdk::pubkey::Pubkey to solana_sdk::pubkey::Pubkey
pub fn pubkey_from_spl_token_v2_0(pubkey: &SplTokenPubkey) -> Pubkey {
Pubkey::new_from_array(pubkey.to_bytes())
Pubkey::from_str(&pubkey.to_string()).unwrap()
}
pub fn parse_token(

View File

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

View File

@@ -6,12 +6,10 @@ use rayon::prelude::*;
use solana_measure::measure::Measure;
use solana_runtime::{
accounts::{create_test_accounts, update_accounts_bench, Accounts},
accounts_db::AccountShrinkThreshold,
accounts_index::AccountSecondaryIndexes,
ancestors::Ancestors,
accounts_index::Ancestors,
};
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
use std::{env, fs, path::PathBuf};
use std::{collections::HashSet, env, fs, path::PathBuf};
fn main() {
solana_logger::setup();
@@ -60,13 +58,8 @@ fn main() {
if fs::remove_dir_all(path.clone()).is_err() {
println!("Warning: Couldn't remove {:?}", path);
}
let accounts = Accounts::new_with_config(
vec![path],
&ClusterType::Testnet,
AccountSecondaryIndexes::default(),
false,
AccountShrinkThreshold::default(),
);
let accounts =
Accounts::new_with_config(vec![path], &ClusterType::Testnet, HashSet::new(), false);
println!("Creating {} accounts", num_accounts);
let mut create_time = Measure::start("create accounts");
let pubkeys: Vec<_> = (0..num_slots)
@@ -90,19 +83,17 @@ fn main() {
num_slots,
create_time
);
let mut ancestors = Vec::with_capacity(num_slots);
ancestors.push(0);
let mut ancestors: Ancestors = vec![(0, 0)].into_iter().collect();
for i in 1..num_slots {
ancestors.push(i as u64);
ancestors.insert(i as u64, i - 1);
accounts.add_root(i as u64);
}
let ancestors = Ancestors::from(ancestors);
let mut elapsed = vec![0; iterations];
let mut elapsed_store = vec![0; iterations];
for x in 0..iterations {
if clean {
let mut time = Measure::start("clean");
accounts.accounts_db.clean_accounts(None, false);
accounts.accounts_db.clean_accounts(None);
time.stop();
println!("{}", time);
for slot in 0..num_slots {
@@ -121,7 +112,6 @@ fn main() {
solana_sdk::clock::Slot::default(),
&ancestors,
None,
false,
);
time_store.stop();
if results != results_store {

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-accounts-cluster-bench"
version = "1.7.8"
version = "1.6.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -13,23 +13,22 @@ clap = "2.33.1"
log = "0.4.11"
rand = "0.7.0"
rayon = "1.4.1"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.8" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.8" }
solana-client = { path = "../client", version = "=1.7.8" }
solana-core = { path = "../core", version = "=1.7.8" }
solana-faucet = { path = "../faucet", version = "=1.7.8" }
solana-gossip = { path = "../gossip", version = "=1.7.8" }
solana-logger = { path = "../logger", version = "=1.7.8" }
solana-measure = { path = "../measure", version = "=1.7.8" }
solana-net-utils = { path = "../net-utils", version = "=1.7.8" }
solana-runtime = { path = "../runtime", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.8" }
solana-version = { path = "../version", version = "=1.7.8" }
spl-token-v2-0 = { package = "spl-token", version = "=3.2.0", features = ["no-entrypoint"] }
solana-account-decoder = { path = "../account-decoder", version = "=1.6.2" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.2" }
solana-client = { path = "../client", version = "=1.6.2" }
solana-core = { path = "../core", version = "=1.6.2" }
solana-measure = { path = "../measure", version = "=1.6.2" }
solana-logger = { path = "../logger", version = "=1.6.2" }
solana-net-utils = { path = "../net-utils", version = "=1.6.2" }
solana-faucet = { path = "../faucet", version = "=1.6.2" }
solana-runtime = { path = "../runtime", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.6.2" }
solana-version = { path = "../version", version = "=1.6.2" }
spl-token-v2-0 = { package = "spl-token", version = "=3.1.0", features = ["no-entrypoint"] }
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "=1.7.8" }
solana-local-cluster = { path = "../local-cluster", version = "=1.6.2" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -1,13 +1,13 @@
#![allow(clippy::integer_arithmetic)]
use clap::{crate_description, crate_name, value_t, values_t_or_exit, App, Arg};
use clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg};
use log::*;
use rand::{thread_rng, Rng};
use rayon::prelude::*;
use solana_account_decoder::parse_token::spl_token_v2_0_pubkey;
use solana_clap_utils::input_parsers::pubkey_of;
use solana_client::rpc_client::RpcClient;
use solana_core::gossip_service::discover;
use solana_faucet::faucet::{request_airdrop_transaction, FAUCET_PORT};
use solana_gossip::gossip_service::discover;
use solana_measure::measure::Measure;
use solana_runtime::inline_spl_token_v2_0;
use solana_sdk::{
@@ -32,10 +32,6 @@ use std::{
time::{Duration, Instant},
};
// Create and close messages both require 2 signatures; if transaction construction changes, update
// this magic number
const NUM_SIGNATURES: u64 = 2;
pub fn airdrop_lamports(
client: &RpcClient,
faucet_addr: &SocketAddr,
@@ -55,7 +51,7 @@ pub fn airdrop_lamports(
);
let (blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => {
let mut tries = 0;
loop {
@@ -189,13 +185,14 @@ impl TransactionExecutor {
let mut start = Measure::start("sig_status");
let statuses: Vec<_> = sigs_w
.chunks(200)
.flat_map(|sig_chunk| {
.map(|sig_chunk| {
let only_sigs: Vec<_> = sig_chunk.iter().map(|s| s.0).collect();
client
.get_signature_statuses(&only_sigs)
.expect("status fail")
.value
})
.flatten()
.collect();
let mut num_cleared = 0;
let start_len = sigs_w.len();
@@ -359,11 +356,11 @@ fn make_close_message(
fn run_accounts_bench(
entrypoint_addr: SocketAddr,
faucet_addr: SocketAddr,
payer_keypairs: &[&Keypair],
keypair: &Keypair,
iterations: usize,
maybe_space: Option<u64>,
batch_size: usize,
close_nth_batch: u64,
close_nth: u64,
maybe_lamports: Option<u64>,
num_instructions: usize,
mint: Option<Pubkey>,
@@ -372,7 +369,7 @@ fn run_accounts_bench(
let client =
RpcClient::new_socket_with_commitment(entrypoint_addr, CommitmentConfig::confirmed());
info!("Targeting {}", entrypoint_addr);
info!("Targetting {}", entrypoint_addr);
let mut last_blockhash = Instant::now();
let mut last_log = Instant::now();
@@ -381,10 +378,7 @@ fn run_accounts_bench(
let mut tx_sent_count = 0;
let mut total_accounts_created = 0;
let mut total_accounts_closed = 0;
let mut balances: Vec<_> = payer_keypairs
.iter()
.map(|keypair| client.get_balance(&keypair.pubkey()).unwrap_or(0))
.collect();
let mut balance = client.get_balance(&keypair.pubkey()).unwrap_or(0);
let mut last_balance = Instant::now();
let default_max_lamports = 1000;
@@ -401,7 +395,7 @@ fn run_accounts_bench(
max_closed: Arc::new(AtomicU64::default()),
};
info!("Starting balance(s): {:?}", balances);
info!("Starting balance: {}", balance);
let executor = TransactionExecutor::new(entrypoint_addr);
@@ -411,94 +405,81 @@ fn run_accounts_bench(
last_blockhash = Instant::now();
}
let fee = recent_blockhash
.1
.lamports_per_signature
.saturating_mul(NUM_SIGNATURES);
let message = make_create_message(
keypair,
&base_keypair,
seed_tracker.max_created.clone(),
num_instructions,
min_balance,
maybe_space,
mint,
);
let fee = recent_blockhash.1.calculate_fee(&message);
let lamports = min_balance + fee;
for (i, balance) in balances.iter_mut().enumerate() {
if *balance < lamports || last_balance.elapsed().as_millis() > 2000 {
if let Ok(b) = client.get_balance(&payer_keypairs[i].pubkey()) {
*balance = b;
}
last_balance = Instant::now();
if *balance < lamports * 2 {
info!(
"Balance {} is less than needed: {}, doing aidrop...",
balance, lamports
);
if !airdrop_lamports(
&client,
&faucet_addr,
payer_keypairs[i],
lamports * 100_000,
) {
warn!("failed airdrop, exiting");
return;
}
if balance < lamports || last_balance.elapsed().as_millis() > 2000 {
if let Ok(b) = client.get_balance(&keypair.pubkey()) {
balance = b;
}
last_balance = Instant::now();
if balance < lamports {
info!(
"Balance {} is less than needed: {}, doing aidrop...",
balance, lamports
);
if !airdrop_lamports(&client, &faucet_addr, keypair, lamports * 100_000) {
warn!("failed airdrop, exiting");
return;
}
}
}
// Create accounts
let sigs_len = executor.num_outstanding();
if sigs_len < batch_size {
let num_to_create = batch_size - sigs_len;
if num_to_create >= payer_keypairs.len() {
info!("creating {} new", num_to_create);
let chunk_size = num_to_create / payer_keypairs.len();
if chunk_size > 0 {
for (i, keypair) in payer_keypairs.iter().enumerate() {
let txs: Vec<_> = (0..chunk_size)
.into_par_iter()
.map(|_| {
let message = make_create_message(
keypair,
&base_keypair,
seed_tracker.max_created.clone(),
num_instructions,
min_balance,
maybe_space,
mint,
);
let signers: Vec<&Keypair> = vec![keypair, &base_keypair];
Transaction::new(&signers, message, recent_blockhash.0)
})
.collect();
balances[i] = balances[i].saturating_sub(lamports * txs.len() as u64);
info!("txs: {}", txs.len());
let new_ids = executor.push_transactions(txs);
info!("ids: {}", new_ids.len());
tx_sent_count += new_ids.len();
total_accounts_created += num_instructions * new_ids.len();
}
}
}
info!("creating {} new", num_to_create);
let txs: Vec<_> = (0..num_to_create)
.into_par_iter()
.map(|_| {
let message = make_create_message(
keypair,
&base_keypair,
seed_tracker.max_created.clone(),
num_instructions,
min_balance,
maybe_space,
mint,
);
let signers: Vec<&Keypair> = vec![keypair, &base_keypair];
Transaction::new(&signers, message, recent_blockhash.0)
})
.collect();
balance = balance.saturating_sub(lamports * txs.len() as u64);
info!("txs: {}", txs.len());
let new_ids = executor.push_transactions(txs);
info!("ids: {}", new_ids.len());
tx_sent_count += new_ids.len();
total_accounts_created += num_instructions * new_ids.len();
if close_nth_batch > 0 {
let num_batches_to_close =
total_accounts_created as u64 / (close_nth_batch * batch_size as u64);
let expected_closed = num_batches_to_close * batch_size as u64;
let max_closed_seed = seed_tracker.max_closed.load(Ordering::Relaxed);
// Close every account we've created with seed between max_closed_seed..expected_closed
if max_closed_seed < expected_closed {
let txs: Vec<_> = (0..expected_closed - max_closed_seed)
if close_nth > 0 {
let expected_closed = total_accounts_created as u64 / close_nth;
if expected_closed > total_accounts_closed {
let txs: Vec<_> = (0..expected_closed - total_accounts_closed)
.into_par_iter()
.map(|_| {
let message = make_close_message(
payer_keypairs[0],
keypair,
&base_keypair,
seed_tracker.max_closed.clone(),
1,
min_balance,
mint.is_some(),
);
let signers: Vec<&Keypair> = vec![payer_keypairs[0], &base_keypair];
let signers: Vec<&Keypair> = vec![keypair, &base_keypair];
Transaction::new(&signers, message, recent_blockhash.0)
})
.collect();
balances[0] = balances[0].saturating_sub(fee * txs.len() as u64);
balance = balance.saturating_sub(fee * txs.len() as u64);
info!("close txs: {}", txs.len());
let new_ids = executor.push_transactions(txs);
info!("close ids: {}", new_ids.len());
@@ -513,8 +494,8 @@ fn run_accounts_bench(
count += 1;
if last_log.elapsed().as_millis() > 3000 {
info!(
"total_accounts_created: {} total_accounts_closed: {} tx_sent_count: {} loop_count: {} balance(s): {:?}",
total_accounts_created, total_accounts_closed, tx_sent_count, count, balances
"total_accounts_created: {} total_accounts_closed: {} tx_sent_count: {} loop_count: {} balance: {}",
total_accounts_created, total_accounts_closed, tx_sent_count, count, balance
);
last_log = Instant::now();
}
@@ -565,7 +546,6 @@ fn main() {
Arg::with_name("identity")
.long("identity")
.takes_value(true)
.multiple(true)
.value_name("FILE")
.help("keypair file"),
)
@@ -577,17 +557,11 @@ fn main() {
.help("Number of transactions to send per batch"),
)
.arg(
Arg::with_name("close_nth_batch")
Arg::with_name("close_nth")
.long("close-frequency")
.takes_value(true)
.value_name("BYTES")
.help(
"Every `n` batches, create a batch of close transactions for
the earliest remaining batch of accounts created.
Note: Should be > 1 to avoid situations where the close \
transactions will be submitted before the corresponding \
create transactions have been confirmed",
),
.help("Send close transactions after this many accounts created"),
)
.arg(
Arg::with_name("num_instructions")
@@ -637,7 +611,7 @@ fn main() {
let space = value_t!(matches, "space", u64).ok();
let lamports = value_t!(matches, "lamports", u64).ok();
let batch_size = value_t!(matches, "batch_size", usize).unwrap_or(4);
let close_nth_batch = value_t!(matches, "close_nth_batch", u64).unwrap_or(0);
let close_nth = value_t!(matches, "close_nth", u64).unwrap_or(0);
let iterations = value_t!(matches, "iterations", usize).unwrap_or(10);
let num_instructions = value_t!(matches, "num_instructions", usize).unwrap_or(1);
if num_instructions == 0 || num_instructions > 500 {
@@ -647,29 +621,20 @@ fn main() {
let mint = pubkey_of(&matches, "mint");
let payer_keypairs: Vec<_> = values_t_or_exit!(matches, "identity", String)
.iter()
.map(|keypair_string| {
read_keypair_file(keypair_string)
.unwrap_or_else(|_| panic!("bad keypair {:?}", keypair_string))
})
.collect();
let mut payer_keypair_refs: Vec<&Keypair> = vec![];
for keypair in payer_keypairs.iter() {
payer_keypair_refs.push(keypair);
}
let keypair =
read_keypair_file(&value_t_or_exit!(matches, "identity", String)).expect("bad keypair");
let rpc_addr = if !skip_gossip {
info!("Finding cluster entry: {:?}", entrypoint_addr);
let (gossip_nodes, _validators) = discover(
None, // keypair
None,
Some(&entrypoint_addr),
None, // num_nodes
Duration::from_secs(60), // timeout
None, // find_node_by_pubkey
Some(&entrypoint_addr), // find_node_by_gossip_addr
None, // my_gossip_addr
0, // my_shred_version
None,
Some(60),
None,
Some(&entrypoint_addr),
None,
0,
)
.unwrap_or_else(|err| {
eprintln!("Failed to discover {} node: {:?}", entrypoint_addr, err);
@@ -686,11 +651,11 @@ fn main() {
run_accounts_bench(
rpc_addr,
faucet_addr,
&payer_keypair_refs,
&keypair,
iterations,
space,
batch_size,
close_nth_batch,
close_nth,
lamports,
num_instructions,
mint,
@@ -725,18 +690,18 @@ pub mod test {
let iterations = 10;
let maybe_space = None;
let batch_size = 100;
let close_nth_batch = 100;
let close_nth = 100;
let maybe_lamports = None;
let num_instructions = 2;
let mut start = Measure::start("total accounts run");
run_accounts_bench(
cluster.entry_point_info.rpc,
faucet_addr,
&[&cluster.funding_keypair],
&cluster.funding_keypair,
iterations,
maybe_space,
batch_size,
close_nth_batch,
close_nth,
maybe_lamports,
num_instructions,
None,

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-banking-bench"
version = "1.7.8"
version = "1.6.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -14,18 +14,16 @@ crossbeam-channel = "0.4"
log = "0.4.11"
rand = "0.7.0"
rayon = "1.5.0"
solana-core = { path = "../core", version = "=1.7.8" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.8" }
solana-gossip = { path = "../gossip", version = "=1.7.8" }
solana-ledger = { path = "../ledger", version = "=1.7.8" }
solana-logger = { path = "../logger", version = "=1.7.8" }
solana-measure = { path = "../measure", version = "=1.7.8" }
solana-perf = { path = "../perf", version = "=1.7.8" }
solana-poh = { path = "../poh", version = "=1.7.8" }
solana-runtime = { path = "../runtime", version = "=1.7.8" }
solana-streamer = { path = "../streamer", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-version = { path = "../version", version = "=1.7.8" }
solana-core = { path = "../core", version = "=1.6.2" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.2" }
solana-streamer = { path = "../streamer", version = "=1.6.2" }
solana-perf = { path = "../perf", version = "=1.6.2" }
solana-ledger = { path = "../ledger", version = "=1.6.2" }
solana-logger = { path = "../logger", version = "=1.6.2" }
solana-runtime = { path = "../runtime", version = "=1.6.2" }
solana-measure = { path = "../measure", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-version = { path = "../version", version = "=1.6.2" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -4,8 +4,13 @@ use crossbeam_channel::unbounded;
use log::*;
use rand::{thread_rng, Rng};
use rayon::prelude::*;
use solana_core::banking_stage::BankingStage;
use solana_gossip::{cluster_info::ClusterInfo, cluster_info::Node};
use solana_core::{
banking_stage::{create_test_recorder, BankingStage},
cluster_info::ClusterInfo,
cluster_info::Node,
poh_recorder::PohRecorder,
poh_recorder::WorkingBankEntry,
};
use solana_ledger::{
blockstore::Blockstore,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
@@ -13,7 +18,6 @@ use solana_ledger::{
};
use solana_measure::measure::Measure;
use solana_perf::packet::to_packets_chunked;
use solana_poh::poh_recorder::{create_test_recorder, PohRecorder, WorkingBankEntry};
use solana_runtime::{
accounts_background_service::AbsRequestSender, bank::Bank, bank_forks::BankForks,
};
@@ -74,7 +78,7 @@ fn make_accounts_txs(
.into_par_iter()
.map(|_| {
let mut new = dummy.clone();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
if !same_payer {
new.message.account_keys[0] = solana_sdk::pubkey::new_rand();
}
@@ -185,7 +189,7 @@ fn main() {
genesis_config.hash(),
);
// Ignore any pesky duplicate signature errors in the case we are using single-payer
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
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();
@@ -195,7 +199,7 @@ fn main() {
if !skip_sanity {
//sanity check, make sure all the transactions can execute sequentially
transactions.iter().for_each(|tx| {
let res = bank.process_transaction(tx);
let res = bank.process_transaction(&tx);
assert!(res.is_ok(), "sanity test transactions error: {:?}", res);
});
bank.clear_signatures();
@@ -351,7 +355,7 @@ fn main() {
if bank.slot() > 0 && bank.slot() % 16 == 0 {
for tx in transactions.iter_mut() {
tx.message.recent_blockhash = bank.last_blockhash();
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
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_chunk);

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-client"
version = "1.7.8"
version = "1.6.2"
description = "Solana banks client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -11,20 +11,20 @@ edition = "2018"
[dependencies]
bincode = "1.3.1"
borsh = "0.9.0"
borsh-derive = "0.9.0"
borsh = "0.8.1"
borsh-derive = "0.8.1"
futures = "0.3"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "=1.7.8" }
solana-program = { path = "../sdk/program", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-banks-interface = { path = "../banks-interface", version = "=1.6.2" }
solana-program = { path = "../sdk/program", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
tarpc = { version = "0.24.1", features = ["full"] }
tokio = { version = "1", features = ["full"] }
tokio = { version = "1.1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }
[dev-dependencies]
solana-runtime = { path = "../runtime", version = "=1.7.8" }
solana-banks-server = { path = "../banks-server", version = "=1.7.8" }
solana-runtime = { path = "../runtime", version = "=1.6.2" }
solana-banks-server = { path = "../banks-server", version = "=1.6.2" }
[lib]
crate-type = ["lib"]

View File

@@ -11,7 +11,7 @@ pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus};
use solana_banks_interface::{BanksRequest, BanksResponse};
use solana_program::{
clock::Slot, fee_calculator::FeeCalculator, hash::Hash, program_pack::Pack, pubkey::Pubkey,
rent::Rent, sysvar::Sysvar,
rent::Rent, sysvar,
};
use solana_sdk::{
account::{from_account, Account},
@@ -124,19 +124,15 @@ impl BanksClient {
self.get_fees_with_commitment_and_context(context::current(), CommitmentLevel::default())
}
/// Return the cluster Sysvar
pub fn get_sysvar<T: Sysvar>(&mut self) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(T::id()).map(|result| {
let sysvar = result?
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Sysvar not present"))?;
from_account::<T, _>(&sysvar)
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to deserialize sysvar"))
})
}
/// Return the cluster rent
pub fn get_rent(&mut self) -> impl Future<Output = io::Result<Rent>> + '_ {
self.get_sysvar::<Rent>()
self.get_account(sysvar::rent::id()).map(|result| {
let rent_sysvar = result?
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Rent sysvar not present"))?;
from_account::<Rent, _>(&rent_sysvar).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "Failed to deserialize Rent sysvar")
})
})
}
/// Return a recent, rooted blockhash from the server. The cluster will only accept
@@ -381,8 +377,8 @@ mod tests {
let mint_pubkey = &genesis.mint_keypair.pubkey();
let bob_pubkey = solana_sdk::pubkey::new_rand();
let instruction = system_instruction::transfer(mint_pubkey, &bob_pubkey, 1);
let message = Message::new(&[instruction], Some(mint_pubkey));
let instruction = system_instruction::transfer(&mint_pubkey, &bob_pubkey, 1);
let message = Message::new(&[instruction], Some(&mint_pubkey));
Runtime::new()?.block_on(async {
let client_transport = start_local_server(bank_forks, block_commitment_cache).await;

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-interface"
version = "1.7.8"
version = "1.6.2"
description = "Solana banks RPC interface"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -12,11 +12,11 @@ edition = "2018"
[dependencies]
mio = "0.7.6"
serde = { version = "1.0.122", features = ["derive"] }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
tarpc = { version = "0.24.1", features = ["full"] }
[dev-dependencies]
tokio = { version = "1", features = ["full"] }
tokio = { version = "1.1", features = ["full"] }
[lib]
crate-type = ["lib"]

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-banks-server"
version = "1.7.8"
version = "1.6.2"
description = "Solana banks server"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -14,12 +14,12 @@ bincode = "1.3.1"
futures = "0.3"
log = "0.4.11"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "=1.7.8" }
solana-runtime = { path = "../runtime", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-metrics = { path = "../metrics", version = "=1.7.8" }
solana-banks-interface = { path = "../banks-interface", version = "=1.6.2" }
solana-runtime = { path = "../runtime", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-metrics = { path = "../metrics", version = "=1.6.2" }
tarpc = { version = "0.24.1", features = ["full"] }
tokio = { version = "1", features = ["full"] }
tokio = { version = "1.1", features = ["full"] }
tokio-serde = { version = "0.8", features = ["bincode"] }
tokio-stream = "0.1"

View File

@@ -131,13 +131,10 @@ impl BanksServer {
}
}
fn verify_transaction(
transaction: &Transaction,
libsecp256k1_0_5_upgrade_enabled: bool,
) -> transaction::Result<()> {
fn verify_transaction(transaction: &Transaction) -> transaction::Result<()> {
if let Err(err) = transaction.verify() {
Err(err)
} else if let Err(err) = transaction.verify_precompiles(libsecp256k1_0_5_upgrade_enabled) {
} else if let Err(err) = transaction.verify_precompiles() {
Err(err)
} else {
Ok(())
@@ -153,7 +150,7 @@ impl Banks for BanksServer {
.read()
.unwrap()
.root_bank()
.get_blockhash_last_valid_slot(blockhash)
.get_blockhash_last_valid_slot(&blockhash)
.unwrap();
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
let info =
@@ -218,10 +215,7 @@ impl Banks for BanksServer {
transaction: Transaction,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>> {
if let Err(err) = verify_transaction(
&transaction,
self.bank(commitment).libsecp256k1_0_5_upgrade_enabled(),
) {
if let Err(err) = verify_transaction(&transaction) {
return Some(Err(err));
}

View File

@@ -138,8 +138,8 @@ impl SendTransactionService {
result.retried += 1;
inc_new_counter_info!("send_transaction_service-retry", 1);
Self::send_transaction(
send_socket,
tpu_address,
&send_socket,
&tpu_address,
&transaction_info.wire_transaction,
);
true

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-bench-exchange"
version = "1.7.8"
version = "1.6.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -18,22 +18,21 @@ rand = "0.7.0"
rayon = "1.5.0"
serde_json = "1.0.56"
serde_yaml = "0.8.13"
solana-clap-utils = { path = "../clap-utils", version = "=1.7.8" }
solana-core = { path = "../core", version = "=1.7.8" }
solana-genesis = { path = "../genesis", version = "=1.7.8" }
solana-client = { path = "../client", version = "=1.7.8" }
solana-exchange-program = { path = "../programs/exchange", version = "=1.7.8" }
solana-faucet = { path = "../faucet", version = "=1.7.8" }
solana-gossip = { path = "../gossip", version = "=1.7.8" }
solana-logger = { path = "../logger", version = "=1.7.8" }
solana-metrics = { path = "../metrics", version = "=1.7.8" }
solana-net-utils = { path = "../net-utils", version = "=1.7.8" }
solana-runtime = { path = "../runtime", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-version = { path = "../version", version = "=1.7.8" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.2" }
solana-core = { path = "../core", version = "=1.6.2" }
solana-genesis = { path = "../genesis", version = "=1.6.2" }
solana-client = { path = "../client", version = "=1.6.2" }
solana-faucet = { path = "../faucet", version = "=1.6.2" }
solana-exchange-program = { path = "../programs/exchange", version = "=1.6.2" }
solana-logger = { path = "../logger", version = "=1.6.2" }
solana-metrics = { path = "../metrics", version = "=1.6.2" }
solana-net-utils = { path = "../net-utils", version = "=1.6.2" }
solana-runtime = { path = "../runtime", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-version = { path = "../version", version = "=1.6.2" }
[dev-dependencies]
solana-local-cluster = { path = "../local-cluster", version = "=1.7.8" }
solana-local-cluster = { path = "../local-cluster", version = "=1.6.2" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -451,13 +451,13 @@ fn swapper<T>(
let to_swap_txs: Vec<_> = to_swap
.par_iter()
.map(|(signer, swap, profit)| {
let s: &Keypair = signer;
let s: &Keypair = &signer;
let owner = &signer.pubkey();
let instruction = exchange_instruction::swap_request(
owner,
&swap.0.pubkey,
&swap.1.pubkey,
profit,
&profit,
);
let message = Message::new(&[instruction], Some(&s.pubkey()));
Transaction::new(&[s], message, blockhash)
@@ -600,7 +600,7 @@ fn trader<T>(
src,
),
];
let message = Message::new(&instructions, Some(owner_pubkey));
let message = Message::new(&instructions, Some(&owner_pubkey));
Transaction::new(&[owner.as_ref(), trade], message, blockhash)
})
.collect();
@@ -739,7 +739,7 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
let mut to_fund_txs: Vec<_> = chunk
.par_iter()
.map(|(k, m)| {
let instructions = system_instruction::transfer_many(&k.pubkey(), m);
let instructions = system_instruction::transfer_many(&k.pubkey(), &m);
let message = Message::new(&instructions, Some(&k.pubkey()));
(k.clone(), Transaction::new_unsigned(message))
})
@@ -777,7 +777,7 @@ pub fn fund_keys<T: Client>(client: &T, source: &Keypair, dests: &[Arc<Keypair>]
let mut waits = 0;
loop {
sleep(Duration::from_millis(200));
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, tx, amount));
to_fund_txs.retain(|(_, tx)| !verify_funding_transfer(client, &tx, amount));
if to_fund_txs.is_empty() {
break;
}
@@ -836,7 +836,7 @@ pub fn create_token_accounts<T: Client>(
);
let request_ix =
exchange_instruction::account_request(owner_pubkey, &new_keypair.pubkey());
let message = Message::new(&[create_ix, request_ix], Some(owner_pubkey));
let message = Message::new(&[create_ix, request_ix], Some(&owner_pubkey));
(
(from_keypair, new_keypair),
Transaction::new_unsigned(message),
@@ -872,7 +872,7 @@ pub fn create_token_accounts<T: Client>(
let mut waits = 0;
while !to_create_txs.is_empty() {
sleep(Duration::from_millis(200));
to_create_txs.retain(|(_, tx)| !verify_transaction(client, tx));
to_create_txs.retain(|(_, tx)| !verify_transaction(client, &tx));
if to_create_txs.is_empty() {
break;
}
@@ -958,7 +958,7 @@ fn compute_and_report_stats(maxes: &Arc<RwLock<Vec<(String, SampleStats)>>>, tot
fn generate_keypairs(num: u64) -> Vec<Keypair> {
let mut seed = [0_u8; 32];
seed.copy_from_slice(Keypair::new().pubkey().as_ref());
seed.copy_from_slice(&Keypair::new().pubkey().as_ref());
let mut rnd = GenKeys::new(seed);
rnd.gen_n_keypairs(num)
}
@@ -989,7 +989,7 @@ pub fn airdrop_lamports<T: Client>(
let (blockhash, _fee_calculator, _last_valid_slot) = client
.get_recent_blockhash_with_commitment(CommitmentConfig::processed())
.expect("Failed to get blockhash");
match request_airdrop_transaction(faucet_addr, &id.pubkey(), amount_to_drop, blockhash) {
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), amount_to_drop, blockhash) {
Ok(transaction) => {
let signature = client.async_send_transaction(transaction).unwrap();

View File

@@ -5,7 +5,7 @@ pub mod order_book;
use crate::bench::{airdrop_lamports, create_client_accounts_file, do_bench_exchange, Config};
use log::*;
use solana_gossip::gossip_service::{discover_cluster, get_multi_client};
use solana_core::gossip_service::{discover_cluster, get_multi_client};
use solana_sdk::signature::Signer;
fn main() {

View File

@@ -1,11 +1,13 @@
use log::*;
use solana_bench_exchange::bench::{airdrop_lamports, do_bench_exchange, Config};
use solana_core::validator::ValidatorConfig;
use solana_core::{
gossip_service::{discover_cluster, get_multi_client},
validator::ValidatorConfig,
};
use solana_exchange_program::{
exchange_processor::process_instruction, id, solana_exchange_program,
};
use solana_faucet::faucet::run_local_faucet_with_port;
use solana_gossip::gossip_service::{discover_cluster, get_multi_client};
use solana_local_cluster::{
local_cluster::{ClusterConfig, LocalCluster},
validator_configs::make_identical_validator_configs,

View File

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

View File

@@ -18,7 +18,7 @@ fn producer(addr: &SocketAddr, exit: Arc<AtomicBool>) -> JoinHandle<()> {
msgs.packets.resize(10, Packet::default());
for w in msgs.packets.iter_mut() {
w.meta.size = PACKET_DATA_SIZE;
w.meta.set_addr(addr);
w.meta.set_addr(&addr);
}
let msgs = Arc::new(msgs);
spawn(move || loop {
@@ -75,7 +75,7 @@ fn main() -> Result<()> {
let mut read_channels = Vec::new();
let mut read_threads = Vec::new();
let recycler = PacketsRecycler::default();
let recycler = PacketsRecycler::new_without_limit("bench-streamer-recycler-shrink-stats");
for _ in 0..num_sockets {
let read = solana_net_utils::bind_to(ip_addr, port, false).unwrap();
read.set_read_timeout(Some(Duration::new(1, 0))).unwrap();
@@ -92,7 +92,6 @@ fn main() -> Result<()> {
recycler.clone(),
"bench-streamer-test",
1,
true,
));
}

View File

@@ -2,7 +2,7 @@
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-bench-tps"
version = "1.7.8"
version = "1.6.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -15,23 +15,22 @@ log = "0.4.11"
rayon = "1.5.0"
serde_json = "1.0.56"
serde_yaml = "0.8.13"
solana-clap-utils = { path = "../clap-utils", version = "=1.7.8" }
solana-core = { path = "../core", version = "=1.7.8" }
solana-genesis = { path = "../genesis", version = "=1.7.8" }
solana-client = { path = "../client", version = "=1.7.8" }
solana-faucet = { path = "../faucet", version = "=1.7.8" }
solana-gossip = { path = "../gossip", version = "=1.7.8" }
solana-logger = { path = "../logger", version = "=1.7.8" }
solana-metrics = { path = "../metrics", version = "=1.7.8" }
solana-measure = { path = "../measure", version = "=1.7.8" }
solana-net-utils = { path = "../net-utils", version = "=1.7.8" }
solana-runtime = { path = "../runtime", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-version = { path = "../version", version = "=1.7.8" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.2" }
solana-core = { path = "../core", version = "=1.6.2" }
solana-genesis = { path = "../genesis", version = "=1.6.2" }
solana-client = { path = "../client", version = "=1.6.2" }
solana-faucet = { path = "../faucet", version = "=1.6.2" }
solana-logger = { path = "../logger", version = "=1.6.2" }
solana-metrics = { path = "../metrics", version = "=1.6.2" }
solana-measure = { path = "../measure", version = "=1.6.2" }
solana-net-utils = { path = "../net-utils", version = "=1.6.2" }
solana-runtime = { path = "../runtime", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-version = { path = "../version", version = "=1.6.2" }
[dev-dependencies]
serial_test = "0.4.0"
solana-local-cluster = { path = "../local-cluster", version = "=1.7.8" }
solana-local-cluster = { path = "../local-cluster", version = "=1.6.2" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -544,12 +544,12 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
// re-sign retained to_fund_txes with updated blockhash
self.sign(blockhash);
self.send(client);
self.send(&client);
// Sleep a few slots to allow transactions to process
sleep(Duration::from_secs(1));
self.verify(client, to_lamports);
self.verify(&client, to_lamports);
// retry anything that seems to have dropped through cracks
// again since these txs are all or nothing, they're fine to
@@ -564,7 +564,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
let to_fund_txs: Vec<(&Keypair, Transaction)> = to_fund
.par_iter()
.map(|(k, t)| {
let instructions = system_instruction::transfer_many(&k.pubkey(), t);
let instructions = system_instruction::transfer_many(&k.pubkey(), &t);
let message = Message::new(&instructions, Some(&k.pubkey()));
(*k, Transaction::new_unsigned(message))
})
@@ -617,7 +617,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
return None;
}
let verified = if verify_funding_transfer(&client, tx, to_lamports) {
let verified = if verify_funding_transfer(&client, &tx, to_lamports) {
verified_txs.fetch_add(1, Ordering::Relaxed);
Some(k.pubkey())
} else {
@@ -733,7 +733,7 @@ pub fn airdrop_lamports<T: Client>(
);
let (blockhash, _fee_calculator) = get_recent_blockhash(client);
match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
match request_airdrop_transaction(&faucet_addr, &id.pubkey(), airdrop_amount, blockhash) {
Ok(transaction) => {
let mut tries = 0;
loop {

View File

@@ -2,8 +2,8 @@
use log::*;
use solana_bench_tps::bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs};
use solana_bench_tps::cli;
use solana_core::gossip_service::{discover_cluster, get_client, get_multi_client};
use solana_genesis::Base64Account;
use solana_gossip::gossip_service::{discover_cluster, get_client, get_multi_client};
use solana_sdk::fee_calculator::FeeRateGovernor;
use solana_sdk::signature::{Keypair, Signer};
use solana_sdk::system_program;
@@ -39,7 +39,7 @@ fn main() {
let keypair_count = *tx_count * keypair_multiplier;
if *write_to_client_file {
info!("Generating {} keypairs", keypair_count);
let (keypairs, _) = generate_keypairs(id, keypair_count as u64);
let (keypairs, _) = generate_keypairs(&id, keypair_count as u64);
let num_accounts = keypairs.len() as u64;
let max_fee =
FeeRateGovernor::new(*target_lamports_per_signature, 0).max_lamports_per_signature;
@@ -68,7 +68,7 @@ fn main() {
}
info!("Connecting to the cluster");
let nodes = discover_cluster(entrypoint_addr, *num_nodes).unwrap_or_else(|err| {
let nodes = discover_cluster(&entrypoint_addr, *num_nodes).unwrap_or_else(|err| {
eprintln!("Failed to discover {} nodes: {:?}", num_nodes, err);
exit(1);
});
@@ -135,7 +135,7 @@ fn main() {
generate_and_fund_keypairs(
client.clone(),
Some(*faucet_addr),
id,
&id,
keypair_count,
*num_lamports_per_account,
)

View File

@@ -5,9 +5,8 @@ use solana_bench_tps::{
cli::Config,
};
use solana_client::thin_client::create_client;
use solana_core::validator::ValidatorConfig;
use solana_core::{cluster_info::VALIDATOR_PORT_RANGE, validator::ValidatorConfig};
use solana_faucet::faucet::run_local_faucet_with_port;
use solana_gossip::cluster_info::VALIDATOR_PORT_RANGE;
use solana_local_cluster::{
local_cluster::{ClusterConfig, LocalCluster},
validator_configs::make_identical_validator_configs,

9
cargo
View File

@@ -3,22 +3,25 @@
# shellcheck source=ci/rust-version.sh
here=$(dirname "$0")
source "${here}"/ci/rust-version.sh all
toolchain=
case "$1" in
stable)
source "${here}"/ci/rust-version.sh stable
# shellcheck disable=SC2054 # rust_stable is sourced from rust-version.sh
toolchain="$rust_stable"
shift
;;
nightly)
source "${here}"/ci/rust-version.sh nightly
# shellcheck disable=SC2054 # rust_nightly is sourced from rust-version.sh
toolchain="$rust_nightly"
shift
;;
+*)
toolchain="${1#+}"
shift
;;
*)
source "${here}"/ci/rust-version.sh stable
# shellcheck disable=SC2054 # rust_stable is sourced from rust-version.sh
toolchain="$rust_stable"
;;

View File

@@ -148,33 +148,6 @@ all_test_steps() {
command_step stable ". ci/rust-version.sh; ci/docker-run.sh \$\$rust_stable_docker_image ci/test-stable.sh" 60
wait_step
# BPF test suite
if affects \
.rs$ \
Cargo.lock$ \
Cargo.toml$ \
^ci/rust-version.sh \
^ci/test-stable-bpf.sh \
^ci/test-stable.sh \
^ci/test-local-cluster.sh \
^core/build.rs \
^fetch-perf-libs.sh \
^programs/ \
^sdk/ \
; then
cat >> "$output_file" <<"EOF"
- command: "ci/test-stable-bpf.sh"
name: "stable-bpf"
timeout_in_minutes: 20
artifact_paths: "bpf-dumps.tar.bz2"
agents:
- "queue=default"
EOF
else
annotate --style info \
"Stable-BPF skipped as no relevant files were modified"
fi
# Perf test suite
if affects \
.rs$ \
@@ -192,7 +165,7 @@ EOF
cat >> "$output_file" <<"EOF"
- command: "ci/test-stable-perf.sh"
name: "stable-perf"
timeout_in_minutes: 20
timeout_in_minutes: 40
artifact_paths: "log-*.txt"
agents:
- "queue=cuda"

View File

@@ -3,19 +3,16 @@
# Pull requests to not run these steps.
steps:
- command: "ci/publish-tarball.sh"
agents:
- "queue=release-build"
timeout_in_minutes: 60
name: "publish tarball"
- command: "ci/publish-bpf-sdk.sh"
timeout_in_minutes: 5
name: "publish bpf sdk"
- wait
- command: "sdk/docker-solana/build.sh"
agents:
- "queue=release-build"
timeout_in_minutes: 60
name: "publish docker"
- command: "ci/publish-crate.sh"
agents:
- "queue=release-build"
timeout_in_minutes: 240
name: "publish crate"
branches: "!master"

View File

@@ -105,18 +105,11 @@ if [[ -z "$CHANNEL" ]]; then
fi
fi
if [[ $CHANNEL = beta ]]; then
CHANNEL_LATEST_TAG="$BETA_CHANNEL_LATEST_TAG"
elif [[ $CHANNEL = stable ]]; then
CHANNEL_LATEST_TAG="$STABLE_CHANNEL_LATEST_TAG"
fi
echo EDGE_CHANNEL="$EDGE_CHANNEL"
echo BETA_CHANNEL="$BETA_CHANNEL"
echo BETA_CHANNEL_LATEST_TAG="$BETA_CHANNEL_LATEST_TAG"
echo STABLE_CHANNEL="$STABLE_CHANNEL"
echo STABLE_CHANNEL_LATEST_TAG="$STABLE_CHANNEL_LATEST_TAG"
echo CHANNEL="$CHANNEL"
echo CHANNEL_LATEST_TAG="$CHANNEL_LATEST_TAG"
exit 0

View File

@@ -7,6 +7,8 @@ src_root="$(readlink -f "${here}/..")"
cd "${src_root}"
source ci/rust-version.sh stable
cargo_audit_ignores=(
# failure is officially deprecated/unmaintained
#
@@ -40,4 +42,4 @@ cargo_audit_ignores=(
--ignore RUSTSEC-2020-0146
)
scripts/cargo-for-all-lock-files.sh stable audit "${cargo_audit_ignores[@]}"
scripts/cargo-for-all-lock-files.sh +"$rust_stable" audit "${cargo_audit_ignores[@]}"

View File

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

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.52.1
FROM rust:1.50.0
# Add Google Protocol Buffers for Libra's metrics library.
ENV PROTOC_VERSION 3.8.0

View File

@@ -74,13 +74,10 @@ else
export CI_BUILD_ID=
export CI_COMMIT=
export CI_JOB_ID=
export CI_OS_NAME=
export CI_PULL_REQUEST=
export CI_REPO_SLUG=
export CI_TAG=
# Don't override ci/run-local.sh
if [[ -z $CI_LOCAL_RUN ]]; then
export CI_OS_NAME=
fi
fi
cat <<EOF

View File

@@ -70,7 +70,7 @@ done
source ci/upload-ci-artifact.sh
source scripts/configure-metrics.sh
source multinode-demo/common.sh --prebuild
source multinode-demo/common.sh
nodes=(
"multinode-demo/bootstrap-validator.sh \
@@ -127,7 +127,7 @@ startNode() {
waitForNodeToInit() {
declare initCompleteFile=$1
while [[ ! -r $initCompleteFile ]]; do
if [[ $SECONDS -ge 300 ]]; then
if [[ $SECONDS -ge 240 ]]; then
echo "^^^ +++"
echo "Error: $initCompleteFile not found in $SECONDS seconds"
exit 1

View File

@@ -12,14 +12,10 @@ import json
import subprocess
import sys;
real_file = os.path.realpath(__file__)
ci_path = os.path.dirname(real_file)
src_root = os.path.dirname(ci_path)
def load_metadata():
cmd = f'{src_root}/cargo metadata --no-deps --format-version=1'
return json.loads(subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE).communicate()[0])
'cargo metadata --no-deps --format-version=1',
shell=True, stdout=subprocess.PIPE).communicate()[0])
def get_packages():
metadata = load_metadata()

27
ci/publish-bpf-sdk.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
eval "$(ci/channel-info.sh)"
if [[ -n "$CI_TAG" ]]; then
CHANNEL_OR_TAG=$CI_TAG
else
CHANNEL_OR_TAG=$CHANNEL
fi
(
set -x
sdk/bpf/scripts/package.sh
[[ -f bpf-sdk.tar.bz2 ]]
)
source ci/upload-ci-artifact.sh
echo --- AWS S3 Store
if [[ -z $CHANNEL_OR_TAG ]]; then
echo Skipped
else
upload-s3-artifact "/solana/bpf-sdk.tar.bz2" "s3://solana-sdk/$CHANNEL_OR_TAG/bpf-sdk.tar.bz2"
fi
exit 0

View File

@@ -83,7 +83,7 @@ echo --- Creating release tarball
export CHANNEL
source ci/rust-version.sh stable
scripts/cargo-install-all.sh stable "${RELEASE_BASENAME}"
scripts/cargo-install-all.sh +"$rust_stable" "${RELEASE_BASENAME}"
tar cvf "${TARBALL_BASENAME}"-$TARGET.tar "${RELEASE_BASENAME}"
bzip2 "${TARBALL_BASENAME}"-$TARGET.tar

View File

@@ -1,55 +0,0 @@
#!/usr/bin/env bash
cd "$(dirname "$0")/.."
export CI_LOCAL_RUN=true
set -e
case $(uname -o) in
*/Linux)
export CI_OS_NAME=linux
;;
*)
echo "local CI runs are only supported on Linux" 1>&2
exit 1
;;
esac
steps=()
steps+=(test-sanity)
steps+=(shellcheck)
steps+=(test-checks)
steps+=(test-coverage)
steps+=(test-stable)
steps+=(test-stable-bpf)
steps+=(test-stable-perf)
steps+=(test-downstream-builds)
steps+=(test-bench)
steps+=(test-local-cluster)
step_index=0
if [[ -n "$1" ]]; then
start_step="$1"
while [[ $step_index -lt ${#steps[@]} ]]; do
step="${steps[$step_index]}"
if [[ "$step" = "$start_step" ]]; then
break
fi
step_index=$((step_index + 1))
done
if [[ $step_index -eq ${#steps[@]} ]]; then
echo "unexpected start step: \"$start_step\"" 1>&2
exit 1
else
echo "** starting at step: \"$start_step\" **"
echo
fi
fi
while [[ $step_index -lt ${#steps[@]} ]]; do
step="${steps[$step_index]}"
cmd="ci/${step}.sh"
$cmd
step_index=$((step_index + 1))
done

View File

@@ -7,7 +7,7 @@ source multinode-demo/common.sh
rm -rf config/run/init-completed config/ledger config/snapshot-ledger
SOLANA_RUN_SH_VALIDATOR_ARGS="--snapshot-interval-slots 200" timeout 120 ./run.sh &
timeout 120 ./run.sh &
pid=$!
attempts=20
@@ -16,17 +16,14 @@ while [[ ! -f config/run/init-completed ]]; do
if ((--attempts == 0)); then
echo "Error: validator failed to boot"
exit 1
else
echo "Checking init"
fi
done
snapshot_slot=1
# wait a bit longer than snapshot_slot
while [[ $($solana_cli --url http://localhost:8899 slot --commitment processed) -le $((snapshot_slot + 1)) ]]; do
while [[ $($solana_cli --url http://localhost:8899 slot --commitment recent) -le $((snapshot_slot + 1)) ]]; do
sleep 1
echo "Checking slot"
done
$solana_validator --ledger config/ledger exit --force || true

View File

@@ -18,13 +18,13 @@
if [[ -n $RUST_STABLE_VERSION ]]; then
stable_version="$RUST_STABLE_VERSION"
else
stable_version=1.52.1
stable_version=1.50.0
fi
if [[ -n $RUST_NIGHTLY_VERSION ]]; then
nightly_version="$RUST_NIGHTLY_VERSION"
else
nightly_version=2021-05-18
nightly_version=2021-02-18
fi

View File

@@ -27,7 +27,7 @@ BENCH_ARTIFACT=current_bench_results.log
_ "$cargo" build --manifest-path=keygen/Cargo.toml
export PATH="$PWD/target/debug":$PATH
# Clear the C dependency files, if dependency moves these files are not regenerated
# Clear the C dependency files, if dependeny moves these files are not regenerated
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
@@ -45,14 +45,6 @@ _ "$cargo" nightly bench --manifest-path sdk/Cargo.toml ${V:+--verbose} \
_ "$cargo" nightly bench --manifest-path runtime/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run gossip benches
_ "$cargo" nightly bench --manifest-path gossip/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run poh benches
_ "$cargo" nightly bench --manifest-path poh/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"
# Run core benches
_ "$cargo" nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \
-- -Z unstable-options --format=json | tee -a "$BENCH_FILE"

View File

@@ -14,7 +14,7 @@ scripts/increment-cargo-version.sh check
# Disallow uncommitted Cargo.lock changes
(
_ scripts/cargo-for-all-lock-files.sh tree >/dev/null
_ scripts/cargo-for-all-lock-files.sh tree
set +e
if ! _ git diff --exit-code; then
echo -e "\nError: Uncommitted Cargo.lock changes" 1>&2
@@ -35,10 +35,8 @@ echo --- build environment
"$cargo" stable clippy --version --verbose
"$cargo" nightly clippy --version --verbose
# audit is done only with "$cargo stable"
# audit is done only with stable
"$cargo" stable audit --version
grcov --version
)
export RUST_BACKTRACE=1
@@ -47,7 +45,7 @@ export RUSTFLAGS="-D warnings -A incomplete_features"
# Only force up-to-date lock files on edge
if [[ $CI_BASE_BRANCH = "$EDGE_CHANNEL" ]]; then
# Exclude --benches as it's not available in rust stable yet
if _ scripts/cargo-for-all-lock-files.sh stable check --locked --tests --bins --examples; then
if _ scripts/cargo-for-all-lock-files.sh +"$rust_stable" check --locked --tests --bins --examples; then
true
else
check_status=$?
@@ -58,7 +56,7 @@ if [[ $CI_BASE_BRANCH = "$EDGE_CHANNEL" ]]; then
fi
# Ensure nightly and --benches
_ scripts/cargo-for-all-lock-files.sh nightly check --locked --all-targets
_ scripts/cargo-for-all-lock-files.sh +"$rust_nightly" check --locked --all-targets
else
echo "Note: cargo-for-all-lock-files.sh skipped because $CI_BASE_BRANCH != $EDGE_CHANNEL"
fi
@@ -67,8 +65,7 @@ _ ci/order-crates-for-publishing.py
# -Z... is needed because of clippy bug: https://github.com/rust-lang/rust-clippy/issues/4612
# run nightly clippy for `sdk/` as there's a moderate amount of nightly-only code there
_ "$cargo" nightly clippy -Zunstable-options --workspace --all-targets -- \
--deny=warnings --deny=clippy::integer_arithmetic --allow=clippy::inconsistent_struct_constructor
_ "$cargo" nightly clippy -Zunstable-options --workspace --all-targets -- --deny=warnings --deny=clippy::integer_arithmetic
_ "$cargo" stable fmt --all -- --check
@@ -82,6 +79,7 @@ _ ci/do-audit.sh
cd "$project"
_ "$cargo" nightly clippy -- --deny=warnings --allow=clippy::missing_safety_doc
_ "$cargo" stable fmt -- --check
_ "$cargo" nightly test
)
done
}

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
cd "$(dirname "$0")/.."
export CI_LOCAL_RUN=true
set -ex
scripts/build-downstream-projects.sh

View File

@@ -25,29 +25,4 @@ echo
_ ci/nits.sh
_ ci/check-ssh-keys.sh
# Ensure the current channel version is not equal ("greater") than
# the version of the latest tag
if [[ -z $CI_TAG ]]; then
echo "--- channel version check"
(
eval "$(ci/channel-info.sh)"
if [[ -n $CHANNEL_LATEST_TAG ]]; then
source scripts/read-cargo-variable.sh
version=$(readCargoVariable version "version/Cargo.toml")
echo "version: v$version"
echo "latest channel tag: $CHANNEL_LATEST_TAG"
if [[ $CHANNEL_LATEST_TAG = v$version ]]; then
echo "Error: please run ./scripts/increment-cargo-version.sh"
exit 1
fi
else
echo "Skipped. CHANNEL_LATEST_TAG (CHANNEL=$CHANNEL) unset"
fi
)
fi
echo --- ok

View File

@@ -1 +0,0 @@
test-stable.sh

View File

@@ -21,6 +21,10 @@ export RUST_BACKTRACE=1
export RUSTFLAGS="-D warnings"
source scripts/ulimit-n.sh
# Clear the C dependency files, if dependency moves these files are not regenerated
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
# Limit compiler jobs to reduce memory usage
# on machines with 2gb/thread of memory
NPROC=$(nproc)
@@ -31,57 +35,25 @@ case $testName in
test-stable)
_ "$cargo" stable test --jobs "$NPROC" --all --exclude solana-local-cluster ${V:+--verbose} -- --nocapture
;;
test-stable-bpf)
# Clear the C dependency files, if dependency moves these files are not regenerated
test -d target/debug/bpf && find target/debug/bpf -name '*.d' -delete
test -d target/release/bpf && find target/release/bpf -name '*.d' -delete
# rustfilt required for dumping BPF assembly listings
"$cargo" install rustfilt
test-stable-perf)
# solana-keygen required when building C programs
_ "$cargo" build --manifest-path=keygen/Cargo.toml
export PATH="$PWD/target/debug":$PATH
cargo_build_bpf="$(realpath ./cargo-build-bpf)"
# BPF solana-sdk legacy compile test
"$cargo_build_bpf" --manifest-path sdk/Cargo.toml
./cargo-build-bpf --manifest-path sdk/Cargo.toml
# BPF Program unit tests
"$cargo" test --manifest-path programs/bpf/Cargo.toml
"$cargo_build_bpf" --manifest-path programs/bpf/Cargo.toml --bpf-sdk sdk/bpf
# BPF program system tests
# BPF program tests
_ make -C programs/bpf/c tests
_ "$cargo" stable test \
--manifest-path programs/bpf/Cargo.toml \
--no-default-features --features=bpf_c,bpf_rust -- --nocapture
# Dump BPF program assembly listings
for bpf_test in programs/bpf/rust/*; do
if pushd "$bpf_test"; then
"$cargo_build_bpf" --dump
popd
fi
done
# BPF program instruction count assertion
bpf_target_path=programs/bpf/target
_ "$cargo" stable test \
--manifest-path programs/bpf/Cargo.toml \
--no-default-features --features=bpf_c,bpf_rust assert_instruction_count \
-- --nocapture &> "${bpf_target_path}"/deploy/instuction_counts.txt
bpf_dump_archive="bpf-dumps.tar.bz2"
rm -f "$bpf_dump_archive"
tar cjvf "$bpf_dump_archive" "${bpf_target_path}"/{deploy/*.txt,bpfel-unknown-unknown/release/*.so}
;;
test-stable-perf)
if [[ $(uname) = Linux ]]; then
# Enable persistence mode to keep the CUDA kernel driver loaded, avoiding a
# lengthy and unexpected delay the first time CUDA is involved when the driver
# is not yet loaded.
sudo --non-interactive ./net/scripts/enable-nvidia-persistence-mode.sh || true
sudo --non-interactive ./net/scripts/enable-nvidia-persistence-mode.sh
rm -rf target/perf-libs
./fetch-perf-libs.sh

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-clap-utils"
version = "1.7.8"
version = "1.6.2"
description = "Solana utilities for the clap"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -12,17 +12,13 @@ edition = "2018"
[dependencies]
clap = "2.33.0"
rpassword = "4.0"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
thiserror = "1.0.21"
tiny-bip39 = "0.8.0"
uriparse = "0.6.3"
url = "2.1.0"
chrono = "0.4"
[dev-dependencies]
tempfile = "3.1.0"
[lib]
name = "solana_clap_utils"

View File

@@ -1,7 +1,5 @@
use {
crate::{input_validators, ArgConstant},
clap::Arg,
};
use crate::{input_validators, ArgConstant};
use clap::Arg;
pub const FEE_PAYER_ARG: ArgConstant<'static> = ArgConstant {
name: "fee_payer",

View File

@@ -1,24 +1,19 @@
use {
crate::keypair::{
keypair_from_seed_phrase, pubkey_from_path, resolve_signer_from_path, signer_from_path,
ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
},
chrono::DateTime,
clap::ArgMatches,
solana_remote_wallet::remote_wallet::RemoteWalletManager,
solana_sdk::{
clock::UnixTimestamp,
commitment_config::CommitmentConfig,
genesis_config::ClusterType,
native_token::sol_to_lamports,
pubkey::Pubkey,
signature::{read_keypair_file, Keypair, Signature, Signer},
},
std::{str::FromStr, sync::Arc},
use crate::keypair::{
keypair_from_seed_phrase, pubkey_from_path, resolve_signer_from_path, signer_from_path,
ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
};
// Sentinel value used to indicate to write to screen instead of file
pub const STDOUT_OUTFILE_TOKEN: &str = "-";
use chrono::DateTime;
use clap::ArgMatches;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
clock::UnixTimestamp,
commitment_config::CommitmentConfig,
genesis_config::ClusterType,
native_token::sol_to_lamports,
pubkey::Pubkey,
signature::{read_keypair_file, Keypair, Signature, Signer},
};
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>>
@@ -60,7 +55,7 @@ pub fn keypair_of(matches: &ArgMatches<'_>, name: &str) -> Option<Keypair> {
if let Some(value) = matches.value_of(name) {
if value == ASK_KEYWORD {
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
keypair_from_seed_phrase(name, skip_validation, true, None, true).ok()
keypair_from_seed_phrase(name, skip_validation, true).ok()
} else {
read_keypair_file(value).ok()
}
@@ -75,7 +70,7 @@ pub fn keypairs_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<Keypair>>
.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, None, true).ok()
keypair_from_seed_phrase(name, skip_validation, true).ok()
} else {
read_keypair_file(value).ok()
}

View File

@@ -1,15 +1,13 @@
use {
crate::keypair::{parse_signer_source, SignerSourceKind, ASK_KEYWORD},
chrono::DateTime,
solana_sdk::{
clock::{Epoch, Slot},
hash::Hash,
pubkey::{Pubkey, MAX_SEED_LEN},
signature::{read_keypair_file, Signature},
},
std::fmt::Display,
std::str::FromStr,
use crate::keypair::{parse_keypair_path, KeypairUrl, ASK_KEYWORD};
use chrono::DateTime;
use solana_sdk::{
clock::{Epoch, Slot},
hash::Hash,
pubkey::{Pubkey, MAX_SEED_LEN},
signature::{read_keypair_file, Signature},
};
use std::fmt::Display;
use std::str::FromStr;
fn is_parsable_generic<U, T>(string: T) -> Result<(), String>
where
@@ -34,29 +32,6 @@ where
is_parsable_generic::<T, String>(string)
}
// Return an error if string cannot be parsed as numeric type T, and value not within specified
// range
pub fn is_within_range<T>(string: String, range_min: T, range_max: T) -> Result<(), String>
where
T: FromStr + Copy + std::fmt::Debug + PartialOrd + std::ops::Add<Output = T> + From<usize>,
T::Err: Display,
{
match string.parse::<T>() {
Ok(input) => {
let range = range_min..range_max + 1.into();
if !range.contains(&input) {
Err(format!(
"input '{:?}' out of range ({:?}..{:?}]",
input, range_min, range_max
))
} else {
Ok(())
}
}
Err(err) => Err(format!("error parsing '{}': {}", string, err)),
}
}
// Return an error if a pubkey cannot be parsed.
pub fn is_pubkey<T>(string: T) -> Result<(), String>
where
@@ -96,26 +71,6 @@ where
.map_err(|err| format!("{}", err))
}
// Return an error if a `SignerSourceKind::Prompt` cannot be parsed
pub fn is_prompt_signer_source<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
if string.as_ref() == ASK_KEYWORD {
return Ok(());
}
match parse_signer_source(string.as_ref())
.map_err(|err| format!("{}", err))?
.kind
{
SignerSourceKind::Prompt => Ok(()),
_ => Err(format!(
"Unable to parse input as `prompt:` URI scheme or `ASK` keyword: {}",
string
)),
}
}
// Return an error if string cannot be parsed as pubkey string or keypair file location
pub fn is_pubkey_or_keypair<T>(string: T) -> Result<(), String>
where
@@ -130,11 +85,8 @@ pub fn is_valid_pubkey<T>(string: T) -> Result<(), String>
where
T: AsRef<str> + Display,
{
match parse_signer_source(string.as_ref())
.map_err(|err| format!("{}", err))?
.kind
{
SignerSourceKind::Filepath(path) => is_keypair(path),
match parse_keypair_path(string.as_ref()) {
KeypairUrl::Filepath(path) => is_keypair(path),
_ => Ok(()),
}
}
@@ -215,8 +167,8 @@ where
pub fn normalize_to_url_if_moniker<T: AsRef<str>>(url_or_moniker: T) -> String {
match url_or_moniker.as_ref() {
"m" | "mainnet-beta" => "https://api.mainnet-beta.solana.com",
"t" | "testnet" => "https://api.testnet.solana.com",
"d" | "devnet" => "https://api.devnet.solana.com",
"t" | "testnet" => "https://testnet.solana.com",
"d" | "devnet" => "https://devnet.solana.com",
"l" | "localhost" => "http://localhost:8899",
url => url,
}

View File

@@ -1,39 +1,30 @@
use {
crate::{
input_parsers::{pubkeys_sigs_of, STDOUT_OUTFILE_TOKEN},
offline::{SIGNER_ARG, SIGN_ONLY_ARG},
ArgConstant,
use crate::{
input_parsers::pubkeys_sigs_of,
offline::{SIGNER_ARG, SIGN_ONLY_ARG},
ArgConstant,
};
use bip39::{Language, Mnemonic, Seed};
use clap::ArgMatches;
use rpassword::prompt_password_stderr;
use solana_remote_wallet::{
remote_keypair::generate_remote_keypair,
remote_wallet::{maybe_wallet_manager, RemoteWalletError, RemoteWalletManager},
};
use solana_sdk::{
hash::Hash,
message::Message,
pubkey::Pubkey,
signature::{
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair,
read_keypair_file, Keypair, NullSigner, Presigner, Signature, Signer,
},
bip39::{Language, Mnemonic, Seed},
clap::ArgMatches,
rpassword::prompt_password_stderr,
solana_remote_wallet::{
locator::{Locator as RemoteWalletLocator, LocatorError as RemoteWalletLocatorError},
remote_keypair::generate_remote_keypair,
remote_wallet::{maybe_wallet_manager, RemoteWalletError, RemoteWalletManager},
},
solana_sdk::{
derivation_path::{DerivationPath, DerivationPathError},
hash::Hash,
message::Message,
pubkey::Pubkey,
signature::{
generate_seed_from_seed_phrase_and_passphrase, keypair_from_seed,
keypair_from_seed_and_derivation_path, keypair_from_seed_phrase_and_passphrase,
read_keypair, read_keypair_file, Keypair, NullSigner, Presigner, Signature, Signer,
},
},
std::{
cell::RefCell,
convert::TryFrom,
error,
io::{stdin, stdout, Write},
ops::Deref,
process::exit,
str::FromStr,
sync::Arc,
},
thiserror::Error,
};
use std::{
error,
io::{stdin, stdout, Write},
process::exit,
str::FromStr,
sync::Arc,
};
pub struct SignOnly {
@@ -92,48 +83,12 @@ impl CliSignerInfo {
}
}
#[derive(Debug, Default)]
pub struct DefaultSigner {
pub arg_name: String,
pub path: String,
is_path_checked: RefCell<bool>,
}
impl DefaultSigner {
pub fn new<AN: AsRef<str>, P: AsRef<str>>(arg_name: AN, path: P) -> Self {
let arg_name = arg_name.as_ref().to_string();
let path = path.as_ref().to_string();
Self {
arg_name,
path,
..Self::default()
}
}
fn path(&self) -> Result<&str, Box<dyn std::error::Error>> {
if !self.is_path_checked.borrow().deref() {
parse_signer_source(&self.path)
.and_then(|s| {
if let SignerSourceKind::Filepath(path) = &s.kind {
std::fs::metadata(path).map(|_| ()).map_err(|e| e.into())
} else {
Ok(())
}
})
.map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"No default signer found, run \"solana-keygen new -o {}\" to create a new one",
self.path
),
)
})?;
*self.is_path_checked.borrow_mut() = true;
}
Ok(&self.path)
}
pub fn generate_unique_signers(
&self,
bulk_signers: Vec<Option<Box<dyn Signer>>>,
@@ -148,9 +103,11 @@ impl DefaultSigner {
unique_signers.push(default_signer);
}
for signer in bulk_signers.into_iter().flatten() {
if !unique_signers.iter().any(|s| s == &signer) {
unique_signers.push(signer);
for signer in bulk_signers.into_iter() {
if let Some(signer) = signer {
if !unique_signers.iter().any(|s| s == &signer) {
unique_signers.push(signer);
}
}
}
Ok(CliSignerInfo {
@@ -163,7 +120,7 @@ impl DefaultSigner {
matches: &ArgMatches,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
signer_from_path(matches, self.path()?, &self.arg_name, wallet_manager)
signer_from_path(matches, &self.path, &self.arg_name, wallet_manager)
}
pub fn signer_from_path_with_config(
@@ -172,142 +129,29 @@ impl DefaultSigner {
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
config: &SignerFromPathConfig,
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
signer_from_path_with_config(
matches,
self.path()?,
&self.arg_name,
wallet_manager,
config,
)
signer_from_path_with_config(matches, &self.path, &self.arg_name, wallet_manager, config)
}
}
pub(crate) struct SignerSource {
pub kind: SignerSourceKind,
pub derivation_path: Option<DerivationPath>,
pub legacy: bool,
}
impl SignerSource {
fn new(kind: SignerSourceKind) -> Self {
Self {
kind,
derivation_path: None,
legacy: false,
}
}
fn new_legacy(kind: SignerSourceKind) -> Self {
Self {
kind,
derivation_path: None,
legacy: true,
}
}
}
const SIGNER_SOURCE_PROMPT: &str = "prompt";
const SIGNER_SOURCE_FILEPATH: &str = "file";
const SIGNER_SOURCE_USB: &str = "usb";
const SIGNER_SOURCE_STDIN: &str = "stdin";
const SIGNER_SOURCE_PUBKEY: &str = "pubkey";
pub(crate) enum SignerSourceKind {
Prompt,
pub enum KeypairUrl {
Ask,
Filepath(String),
Usb(RemoteWalletLocator),
Usb(String),
Stdin,
Pubkey(Pubkey),
}
impl AsRef<str> for SignerSourceKind {
fn as_ref(&self) -> &str {
match self {
Self::Prompt => SIGNER_SOURCE_PROMPT,
Self::Filepath(_) => SIGNER_SOURCE_FILEPATH,
Self::Usb(_) => SIGNER_SOURCE_USB,
Self::Stdin => SIGNER_SOURCE_STDIN,
Self::Pubkey(_) => SIGNER_SOURCE_PUBKEY,
}
}
}
impl std::fmt::Debug for SignerSourceKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let s: &str = self.as_ref();
write!(f, "{}", s)
}
}
#[derive(Debug, Error)]
pub(crate) enum SignerSourceError {
#[error("unrecognized signer source")]
UnrecognizedSource,
#[error(transparent)]
RemoteWalletLocatorError(#[from] RemoteWalletLocatorError),
#[error(transparent)]
DerivationPathError(#[from] DerivationPathError),
#[error(transparent)]
IoError(#[from] std::io::Error),
}
pub(crate) fn parse_signer_source<S: AsRef<str>>(
source: S,
) -> Result<SignerSource, SignerSourceError> {
let source = source.as_ref();
let source = {
#[cfg(target_family = "windows")]
{
source.replace("\\", "/")
}
#[cfg(not(target_family = "windows"))]
{
source.to_string()
}
};
match uriparse::URIReference::try_from(source.as_str()) {
Err(_) => Err(SignerSourceError::UnrecognizedSource),
Ok(uri) => {
if let Some(scheme) = uri.scheme() {
let scheme = scheme.as_str().to_ascii_lowercase();
match scheme.as_str() {
SIGNER_SOURCE_PROMPT => Ok(SignerSource {
kind: SignerSourceKind::Prompt,
derivation_path: DerivationPath::from_uri_any_query(&uri)?,
legacy: false,
}),
SIGNER_SOURCE_FILEPATH => Ok(SignerSource::new(SignerSourceKind::Filepath(
uri.path().to_string(),
))),
SIGNER_SOURCE_USB => Ok(SignerSource {
kind: SignerSourceKind::Usb(RemoteWalletLocator::new_from_uri(&uri)?),
derivation_path: DerivationPath::from_uri_key_query(&uri)?,
legacy: false,
}),
SIGNER_SOURCE_STDIN => Ok(SignerSource::new(SignerSourceKind::Stdin)),
_ => {
#[cfg(target_family = "windows")]
// On Windows, an absolute path's drive letter will be parsed as the URI
// scheme. Assume a filepath source in case of a single character shceme.
if scheme.len() == 1 {
return Ok(SignerSource::new(SignerSourceKind::Filepath(source)));
}
Err(SignerSourceError::UnrecognizedSource)
}
}
} else {
match source.as_str() {
STDOUT_OUTFILE_TOKEN => Ok(SignerSource::new(SignerSourceKind::Stdin)),
ASK_KEYWORD => Ok(SignerSource::new_legacy(SignerSourceKind::Prompt)),
_ => match Pubkey::from_str(source.as_str()) {
Ok(pubkey) => Ok(SignerSource::new(SignerSourceKind::Pubkey(pubkey))),
Err(_) => std::fs::metadata(source.as_str())
.map(|_| SignerSource::new(SignerSourceKind::Filepath(source)))
.map_err(|err| err.into()),
},
}
}
}
pub fn parse_keypair_path(path: &str) -> KeypairUrl {
if path == "-" {
KeypairUrl::Stdin
} else if path == ASK_KEYWORD {
KeypairUrl::Ask
} else if path.starts_with("usb://") {
KeypairUrl::Usb(path.to_string())
} else if let Ok(pubkey) = Pubkey::from_str(path) {
KeypairUrl::Pubkey(pubkey)
} else {
KeypairUrl::Filepath(path.to_string())
}
}
@@ -354,23 +198,16 @@ pub fn signer_from_path_with_config(
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
config: &SignerFromPathConfig,
) -> Result<Box<dyn Signer>, Box<dyn error::Error>> {
let SignerSource {
kind,
derivation_path,
legacy,
} = parse_signer_source(path)?;
match kind {
SignerSourceKind::Prompt => {
match parse_keypair_path(path) {
KeypairUrl::Ask => {
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
Ok(Box::new(keypair_from_seed_phrase(
keypair_name,
skip_validation,
false,
derivation_path,
legacy,
)?))
}
SignerSourceKind::Filepath(path) => match 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 read keypair file \"{}\". Run \"solana-keygen new\" to create a keypair file: {}", path, e),
@@ -378,18 +215,17 @@ pub fn signer_from_path_with_config(
.into()),
Ok(file) => Ok(Box::new(file)),
},
SignerSourceKind::Stdin => {
KeypairUrl::Stdin => {
let mut stdin = std::io::stdin();
Ok(Box::new(read_keypair(&mut stdin)?))
}
SignerSourceKind::Usb(locator) => {
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(
locator,
derivation_path.unwrap_or_default(),
path,
wallet_manager,
matches.is_present("confirm_key"),
keypair_name,
@@ -398,7 +234,7 @@ pub fn signer_from_path_with_config(
Err(RemoteWalletError::NoDeviceFound.into())
}
}
SignerSourceKind::Pubkey(pubkey) => {
KeypairUrl::Pubkey(pubkey) => {
let presigner = pubkeys_sigs_of(matches, SIGNER_ARG.name)
.as_ref()
.and_then(|presigners| presigner_from_pubkey_sigs(&pubkey, presigners));
@@ -423,9 +259,8 @@ pub fn pubkey_from_path(
keypair_name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Pubkey, Box<dyn error::Error>> {
let SignerSource { kind, .. } = parse_signer_source(path)?;
match kind {
SignerSourceKind::Pubkey(pubkey) => Ok(pubkey),
match parse_keypair_path(path) {
KeypairUrl::Pubkey(pubkey) => Ok(pubkey),
_ => Ok(signer_from_path(matches, path, keypair_name, wallet_manager)?.pubkey()),
}
}
@@ -436,51 +271,34 @@ pub fn resolve_signer_from_path(
keypair_name: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Option<String>, Box<dyn error::Error>> {
let SignerSource {
kind,
derivation_path,
legacy,
} = parse_signer_source(path)?;
match kind {
SignerSourceKind::Prompt => {
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,
derivation_path,
legacy,
)
.map(|_| None)
keypair_from_seed_phrase(keypair_name, skip_validation, false).map(|_| None)
}
SignerSourceKind::Filepath(path) => match 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 read keypair file \"{}\". \
Run \"solana-keygen new\" to create a keypair file: {}",
path, e
),
format!("could not read keypair file \"{}\". Run \"solana-keygen new\" to create a keypair file: {}", path, e),
)
.into()),
Ok(_) => Ok(Some(path.to_string())),
},
SignerSourceKind::Stdin => {
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)
}
SignerSourceKind::Usb(locator) => {
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(
locator,
derivation_path.unwrap_or_default(),
path,
wallet_manager,
matches.is_present("confirm_key"),
keypair_name,
@@ -495,7 +313,7 @@ pub fn resolve_signer_from_path(
}
}
// Keyword used to indicate that the user should be prompted for a keypair seed phrase
// Keyword used to indicate that the user should be asked for a keypair seed phrase
pub const ASK_KEYWORD: &str = "ASK";
pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
@@ -506,7 +324,7 @@ pub const SKIP_SEED_PHRASE_VALIDATION_ARG: ArgConstant<'static> = ArgConstant {
/// Prompts user for a passphrase and then asks for confirmirmation to check for mistakes
pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>> {
let passphrase = prompt_password_stderr(prompt)?;
let passphrase = prompt_password_stderr(&prompt)?;
if !passphrase.is_empty() {
let confirmed = rpassword::prompt_password_stderr("Enter same passphrase again: ")?;
if confirmed != passphrase {
@@ -516,56 +334,6 @@ pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>>
Ok(passphrase)
}
/// Parses a path into a SignerSource and returns a Keypair for supporting SignerSourceKinds
pub fn keypair_from_path(
matches: &ArgMatches,
path: &str,
keypair_name: &str,
confirm_pubkey: bool,
) -> Result<Keypair, Box<dyn error::Error>> {
let SignerSource {
kind,
derivation_path,
legacy,
} = parse_signer_source(path)?;
match kind {
SignerSourceKind::Prompt => {
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
Ok(keypair_from_seed_phrase(
keypair_name,
skip_validation,
confirm_pubkey,
derivation_path,
legacy,
)?)
}
SignerSourceKind::Filepath(path) => match read_keypair_file(&path) {
Err(e) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"could not read keypair file \"{}\". \
Run \"solana-keygen new\" to create a keypair file: {}",
path, e
),
)
.into()),
Ok(file) => Ok(file),
},
SignerSourceKind::Stdin => {
let mut stdin = std::io::stdin();
Ok(read_keypair(&mut stdin)?)
}
_ => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"signer of type `{:?}` does not support Keypair output",
kind
),
)
.into()),
}
}
/// Reads user input from stdin to retrieve a seed phrase and passphrase for keypair derivation
/// Optionally skips validation of seed phrase
/// Optionally confirms recovered public key
@@ -573,8 +341,6 @@ pub fn keypair_from_seed_phrase(
keypair_name: &str,
skip_validation: bool,
confirm_pubkey: bool,
derivation_path: Option<DerivationPath>,
legacy: bool,
) -> Result<Keypair, Box<dyn error::Error>> {
let seed_phrase = prompt_password_stderr(&format!("[{}] seed phrase: ", keypair_name))?;
let seed_phrase = seed_phrase.trim();
@@ -585,12 +351,7 @@ pub fn keypair_from_seed_phrase(
let keypair = if skip_validation {
let passphrase = prompt_passphrase(&passphrase_prompt)?;
if legacy {
keypair_from_seed_phrase_and_passphrase(seed_phrase, &passphrase)?
} else {
let seed = generate_seed_from_seed_phrase_and_passphrase(seed_phrase, &passphrase);
keypair_from_seed_and_derivation_path(&seed, derivation_path)?
}
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)?
} else {
let sanitized = sanitize_seed_phrase(seed_phrase);
let parse_language_fn = || {
@@ -613,11 +374,7 @@ pub fn keypair_from_seed_phrase(
let mnemonic = parse_language_fn()?;
let passphrase = prompt_passphrase(&passphrase_prompt)?;
let seed = Seed::new(&mnemonic, &passphrase);
if legacy {
keypair_from_seed(seed.as_bytes())?
} else {
keypair_from_seed_and_derivation_path(seed.as_bytes(), derivation_path)?
}
keypair_from_seed(seed.as_bytes())?
};
if confirm_pubkey {
@@ -645,9 +402,7 @@ fn sanitize_seed_phrase(seed_phrase: &str) -> String {
#[cfg(test)]
mod tests {
use super::*;
use solana_remote_wallet::locator::Manufacturer;
use solana_sdk::system_instruction;
use tempfile::NamedTempFile;
#[test]
fn test_sanitize_seed_phrase() {
@@ -688,122 +443,4 @@ mod tests {
];
assert_eq!(signer_pubkeys, expect);
}
#[test]
fn test_parse_signer_source() {
assert!(matches!(
parse_signer_source(STDOUT_OUTFILE_TOKEN).unwrap(),
SignerSource {
kind: SignerSourceKind::Stdin,
derivation_path: None,
legacy: false,
}
));
let stdin = "stdin:".to_string();
assert!(matches!(
parse_signer_source(&stdin).unwrap(),
SignerSource {
kind: SignerSourceKind::Stdin,
derivation_path: None,
legacy: false,
}
));
assert!(matches!(
parse_signer_source(ASK_KEYWORD).unwrap(),
SignerSource {
kind: SignerSourceKind::Prompt,
derivation_path: None,
legacy: true,
}
));
let pubkey = Pubkey::new_unique();
assert!(
matches!(parse_signer_source(&pubkey.to_string()).unwrap(), SignerSource {
kind: SignerSourceKind::Pubkey(p),
derivation_path: None,
legacy: false,
}
if p == pubkey)
);
// Set up absolute and relative path strs
let file0 = NamedTempFile::new().unwrap();
let path = file0.path();
assert!(path.is_absolute());
let absolute_path_str = path.to_str().unwrap();
let file1 = NamedTempFile::new_in(std::env::current_dir().unwrap()).unwrap();
let path = file1.path().file_name().unwrap().to_str().unwrap();
let path = std::path::Path::new(path);
assert!(path.is_relative());
let relative_path_str = path.to_str().unwrap();
assert!(
matches!(parse_signer_source(absolute_path_str).unwrap(), SignerSource {
kind: SignerSourceKind::Filepath(p),
derivation_path: None,
legacy: false,
} if p == absolute_path_str)
);
assert!(
matches!(parse_signer_source(&relative_path_str).unwrap(), SignerSource {
kind: SignerSourceKind::Filepath(p),
derivation_path: None,
legacy: false,
} if p == relative_path_str)
);
let usb = "usb://ledger".to_string();
let expected_locator = RemoteWalletLocator {
manufacturer: Manufacturer::Ledger,
pubkey: None,
};
assert!(matches!(parse_signer_source(&usb).unwrap(), SignerSource {
kind: SignerSourceKind::Usb(u),
derivation_path: None,
legacy: false,
} if u == expected_locator));
let usb = "usb://ledger?key=0/0".to_string();
let expected_locator = RemoteWalletLocator {
manufacturer: Manufacturer::Ledger,
pubkey: None,
};
let expected_derivation_path = Some(DerivationPath::new_bip44(Some(0), Some(0)));
assert!(matches!(parse_signer_source(&usb).unwrap(), SignerSource {
kind: SignerSourceKind::Usb(u),
derivation_path: d,
legacy: false,
} if u == expected_locator && d == expected_derivation_path));
// Catchall into SignerSource::Filepath fails
let junk = "sometextthatisnotapubkeyorfile".to_string();
assert!(Pubkey::from_str(&junk).is_err());
assert!(matches!(
parse_signer_source(&junk),
Err(SignerSourceError::IoError(_))
));
let prompt = "prompt:".to_string();
assert!(matches!(
parse_signer_source(&prompt).unwrap(),
SignerSource {
kind: SignerSourceKind::Prompt,
derivation_path: None,
legacy: false,
}
));
assert!(
matches!(parse_signer_source(&format!("file:{}", absolute_path_str)).unwrap(), SignerSource {
kind: SignerSourceKind::Filepath(p),
derivation_path: None,
legacy: false,
} if p == absolute_path_str)
);
assert!(
matches!(parse_signer_source(&format!("file:{}", relative_path_str)).unwrap(), SignerSource {
kind: SignerSourceKind::Filepath(p),
derivation_path: None,
legacy: false,
} if p == relative_path_str)
);
}
}

View File

@@ -27,6 +27,5 @@ pub mod fee_payer;
pub mod input_parsers;
pub mod input_validators;
pub mod keypair;
pub mod memo;
pub mod nonce;
pub mod offline;

View File

@@ -1,15 +0,0 @@
use {crate::ArgConstant, clap::Arg};
pub const MEMO_ARG: ArgConstant<'static> = ArgConstant {
name: "memo",
long: "--with-memo",
help: "Specify a memo string to include in the transaction.",
};
pub fn memo_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(MEMO_ARG.name)
.long(MEMO_ARG.long)
.takes_value(true)
.value_name("MEMO")
.help(MEMO_ARG.help)
}

View File

@@ -1,7 +1,5 @@
use {
crate::{input_validators::*, offline::BLOCKHASH_ARG, ArgConstant},
clap::{App, Arg},
};
use crate::{input_validators::*, offline::BLOCKHASH_ARG, ArgConstant};
use clap::{App, Arg};
pub const NONCE_ARG: ArgConstant<'static> = ArgConstant {
name: "nonce",

View File

@@ -1,7 +1,5 @@
use {
crate::{input_validators::*, ArgConstant},
clap::{App, Arg},
};
use crate::{input_validators::*, ArgConstant};
use clap::{App, Arg};
pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant {
name: "blockhash",

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli-config"
description = "Blockchain, Rebuilt for Scale"
version = "1.7.8"
version = "1.6.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"

View File

@@ -107,24 +107,24 @@ mod test {
#[test]
fn compute_websocket_url() {
assert_eq!(
Config::compute_websocket_url("http://api.devnet.solana.com"),
"ws://api.devnet.solana.com/".to_string()
Config::compute_websocket_url(&"http://devnet.solana.com"),
"ws://devnet.solana.com/".to_string()
);
assert_eq!(
Config::compute_websocket_url("https://api.devnet.solana.com"),
"wss://api.devnet.solana.com/".to_string()
Config::compute_websocket_url(&"https://devnet.solana.com"),
"wss://devnet.solana.com/".to_string()
);
assert_eq!(
Config::compute_websocket_url("http://example.com:8899"),
Config::compute_websocket_url(&"http://example.com:8899"),
"ws://example.com:8900/".to_string()
);
assert_eq!(
Config::compute_websocket_url("https://example.com:1234"),
Config::compute_websocket_url(&"https://example.com:1234"),
"wss://example.com:1235/".to_string()
);
assert_eq!(Config::compute_websocket_url("garbage"), String::new());
assert_eq!(Config::compute_websocket_url(&"garbage"), String::new());
}
}

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli-output"
description = "Blockchain, Rebuilt for Scale"
version = "1.7.8"
version = "1.6.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -12,20 +12,20 @@ documentation = "https://docs.rs/solana-cli-output"
[dependencies]
base64 = "0.13.0"
chrono = { version = "0.4.11", features = ["serde"] }
console = "0.14.1"
console = "0.11.3"
humantime = "2.0.1"
Inflector = "0.11.4"
indicatif = "0.15.0"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.8" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.8" }
solana-client = { path = "../client", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.8" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.8" }
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
solana-account-decoder = { path = "../account-decoder", version = "=1.6.2" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.2" }
solana-client = { path = "../client", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.6.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.6.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.2" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -15,8 +15,8 @@ use {
solana_account_decoder::parse_token::UiTokenAccount,
solana_clap_utils::keypair::SignOnly,
solana_client::rpc_response::{
RpcAccountBalance, RpcContactInfo, RpcInflationGovernor, RpcInflationRate, RpcKeyedAccount,
RpcSupply, RpcVoteAccountInfo,
RpcAccountBalance, RpcInflationGovernor, RpcInflationRate, RpcKeyedAccount, RpcSupply,
RpcVoteAccountInfo,
},
solana_sdk::{
clock::{Epoch, Slot, UnixTimestamp},
@@ -25,10 +25,10 @@ use {
native_token::lamports_to_sol,
pubkey::Pubkey,
signature::Signature,
stake::state::{Authorized, Lockup},
stake_history::StakeHistoryEntry,
transaction::{Transaction, TransactionError},
},
solana_stake_program::stake_state::{Authorized, Lockup},
solana_transaction_status::{
EncodedConfirmedBlock, EncodedTransaction, TransactionConfirmationStatus,
UiTransactionStatusMeta,
@@ -233,10 +233,6 @@ pub struct CliEpochInfo {
pub epoch_info: EpochInfo,
#[serde(skip)]
pub average_slot_time_ms: u64,
#[serde(skip)]
pub start_block_time: Option<UnixTimestamp>,
#[serde(skip)]
pub current_block_time: Option<UnixTimestamp>,
}
impl QuietDisplay for CliEpochInfo {}
@@ -281,41 +277,21 @@ impl fmt::Display for CliEpochInfo {
remaining_slots_in_epoch
),
)?;
let (time_elapsed, annotation) = if let (Some(start_block_time), Some(current_block_time)) =
(self.start_block_time, self.current_block_time)
{
(
Duration::from_secs((current_block_time - start_block_time) as u64),
None,
)
} else {
(
slot_to_duration(self.epoch_info.slot_index, self.average_slot_time_ms),
Some("* estimated based on current slot durations"),
)
};
let time_remaining = slot_to_duration(remaining_slots_in_epoch, self.average_slot_time_ms);
writeln_name_value(
f,
"Epoch Completed Time:",
&format!(
"{}{}/{} ({} remaining)",
humantime::format_duration(time_elapsed).to_string(),
if annotation.is_some() { "*" } else { "" },
humantime::format_duration(time_elapsed + time_remaining).to_string(),
humantime::format_duration(time_remaining).to_string(),
"{}/{} ({} remaining)",
slot_to_human_time(self.epoch_info.slot_index, self.average_slot_time_ms),
slot_to_human_time(self.epoch_info.slots_in_epoch, self.average_slot_time_ms),
slot_to_human_time(remaining_slots_in_epoch, self.average_slot_time_ms)
),
)?;
if let Some(annotation) = annotation {
writeln!(f)?;
writeln!(f, "{}", annotation)?;
}
Ok(())
)
}
}
fn slot_to_duration(slot: Slot, slot_time_ms: u64) -> Duration {
Duration::from_secs((slot * slot_time_ms) / 1000)
fn slot_to_human_time(slot: Slot, slot_time_ms: u64) -> String {
humantime::format_duration(Duration::from_secs((slot * slot_time_ms) / 1000)).to_string()
}
#[derive(Serialize, Deserialize, Default)]
@@ -327,34 +303,14 @@ pub struct CliValidatorsStakeByVersion {
pub delinquent_active_stake: u64,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
pub enum CliValidatorsSortOrder {
Delinquent,
Commission,
EpochCredits,
Identity,
LastVote,
Root,
SkipRate,
Stake,
VoteAccount,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliValidators {
pub total_active_stake: u64,
pub total_current_stake: u64,
pub total_delinquent_stake: u64,
pub validators: Vec<CliValidator>,
pub average_skip_rate: f64,
pub average_stake_weighted_skip_rate: f64,
#[serde(skip_serializing)]
pub validators_sort_order: CliValidatorsSortOrder,
#[serde(skip_serializing)]
pub validators_reverse_sort: bool,
#[serde(skip_serializing)]
pub number_validators: bool,
pub current_validators: Vec<CliValidator>,
pub delinquent_validators: Vec<CliValidator>,
pub stake_by_version: BTreeMap<String, CliValidatorsStakeByVersion>,
#[serde(skip_serializing)]
pub use_lamports_unit: bool,
@@ -370,40 +326,30 @@ impl fmt::Display for CliValidators {
validator: &CliValidator,
total_active_stake: u64,
use_lamports_unit: bool,
highest_last_vote: u64,
highest_root: u64,
delinquent: bool,
) -> fmt::Result {
fn non_zero_or_dash(v: u64, max_v: u64) -> String {
fn non_zero_or_dash(v: u64) -> String {
if v == 0 {
"- ".into()
} else if v == max_v {
format!("{:>8} ( 0)", v)
} else if v > max_v.saturating_sub(100) {
format!("{:>8} ({:>3})", v, -(max_v.saturating_sub(v) as isize))
"-".into()
} else {
format!("{:>8} ", v)
format!("{}", v)
}
}
writeln!(
f,
"{} {:<44} {:<44} {:>3}% {:>14} {:>14} {:>7} {:>8} {:>7} {}",
if validator.delinquent {
"{} {:<44} {:<44} {:>3}% {:>8} {:>10} {:>10} {:>8} {}",
if delinquent {
WARNING.to_string()
} else {
"\u{a0}".to_string()
" ".to_string()
},
validator.identity_pubkey,
validator.vote_account_pubkey,
validator.commission,
non_zero_or_dash(validator.last_vote, highest_last_vote),
non_zero_or_dash(validator.root_slot, highest_root),
if let Some(skip_rate) = validator.skip_rate {
format!("{:.2}%", skip_rate)
} else {
"- ".to_string()
},
validator.epoch_credits,
non_zero_or_dash(validator.last_vote),
non_zero_or_dash(validator.root_slot),
validator.credits,
validator.version,
if validator.activated_stake > 0 {
format!(
@@ -416,114 +362,41 @@ impl fmt::Display for CliValidators {
},
)
}
let padding = if self.number_validators {
((self.validators.len() + 1) as f64).log10().floor() as usize + 1
} else {
0
};
let header = style(format!(
"{:padding$} {:<44} {:<38} {} {} {} {} {} {} {}",
" ",
"Identity",
"Vote Account",
"Commission",
"Last Vote ",
"Root Slot ",
"Skip Rate",
"Credits",
"Version",
"Active Stake",
padding = padding + 1
))
.bold();
writeln!(f, "{}", header)?;
let mut sorted_validators = self.validators.clone();
match self.validators_sort_order {
CliValidatorsSortOrder::Delinquent => {
sorted_validators.sort_by_key(|a| a.delinquent);
}
CliValidatorsSortOrder::Commission => {
sorted_validators.sort_by_key(|a| a.commission);
}
CliValidatorsSortOrder::EpochCredits => {
sorted_validators.sort_by_key(|a| a.epoch_credits);
}
CliValidatorsSortOrder::Identity => {
sorted_validators.sort_by(|a, b| a.identity_pubkey.cmp(&b.identity_pubkey));
}
CliValidatorsSortOrder::LastVote => {
sorted_validators.sort_by_key(|a| a.last_vote);
}
CliValidatorsSortOrder::Root => {
sorted_validators.sort_by_key(|a| a.root_slot);
}
CliValidatorsSortOrder::VoteAccount => {
sorted_validators.sort_by(|a, b| a.vote_account_pubkey.cmp(&b.vote_account_pubkey));
}
CliValidatorsSortOrder::SkipRate => {
sorted_validators.sort_by(|a, b| {
use std::cmp::Ordering;
match (a.skip_rate, b.skip_rate) {
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Greater,
(Some(_), None) => Ordering::Less,
(Some(a), Some(b)) => a.partial_cmp(&b).unwrap_or(Ordering::Equal),
}
});
}
CliValidatorsSortOrder::Stake => {
sorted_validators.sort_by_key(|a| a.activated_stake);
}
}
if self.validators_reverse_sort {
sorted_validators.reverse();
}
let highest_root = sorted_validators
.iter()
.map(|v| v.root_slot)
.max()
.unwrap_or_default();
let highest_last_vote = sorted_validators
.iter()
.map(|v| v.last_vote)
.max()
.unwrap_or_default();
for (i, validator) in sorted_validators.iter().enumerate() {
if padding > 0 {
write!(f, "{:padding$}", i + 1, padding = padding)?;
}
writeln!(
f,
"{}",
style(format!(
" {:<44} {:<38} {} {} {} {:>10} {:^8} {}",
"Identity",
"Vote Account",
"Commission",
"Last Vote",
"Root Block",
"Credits",
"Version",
"Active Stake",
))
.bold()
)?;
for validator in &self.current_validators {
write_vote_account(
f,
validator,
self.total_active_stake,
self.use_lamports_unit,
highest_last_vote,
highest_root,
false,
)?;
}
// The actual header has long scrolled away. Print the header once more as a footer
if self.validators.len() > 100 {
writeln!(f, "{}", header)?;
for validator in &self.delinquent_validators {
write_vote_account(
f,
validator,
self.total_active_stake,
self.use_lamports_unit,
true,
)?;
}
writeln!(f)?;
writeln_name_value(
f,
"Average Stake-Weighted Skip Rate:",
&format!("{:.2}%", self.average_stake_weighted_skip_rate,),
)?;
writeln_name_value(
f,
"Average Unweighted Skip Rate: ",
&format!("{:.2}%", self.average_skip_rate),
)?;
writeln!(f)?;
writeln_name_value(
f,
@@ -580,7 +453,7 @@ impl fmt::Display for CliValidators {
}
}
#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliValidator {
pub identity_pubkey: String,
@@ -588,12 +461,9 @@ pub struct CliValidator {
pub commission: u8,
pub last_vote: u64,
pub root_slot: u64,
pub credits: u64, // lifetime credits
pub epoch_credits: u64, // credits earned in the current epoch
pub credits: u64,
pub activated_stake: u64,
pub version: String,
pub delinquent: bool,
pub skip_rate: Option<f64>,
}
impl CliValidator {
@@ -601,67 +471,27 @@ impl CliValidator {
vote_account: &RpcVoteAccountInfo,
current_epoch: Epoch,
version: String,
skip_rate: Option<f64>,
address_labels: &HashMap<String, String>,
) -> Self {
Self::_new(
vote_account,
current_epoch,
version,
skip_rate,
address_labels,
false,
)
}
pub fn new_delinquent(
vote_account: &RpcVoteAccountInfo,
current_epoch: Epoch,
version: String,
skip_rate: Option<f64>,
address_labels: &HashMap<String, String>,
) -> Self {
Self::_new(
vote_account,
current_epoch,
version,
skip_rate,
address_labels,
true,
)
}
fn _new(
vote_account: &RpcVoteAccountInfo,
current_epoch: Epoch,
version: String,
skip_rate: Option<f64>,
address_labels: &HashMap<String, String>,
delinquent: bool,
) -> Self {
let (credits, epoch_credits) = vote_account
.epoch_credits
.iter()
.find_map(|(epoch, credits, pre_credits)| {
if *epoch == current_epoch {
Some((*credits, credits.saturating_sub(*pre_credits)))
} else {
None
}
})
.unwrap_or((0, 0));
Self {
identity_pubkey: format_labeled_address(&vote_account.node_pubkey, address_labels),
vote_account_pubkey: format_labeled_address(&vote_account.vote_pubkey, address_labels),
commission: vote_account.commission,
last_vote: vote_account.last_vote,
root_slot: vote_account.root_slot,
credits,
epoch_credits,
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,
version,
delinquent,
skip_rate,
}
}
}
@@ -771,81 +601,6 @@ pub struct CliEpochReward {
pub post_balance: u64, // lamports
pub percent_change: f64,
pub apr: Option<f64>,
pub commission: Option<u8>,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliKeyedEpochReward {
pub address: String,
pub reward: Option<CliEpochReward>,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliEpochRewardshMetadata {
pub epoch: Epoch,
pub effective_slot: Slot,
pub block_time: UnixTimestamp,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliKeyedEpochRewards {
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub epoch_metadata: Option<CliEpochRewardshMetadata>,
pub rewards: Vec<CliKeyedEpochReward>,
}
impl QuietDisplay for CliKeyedEpochRewards {}
impl VerboseDisplay for CliKeyedEpochRewards {}
impl fmt::Display for CliKeyedEpochRewards {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.rewards.is_empty() {
writeln!(f, "No rewards found in epoch")?;
return Ok(());
}
if let Some(metadata) = &self.epoch_metadata {
writeln!(f, "Epoch: {}", metadata.epoch)?;
writeln!(f, "Reward Slot: {}", metadata.effective_slot)?;
let timestamp = metadata.block_time;
writeln!(f, "Block Time: {}", unix_timestamp_to_string(timestamp))?;
}
writeln!(f, "Epoch Rewards:")?;
writeln!(
f,
" {:<44} {:<18} {:<18} {:>14} {:>14} {:>10}",
"Address", "Amount", "New Balance", "Percent Change", "APR", "Commission"
)?;
for keyed_reward in &self.rewards {
match &keyed_reward.reward {
Some(reward) => {
writeln!(
f,
" {:<44} ◎{:<17.9} ◎{:<17.9} {:>13.9}% {:>14} {:>10}",
keyed_reward.address,
lamports_to_sol(reward.amount),
lamports_to_sol(reward.post_balance),
reward.percent_change,
reward
.apr
.map(|apr| format!("{:.2}%", apr))
.unwrap_or_default(),
reward
.commission
.map(|commission| format!("{}%", commission))
.unwrap_or_else(|| "-".to_string())
)?;
}
None => {
writeln!(f, " {:<44} No rewards in epoch", keyed_reward.address,)?;
}
}
}
Ok(())
}
}
fn show_votes_and_credits(
@@ -953,13 +708,13 @@ fn show_epoch_rewards(
writeln!(f, "Epoch Rewards:")?;
writeln!(
f,
" {:<6} {:<11} {:<18} {:<18} {:>14} {:>14} {:>10}",
"Epoch", "Reward Slot", "Amount", "New Balance", "Percent Change", "APR", "Commission"
" {:<6} {:<11} {:<16} {:<16} {:>14} {:>14}",
"Epoch", "Reward Slot", "Amount", "New Balance", "Percent Change", "APR"
)?;
for reward in epoch_rewards {
writeln!(
f,
" {:<6} {:<11} ◎{:<17.9} ◎{:<17.9} {:>13.9}% {:>14} {:>10}",
" {:<6} {:<11} ◎{:<16.9} ◎{:<14.9} {:>13.2}% {}",
reward.epoch,
reward.effective_slot,
lamports_to_sol(reward.amount),
@@ -967,12 +722,8 @@ fn show_epoch_rewards(
reward.percent_change,
reward
.apr
.map(|apr| format!("{:.2}%", apr))
.map(|apr| format!("{:>13.2}%", apr))
.unwrap_or_default(),
reward
.commission
.map(|commission| format!("{}%", commission))
.unwrap_or_else(|| "-".to_string())
)?;
}
}
@@ -1334,7 +1085,7 @@ impl fmt::Display for CliValidatorInfo {
writeln_name_value(
f,
&format!(" {}:", to_title_case(key)),
value.as_str().unwrap_or("?"),
&value.as_str().unwrap_or("?"),
)?;
}
Ok(())
@@ -1372,8 +1123,8 @@ impl fmt::Display for CliVoteAccount {
build_balance_message(self.account_balance, self.use_lamports_unit, true)
)?;
writeln!(f, "Validator Identity: {}", self.validator_identity)?;
writeln!(f, "Vote Authority: {}", self.authorized_voters)?;
writeln!(f, "Withdraw Authority: {}", self.authorized_withdrawer)?;
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!(
@@ -1508,18 +1259,18 @@ impl fmt::Display for CliInflation {
if (self.governor.initial - self.governor.terminal).abs() < f64::EPSILON {
writeln!(
f,
"Fixed rate: {:>5.2}%",
"Fixed APR: {:>5.2}%",
self.governor.terminal * 100.
)?;
} else {
writeln!(
f,
"Initial rate: {:>5.2}%",
"Initial APR: {:>5.2}%",
self.governor.initial * 100.
)?;
writeln!(
f,
"Terminal rate: {:>5.2}%",
"Terminal APR: {:>5.2}%",
self.governor.terminal * 100.
)?;
writeln!(
@@ -1527,10 +1278,6 @@ impl fmt::Display for CliInflation {
"Rate reduction per year: {:>5.2}%",
self.governor.taper * 100.
)?;
writeln!(
f,
"* Rate reduction is derived using the target slot time in genesis config"
)?;
}
if self.governor.foundation_term > 0. {
writeln!(
@@ -1552,23 +1299,19 @@ impl fmt::Display for CliInflation {
)?;
writeln!(
f,
"Total rate: {:>5.2}%",
"Total APR: {:>5.2}%",
self.current_rate.total * 100.
)?;
writeln!(
f,
"Staking rate: {:>5.2}%",
"Staking APR: {:>5.2}%",
self.current_rate.validator * 100.
)?;
if self.current_rate.foundation > 0. {
writeln!(
f,
"Foundation rate: {:>5.2}%",
self.current_rate.foundation * 100.
)?;
}
Ok(())
writeln!(
f,
"Foundation APR: {:>5.2}%",
self.current_rate.foundation * 100.
)
}
}
@@ -1720,7 +1463,6 @@ pub struct CliFeesInner {
pub blockhash: String,
pub lamports_per_signature: u64,
pub last_valid_slot: Option<Slot>,
pub last_valid_block_height: Option<Slot>,
}
impl QuietDisplay for CliFeesInner {}
@@ -1734,11 +1476,11 @@ impl fmt::Display for CliFeesInner {
"Lamports per signature:",
&self.lamports_per_signature.to_string(),
)?;
let last_valid_block_height = self
.last_valid_block_height
let last_valid_slot = self
.last_valid_slot
.map(|s| s.to_string())
.unwrap_or_default();
writeln_name_value(f, "Last valid block height:", &last_valid_block_height)
writeln_name_value(f, "Last valid slot:", &last_valid_slot)
}
}
@@ -1767,7 +1509,6 @@ impl CliFees {
blockhash: Hash,
lamports_per_signature: u64,
last_valid_slot: Option<Slot>,
last_valid_block_height: Option<Slot>,
) -> Self {
Self {
inner: Some(CliFeesInner {
@@ -1775,7 +1516,6 @@ impl CliFees {
blockhash: blockhash.to_string(),
lamports_per_signature,
last_valid_slot,
last_valid_block_height,
}),
}
}
@@ -1822,7 +1562,7 @@ impl fmt::Display for CliTokenAccount {
writeln_name_value(
f,
"Close authority:",
account.close_authority.as_ref().unwrap_or(&String::new()),
&account.close_authority.as_ref().unwrap_or(&String::new()),
)?;
Ok(())
}
@@ -2060,7 +1800,7 @@ pub fn return_signers_with_config(
}
pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
let object: Value = serde_json::from_str(reply).unwrap();
let object: Value = serde_json::from_str(&reply).unwrap();
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
let blockhash = blockhash_str.parse::<Hash>().unwrap();
let mut present_signers: Vec<(Pubkey, Signature)> = Vec::new();
@@ -2180,9 +1920,6 @@ impl fmt::Display for CliBlock {
if let Some(block_time) = self.encoded_confirmed_block.block_time {
writeln!(f, "Block Time: {:?}", Local.timestamp(block_time, 0))?;
}
if let Some(block_height) = self.encoded_confirmed_block.block_height {
writeln!(f, "Block Height: {:?}", block_height)?;
}
if !self.encoded_confirmed_block.rewards.is_empty() {
let mut rewards = self.encoded_confirmed_block.rewards.clone();
rewards.sort_by(|a, b| a.pubkey.cmp(&b.pubkey));
@@ -2190,8 +1927,8 @@ impl fmt::Display for CliBlock {
writeln!(f, "Rewards:")?;
writeln!(
f,
" {:<44} {:^15} {:<15} {:<20} {:>14} {:>10}",
"Address", "Type", "Amount", "New Balance", "Percent Change", "Commission"
" {:<44} {:^15} {:<15} {:<20} {:>14}",
"Address", "Type", "Amount", "New Balance", "Percent Change"
)?;
for reward in rewards {
let sign = if reward.lamports < 0 { "-" } else { "" };
@@ -2199,7 +1936,7 @@ impl fmt::Display for CliBlock {
total_rewards += reward.lamports;
writeln!(
f,
" {:<44} {:^15} {:>15} {} {}",
" {:<44} {:^15} {:>15} {}",
reward.pubkey,
if let Some(reward_type) = reward.reward_type {
format!("{}", reward_type)
@@ -2221,11 +1958,7 @@ impl fmt::Display for CliBlock {
/ (reward.post_balance as f64 - reward.lamports as f64))
* 100.0
)
},
reward
.commission
.map(|commission| format!("{:>9}%", commission))
.unwrap_or_else(|| " -".to_string())
}
)?;
}
@@ -2344,97 +2077,6 @@ impl fmt::Display for CliTransactionConfirmation {
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliGossipNode {
#[serde(skip_serializing_if = "Option::is_none")]
pub ip_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub identity_label: Option<String>,
pub identity_pubkey: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub gossip_port: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tpu_port: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rpc_host: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
}
impl CliGossipNode {
pub fn new(info: RpcContactInfo, labels: &HashMap<String, String>) -> Self {
Self {
ip_address: info.gossip.map(|addr| addr.ip().to_string()),
identity_label: labels.get(&info.pubkey).cloned(),
identity_pubkey: info.pubkey,
gossip_port: info.gossip.map(|addr| addr.port()),
tpu_port: info.tpu.map(|addr| addr.port()),
rpc_host: info.rpc.map(|addr| addr.to_string()),
version: info.version,
}
}
}
fn unwrap_to_string_or_none<T>(option: Option<T>) -> String
where
T: std::string::ToString,
{
unwrap_to_string_or_default(option, "none")
}
fn unwrap_to_string_or_default<T>(option: Option<T>, default: &str) -> String
where
T: std::string::ToString,
{
option
.as_ref()
.map(|v| v.to_string())
.unwrap_or_else(|| default.to_string())
}
impl fmt::Display for CliGossipNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:15} | {:44} | {:6} | {:5} | {:21} | {}",
unwrap_to_string_or_none(self.ip_address.as_ref()),
self.identity_label
.as_ref()
.unwrap_or(&self.identity_pubkey),
unwrap_to_string_or_none(self.gossip_port.as_ref()),
unwrap_to_string_or_none(self.tpu_port.as_ref()),
unwrap_to_string_or_none(self.rpc_host.as_ref()),
unwrap_to_string_or_default(self.version.as_ref(), "unknown"),
)
}
}
impl QuietDisplay for CliGossipNode {}
impl VerboseDisplay for CliGossipNode {}
#[derive(Serialize, Deserialize)]
pub struct CliGossipNodes(pub Vec<CliGossipNode>);
impl fmt::Display for CliGossipNodes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"IP Address | Node identifier \
| Gossip | TPU | RPC Address | Version\n\
----------------+----------------------------------------------+\
--------+-------+-----------------------+----------------",
)?;
for node in self.0.iter() {
writeln!(f, "{}", node)?;
}
writeln!(f, "Nodes: {}", self.0.len())
}
}
impl QuietDisplay for CliGossipNodes {}
impl VerboseDisplay for CliGossipNodes {}
#[cfg(test)]
mod tests {
use super::*;
@@ -2466,10 +2108,6 @@ mod tests {
fn try_sign_message(&self, _message: &[u8]) -> Result<Signature, SignerError> {
Ok(Signature::new(&[1u8; 64]))
}
fn is_interactive(&self) -> bool {
false
}
}
let present: Box<dyn Signer> = Box::new(keypair_from_seed(&[2u8; 32]).unwrap());

View File

@@ -5,11 +5,9 @@ use {
indicatif::{ProgressBar, ProgressStyle},
solana_sdk::{
clock::UnixTimestamp, hash::Hash, message::Message, native_token::lamports_to_sol,
program_utils::limited_deserialize, pubkey::Pubkey, stake, transaction::Transaction,
program_utils::limited_deserialize, transaction::Transaction,
},
solana_transaction_status::UiTransactionStatusMeta,
spl_memo::id as spl_memo_id,
spl_memo::v1::id as spl_memo_v1_id,
std::{collections::HashMap, fmt, io},
};
@@ -30,11 +28,6 @@ impl Default for BuildBalanceMessageConfig {
}
}
fn is_memo_program(k: &Pubkey) -> bool {
let k_str = k.to_string();
(k_str == spl_memo_v1_id().to_string()) || (k_str == spl_memo_id().to_string())
}
pub fn build_balance_message_with_config(
lamports: u64,
config: &BuildBalanceMessageConfig,
@@ -244,9 +237,10 @@ pub fn write_transaction<W: io::Write>(
writeln!(w, "{} {:?}", prefix, vote_instruction)?;
raw = false;
}
} else if program_pubkey == stake::program::id() {
if let Ok(stake_instruction) =
limited_deserialize::<stake::instruction::StakeInstruction>(&instruction.data)
} 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;
@@ -259,11 +253,6 @@ pub fn write_transaction<W: io::Write>(
writeln!(w, "{} {:?}", prefix, system_instruction)?;
raw = false;
}
} else if is_memo_program(&program_pubkey) {
if let Ok(s) = std::str::from_utf8(&instruction.data) {
writeln!(w, "{} Data: \"{}\"", prefix, s)?;
raw = false;
}
}
if raw {
@@ -321,38 +310,7 @@ pub fn write_transaction<W: io::Write>(
if !log_messages.is_empty() {
writeln!(w, "{}Log Messages:", prefix,)?;
for log_message in log_messages {
writeln!(w, "{} {}", prefix, log_message)?;
}
}
}
if let Some(rewards) = &transaction_status.rewards {
if !rewards.is_empty() {
writeln!(w, "{}Rewards:", prefix,)?;
writeln!(
w,
"{} {:<44} {:^15} {:<15} {:<20}",
prefix, "Address", "Type", "Amount", "New Balance"
)?;
for reward in rewards {
let sign = if reward.lamports < 0 { "-" } else { "" };
writeln!(
w,
"{} {:<44} {:^15} {:<15} {}",
prefix,
reward.pubkey,
if let Some(reward_type) = reward.reward_type {
format!("{}", reward_type)
} else {
"-".to_string()
},
format!(
"{}{:<14.9}",
sign,
lamports_to_sol(reward.lamports.abs() as u64)
),
format!("{:<18.9}", lamports_to_sol(reward.post_balance),)
)?;
writeln!(w, "{} {}", prefix, log_message,)?;
}
}
}

View File

@@ -3,7 +3,7 @@ authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli"
description = "Blockchain, Rebuilt for Scale"
version = "1.7.8"
version = "1.6.2"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
@@ -16,8 +16,7 @@ chrono = { version = "0.4.11", features = ["serde"] }
clap = "2.33.1"
criterion-stats = "0.3.0"
ctrlc = { version = "3.1.5", features = ["termination"] }
console = "0.14.1"
const_format = "0.2.14"
console = "0.11.3"
dirs-next = "2.0.0"
log = "0.4.11"
Inflector = "0.11.4"
@@ -29,29 +28,29 @@ reqwest = { version = "0.11.2", default-features = false, features = ["blocking"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.8" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.7.8" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.8" }
solana-cli-config = { path = "../cli-config", version = "=1.7.8" }
solana-cli-output = { path = "../cli-output", version = "=1.7.8" }
solana-client = { path = "../client", version = "=1.7.8" }
solana-config-program = { path = "../programs/config", version = "=1.7.8" }
solana-faucet = { path = "../faucet", version = "=1.7.8" }
solana-logger = { path = "../logger", version = "=1.7.8" }
solana-net-utils = { path = "../net-utils", version = "=1.7.8" }
solana_rbpf = "=0.2.11"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.8" }
solana-version = { path = "../version", version = "=1.7.8" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.8" }
spl-memo = { version = "=3.0.1", features = ["no-entrypoint"] }
solana-account-decoder = { path = "../account-decoder", version = "=1.6.2" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.6.2" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.2" }
solana-cli-config = { path = "../cli-config", version = "=1.6.2" }
solana-cli-output = { path = "../cli-output", version = "=1.6.2" }
solana-client = { path = "../client", version = "=1.6.2" }
solana-config-program = { path = "../programs/config", version = "=1.6.2" }
solana-faucet = { path = "../faucet", version = "=1.6.2" }
solana-logger = { path = "../logger", version = "=1.6.2" }
solana-net-utils = { path = "../net-utils", version = "=1.6.2" }
solana_rbpf = "=0.2.5"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-stake-program = { path = "../programs/stake", version = "=1.6.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.6.2" }
solana-version = { path = "../version", version = "=1.6.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.2" }
thiserror = "1.0.21"
tiny-bip39 = "0.7.0"
url = "2.1.1"
[dev-dependencies]
solana-core = { path = "../core", version = "=1.7.8" }
solana-core = { path = "../core", version = "=1.6.2" }
tempfile = "3.1.0"
[[bin]]

View File

@@ -231,9 +231,18 @@ mod tests {
mocks.insert(RpcRequest::GetBalance, account_balance_response);
let rpc_client = RpcClient::new_mock_with_mocks("".to_string(), mocks);
assert!(check_account_for_balance(&rpc_client, &pubkey, 1).unwrap());
assert!(check_account_for_balance(&rpc_client, &pubkey, account_balance).unwrap());
assert!(!check_account_for_balance(&rpc_client, &pubkey, account_balance + 1).unwrap());
assert_eq!(
check_account_for_balance(&rpc_client, &pubkey, 1).unwrap(),
true
);
assert_eq!(
check_account_for_balance(&rpc_client, &pubkey, account_balance).unwrap(),
true
);
assert_eq!(
check_account_for_balance(&rpc_client, &pubkey, account_balance + 1).unwrap(),
false
);
}
#[test]

File diff suppressed because it is too large Load Diff

View File

@@ -24,12 +24,11 @@ use solana_client::{
pubsub_client::PubsubClient,
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
rpc_config::{
RpcAccountInfoConfig, RpcBlockConfig, RpcGetVoteAccountsConfig, RpcLargestAccountsConfig,
RpcLargestAccountsFilter, RpcProgramAccountsConfig, RpcTransactionConfig,
RpcTransactionLogsConfig, RpcTransactionLogsFilter,
RpcAccountInfoConfig, RpcConfirmedBlockConfig, RpcLargestAccountsConfig,
RpcLargestAccountsFilter, RpcProgramAccountsConfig, RpcTransactionLogsConfig,
RpcTransactionLogsFilter,
},
rpc_filter,
rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE,
rpc_response::SlotInfo,
};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
@@ -42,28 +41,23 @@ use solana_sdk::{
hash::Hash,
message::Message,
native_token::lamports_to_sol,
nonce::State as NonceState,
pubkey::{self, Pubkey},
rent::Rent,
rpc_port::DEFAULT_RPC_PORT_STR,
signature::Signature,
slot_history,
stake::{self, state::StakeState},
system_instruction, system_program,
sysvar::{
self,
slot_history::SlotHistory,
stake_history::{self},
},
timing,
transaction::Transaction,
};
use solana_transaction_status::UiTransactionEncoding;
use solana_vote_program::vote_state::VoteState;
use std::{
collections::{BTreeMap, HashMap, VecDeque},
fmt,
str::FromStr,
net::SocketAddr,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
@@ -71,7 +65,6 @@ use std::{
thread::sleep,
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
};
use thiserror::Error;
static CHECK_MARK: Emoji = Emoji("", "");
static CROSS_MARK: Emoji = Emoji("", "");
@@ -123,7 +116,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.long("our-localhost")
.takes_value(false)
.value_name("PORT")
.default_value(DEFAULT_RPC_PORT_STR)
.default_value(&DEFAULT_RPC_PORT_STR)
.validator(is_port)
.help("Guess Identity pubkey and validator rpc node assuming local (possibly private) validator"),
)
@@ -177,7 +170,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.takes_value(true)
.value_name("EPOCH")
.validator(is_epoch)
.help("Epoch to show leader schedule for. [default: current]")
.help("Epoch to show leader schedule for. (default: current)")
)
)
.subcommand(
@@ -351,57 +344,6 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.long("lamports")
.takes_value(false)
.help("Display balance in lamports instead of SOL"),
)
.arg(
Arg::with_name("number")
.long("number")
.short("n")
.takes_value(false)
.help("Number the validators"),
)
.arg(
Arg::with_name("reverse")
.long("reverse")
.short("r")
.takes_value(false)
.help("Reverse order while sorting"),
)
.arg(
Arg::with_name("sort")
.long("sort")
.takes_value(true)
.possible_values(&[
"delinquent",
"commission",
"credits",
"identity",
"last-vote",
"root",
"skip-rate",
"stake",
"vote-account",
])
.default_value("stake")
.help("Sort order (does not affect JSON output)"),
)
.arg(
Arg::with_name("keep_unstaked_delinquents")
.long("keep-unstaked-delinquents")
.takes_value(false)
.help("Don't discard unstaked, delinquent validators")
)
.arg(
Arg::with_name("delinquent_slot_distance")
.long("delinquent-slot-distance")
.takes_value(true)
.value_name("SLOT_DISTANCE")
.validator(is_slot)
.help(
concatcp!(
"Minimum slot distance from the tip to consider a validator delinquent. [default: ",
DELINQUENT_VALIDATOR_SLOT_DISTANCE,
"]",
))
),
)
.subcommand(
@@ -455,14 +397,9 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.arg(
Arg::with_name("data_length")
.index(1)
.value_name("DATA_LENGTH_OR_MONIKER")
.value_name("DATA_LENGTH")
.required(true)
.validator(|s| {
RentLengthValue::from_str(&s)
.map(|_| ())
.map_err(|e| e.to_string())
})
.help("Length of data in the account to calculate rent for, or moniker: [nonce, stake, system, vote]"),
.help("Length of data in the account to calculate rent for"),
)
.arg(
Arg::with_name("lamports")
@@ -635,33 +572,9 @@ pub fn parse_show_stakes(
pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let use_lamports_unit = matches.is_present("lamports");
let number_validators = matches.is_present("number");
let reverse_sort = matches.is_present("reverse");
let keep_unstaked_delinquents = matches.is_present("keep_unstaked_delinquents");
let delinquent_slot_distance = value_of(matches, "delinquent_slot_distance");
let sort_order = match value_t_or_exit!(matches, "sort", String).as_str() {
"delinquent" => CliValidatorsSortOrder::Delinquent,
"commission" => CliValidatorsSortOrder::Commission,
"credits" => CliValidatorsSortOrder::EpochCredits,
"identity" => CliValidatorsSortOrder::Identity,
"last-vote" => CliValidatorsSortOrder::LastVote,
"root" => CliValidatorsSortOrder::Root,
"skip-rate" => CliValidatorsSortOrder::SkipRate,
"stake" => CliValidatorsSortOrder::Stake,
"vote-account" => CliValidatorsSortOrder::VoteAccount,
_ => unreachable!(),
};
Ok(CliCommandInfo {
command: CliCommand::ShowValidators {
use_lamports_unit,
sort_order,
reverse_sort,
number_validators,
keep_unstaked_delinquents,
delinquent_slot_distance,
},
command: CliCommand::ShowValidators { use_lamports_unit },
signers: vec![],
})
}
@@ -962,19 +875,18 @@ pub fn process_fees(
*recent_blockhash,
fee_calculator.lamports_per_signature,
None,
None,
)
} else {
CliFees::none()
}
} else {
let result = rpc_client.get_fees_with_commitment(config.commitment)?;
let result = rpc_client.get_recent_blockhash_with_commitment(config.commitment)?;
let (recent_blockhash, fee_calculator, last_valid_slot) = result.value;
CliFees::some(
result.context.slot,
result.value.blockhash,
result.value.fee_calculator.lamports_per_signature,
None,
Some(result.value.last_valid_block_height),
recent_blockhash,
fee_calculator.lamports_per_signature,
Some(last_valid_slot),
)
};
Ok(config.output_format.formatted_string(&fees))
@@ -1053,12 +965,12 @@ pub fn process_get_block(
};
let encoded_confirmed_block = rpc_client
.get_block_with_config(
.get_confirmed_block_with_config(
slot,
RpcBlockConfig {
RpcConfirmedBlockConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(CommitmentConfig::confirmed()),
..RpcBlockConfig::default()
..RpcConfirmedBlockConfig::default()
},
)?
.into();
@@ -1101,15 +1013,9 @@ pub fn process_get_epoch_info(rpc_client: &RpcClient, config: &CliConfig) -> Pro
(secs as u64).saturating_mul(1000).checked_div(slots)
})
.unwrap_or(clock::DEFAULT_MS_PER_SLOT);
let start_block_time = rpc_client
.get_block_time(epoch_info.absolute_slot - epoch_info.slot_index)
.ok();
let current_block_time = rpc_client.get_block_time(epoch_info.absolute_slot).ok();
let epoch_info = CliEpochInfo {
epoch_info,
average_slot_time_ms,
start_block_time,
current_block_time,
};
Ok(config.output_format.formatted_string(&epoch_info))
}
@@ -1125,8 +1031,8 @@ pub fn process_get_slot(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessR
}
pub fn process_get_block_height(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessResult {
let block_height = rpc_client.get_block_height()?;
Ok(block_height.to_string())
let epoch_info = rpc_client.get_epoch_info()?;
Ok(epoch_info.block_height.to_string())
}
pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
@@ -1153,6 +1059,8 @@ pub fn process_show_block_production(
return Err(format!("Epoch {} is in the future", epoch).into());
}
let minimum_ledger_slot = rpc_client.minimum_ledger_slot()?;
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
let end_slot = std::cmp::min(
epoch_info.absolute_slot,
@@ -1165,60 +1073,32 @@ pub fn process_show_block_production(
first_slot_in_epoch
};
if minimum_ledger_slot > end_slot {
return Err(format!(
"Ledger data not available for slots {} to {} (minimum ledger slot is {})",
start_slot, end_slot, minimum_ledger_slot
)
.into());
}
if minimum_ledger_slot > start_slot {
println!(
"\n{}",
style(format!(
"Note: Requested start slot was {} but minimum ledger slot is {}",
start_slot, minimum_ledger_slot
))
.italic(),
);
start_slot = minimum_ledger_slot;
}
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message(&format!(
"Fetching confirmed blocks between slots {} and {}...",
start_slot, end_slot
));
let slot_history_account = rpc_client
.get_account_with_commitment(&sysvar::slot_history::id(), CommitmentConfig::finalized())?
.value
.unwrap();
let slot_history: SlotHistory = from_account(&slot_history_account).ok_or_else(|| {
CliError::RpcRequestError("Failed to deserialize slot history".to_string())
})?;
let (confirmed_blocks, start_slot) =
if start_slot >= slot_history.oldest() && end_slot <= slot_history.newest() {
// Fast, more reliable path using the SlotHistory sysvar
let confirmed_blocks: Vec<_> = (start_slot..=end_slot)
.filter(|slot| slot_history.check(*slot) == slot_history::Check::Found)
.collect();
(confirmed_blocks, start_slot)
} else {
// Slow, less reliable path using `getBlocks`.
//
// "less reliable" because if the RPC node has holds in its ledger then the block production data will be
// incorrect. This condition currently can't be detected over RPC
//
let minimum_ledger_slot = rpc_client.minimum_ledger_slot()?;
if minimum_ledger_slot > end_slot {
return Err(format!(
"Ledger data not available for slots {} to {} (minimum ledger slot is {})",
start_slot, end_slot, minimum_ledger_slot
)
.into());
}
if minimum_ledger_slot > start_slot {
progress_bar.println(format!(
"{}",
style(format!(
"Note: Requested start slot was {} but minimum ledger slot is {}",
start_slot, minimum_ledger_slot
))
.italic(),
));
start_slot = minimum_ledger_slot;
}
let confirmed_blocks = rpc_client.get_blocks(start_slot, Some(end_slot))?;
(confirmed_blocks, start_slot)
};
let confirmed_blocks = rpc_client.get_confirmed_blocks(start_slot, Some(end_slot))?;
let start_slot_index = (start_slot - first_slot_in_epoch) as usize;
let end_slot_index = (end_slot - first_slot_in_epoch) as usize;
@@ -1344,8 +1224,8 @@ pub fn process_supply(
}
pub fn process_total_supply(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessResult {
let supply = rpc_client.supply()?.value;
Ok(format!("{} SOL", lamports_to_sol(supply.total)))
let total_supply = rpc_client.total_supply()?;
Ok(format!("{} SOL", lamports_to_sol(total_supply)))
}
pub fn process_get_transaction_count(rpc_client: &RpcClient, _config: &CliConfig) -> ProcessResult {
@@ -1686,14 +1566,40 @@ pub fn process_live_slots(config: &CliConfig) -> ProcessResult {
pub fn process_show_gossip(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
let cluster_nodes = rpc_client.get_cluster_nodes()?;
let nodes: Vec<_> = cluster_nodes
fn format_port(addr: Option<SocketAddr>) -> String {
addr.map(|addr| addr.port().to_string())
.unwrap_or_else(|| "none".to_string())
}
let s: Vec<_> = cluster_nodes
.into_iter()
.map(|node| CliGossipNode::new(node, &config.address_labels))
.map(|node| {
format!(
"{:15} | {:44} | {:6} | {:5} | {:21} | {}",
node.gossip
.map(|addr| addr.ip().to_string())
.unwrap_or_else(|| "none".to_string()),
format_labeled_address(&node.pubkey, &config.address_labels),
format_port(node.gossip),
format_port(node.tpu),
node.rpc
.map(|addr| addr.to_string())
.unwrap_or_else(|| "none".to_string()),
node.version.unwrap_or_else(|| "unknown".to_string()),
)
})
.collect();
Ok(config
.output_format
.formatted_string(&CliGossipNodes(nodes)))
Ok(format!(
"IP Address | Node identifier \
| Gossip | TPU | RPC Address | Version\n\
----------------+----------------------------------------------+\
--------+-------+-----------------------+----------------\n\
{}\n\
Nodes: {}",
s.join("\n"),
s.len(),
))
}
pub fn process_show_stakes(
@@ -1703,16 +1609,17 @@ pub fn process_show_stakes(
vote_account_pubkeys: Option<&[Pubkey]>,
) -> ProcessResult {
use crate::stake::build_stake_state;
use solana_stake_program::stake_state::StakeState;
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message("Fetching stake accounts...");
let mut program_accounts_config = RpcProgramAccountsConfig {
filters: None,
account_config: RpcAccountInfoConfig {
encoding: Some(solana_account_decoder::UiAccountEncoding::Base64),
..RpcAccountInfoConfig::default()
},
..RpcProgramAccountsConfig::default()
};
if let Some(vote_account_pubkeys) = vote_account_pubkeys {
@@ -1739,7 +1646,7 @@ pub fn process_show_stakes(
}
}
let all_stake_accounts = rpc_client
.get_program_accounts_with_config(&stake::program::id(), program_accounts_config)?;
.get_program_accounts_with_config(&solana_stake_program::id(), program_accounts_config)?;
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
let clock_account = rpc_client.get_account(&sysvar::clock::id())?;
let clock: Clock = from_account(&clock_account).ok_or_else(|| {
@@ -1814,42 +1721,10 @@ pub fn process_show_validators(
rpc_client: &RpcClient,
config: &CliConfig,
use_lamports_unit: bool,
validators_sort_order: CliValidatorsSortOrder,
validators_reverse_sort: bool,
number_validators: bool,
keep_unstaked_delinquents: bool,
delinquent_slot_distance: Option<Slot>,
) -> ProcessResult {
let progress_bar = new_spinner_progress_bar();
progress_bar.set_message("Fetching vote accounts...");
let epoch_info = rpc_client.get_epoch_info()?;
let vote_accounts = rpc_client.get_vote_accounts_with_config(RpcGetVoteAccountsConfig {
keep_unstaked_delinquents: Some(keep_unstaked_delinquents),
delinquent_slot_distance,
..RpcGetVoteAccountsConfig::default()
})?;
let vote_accounts = rpc_client.get_vote_accounts()?;
progress_bar.set_message("Fetching block production...");
let skip_rate: HashMap<_, _> = rpc_client
.get_block_production()
.ok()
.map(|result| {
result
.value
.by_identity
.into_iter()
.map(|(identity, (leader_slots, blocks_produced))| {
(
identity,
100. * (leader_slots.saturating_sub(blocks_produced)) as f64
/ leader_slots as f64,
)
})
.collect()
})
.unwrap_or_default();
progress_bar.set_message("Fetching version information...");
let mut node_version = HashMap::new();
let unknown_version = "unknown".to_string();
for contact_info in rpc_client.get_cluster_nodes()? {
@@ -1861,8 +1736,6 @@ pub fn process_show_validators(
);
}
progress_bar.finish_and_clear();
let total_active_stake = vote_accounts
.current
.iter()
@@ -1877,8 +1750,9 @@ pub fn process_show_validators(
.sum();
let total_current_stake = total_active_stake - total_delinquent_stake;
let current_validators: Vec<CliValidator> = vote_accounts
.current
let mut current = vote_accounts.current;
current.sort_by(|a, b| b.activated_stake.cmp(&a.activated_stake));
let current_validators: Vec<CliValidator> = current
.iter()
.map(|vote_account| {
CliValidator::new(
@@ -1888,23 +1762,22 @@ pub fn process_show_validators(
.get(&vote_account.node_pubkey)
.unwrap_or(&unknown_version)
.clone(),
skip_rate.get(&vote_account.node_pubkey).cloned(),
&config.address_labels,
)
})
.collect();
let delinquent_validators: Vec<CliValidator> = vote_accounts
.delinquent
let mut delinquent = vote_accounts.delinquent;
delinquent.sort_by(|a, b| b.activated_stake.cmp(&a.activated_stake));
let delinquent_validators: Vec<CliValidator> = delinquent
.iter()
.map(|vote_account| {
CliValidator::new_delinquent(
CliValidator::new(
vote_account,
epoch_info.epoch,
node_version
.get(&vote_account.node_pubkey)
.unwrap_or(&unknown_version)
.clone(),
skip_rate.get(&vote_account.node_pubkey).cloned(),
&config.address_labels,
)
})
@@ -1926,43 +1799,12 @@ pub fn process_show_validators(
entry.delinquent_active_stake += validator.activated_stake;
}
let validators: Vec<_> = current_validators
.into_iter()
.chain(delinquent_validators.into_iter())
.collect();
let (average_skip_rate, average_stake_weighted_skip_rate) = {
let mut skip_rate_len = 0;
let mut skip_rate_sum = 0.;
let mut skip_rate_weighted_sum = 0.;
for validator in validators.iter() {
if let Some(skip_rate) = validator.skip_rate {
skip_rate_sum += skip_rate;
skip_rate_len += 1;
skip_rate_weighted_sum += skip_rate * validator.activated_stake as f64;
}
}
if skip_rate_len > 0 && total_active_stake > 0 {
(
skip_rate_sum / skip_rate_len as f64,
skip_rate_weighted_sum / total_active_stake as f64,
)
} else {
(100., 100.) // Impossible?
}
};
let cli_validators = CliValidators {
total_active_stake,
total_current_stake,
total_delinquent_stake,
validators,
average_skip_rate,
average_stake_weighted_skip_rate,
validators_sort_order,
validators_reverse_sort,
number_validators,
current_validators,
delinquent_validators,
stake_by_version,
use_lamports_unit,
};
@@ -1978,13 +1820,12 @@ pub fn process_transaction_history(
limit: usize,
show_transactions: bool,
) -> ProcessResult {
let results = rpc_client.get_signatures_for_address_with_config(
let results = rpc_client.get_confirmed_signatures_for_address2_with_config(
address,
GetConfirmedSignaturesForAddress2Config {
before,
until,
limit: Some(limit),
commitment: Some(CommitmentConfig::confirmed()),
},
)?;
@@ -2001,13 +1842,9 @@ pub fn process_transaction_history(
Some(block_time) =>
format!("timestamp={} ", unix_timestamp_to_string(block_time)),
},
if let Some(err) = result.err {
format!("Failed: {:?}", err)
} else {
match result.confirmation_status {
None => "Finalized".to_string(),
Some(status) => format!("{:?}", status),
}
match result.err {
None => "Confirmed".to_string(),
Some(err) => format!("Failed: {:?}", err),
},
result.memo.unwrap_or_else(|| "".to_string()),
);
@@ -2017,13 +1854,9 @@ pub fn process_transaction_history(
if show_transactions {
if let Ok(signature) = result.signature.parse::<Signature>() {
match rpc_client.get_transaction_with_config(
&signature,
RpcTransactionConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(CommitmentConfig::confirmed()),
},
) {
match rpc_client
.get_confirmed_transaction(&signature, UiTransactionEncoding::Base64)
{
Ok(confirmed_transaction) => {
println_transaction(
&confirmed_transaction
@@ -2076,47 +1909,6 @@ impl fmt::Display for CliRentCalculation {
impl QuietDisplay for CliRentCalculation {}
impl VerboseDisplay for CliRentCalculation {}
#[derive(Debug, PartialEq)]
pub enum RentLengthValue {
Nonce,
Stake,
System,
Vote,
Bytes(usize),
}
impl RentLengthValue {
pub fn length(&self) -> usize {
match self {
Self::Nonce => NonceState::size(),
Self::Stake => std::mem::size_of::<StakeState>(),
Self::System => 0,
Self::Vote => VoteState::size_of(),
Self::Bytes(l) => *l,
}
}
}
#[derive(Debug, Error)]
#[error("expected number or moniker, got \"{0}\"")]
pub struct RentLengthValueError(pub String);
impl FromStr for RentLengthValue {
type Err = RentLengthValueError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_ascii_lowercase();
match s.as_str() {
"nonce" => Ok(Self::Nonce),
"stake" => Ok(Self::Stake),
"system" => Ok(Self::System),
"vote" => Ok(Self::Vote),
_ => usize::from_str(&s)
.map(Self::Bytes)
.map_err(|_| RentLengthValueError(s)),
}
}
}
pub fn process_calculate_rent(
rpc_client: &RpcClient,
config: &CliConfig,
@@ -2162,7 +1954,10 @@ mod tests {
let default_keypair = Keypair::new();
let (default_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
let default_signer = DefaultSigner::new("", &default_keypair_file);
let default_signer = DefaultSigner {
path: default_keypair_file,
arg_name: String::new(),
};
let test_cluster_version = test_commands
.clone()

View File

@@ -10,7 +10,6 @@ use solana_cli_output::{QuietDisplay, VerboseDisplay};
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account::Account,
clock::Slot,
feature::{self, Feature},
feature_set::FEATURE_NAMES,
@@ -313,31 +312,6 @@ fn feature_activation_allowed(rpc_client: &RpcClient, quiet: bool) -> Result<boo
Ok(feature_activation_allowed)
}
fn status_from_account(account: Account) -> Option<CliFeatureStatus> {
feature::from_account(&account).map(|feature| match feature.activated_at {
None => CliFeatureStatus::Pending,
Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
})
}
fn get_feature_status(
rpc_client: &RpcClient,
feature_id: &Pubkey,
) -> Result<Option<CliFeatureStatus>, Box<dyn std::error::Error>> {
rpc_client
.get_account(feature_id)
.map(status_from_account)
.map_err(|e| e.into())
}
pub fn get_feature_is_active(
rpc_client: &RpcClient,
feature_id: &Pubkey,
) -> Result<bool, Box<dyn std::error::Error>> {
get_feature_status(rpc_client, feature_id)
.map(|status| matches!(status, Some(CliFeatureStatus::Active(_))))
}
fn process_status(
rpc_client: &RpcClient,
config: &CliConfig,
@@ -353,7 +327,11 @@ fn process_status(
let feature_id = &feature_ids[i];
let feature_name = FEATURE_NAMES.get(feature_id).unwrap();
if let Some(account) = account {
if let Some(feature_status) = status_from_account(account) {
if let Some(feature) = feature::from_account(&account) {
let feature_status = match feature.activated_at {
None => CliFeatureStatus::Pending,
Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
};
features.push(CliFeature {
id: feature_id.to_string(),
description: feature_name.to_string(),

View File

@@ -1,22 +1,14 @@
use crate::cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult};
use clap::{App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{
input_parsers::{pubkeys_of, value_of},
input_validators::is_valid_pubkey,
keypair::*,
};
use solana_cli_output::{
CliEpochRewardshMetadata, CliInflation, CliKeyedEpochReward, CliKeyedEpochRewards,
};
use clap::{App, ArgMatches, SubCommand};
use solana_clap_utils::keypair::*;
use solana_cli_output::CliInflation;
use solana_client::rpc_client::RpcClient;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{clock::Epoch, pubkey::Pubkey};
use std::sync::Arc;
#[derive(Debug, PartialEq)]
pub enum InflationCliCommand {
Show,
Rewards(Vec<Pubkey>, Option<Epoch>),
}
pub trait InflationSubCommands {
@@ -25,47 +17,17 @@ pub trait InflationSubCommands {
impl InflationSubCommands for App<'_, '_> {
fn inflation_subcommands(self) -> Self {
self.subcommand(
SubCommand::with_name("inflation")
.about("Show inflation information")
.subcommand(
SubCommand::with_name("rewards")
.about("Show inflation rewards for a set of addresses")
.arg(pubkey!(
Arg::with_name("addresses")
.value_name("ADDRESS")
.index(1)
.multiple(true)
.required(true),
"Address of account to query for rewards. "
))
.arg(
Arg::with_name("rewards_epoch")
.long("rewards-epoch")
.takes_value(true)
.value_name("EPOCH")
.help("Display rewards for specific epoch [default: latest epoch]"),
),
),
)
self.subcommand(SubCommand::with_name("inflation").about("Show inflation information"))
}
}
pub fn parse_inflation_subcommand(
matches: &ArgMatches<'_>,
_matches: &ArgMatches<'_>,
_default_signer: &DefaultSigner,
_wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let command = match matches.subcommand() {
("rewards", Some(matches)) => {
let addresses = pubkeys_of(matches, "addresses").unwrap();
let rewards_epoch = value_of(matches, "rewards_epoch");
InflationCliCommand::Rewards(addresses, rewards_epoch)
}
_ => InflationCliCommand::Show,
};
Ok(CliCommandInfo {
command: CliCommand::Inflation(command),
command: CliCommand::Inflation(InflationCliCommand::Show),
signers: vec![],
})
}
@@ -75,15 +37,8 @@ pub fn process_inflation_subcommand(
config: &CliConfig,
inflation_subcommand: &InflationCliCommand,
) -> ProcessResult {
match inflation_subcommand {
InflationCliCommand::Show => process_show(rpc_client, config),
InflationCliCommand::Rewards(ref addresses, rewards_epoch) => {
process_rewards(rpc_client, config, addresses, *rewards_epoch)
}
}
}
assert_eq!(*inflation_subcommand, InflationCliCommand::Show);
fn process_show(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
let governor = rpc_client.get_inflation_governor()?;
let current_rate = rpc_client.get_inflation_rate()?;
@@ -94,49 +49,3 @@ fn process_show(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
Ok(config.output_format.formatted_string(&inflation))
}
fn process_rewards(
rpc_client: &RpcClient,
config: &CliConfig,
addresses: &[Pubkey],
rewards_epoch: Option<Epoch>,
) -> ProcessResult {
let rewards = rpc_client
.get_inflation_reward(addresses, rewards_epoch)
.map_err(|err| {
if let Some(epoch) = rewards_epoch {
format!("Rewards not available for epoch {}", epoch)
} else {
format!("Rewards not available {}", err)
}
})?;
let epoch_schedule = rpc_client.get_epoch_schedule()?;
let mut epoch_rewards: Vec<CliKeyedEpochReward> = vec![];
let epoch_metadata = if let Some(Some(first_reward)) = rewards.iter().find(|&v| v.is_some()) {
let (epoch_start_time, epoch_end_time) =
crate::stake::get_epoch_boundary_timestamps(rpc_client, first_reward, &epoch_schedule)?;
for (reward, address) in rewards.iter().zip(addresses) {
let cli_reward = reward.as_ref().and_then(|reward| {
crate::stake::make_cli_reward(reward, epoch_start_time, epoch_end_time)
});
epoch_rewards.push(CliKeyedEpochReward {
address: address.to_string(),
reward: cli_reward,
});
}
let block_time = rpc_client.get_block_time(first_reward.effective_slot)?;
Some(CliEpochRewardshMetadata {
epoch: first_reward.epoch,
effective_slot: first_reward.effective_slot,
block_time,
})
} else {
None
};
let cli_rewards = CliKeyedEpochRewards {
epoch_metadata,
rewards: epoch_rewards,
};
Ok(config.output_format.formatted_string(&cli_rewards))
}

View File

@@ -10,6 +10,7 @@ macro_rules! ACCOUNT_STRING {
};
}
#[macro_use]
macro_rules! pubkey {
($arg:expr, $help:expr) => {
$arg.takes_value(true)
@@ -18,9 +19,6 @@ macro_rules! pubkey {
};
}
#[macro_use]
extern crate const_format;
extern crate serde_derive;
pub mod checks;
@@ -28,9 +26,9 @@ pub mod cli;
pub mod cluster_query;
pub mod feature;
pub mod inflation;
pub mod memo;
pub mod nonce;
pub mod program;
pub mod send_tpu;
pub mod spend_utils;
pub mod stake;
pub mod test_utils;

View File

@@ -10,7 +10,7 @@ use solana_clap_utils::{
};
use solana_cli::cli::{
app, parse_command, process_command, CliCommandInfo, CliConfig, SettingType,
DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS, DEFAULT_RPC_TIMEOUT_SECONDS,
DEFAULT_RPC_TIMEOUT_SECONDS,
};
use solana_cli_config::{Config, CONFIG_FILE};
use solana_cli_output::{display::println_name_value, OutputFormat};
@@ -167,11 +167,6 @@ pub fn parse_args<'a>(
let rpc_timeout = value_t_or_exit!(matches, "rpc_timeout", u64);
let rpc_timeout = Duration::from_secs(rpc_timeout);
let confirm_transaction_initial_timeout =
value_t_or_exit!(matches, "confirm_transaction_initial_timeout", u64);
let confirm_transaction_initial_timeout =
Duration::from_secs(confirm_transaction_initial_timeout);
let (_, websocket_url) = CliConfig::compute_websocket_url_setting(
matches.value_of("websocket_url").unwrap_or(""),
&config.websocket_url,
@@ -184,12 +179,15 @@ pub fn parse_args<'a>(
&config.keypair_path,
);
let default_signer = DefaultSigner::new(default_signer_arg_name, &default_signer_path);
let default_signer = DefaultSigner {
arg_name: default_signer_arg_name,
path: default_signer_path.clone(),
};
let CliCommandInfo {
command,
mut signers,
} = parse_command(matches, &default_signer, &mut wallet_manager)?;
} = parse_command(&matches, &default_signer, &mut wallet_manager)?;
if signers.is_empty() {
if let Ok(signer_info) =
@@ -240,7 +238,6 @@ pub fn parse_args<'a>(
preflight_commitment: Some(commitment.commitment),
..RpcSendTransactionConfig::default()
},
confirm_transaction_initial_timeout,
address_labels,
},
signers,
@@ -263,7 +260,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.global(true)
.help("Configuration file to use");
if let Some(ref config_file) = *CONFIG_FILE {
arg.default_value(config_file)
arg.default_value(&config_file)
} else {
arg
}
@@ -356,16 +353,6 @@ fn main() -> Result<(), Box<dyn error::Error>> {
.hidden(true)
.help("Timeout value for RPC requests"),
)
.arg(
Arg::with_name("confirm_transaction_initial_timeout")
.long("confirm-timeout")
.value_name("SECONDS")
.takes_value(true)
.default_value(DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS)
.global(true)
.hidden(true)
.help("Timeout value for initial transaction status"),
)
.subcommand(
SubCommand::with_name("config")
.about("Solana command-line tool configuration settings")
@@ -427,10 +414,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
}
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
if parse_settings(matches)? {
if parse_settings(&matches)? {
let mut wallet_manager = None;
let (mut config, signers) = parse_args(matches, &mut wallet_manager)?;
let (mut config, signers) = parse_args(&matches, &mut wallet_manager)?;
config.signers = signers.iter().map(|s| s.as_ref()).collect();
let result = process_command(&config)?;
println!("{}", result);

View File

@@ -1,22 +0,0 @@
use solana_sdk::instruction::Instruction;
use solana_sdk::pubkey::Pubkey;
use spl_memo::id;
pub trait WithMemo {
fn with_memo<T: AsRef<str>>(self, memo: Option<T>) -> Self;
}
impl WithMemo for Vec<Instruction> {
fn with_memo<T: AsRef<str>>(mut self, memo: Option<T>) -> Self {
if let Some(memo) = &memo {
let memo = memo.as_ref();
let memo_ix = Instruction {
program_id: Pubkey::new(&id().to_bytes()),
accounts: vec![],
data: memo.as_bytes().to_vec(),
};
self.push(memo_ix);
}
self
}
}

View File

@@ -1,11 +1,9 @@
use crate::{
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
cli::{
log_instruction_custom_error, log_instruction_custom_error_ex, CliCommand, CliCommandInfo,
CliConfig, CliError, ProcessResult,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
feature::get_feature_is_active,
memo::WithMemo,
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
use clap::{App, Arg, ArgMatches, SubCommand};
@@ -13,7 +11,6 @@ use solana_clap_utils::{
input_parsers::*,
input_validators::*,
keypair::{DefaultSigner, SignerIndex},
memo::{memo_arg, MEMO_ARG},
nonce::*,
};
use solana_cli_output::CliNonceAccount;
@@ -21,19 +18,16 @@ use solana_client::{nonce_utils::*, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account::Account,
feature_set::merge_nonce_error_into_system_error,
hash::Hash,
instruction::InstructionError,
message::Message,
nonce::{self, State},
pubkey::Pubkey,
system_instruction::{
advance_nonce_account, authorize_nonce_account, create_nonce_account,
create_nonce_account_with_seed, instruction_to_nonce_error, withdraw_nonce_account,
NonceError, SystemError,
create_nonce_account_with_seed, withdraw_nonce_account, NonceError, SystemError,
},
system_program,
transaction::{Transaction, TransactionError},
transaction::Transaction,
};
use std::sync::Arc;
@@ -60,8 +54,7 @@ impl NonceSubCommands for App<'_, '_> {
.required(true),
"Account to be granted authority of the nonce account. "),
)
.arg(nonce_authority_arg())
.arg(memo_arg()),
.arg(nonce_authority_arg()),
)
.subcommand(
SubCommand::with_name("create-nonce-account")
@@ -96,8 +89,7 @@ impl NonceSubCommands for App<'_, '_> {
.value_name("STRING")
.takes_value(true)
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the NONCE_ACCOUNT pubkey")
)
.arg(memo_arg()),
),
)
.subcommand(
SubCommand::with_name("nonce")
@@ -121,8 +113,7 @@ impl NonceSubCommands for App<'_, '_> {
.required(true),
"Address of the nonce account. "),
)
.arg(nonce_authority_arg())
.arg(memo_arg()),
.arg(nonce_authority_arg()),
)
.subcommand(
SubCommand::with_name("nonce-account")
@@ -168,8 +159,7 @@ impl NonceSubCommands for App<'_, '_> {
.validator(is_amount)
.help("The amount to withdraw from the nonce account, in SOL"),
)
.arg(nonce_authority_arg())
.arg(memo_arg()),
.arg(nonce_authority_arg()),
)
}
}
@@ -181,7 +171,6 @@ pub fn parse_authorize_nonce_account(
) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
let new_authority = pubkey_of_signer(matches, "new_authority", wallet_manager)?.unwrap();
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
let (nonce_authority, nonce_authority_pubkey) =
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
@@ -196,7 +185,6 @@ pub fn parse_authorize_nonce_account(
command: CliCommand::AuthorizeNonceAccount {
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
memo,
new_authority,
},
signers: signer_info.signers,
@@ -213,7 +201,6 @@ pub fn parse_nonce_create_account(
let seed = matches.value_of("seed").map(|s| s.to_string());
let amount = SpendAmount::new_from_matches(matches, "amount");
let nonce_authority = pubkey_of_signer(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
let payer_provided = None;
let signer_info = default_signer.generate_unique_signers(
@@ -227,7 +214,6 @@ pub fn parse_nonce_create_account(
nonce_account: signer_info.index_of(nonce_account_pubkey).unwrap(),
seed,
nonce_authority,
memo,
amount,
},
signers: signer_info.signers,
@@ -253,7 +239,6 @@ pub fn parse_new_nonce(
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
let (nonce_authority, nonce_authority_pubkey) =
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
@@ -268,7 +253,6 @@ pub fn parse_new_nonce(
command: CliCommand::NewNonce {
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
memo,
},
signers: signer_info.signers,
})
@@ -300,7 +284,6 @@ pub fn parse_withdraw_from_nonce_account(
let destination_account_pubkey =
pubkey_of_signer(matches, "destination_account_pubkey", wallet_manager)?.unwrap();
let lamports = lamports_of_sol(matches, "amount").unwrap();
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
let (nonce_authority, nonce_authority_pubkey) =
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
@@ -315,7 +298,6 @@ pub fn parse_withdraw_from_nonce_account(
command: CliCommand::WithdrawFromNonceAccount {
nonce_account,
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
memo,
destination_account_pubkey,
lamports,
},
@@ -348,19 +330,13 @@ pub fn process_authorize_nonce_account(
config: &CliConfig,
nonce_account: &Pubkey,
nonce_authority: SignerIndex,
memo: Option<&String>,
new_authority: &Pubkey,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let nonce_authority = config.signers[nonce_authority];
let ixs = vec![authorize_nonce_account(
nonce_account,
&nonce_authority.pubkey(),
new_authority,
)]
.with_memo(memo);
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
let ix = authorize_nonce_account(nonce_account, &nonce_authority.pubkey(), new_authority);
let message = Message::new(&[ix], Some(&config.signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, recent_blockhash)?;
@@ -371,21 +347,8 @@ pub fn process_authorize_nonce_account(
&tx.message,
config.commitment,
)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
log_instruction_custom_error::<NonceError>(result, &config)
}
pub fn process_create_nonce_account(
@@ -394,7 +357,6 @@ pub fn process_create_nonce_account(
nonce_account: SignerIndex,
seed: Option<String>,
nonce_authority: Option<Pubkey>,
memo: Option<&String>,
amount: SpendAmount,
) -> ProcessResult {
let nonce_account_pubkey = config.signers[nonce_account].pubkey();
@@ -421,7 +383,6 @@ pub fn process_create_nonce_account(
&nonce_authority,
lamports,
)
.with_memo(memo)
} else {
create_nonce_account(
&config.signers[0].pubkey(),
@@ -429,7 +390,6 @@ pub fn process_create_nonce_account(
&nonce_authority,
lamports,
)
.with_memo(memo)
};
Message::new(&ixs, Some(&config.signers[0].pubkey()))
};
@@ -469,40 +429,8 @@ pub fn process_create_nonce_account(
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, recent_blockhash)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
let err_ix_index = if let Err(err) = &result {
err.get_transaction_error().and_then(|tx_err| {
if let TransactionError::InstructionError(ix_index, _) = tx_err {
Some(ix_index)
} else {
None
}
})
} else {
None
};
match err_ix_index {
// SystemInstruction::InitializeNonceAccount failed
Some(1) => {
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
}
// SystemInstruction::CreateAccount{,WithSeed} failed
_ => log_instruction_custom_error::<SystemError>(result, config),
}
log_instruction_custom_error::<SystemError>(result, &config)
}
pub fn process_get_nonce(
@@ -523,14 +451,13 @@ pub fn process_new_nonce(
config: &CliConfig,
nonce_account: &Pubkey,
nonce_authority: SignerIndex,
memo: Option<&String>,
) -> ProcessResult {
check_unique_pubkeys(
(&config.signers[0].pubkey(), "cli keypair".to_string()),
(nonce_account, "nonce_account_pubkey".to_string()),
(&nonce_account, "nonce_account_pubkey".to_string()),
)?;
if let Err(err) = rpc_client.get_account(nonce_account) {
if let Err(err) = rpc_client.get_account(&nonce_account) {
return Err(CliError::BadParameter(format!(
"Unable to advance nonce account {}. error: {}",
nonce_account, err
@@ -539,13 +466,9 @@ pub fn process_new_nonce(
}
let nonce_authority = config.signers[nonce_authority];
let ixs = vec![advance_nonce_account(
nonce_account,
&nonce_authority.pubkey(),
)]
.with_memo(memo);
let ix = advance_nonce_account(&nonce_account, &nonce_authority.pubkey());
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
let message = Message::new(&[ix], Some(&config.signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, recent_blockhash)?;
check_account_for_fee_with_commitment(
@@ -555,21 +478,8 @@ pub fn process_new_nonce(
&tx.message,
config.commitment,
)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
log_instruction_custom_error::<SystemError>(result, &config)
}
pub fn process_show_nonce_account(
@@ -588,7 +498,7 @@ pub fn process_show_nonce_account(
use_lamports_unit,
..CliNonceAccount::default()
};
if let Some(data) = data {
if let Some(ref data) = data {
nonce_account.nonce = Some(data.blockhash.to_string());
nonce_account.lamports_per_signature = Some(data.fee_calculator.lamports_per_signature);
nonce_account.authority = Some(data.authority.to_string());
@@ -607,21 +517,19 @@ pub fn process_withdraw_from_nonce_account(
config: &CliConfig,
nonce_account: &Pubkey,
nonce_authority: SignerIndex,
memo: Option<&String>,
destination_account_pubkey: &Pubkey,
lamports: u64,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let nonce_authority = config.signers[nonce_authority];
let ixs = vec![withdraw_nonce_account(
let ix = withdraw_nonce_account(
nonce_account,
&nonce_authority.pubkey(),
destination_account_pubkey,
lamports,
)]
.with_memo(memo);
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
);
let message = Message::new(&[ix], Some(&config.signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, recent_blockhash)?;
check_account_for_fee_with_commitment(
@@ -631,21 +539,8 @@ pub fn process_withdraw_from_nonce_account(
&tx.message,
config.commitment,
)?;
let merge_errors =
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
if merge_errors {
log_instruction_custom_error::<SystemError>(result, config)
} else {
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
if let InstructionError::Custom(_) = ix_error {
instruction_to_nonce_error(ix_error, merge_errors)
} else {
None
}
})
}
log_instruction_custom_error::<NonceError>(result, &config)
}
#[cfg(test)]
@@ -675,7 +570,10 @@ mod tests {
let default_keypair = Keypair::new();
let (default_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
let default_signer = DefaultSigner::new("", &default_keypair_file);
let default_signer = DefaultSigner {
path: default_keypair_file.clone(),
arg_name: String::new(),
};
let (keypair_file, mut tmp_file) = make_tmp_file();
let nonce_account_keypair = Keypair::new();
write_keypair(&nonce_account_keypair, tmp_file.as_file_mut()).unwrap();
@@ -699,7 +597,6 @@ mod tests {
command: CliCommand::AuthorizeNonceAccount {
nonce_account: nonce_account_pubkey,
nonce_authority: 0,
memo: None,
new_authority: Pubkey::default(),
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
@@ -721,7 +618,6 @@ mod tests {
command: CliCommand::AuthorizeNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: 1,
memo: None,
new_authority: Pubkey::default(),
},
signers: vec![
@@ -745,7 +641,6 @@ mod tests {
nonce_account: 1,
seed: None,
nonce_authority: None,
memo: None,
amount: SpendAmount::Some(50_000_000_000),
},
signers: vec![
@@ -771,7 +666,6 @@ mod tests {
nonce_account: 1,
seed: None,
nonce_authority: Some(nonce_authority_keypair.pubkey()),
memo: None,
amount: SpendAmount::Some(50_000_000_000),
},
signers: vec![
@@ -807,7 +701,6 @@ mod tests {
command: CliCommand::NewNonce {
nonce_account: nonce_account.pubkey(),
nonce_authority: 0,
memo: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@@ -828,7 +721,6 @@ mod tests {
command: CliCommand::NewNonce {
nonce_account: nonce_account.pubkey(),
nonce_authority: 1,
memo: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -873,7 +765,6 @@ mod tests {
command: CliCommand::WithdrawFromNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: 0,
memo: None,
destination_account_pubkey: nonce_account_pubkey,
lamports: 42_000_000_000
},
@@ -902,7 +793,6 @@ mod tests {
command: CliCommand::WithdrawFromNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
nonce_authority: 1,
memo: None,
destination_account_pubkey: nonce_account_pubkey,
lamports: 42_000_000_000
},

View File

@@ -1,3 +1,4 @@
use crate::send_tpu::{get_leader_tpus, send_transaction_tpu};
use crate::{
checks::*,
cli::{
@@ -5,6 +6,7 @@ use crate::{
ProcessResult,
},
};
use bincode::serialize;
use bip39::{Language, Mnemonic, MnemonicType, Seed};
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use log::*;
@@ -23,7 +25,7 @@ use solana_client::{
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType},
rpc_request::MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS,
tpu_client::{TpuClient, TpuClientConfig},
rpc_response::RpcLeaderSchedule,
};
use solana_rbpf::vm::{Config, Executable};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
@@ -49,17 +51,20 @@ use solana_sdk::{
};
use solana_transaction_status::TransactionConfirmationStatus;
use std::{
cmp::min,
collections::HashMap,
error,
fs::File,
io::{Read, Write},
net::UdpSocket,
path::PathBuf,
sync::Arc,
thread::sleep,
time::Duration,
time::{Duration, Instant},
};
const DATA_CHUNK_SIZE: usize = 229; // Keep program chunks under PACKET_DATA_SIZE
const NUM_TPU_LEADERS: u64 = 2;
#[derive(Debug, PartialEq)]
pub enum ProgramCliCommand {
@@ -150,7 +155,7 @@ impl ProgramSubCommands for App<'_, '_> {
pubkey!(Arg::with_name("program_id")
.long("program-id")
.value_name("PROGRAM_ID"),
"Executable program's address, must be a keypair for initial deploys, can be a pubkey for upgrades \
"Executable program's address, must be a signer for initial deploys, can be a pubkey for upgrades \
[default: address of keypair at /path/to/program-keypair.json if present, otherwise a random address]"),
)
.arg(
@@ -381,17 +386,22 @@ pub fn parse_program_subcommand(
default_signer.signer_from_path(matches, wallet_manager)?,
)];
let program_location = matches
.value_of("program_location")
.map(|location| location.to_string());
let program_location = if let Some(location) = matches.value_of("program_location") {
Some(location.to_string())
} else {
None
};
let buffer_pubkey = if let Ok((buffer_signer, Some(buffer_pubkey))) =
signer_of(matches, "buffer", wallet_manager)
{
bulk_signers.push(buffer_signer);
Some(buffer_pubkey)
} else if let Some(buffer_pubkey) = pubkey_of_signer(matches, "buffer", wallet_manager)?
{
Some(buffer_pubkey)
} else {
pubkey_of_signer(matches, "buffer", wallet_manager)?
None
};
let program_pubkey = if let Ok((program_signer, Some(program_pubkey))) =
@@ -399,8 +409,12 @@ pub fn parse_program_subcommand(
{
bulk_signers.push(program_signer);
Some(program_pubkey)
} else {
} else if let Some(program_pubkey) =
pubkey_of_signer(matches, "program_id", wallet_manager)?
{
Some(program_pubkey)
} else {
None
};
let upgrade_authority_pubkey =
@@ -449,8 +463,11 @@ pub fn parse_program_subcommand(
{
bulk_signers.push(buffer_signer);
Some(buffer_pubkey)
} else if let Some(buffer_pubkey) = pubkey_of_signer(matches, "buffer", wallet_manager)?
{
Some(buffer_pubkey)
} else {
pubkey_of_signer(matches, "buffer", wallet_manager)?
None
};
let buffer_authority_pubkey =
@@ -617,7 +634,7 @@ pub fn parse_program_subcommand(
}
pub fn process_program_subcommand(
rpc_client: Arc<RpcClient>,
rpc_client: &RpcClient,
config: &CliConfig,
program_subcommand: &ProgramCliCommand,
) -> ProcessResult {
@@ -633,7 +650,7 @@ pub fn process_program_subcommand(
max_len,
allow_excessive_balance,
} => process_program_deploy(
rpc_client,
&rpc_client,
config,
program_location,
*program_signer_index,
@@ -652,7 +669,7 @@ pub fn process_program_subcommand(
buffer_authority_signer_index,
max_len,
} => process_write_buffer(
rpc_client,
&rpc_client,
config,
program_location,
*buffer_signer_index,
@@ -741,7 +758,7 @@ fn get_default_program_keypair(program_location: &Option<String>) -> Keypair {
/// Deploy using upgradeable loader
#[allow(clippy::too_many_arguments)]
fn process_program_deploy(
rpc_client: Arc<RpcClient>,
rpc_client: &RpcClient,
config: &CliConfig,
program_location: &Option<String>,
program_signer_index: Option<SignerIndex>,
@@ -767,7 +784,7 @@ fn process_program_deploy(
};
let upgrade_authority_signer = config.signers[upgrade_authority_signer_index];
let default_program_keypair = get_default_program_keypair(program_location);
let default_program_keypair = get_default_program_keypair(&program_location);
let (program_signer, program_pubkey) = if let Some(i) = program_signer_index {
(Some(config.signers[i]), config.signers[i].pubkey())
} else if let Some(program_pubkey) = program_pubkey {
@@ -843,7 +860,7 @@ fn process_program_deploy(
};
let (program_data, program_len) = if let Some(program_location) = program_location {
let program_data = read_and_verify_elf(program_location)?;
let program_data = read_and_verify_elf(&program_location)?;
let program_len = program_data.len();
(program_data, program_len)
} else if buffer_provided {
@@ -886,13 +903,8 @@ fn process_program_deploy(
)?;
let result = if do_deploy {
if program_signer.is_none() {
return Err(
"Initial deployments require a keypair be provided for the program id".into(),
);
}
do_process_program_write_and_deploy(
rpc_client.clone(),
rpc_client,
config,
&program_data,
buffer_data_len,
@@ -907,7 +919,7 @@ fn process_program_deploy(
)
} else {
do_process_program_upgrade(
rpc_client.clone(),
rpc_client,
config,
&program_data,
&program_pubkey,
@@ -918,7 +930,7 @@ fn process_program_deploy(
};
if result.is_ok() && is_final {
process_set_authority(
&rpc_client,
rpc_client,
config,
Some(program_pubkey),
None,
@@ -933,7 +945,7 @@ fn process_program_deploy(
}
fn process_write_buffer(
rpc_client: Arc<RpcClient>,
rpc_client: &RpcClient,
config: &CliConfig,
program_location: &str,
buffer_signer_index: Option<SignerIndex>,
@@ -1107,7 +1119,6 @@ fn get_buffers(
data_slice: Some(UiDataSliceConfig { offset: 0, length }),
..RpcAccountInfoConfig::default()
},
..RpcProgramAccountsConfig::default()
},
)?;
Ok(results)
@@ -1259,7 +1270,7 @@ fn process_dump(
UpgradeableLoaderState::programdata_data_offset().unwrap_or(0);
let program_data = &programdata_account.data[offset..];
let mut f = File::create(output_location)?;
f.write_all(program_data)?;
f.write_all(&program_data)?;
Ok(format!("Wrote program to {}", output_location))
} else {
Err(
@@ -1279,7 +1290,7 @@ fn process_dump(
let offset = UpgradeableLoaderState::buffer_data_offset().unwrap_or(0);
let program_data = &account.data[offset..];
let mut f = File::create(output_location)?;
f.write_all(program_data)?;
f.write_all(&program_data)?;
Ok(format!("Wrote program to {}", output_location))
} else {
Err(format!(
@@ -1310,8 +1321,8 @@ fn close(
let mut tx = Transaction::new_unsigned(Message::new(
&[bpf_loader_upgradeable::close(
account_pubkey,
recipient_pubkey,
&account_pubkey,
&recipient_pubkey,
&authority_signer.pubkey(),
)],
Some(&config.signers[0].pubkey()),
@@ -1412,7 +1423,6 @@ fn process_close(
data_slice: Some(UiDataSliceConfig { offset: 0, length }),
..RpcAccountInfoConfig::default()
},
..RpcProgramAccountsConfig::default()
},
)?;
@@ -1420,7 +1430,7 @@ fn process_close(
if close(
rpc_client,
config,
address,
&address,
&recipient_pubkey,
authority_signer,
)
@@ -1452,7 +1462,7 @@ fn process_close(
/// Deploy using non-upgradeable loader
pub fn process_deploy(
rpc_client: Arc<RpcClient>,
rpc_client: &RpcClient,
config: &CliConfig,
program_location: &str,
buffer_signer_index: Option<SignerIndex>,
@@ -1497,7 +1507,7 @@ pub fn process_deploy(
#[allow(clippy::too_many_arguments)]
fn do_process_program_write_and_deploy(
rpc_client: Arc<RpcClient>,
rpc_client: &RpcClient,
config: &CliConfig,
program_data: &[u8],
buffer_data_len: usize,
@@ -1521,7 +1531,7 @@ fn do_process_program_write_and_deploy(
.value
{
complete_partial_program_init(
loader_id,
&loader_id,
&config.signers[0].pubkey(),
buffer_pubkey,
&account,
@@ -1551,7 +1561,7 @@ fn do_process_program_write_and_deploy(
buffer_pubkey,
minimum_balance,
buffer_data_len as u64,
loader_id,
&loader_id,
)],
minimum_balance,
)
@@ -1579,7 +1589,7 @@ fn do_process_program_write_and_deploy(
} else {
loader_instruction::write(
buffer_pubkey,
loader_id,
&loader_id,
(i * DATA_CHUNK_SIZE) as u32,
chunk.to_vec(),
)
@@ -1623,7 +1633,7 @@ fn do_process_program_write_and_deploy(
)
} else {
Message::new(
&[loader_instruction::finalize(buffer_pubkey, loader_id)],
&[loader_instruction::finalize(buffer_pubkey, &loader_id)],
Some(&config.signers[0].pubkey()),
)
};
@@ -1635,7 +1645,7 @@ fn do_process_program_write_and_deploy(
messages.push(message);
}
check_payer(&rpc_client, config, balance_needed, &messages)?;
check_payer(rpc_client, config, balance_needed, &messages)?;
send_deploy_messages(
rpc_client,
@@ -1662,7 +1672,7 @@ fn do_process_program_write_and_deploy(
}
fn do_process_program_upgrade(
rpc_client: Arc<RpcClient>,
rpc_client: &RpcClient,
config: &CliConfig,
program_data: &[u8],
program_id: &Pubkey,
@@ -1749,8 +1759,8 @@ fn do_process_program_upgrade(
// Create and add final message
let final_message = Message::new(
&[bpf_loader_upgradeable::upgrade(
program_id,
buffer_pubkey,
&program_id,
&buffer_pubkey,
&upgrade_authority.pubkey(),
&config.signers[0].pubkey(),
)],
@@ -1758,7 +1768,7 @@ fn do_process_program_upgrade(
);
messages.push(&final_message);
check_payer(&rpc_client, config, balance_needed, &messages)?;
check_payer(rpc_client, config, balance_needed, &messages)?;
send_deploy_messages(
rpc_client,
config,
@@ -1784,7 +1794,7 @@ fn read_and_verify_elf(program_location: &str) -> Result<Vec<u8>, Box<dyn std::e
.map_err(|err| format!("Unable to read program file: {}", err))?;
// Verify the program
<dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
Executable::<BpfError, ThisInstructionMeter>::from_elf(
&program_data,
Some(|x| bpf_verifier::check(x)),
Config::default(),
@@ -1818,7 +1828,7 @@ fn complete_partial_program_init(
account_data_len as u64,
));
if account.owner != *loader_id {
instructions.push(system_instruction::assign(elf_pubkey, loader_id));
instructions.push(system_instruction::assign(elf_pubkey, &loader_id));
}
}
if account.lamports < minimum_balance {
@@ -1863,7 +1873,7 @@ fn check_payer(
}
fn send_deploy_messages(
rpc_client: Arc<RpcClient>,
rpc_client: &RpcClient,
config: &CliConfig,
initial_message: &Option<Message>,
write_messages: &Option<Vec<Message>>,
@@ -1890,7 +1900,7 @@ fn send_deploy_messages(
initial_transaction.try_sign(&[payer_signer], blockhash)?;
}
let result = rpc_client.send_and_confirm_transaction_with_spinner(&initial_transaction);
log_instruction_custom_error::<SystemError>(result, config)
log_instruction_custom_error::<SystemError>(result, &config)
.map_err(|err| format!("Account allocation failed: {}", err))?;
} else {
return Err("Buffer account not created yet, must provide a key pair".into());
@@ -1911,8 +1921,7 @@ fn send_deploy_messages(
}
send_and_confirm_transactions_with_spinner(
rpc_client.clone(),
&config.websocket_url,
&rpc_client,
write_transactions,
&[payer_signer, write_signer],
config.commitment,
@@ -1981,8 +1990,7 @@ fn report_ephemeral_mnemonic(words: usize, mnemonic: bip39::Mnemonic) {
}
fn send_and_confirm_transactions_with_spinner<T: Signers>(
rpc_client: Arc<RpcClient>,
websocket_url: &str,
rpc_client: &RpcClient,
mut transactions: Vec<Transaction>,
signer_keys: &T,
commitment: CommitmentConfig,
@@ -1990,19 +1998,39 @@ fn send_and_confirm_transactions_with_spinner<T: Signers>(
) -> Result<(), Box<dyn error::Error>> {
let progress_bar = new_spinner_progress_bar();
let mut send_retries = 5;
let mut leader_schedule: Option<RpcLeaderSchedule> = None;
let mut leader_schedule_epoch = 0;
let send_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
let cluster_nodes = rpc_client.get_cluster_nodes().ok();
progress_bar.set_message("Finding leader nodes...");
let tpu_client = TpuClient::new(
rpc_client.clone(),
websocket_url,
TpuClientConfig::default(),
)?;
loop {
progress_bar.set_message("Finding leader nodes...");
let epoch_info = rpc_client.get_epoch_info()?;
let mut slot = epoch_info.absolute_slot;
let mut last_epoch_fetch = Instant::now();
if epoch_info.epoch > leader_schedule_epoch || leader_schedule.is_none() {
leader_schedule = rpc_client.get_leader_schedule(Some(epoch_info.absolute_slot))?;
leader_schedule_epoch = epoch_info.epoch;
}
let mut tpu_addresses = get_leader_tpus(
min(epoch_info.slot_index + 1, epoch_info.slots_in_epoch),
NUM_TPU_LEADERS,
leader_schedule.as_ref(),
cluster_nodes.as_ref(),
);
// Send all transactions
let mut pending_transactions = HashMap::new();
let num_transactions = transactions.len();
for transaction in transactions {
if !tpu_client.send_transaction(&transaction) {
if !tpu_addresses.is_empty() {
let wire_transaction =
serialize(&transaction).expect("serialization should succeed");
for tpu_address in &tpu_addresses {
send_transaction_tpu(&send_socket, &tpu_address, &wire_transaction);
}
} else {
let _result = rpc_client
.send_transaction_with_config(
&transaction,
@@ -2022,11 +2050,22 @@ fn send_and_confirm_transactions_with_spinner<T: Signers>(
// Throttle transactions to about 100 TPS
sleep(Duration::from_millis(10));
// Update leader periodically
if last_epoch_fetch.elapsed() > Duration::from_millis(400) {
let epoch_info = rpc_client.get_epoch_info()?;
last_epoch_fetch = Instant::now();
tpu_addresses = get_leader_tpus(
min(epoch_info.slot_index + 1, epoch_info.slots_in_epoch),
NUM_TPU_LEADERS,
leader_schedule.as_ref(),
cluster_nodes.as_ref(),
);
}
}
// Collect statuses for all the transactions, drop those that are confirmed
loop {
let mut slot = 0;
let pending_signatures = pending_transactions.keys().cloned().collect::<Vec<_>>();
for pending_signatures_chunk in
pending_signatures.chunks(MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS)
@@ -2068,8 +2107,22 @@ fn send_and_confirm_transactions_with_spinner<T: Signers>(
break;
}
let epoch_info = rpc_client.get_epoch_info()?;
tpu_addresses = get_leader_tpus(
min(epoch_info.slot_index + 1, epoch_info.slots_in_epoch),
NUM_TPU_LEADERS,
leader_schedule.as_ref(),
cluster_nodes.as_ref(),
);
for transaction in pending_transactions.values() {
if !tpu_client.send_transaction(transaction) {
if !tpu_addresses.is_empty() {
let wire_transaction =
serialize(&transaction).expect("serialization should succeed");
for tpu_address in &tpu_addresses {
send_transaction_tpu(&send_socket, &tpu_address, &wire_transaction);
}
} else {
let _result = rpc_client
.send_transaction_with_config(
transaction,
@@ -2136,16 +2189,19 @@ mod tests {
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let default_signer = DefaultSigner::new("", &keypair_file);
let default_signer = DefaultSigner {
path: keypair_file.clone(),
arg_name: "".to_string(),
};
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"deploy",
"/Users/test/program.so",
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some("/Users/test/program.so".to_string()),
@@ -2162,7 +2218,7 @@ mod tests {
}
);
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"deploy",
@@ -2171,7 +2227,7 @@ mod tests {
"42",
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some("/Users/test/program.so".to_string()),
@@ -2191,7 +2247,7 @@ mod tests {
let buffer_keypair = Keypair::new();
let buffer_keypair_file = make_tmp_path("buffer_keypair_file");
write_keypair_file(&buffer_keypair, &buffer_keypair_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"deploy",
@@ -2199,7 +2255,7 @@ mod tests {
&buffer_keypair_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::Deploy {
program_location: None,
@@ -2281,7 +2337,7 @@ mod tests {
let authority_keypair = Keypair::new();
let authority_keypair_file = make_tmp_path("authority_keypair_file");
write_keypair_file(&authority_keypair, &authority_keypair_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"deploy",
@@ -2290,7 +2346,7 @@ mod tests {
&authority_keypair_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some("/Users/test/program.so".to_string()),
@@ -2310,7 +2366,7 @@ mod tests {
}
);
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"deploy",
@@ -2318,7 +2374,7 @@ mod tests {
"--final",
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some("/Users/test/program.so".to_string()),
@@ -2344,17 +2400,20 @@ mod tests {
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let default_signer = DefaultSigner::new("", &keypair_file);
let default_signer = DefaultSigner {
path: keypair_file.clone(),
arg_name: "".to_string(),
};
// defaults
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"write-buffer",
"/Users/test/program.so",
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: "/Users/test/program.so".to_string(),
@@ -2368,7 +2427,7 @@ mod tests {
);
// specify max len
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"write-buffer",
@@ -2377,7 +2436,7 @@ mod tests {
"42",
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: "/Users/test/program.so".to_string(),
@@ -2394,7 +2453,7 @@ mod tests {
let buffer_keypair = Keypair::new();
let buffer_keypair_file = make_tmp_path("buffer_keypair_file");
write_keypair_file(&buffer_keypair, &buffer_keypair_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"write-buffer",
@@ -2403,7 +2462,7 @@ mod tests {
&buffer_keypair_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: "/Users/test/program.so".to_string(),
@@ -2423,7 +2482,7 @@ mod tests {
let authority_keypair = Keypair::new();
let authority_keypair_file = make_tmp_path("authority_keypair_file");
write_keypair_file(&authority_keypair, &authority_keypair_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"write-buffer",
@@ -2432,7 +2491,7 @@ mod tests {
&authority_keypair_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: "/Users/test/program.so".to_string(),
@@ -2455,7 +2514,7 @@ mod tests {
let authority_keypair = Keypair::new();
let authority_keypair_file = make_tmp_path("authority_keypair_file");
write_keypair_file(&authority_keypair, &authority_keypair_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"write-buffer",
@@ -2466,7 +2525,7 @@ mod tests {
&authority_keypair_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::WriteBuffer {
program_location: "/Users/test/program.so".to_string(),
@@ -2492,11 +2551,14 @@ mod tests {
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let default_signer = DefaultSigner::new("", &keypair_file);
let default_signer = DefaultSigner {
path: keypair_file.clone(),
arg_name: "".to_string(),
};
let program_pubkey = Pubkey::new_unique();
let new_authority_pubkey = Pubkey::new_unique();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"set-upgrade-authority",
@@ -2505,7 +2567,7 @@ mod tests {
&new_authority_pubkey.to_string(),
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::SetUpgradeAuthority {
program_pubkey,
@@ -2520,7 +2582,7 @@ mod tests {
let new_authority_pubkey = Keypair::new();
let new_authority_pubkey_file = make_tmp_path("authority_keypair_file");
write_keypair_file(&new_authority_pubkey, &new_authority_pubkey_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"set-upgrade-authority",
@@ -2529,7 +2591,7 @@ mod tests {
&new_authority_pubkey_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::SetUpgradeAuthority {
program_pubkey,
@@ -2544,7 +2606,7 @@ mod tests {
let new_authority_pubkey = Keypair::new();
let new_authority_pubkey_file = make_tmp_path("authority_keypair_file");
write_keypair_file(&new_authority_pubkey, &new_authority_pubkey_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"set-upgrade-authority",
@@ -2552,7 +2614,7 @@ mod tests {
"--final",
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::SetUpgradeAuthority {
program_pubkey,
@@ -2567,7 +2629,7 @@ mod tests {
let authority = Keypair::new();
let authority_keypair_file = make_tmp_path("authority_keypair_file");
write_keypair_file(&authority, &authority_keypair_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"set-upgrade-authority",
@@ -2577,7 +2639,7 @@ mod tests {
"--final",
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::SetUpgradeAuthority {
program_pubkey,
@@ -2600,11 +2662,14 @@ mod tests {
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let default_signer = DefaultSigner::new("", &keypair_file);
let default_signer = DefaultSigner {
path: keypair_file.clone(),
arg_name: "".to_string(),
};
let buffer_pubkey = Pubkey::new_unique();
let new_authority_pubkey = Pubkey::new_unique();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"set-buffer-authority",
@@ -2613,7 +2678,7 @@ mod tests {
&new_authority_pubkey.to_string(),
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::SetBufferAuthority {
buffer_pubkey,
@@ -2628,7 +2693,7 @@ mod tests {
let new_authority_keypair = Keypair::new();
let new_authority_keypair_file = make_tmp_path("authority_keypair_file");
write_keypair_file(&new_authority_keypair, &new_authority_keypair_file).unwrap();
let test_command = test_commands.clone().get_matches_from(vec![
let test_deploy = test_commands.clone().get_matches_from(vec![
"test",
"program",
"set-buffer-authority",
@@ -2637,7 +2702,7 @@ mod tests {
&new_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_command, &default_signer, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Program(ProgramCliCommand::SetBufferAuthority {
buffer_pubkey,
@@ -2657,7 +2722,10 @@ mod tests {
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let default_signer = DefaultSigner::new("", &keypair_file);
let default_signer = DefaultSigner {
path: keypair_file,
arg_name: "".to_string(),
};
// defaults
let buffer_pubkey = Pubkey::new_unique();
@@ -2756,7 +2824,10 @@ mod tests {
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let default_signer = DefaultSigner::new("", &keypair_file);
let default_signer = DefaultSigner {
path: keypair_file.clone(),
arg_name: "".to_string(),
};
// defaults
let buffer_pubkey = Pubkey::new_unique();
@@ -2874,7 +2945,7 @@ mod tests {
write_keypair_file(&program_pubkey, &program_keypair_location).unwrap();
let config = CliConfig {
rpc_client: Some(Arc::new(RpcClient::new_mock("".to_string()))),
rpc_client: Some(RpcClient::new_mock("".to_string())),
command: CliCommand::Program(ProgramCliCommand::Deploy {
program_location: Some(program_location.to_str().unwrap().to_string()),
buffer_signer_index: None,

46
cli/src/send_tpu.rs Normal file
View File

@@ -0,0 +1,46 @@
use log::*;
use solana_client::rpc_response::{RpcContactInfo, RpcLeaderSchedule};
use solana_sdk::clock::NUM_CONSECUTIVE_LEADER_SLOTS;
use std::net::{SocketAddr, UdpSocket};
pub fn get_leader_tpus(
slot_index: u64,
num_leaders: u64,
leader_schedule: Option<&RpcLeaderSchedule>,
cluster_nodes: Option<&Vec<RpcContactInfo>>,
) -> Vec<SocketAddr> {
let leaders: Vec<_> = (0..num_leaders)
.filter_map(|i| {
leader_schedule?
.iter()
.find(|(_pubkey, slots)| {
slots.iter().any(|slot| {
*slot as u64 == (slot_index + (i * NUM_CONSECUTIVE_LEADER_SLOTS))
})
})
.and_then(|(pubkey, _)| {
cluster_nodes?
.iter()
.find(|contact_info| contact_info.pubkey == *pubkey)
.and_then(|contact_info| contact_info.tpu)
})
})
.collect();
let mut unique_leaders = vec![];
for leader in leaders.into_iter() {
if !unique_leaders.contains(&leader) {
unique_leaders.push(leader);
}
}
unique_leaders
}
pub fn send_transaction_tpu(
send_socket: &UdpSocket,
tpu_address: &SocketAddr,
wire_transaction: &[u8],
) {
if let Err(err) = send_socket.send_to(wire_transaction, tpu_address) {
warn!("Failed to send transaction to {}: {:?}", tpu_address, err);
}
}

View File

@@ -92,7 +92,7 @@ where
Ok((message, spend))
} else {
let from_balance = rpc_client
.get_balance_with_commitment(from_pubkey, commitment)?
.get_balance_with_commitment(&from_pubkey, commitment)?
.value;
let (message, SpendAndFee { spend, fee }) = resolve_spend_message(
amount,

File diff suppressed because it is too large Load Diff

View File

@@ -119,7 +119,7 @@ fn parse_validator_info(
let key_list: ConfigKeys = deserialize(&account.data)?;
if !key_list.keys.is_empty() {
let (validator_pubkey, _) = key_list.keys[1];
let validator_info_string: String = deserialize(get_config_data(&account.data)?)?;
let validator_info_string: String = deserialize(&get_config_data(&account.data)?)?;
let validator_info: Map<_, _> = serde_json::from_str(&validator_info_string)?;
Ok((validator_pubkey, validator_info))
} else {
@@ -246,7 +246,7 @@ pub fn process_set_validator_info(
) -> ProcessResult {
// Validate keybase username
if let Some(string) = validator_info.get("keybaseUsername") {
let result = verify_keybase(&config.signers[0].pubkey(), string);
let result = verify_keybase(&config.signers[0].pubkey(), &string);
if result.is_err() {
if force_keybase {
println!("--force supplied, ignoring: {:?}", result);
@@ -272,7 +272,7 @@ pub fn process_set_validator_info(
},
)
.find(|(pubkey, account)| {
let (validator_pubkey, _) = parse_validator_info(pubkey, account).unwrap();
let (validator_pubkey, _) = parse_validator_info(&pubkey, &account).unwrap();
validator_pubkey == config.signers[0].pubkey()
});
@@ -393,7 +393,7 @@ pub fn process_get_validator_info(
}
for (validator_info_pubkey, validator_info_account) in validator_info.iter() {
let (validator_pubkey, validator_info) =
parse_validator_info(validator_info_pubkey, validator_info_account)?;
parse_validator_info(&validator_info_pubkey, &validator_info_account)?;
validator_info_list.push(CliValidatorInfo {
identity_pubkey: validator_pubkey.to_string(),
info_pubkey: validator_info_pubkey.to_string(),
@@ -451,7 +451,7 @@ mod tests {
"name": "Alice",
"keybaseUsername": "alice_keybase",
});
assert_eq!(parse_args(matches), expected);
assert_eq!(parse_args(&matches), expected);
}
#[test]

View File

@@ -4,7 +4,6 @@ use crate::{
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
memo::WithMemo,
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
@@ -12,7 +11,6 @@ use solana_clap_utils::{
input_parsers::*,
input_validators::*,
keypair::{DefaultSigner, SignerIndex},
memo::{memo_arg, MEMO_ARG},
};
use solana_cli_output::{CliEpochVotingHistory, CliLockout, CliVoteAccount};
use solana_client::rpc_client::RpcClient;
@@ -81,8 +79,7 @@ impl VoteSubCommands for App<'_, '_> {
.value_name("STRING")
.takes_value(true)
.help("Seed for address generation; if specified, the resulting account will be at a derived address of the VOTE ACCOUNT pubkey")
)
.arg(memo_arg())
),
)
.subcommand(
SubCommand::with_name("vote-authorize-voter")
@@ -108,8 +105,7 @@ impl VoteSubCommands for App<'_, '_> {
.value_name("NEW_AUTHORIZED_PUBKEY")
.required(true),
"New authorized vote signer. "),
)
.arg(memo_arg())
),
)
.subcommand(
SubCommand::with_name("vote-authorize-withdrawer")
@@ -135,66 +131,7 @@ impl VoteSubCommands for App<'_, '_> {
.value_name("AUTHORIZED_PUBKEY")
.required(true),
"New authorized withdrawer. "),
)
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-authorize-voter-checked")
.about("Authorize a new vote signing keypair for the given vote account, \
checking the new authority as a signer")
.arg(
pubkey!(Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE_ACCOUNT_ADDRESS")
.required(true),
"Vote account in which to set the authorized voter. "),
)
.arg(
Arg::with_name("authorized")
.index(2)
.value_name("AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("Current authorized vote signer."),
)
.arg(
Arg::with_name("new_authorized")
.index(3)
.value_name("NEW_AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("New authorized vote signer."),
)
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-authorize-withdrawer-checked")
.about("Authorize a new withdraw signing keypair for the given vote account, \
checking the new authority as a signer")
.arg(
pubkey!(Arg::with_name("vote_account_pubkey")
.index(1)
.value_name("VOTE_ACCOUNT_ADDRESS")
.required(true),
"Vote account in which to set the authorized withdrawer. "),
)
.arg(
Arg::with_name("authorized")
.index(2)
.value_name("AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("Current authorized withdrawer."),
)
.arg(
Arg::with_name("new_authorized")
.index(3)
.value_name("NEW_AUTHORIZED_KEYPAIR")
.required(true)
.validator(is_valid_signer)
.help("New authorized withdrawer."),
)
.arg(memo_arg())
),
)
.subcommand(
SubCommand::with_name("vote-update-validator")
@@ -224,7 +161,6 @@ impl VoteSubCommands for App<'_, '_> {
.validator(is_valid_signer)
.help("Authorized withdrawer keypair"),
)
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-update-commission")
@@ -254,7 +190,6 @@ impl VoteSubCommands for App<'_, '_> {
.validator(is_valid_signer)
.help("Authorized withdrawer keypair"),
)
.arg(memo_arg())
)
.subcommand(
SubCommand::with_name("vote-account")
@@ -272,22 +207,6 @@ impl VoteSubCommands for App<'_, '_> {
.long("lamports")
.takes_value(false)
.help("Display balance in lamports instead of SOL"),
)
.arg(
Arg::with_name("with_rewards")
.long("with-rewards")
.takes_value(false)
.help("Display inflation rewards"),
)
.arg(
Arg::with_name("num_rewards_epochs")
.long("num-rewards-epochs")
.takes_value(true)
.value_name("NUM")
.validator(|s| is_within_range(s, 1, 10))
.default_value_if("with_rewards", None, "1")
.requires("with_rewards")
.help("Display rewards for NUM recent epochs, max 10 [default: latest epoch only]"),
),
)
.subcommand(
@@ -324,7 +243,6 @@ impl VoteSubCommands for App<'_, '_> {
.validator(is_valid_signer)
.help("Authorized withdrawer [default: cli config keypair]"),
)
.arg(memo_arg())
)
}
}
@@ -341,7 +259,6 @@ pub fn parse_create_vote_account(
let commission = value_t_or_exit!(matches, "commission", u8);
let authorized_voter = pubkey_of_signer(matches, "authorized_voter", wallet_manager)?;
let authorized_withdrawer = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
let payer_provided = None;
let signer_info = default_signer.generate_unique_signers(
@@ -358,7 +275,6 @@ pub fn parse_create_vote_account(
authorized_voter,
authorized_withdrawer,
commission,
memo,
},
signers: signer_info.signers,
})
@@ -369,39 +285,25 @@ pub fn parse_vote_authorize(
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
vote_authorize: VoteAuthorize,
checked: bool,
) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey =
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
let (authorized, authorized_pubkey) = signer_of(matches, "authorized", wallet_manager)?;
let new_authorized_pubkey =
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap();
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
let payer_provided = None;
let mut signers = vec![payer_provided, authorized];
let new_authorized_pubkey = if checked {
let (new_authorized_signer, new_authorized_pubkey) =
signer_of(matches, "new_authorized", wallet_manager)?;
signers.push(new_authorized_signer);
new_authorized_pubkey.unwrap()
} else {
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap()
};
let signer_info = default_signer.generate_unique_signers(signers, matches, wallet_manager)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, authorized],
matches,
wallet_manager,
)?;
Ok(CliCommandInfo {
command: CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey,
vote_authorize,
memo,
authorized: signer_info.index_of(authorized_pubkey).unwrap(),
new_authorized: if checked {
signer_info.index_of(Some(new_authorized_pubkey))
} else {
None
},
},
signers: signer_info.signers,
})
@@ -425,14 +327,12 @@ pub fn parse_vote_update_validator(
matches,
wallet_manager,
)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
Ok(CliCommandInfo {
command: CliCommand::VoteUpdateValidator {
vote_account_pubkey,
new_identity_account: signer_info.index_of(new_identity_pubkey).unwrap(),
withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(),
memo,
},
signers: signer_info.signers,
})
@@ -455,14 +355,12 @@ pub fn parse_vote_update_commission(
matches,
wallet_manager,
)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
Ok(CliCommandInfo {
command: CliCommand::VoteUpdateCommission {
vote_account_pubkey,
commission,
withdraw_authority: signer_info.index_of(authorized_withdrawer_pubkey).unwrap(),
memo,
},
signers: signer_info.signers,
})
@@ -475,16 +373,10 @@ pub fn parse_vote_get_account_command(
let vote_account_pubkey =
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
let use_lamports_unit = matches.is_present("lamports");
let with_rewards = if matches.is_present("with_rewards") {
Some(value_of(matches, "num_rewards_epochs").unwrap())
} else {
None
};
Ok(CliCommandInfo {
command: CliCommand::ShowVoteAccount {
pubkey: vote_account_pubkey,
use_lamports_unit,
with_rewards,
},
signers: vec![],
})
@@ -510,7 +402,6 @@ pub fn parse_withdraw_from_vote_account(
matches,
wallet_manager,
)?;
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
Ok(CliCommandInfo {
command: CliCommand::WithdrawFromVoteAccount {
@@ -518,7 +409,6 @@ pub fn parse_withdraw_from_vote_account(
destination_account_pubkey,
withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(),
withdraw_amount,
memo,
},
signers: signer_info.signers,
})
@@ -533,12 +423,11 @@ pub fn process_create_vote_account(
authorized_voter: &Option<Pubkey>,
authorized_withdrawer: &Option<Pubkey>,
commission: u8,
memo: Option<&String>,
) -> ProcessResult {
let vote_account = config.signers[vote_account];
let vote_account_pubkey = vote_account.pubkey();
let vote_account_address = if let Some(seed) = seed {
Pubkey::create_with_seed(&vote_account_pubkey, seed, &solana_vote_program::id())?
Pubkey::create_with_seed(&vote_account_pubkey, &seed, &solana_vote_program::id())?
} else {
vote_account_pubkey
};
@@ -576,7 +465,6 @@ pub fn process_create_vote_account(
&vote_init,
lamports,
)
.with_memo(memo)
} else {
vote_instruction::create_account(
&config.signers[0].pubkey(),
@@ -584,7 +472,6 @@ pub fn process_create_vote_account(
&vote_init,
lamports,
)
.with_memo(memo)
};
Message::new(&ixs, Some(&config.signers[0].pubkey()))
};
@@ -619,7 +506,7 @@ pub fn process_create_vote_account(
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, recent_blockhash)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<SystemError>(result, config)
log_instruction_custom_error::<SystemError>(result, &config)
}
pub fn process_vote_authorize(
@@ -628,34 +515,26 @@ pub fn process_vote_authorize(
vote_account_pubkey: &Pubkey,
new_authorized_pubkey: &Pubkey,
vote_authorize: VoteAuthorize,
authorized: SignerIndex,
new_authorized: Option<SignerIndex>,
memo: Option<&String>,
) -> ProcessResult {
let authorized = config.signers[authorized];
let new_authorized_signer = new_authorized.map(|index| config.signers[index]);
// If the `authorized_account` is also the fee payer, `config.signers` will only have one
// keypair in it
let authorized = if config.signers.len() == 2 {
config.signers[1]
} else {
config.signers[0]
};
check_unique_pubkeys(
(&authorized.pubkey(), "authorized_account".to_string()),
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
)?;
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let vote_ix = if new_authorized_signer.is_some() {
vote_instruction::authorize_checked(
vote_account_pubkey, // vote account to update
&authorized.pubkey(), // current authorized
new_authorized_pubkey, // new vote signer/withdrawer
vote_authorize, // vote or withdraw
)
} else {
vote_instruction::authorize(
vote_account_pubkey, // vote account to update
&authorized.pubkey(), // current authorized
new_authorized_pubkey, // new vote signer/withdrawer
vote_authorize, // vote or withdraw
)
};
let ixs = vec![vote_ix].with_memo(memo);
let ixs = vec![vote_instruction::authorize(
vote_account_pubkey, // vote account to update
&authorized.pubkey(), // current authorized
new_authorized_pubkey, // new vote signer/withdrawer
vote_authorize, // vote or withdraw
)];
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
@@ -668,7 +547,7 @@ pub fn process_vote_authorize(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<VoteError>(result, config)
log_instruction_custom_error::<VoteError>(result, &config)
}
pub fn process_vote_update_validator(
@@ -677,7 +556,6 @@ pub fn process_vote_update_validator(
vote_account_pubkey: &Pubkey,
new_identity_account: SignerIndex,
withdraw_authority: SignerIndex,
memo: Option<&String>,
) -> ProcessResult {
let authorized_withdrawer = config.signers[withdraw_authority];
let new_identity_account = config.signers[new_identity_account];
@@ -691,8 +569,7 @@ pub fn process_vote_update_validator(
vote_account_pubkey,
&authorized_withdrawer.pubkey(),
&new_identity_pubkey,
)]
.with_memo(memo);
)];
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
@@ -705,7 +582,7 @@ pub fn process_vote_update_validator(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<VoteError>(result, config)
log_instruction_custom_error::<VoteError>(result, &config)
}
pub fn process_vote_update_commission(
@@ -714,7 +591,6 @@ pub fn process_vote_update_commission(
vote_account_pubkey: &Pubkey,
commission: u8,
withdraw_authority: SignerIndex,
memo: Option<&String>,
) -> ProcessResult {
let authorized_withdrawer = config.signers[withdraw_authority];
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
@@ -722,8 +598,7 @@ pub fn process_vote_update_commission(
vote_account_pubkey,
&authorized_withdrawer.pubkey(),
commission,
)]
.with_memo(memo);
)];
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
let mut tx = Transaction::new_unsigned(message);
@@ -736,7 +611,7 @@ pub fn process_vote_update_commission(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
log_instruction_custom_error::<VoteError>(result, config)
log_instruction_custom_error::<VoteError>(result, &config)
}
fn get_vote_account(
@@ -772,7 +647,6 @@ pub fn process_show_vote_account(
config: &CliConfig,
vote_account_address: &Pubkey,
use_lamports_unit: bool,
with_rewards: Option<usize>,
) -> ProcessResult {
let (vote_account, vote_state) =
get_vote_account(rpc_client, vote_account_address, config.commitment)?;
@@ -798,16 +672,14 @@ pub fn process_show_vote_account(
}
}
let epoch_rewards =
with_rewards.and_then(|num_epochs| {
match crate::stake::fetch_epoch_rewards(rpc_client, vote_account_address, num_epochs) {
Ok(rewards) => Some(rewards),
Err(error) => {
eprintln!("Failed to fetch epoch rewards: {:?}", error);
None
}
}
});
let epoch_rewards = match crate::stake::fetch_epoch_rewards(rpc_client, vote_account_address, 1)
{
Ok(rewards) => Some(rewards),
Err(error) => {
eprintln!("Failed to fetch epoch rewards: {:?}", error);
None
}
};
let vote_account_data = CliVoteAccount {
account_balance: vote_account.lamports,
@@ -834,12 +706,11 @@ pub fn process_withdraw_from_vote_account(
withdraw_authority: SignerIndex,
withdraw_amount: SpendAmount,
destination_account_pubkey: &Pubkey,
memo: Option<&String>,
) -> ProcessResult {
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
let withdraw_authority = config.signers[withdraw_authority];
let current_balance = rpc_client.get_balance(vote_account_pubkey)?;
let current_balance = rpc_client.get_balance(&vote_account_pubkey)?;
let minimum_balance = rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?;
let lamports = match withdraw_amount {
@@ -855,15 +726,14 @@ pub fn process_withdraw_from_vote_account(
}
};
let ixs = vec![withdraw(
let ix = withdraw(
vote_account_pubkey,
&withdraw_authority.pubkey(),
lamports,
destination_account_pubkey,
)]
.with_memo(memo);
);
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
let message = Message::new(&[ix], Some(&config.signers[0].pubkey()));
let mut transaction = Transaction::new_unsigned(message);
transaction.try_sign(&config.signers, recent_blockhash)?;
check_account_for_fee_with_commitment(
@@ -874,7 +744,7 @@ pub fn process_withdraw_from_vote_account(
config.commitment,
)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner(&transaction);
log_instruction_custom_error::<VoteError>(result, config)
log_instruction_custom_error::<VoteError>(result, &config)
}
#[cfg(test)]
@@ -902,7 +772,10 @@ mod tests {
let default_keypair = Keypair::new();
let (default_keypair_file, mut tmp_file) = make_tmp_file();
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
let default_signer = DefaultSigner::new("", &default_keypair_file);
let default_signer = DefaultSigner {
path: default_keypair_file.clone(),
arg_name: String::new(),
};
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
@@ -917,10 +790,7 @@ mod tests {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
new_authorized_pubkey: pubkey2,
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 0,
new_authorized: None,
vote_authorize: VoteAuthorize::Voter
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@@ -943,10 +813,7 @@ mod tests {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
new_authorized_pubkey: pubkey2,
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 1,
new_authorized: None,
vote_authorize: VoteAuthorize::Voter
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -955,70 +822,6 @@ mod tests {
}
);
let (voter_keypair_file, mut tmp_file) = make_tmp_file();
let voter_keypair = Keypair::new();
write_keypair(&voter_keypair, tmp_file.as_file_mut()).unwrap();
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
"vote-authorize-voter-checked",
&pubkey_string,
&default_keypair_file,
&voter_keypair_file,
]);
assert_eq!(
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
new_authorized_pubkey: voter_keypair.pubkey(),
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 0,
new_authorized: Some(1),
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
read_keypair_file(&voter_keypair_file).unwrap().into()
],
}
);
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
"vote-authorize-voter-checked",
&pubkey_string,
&authorized_keypair_file,
&voter_keypair_file,
]);
assert_eq!(
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
new_authorized_pubkey: voter_keypair.pubkey(),
vote_authorize: VoteAuthorize::Voter,
memo: None,
authorized: 1,
new_authorized: Some(2),
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
read_keypair_file(&authorized_keypair_file).unwrap().into(),
read_keypair_file(&voter_keypair_file).unwrap().into(),
],
}
);
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
"vote-authorize-voter-checked",
&pubkey_string,
&authorized_keypair_file,
&pubkey2_string,
]);
assert!(parse_command(&test_authorize_voter, &default_signer, &mut None).is_err());
let (keypair_file, mut tmp_file) = make_tmp_file();
let keypair = Keypair::new();
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
@@ -1044,7 +847,6 @@ mod tests {
authorized_voter: None,
authorized_withdrawer: None,
commission: 10,
memo: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -1074,7 +876,6 @@ mod tests {
authorized_voter: None,
authorized_withdrawer: None,
commission: 100,
memo: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -1107,8 +908,7 @@ mod tests {
identity_account: 2,
authorized_voter: Some(authed),
authorized_withdrawer: None,
commission: 100,
memo: None,
commission: 100
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -1139,8 +939,7 @@ mod tests {
identity_account: 2,
authorized_voter: None,
authorized_withdrawer: Some(authed),
commission: 100,
memo: None,
commission: 100
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -1164,7 +963,6 @@ mod tests {
vote_account_pubkey: pubkey,
new_identity_account: 2,
withdraw_authority: 1,
memo: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -1188,7 +986,6 @@ mod tests {
vote_account_pubkey: pubkey,
commission: 42,
withdraw_authority: 1,
memo: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),
@@ -1213,7 +1010,6 @@ mod tests {
destination_account_pubkey: pubkey,
withdraw_authority: 0,
withdraw_amount: SpendAmount::Some(42_000_000_000),
memo: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@@ -1235,7 +1031,6 @@ mod tests {
destination_account_pubkey: pubkey,
withdraw_authority: 0,
withdraw_amount: SpendAmount::All,
memo: None,
},
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
}
@@ -1262,7 +1057,6 @@ mod tests {
destination_account_pubkey: pubkey,
withdraw_authority: 1,
withdraw_amount: SpendAmount::Some(42_000_000_000),
memo: None,
},
signers: vec![
read_keypair_file(&default_keypair_file).unwrap().into(),

View File

@@ -22,38 +22,44 @@ use solana_sdk::{
#[test]
fn test_nonce() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
full_battery_tests(test_validator, None, false);
full_battery_tests(
TestValidator::with_no_fees(mint_keypair.pubkey()),
mint_keypair,
None,
false,
);
}
#[test]
fn test_nonce_with_seed() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
full_battery_tests(test_validator, Some(String::from("seed")), false);
full_battery_tests(
TestValidator::with_no_fees(mint_keypair.pubkey()),
mint_keypair,
Some(String::from("seed")),
false,
);
}
#[test]
fn test_nonce_with_authority() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
full_battery_tests(test_validator, None, true);
full_battery_tests(
TestValidator::with_no_fees(mint_keypair.pubkey()),
mint_keypair,
None,
true,
);
}
fn full_battery_tests(
test_validator: TestValidator,
mint_keypair: Keypair,
seed: Option<String>,
use_nonce_authority: bool,
) {
let faucet_addr = run_local_faucet(mint_keypair, None);
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
let json_rpc_url = test_validator.rpc_url();
@@ -65,9 +71,10 @@ fn full_battery_tests(
request_and_confirm_airdrop(
&rpc_client,
&config_payer,
&faucet_addr,
&config_payer.signers[0].pubkey(),
2000,
&config_payer,
)
.unwrap();
check_recent_balance(2000, &rpc_client, &config_payer.signers[0].pubkey());
@@ -101,7 +108,6 @@ fn full_battery_tests(
nonce_account: 1,
seed,
nonce_authority: optional_authority,
memo: None,
amount: SpendAmount::Some(1000),
};
@@ -135,7 +141,6 @@ fn full_battery_tests(
config_payer.command = CliCommand::NewNonce {
nonce_account,
nonce_authority: index,
memo: None,
};
process_command(&config_payer).unwrap();
@@ -153,7 +158,6 @@ fn full_battery_tests(
config_payer.command = CliCommand::WithdrawFromNonceAccount {
nonce_account,
nonce_authority: index,
memo: None,
destination_account_pubkey: payee_pubkey,
lamports: 100,
};
@@ -174,7 +178,6 @@ fn full_battery_tests(
config_payer.command = CliCommand::AuthorizeNonceAccount {
nonce_account,
nonce_authority: index,
memo: None,
new_authority: new_authority.pubkey(),
};
process_command(&config_payer).unwrap();
@@ -183,7 +186,6 @@ fn full_battery_tests(
config_payer.command = CliCommand::NewNonce {
nonce_account,
nonce_authority: index,
memo: None,
};
process_command(&config_payer).unwrap_err();
@@ -192,7 +194,6 @@ fn full_battery_tests(
config_payer.command = CliCommand::NewNonce {
nonce_account,
nonce_authority: 1,
memo: None,
};
process_command(&config_payer).unwrap();
@@ -200,7 +201,6 @@ fn full_battery_tests(
config_payer.command = CliCommand::WithdrawFromNonceAccount {
nonce_account,
nonce_authority: 1,
memo: None,
destination_account_pubkey: payee_pubkey,
lamports: 100,
};
@@ -214,29 +214,32 @@ fn full_battery_tests(
fn test_create_account_with_seed() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
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::recent_for_tests();
// Setup accounts
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
request_and_confirm_airdrop(
&rpc_client,
&CliConfig::recent_for_tests(),
&faucet_addr,
&offline_nonce_authority_signer.pubkey(),
42,
&config,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&CliConfig::recent_for_tests(),
&faucet_addr,
&online_nonce_creator_signer.pubkey(),
4242,
&config,
)
.unwrap();
check_recent_balance(42, &rpc_client, &offline_nonce_authority_signer.pubkey());
@@ -260,7 +263,6 @@ fn test_create_account_with_seed() {
nonce_account: 0,
seed: Some(seed),
nonce_authority: Some(authority_pubkey),
memo: None,
amount: SpendAmount::Some(241),
};
process_command(&creator_config).unwrap();
@@ -297,7 +299,6 @@ fn test_create_account_with_seed() {
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_address),
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -326,7 +327,6 @@ fn test_create_account_with_seed() {
),
nonce_account: Some(nonce_address),
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,

View File

@@ -28,9 +28,8 @@ fn test_cli_program_deploy_non_upgradeable() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -47,6 +46,8 @@ fn test_cli_program_deploy_non_upgradeable() {
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 4 * minimum_balance_for_rent_exemption, // min balance for rent exemption for three programs + leftover for tx processing
};
@@ -68,11 +69,11 @@ fn test_cli_program_deploy_non_upgradeable() {
.unwrap()
.as_str()
.unwrap();
let program_id = Pubkey::from_str(program_id_str).unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap();
let account0 = rpc_client.get_account(&program_id).unwrap();
assert_eq!(account0.lamports, minimum_balance_for_rent_exemption);
assert_eq!(account0.owner, bpf_loader::id());
assert!(account0.executable);
assert_eq!(account0.executable, true);
let mut file = File::open(pathbuf.to_str().unwrap().to_string()).unwrap();
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
@@ -93,7 +94,7 @@ fn test_cli_program_deploy_non_upgradeable() {
.unwrap();
assert_eq!(account1.lamports, minimum_balance_for_rent_exemption);
assert_eq!(account1.owner, bpf_loader::id());
assert!(account1.executable);
assert_eq!(account1.executable, true);
assert_eq!(account1.data, account0.data);
// Attempt to redeploy to the same address
@@ -103,6 +104,8 @@ fn test_cli_program_deploy_non_upgradeable() {
let custom_address_keypair = Keypair::new();
config.signers = vec![&custom_address_keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 2 * minimum_balance_for_rent_exemption, // Anything over minimum_balance_for_rent_exemption should trigger err
};
@@ -129,7 +132,7 @@ fn test_cli_program_deploy_non_upgradeable() {
.unwrap();
assert_eq!(account2.lamports, 2 * minimum_balance_for_rent_exemption);
assert_eq!(account2.owner, bpf_loader::id());
assert!(account2.executable);
assert_eq!(account2.executable, true);
assert_eq!(account2.data, account0.data);
}
@@ -144,9 +147,8 @@ fn test_cli_program_deploy_no_authority() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -169,6 +171,8 @@ fn test_cli_program_deploy_no_authority() {
let keypair = Keypair::new();
config.json_rpc_url = test_validator.rpc_url();
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 100 * minimum_balance_for_programdata + minimum_balance_for_program,
};
@@ -198,7 +202,7 @@ fn test_cli_program_deploy_no_authority() {
.unwrap()
.as_str()
.unwrap();
let program_id = Pubkey::from_str(program_id_str).unwrap();
let program_id = Pubkey::from_str(&program_id_str).unwrap();
// Attempt to upgrade the program
config.signers = vec![&keypair, &upgrade_authority];
@@ -227,9 +231,8 @@ fn test_cli_program_deploy_with_authority() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -253,6 +256,8 @@ fn test_cli_program_deploy_with_authority() {
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 100 * minimum_balance_for_programdata + minimum_balance_for_program,
};
@@ -284,12 +289,12 @@ fn test_cli_program_deploy_with_authority() {
.unwrap();
assert_eq!(
program_keypair.pubkey(),
Pubkey::from_str(program_pubkey_str).unwrap()
Pubkey::from_str(&program_pubkey_str).unwrap()
);
let program_account = rpc_client.get_account(&program_keypair.pubkey()).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert_eq!(program_account.executable, true);
let (programdata_pubkey, _) = Pubkey::find_program_address(
&[program_keypair.pubkey().as_ref()],
&bpf_loader_upgradeable::id(),
@@ -300,7 +305,7 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert_eq!(programdata_account.executable, false);
assert_eq!(
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
program_data[..]
@@ -328,11 +333,11 @@ fn test_cli_program_deploy_with_authority() {
.unwrap()
.as_str()
.unwrap();
let program_pubkey = Pubkey::from_str(program_pubkey_str).unwrap();
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert_eq!(program_account.executable, true);
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@@ -341,7 +346,7 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert_eq!(programdata_account.executable, false);
assert_eq!(
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
program_data[..]
@@ -364,7 +369,7 @@ fn test_cli_program_deploy_with_authority() {
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert_eq!(program_account.executable, true);
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@@ -373,7 +378,7 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert_eq!(programdata_account.executable, false);
assert_eq!(
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
program_data[..]
@@ -397,7 +402,7 @@ fn test_cli_program_deploy_with_authority() {
.as_str()
.unwrap();
assert_eq!(
Pubkey::from_str(new_upgrade_authority_str).unwrap(),
Pubkey::from_str(&new_upgrade_authority_str).unwrap(),
new_upgrade_authority.pubkey()
);
@@ -418,7 +423,7 @@ fn test_cli_program_deploy_with_authority() {
let program_account = rpc_client.get_account(&program_pubkey).unwrap();
assert_eq!(program_account.lamports, minimum_balance_for_program);
assert_eq!(program_account.owner, bpf_loader_upgradeable::id());
assert!(program_account.executable);
assert_eq!(program_account.executable, true);
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@@ -427,7 +432,7 @@ fn test_cli_program_deploy_with_authority() {
minimum_balance_for_programdata
);
assert_eq!(programdata_account.owner, bpf_loader_upgradeable::id());
assert!(!programdata_account.executable);
assert_eq!(programdata_account.executable, false);
assert_eq!(
programdata_account.data[UpgradeableLoaderState::programdata_data_offset().unwrap()..],
program_data[..]
@@ -452,7 +457,7 @@ fn test_cli_program_deploy_with_authority() {
.unwrap();
assert_eq!(
new_upgrade_authority.pubkey(),
Pubkey::from_str(authority_pubkey_str).unwrap()
Pubkey::from_str(&authority_pubkey_str).unwrap()
);
// Set no authority
@@ -510,7 +515,7 @@ fn test_cli_program_deploy_with_authority() {
.unwrap()
.as_str()
.unwrap();
let program_pubkey = Pubkey::from_str(program_pubkey_str).unwrap();
let program_pubkey = Pubkey::from_str(&program_pubkey_str).unwrap();
let (programdata_pubkey, _) =
Pubkey::find_program_address(&[program_pubkey.as_ref()], &bpf_loader_upgradeable::id());
let programdata_account = rpc_client.get_account(&programdata_pubkey).unwrap();
@@ -555,9 +560,8 @@ fn test_cli_program_write_buffer() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -582,6 +586,8 @@ fn test_cli_program_write_buffer() {
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 100 * minimum_balance_for_buffer,
};
@@ -606,7 +612,7 @@ fn test_cli_program_write_buffer() {
.unwrap()
.as_str()
.unwrap();
let new_buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
let new_buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
let buffer_account = rpc_client.get_account(&new_buffer_pubkey).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
@@ -641,7 +647,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
buffer_keypair.pubkey(),
Pubkey::from_str(buffer_pubkey_str).unwrap()
Pubkey::from_str(&buffer_pubkey_str).unwrap()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer);
@@ -675,7 +681,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
keypair.pubkey(),
Pubkey::from_str(authority_pubkey_str).unwrap()
Pubkey::from_str(&authority_pubkey_str).unwrap()
);
// Specify buffer authority
@@ -700,7 +706,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
buffer_keypair.pubkey(),
Pubkey::from_str(buffer_pubkey_str).unwrap()
Pubkey::from_str(&buffer_pubkey_str).unwrap()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
@@ -735,7 +741,7 @@ fn test_cli_program_write_buffer() {
.unwrap()
.as_str()
.unwrap();
let buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
let buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
let buffer_account = rpc_client.get_account(&buffer_pubkey).unwrap();
assert_eq!(buffer_account.lamports, minimum_balance_for_buffer_default);
assert_eq!(buffer_account.owner, bpf_loader_upgradeable::id());
@@ -768,7 +774,7 @@ fn test_cli_program_write_buffer() {
.unwrap();
assert_eq!(
authority_keypair.pubkey(),
Pubkey::from_str(authority_pubkey_str).unwrap()
Pubkey::from_str(&authority_pubkey_str).unwrap()
);
// Close buffer
@@ -806,7 +812,7 @@ fn test_cli_program_write_buffer() {
.unwrap()
.as_str()
.unwrap();
let new_buffer_pubkey = Pubkey::from_str(buffer_pubkey_str).unwrap();
let new_buffer_pubkey = Pubkey::from_str(&buffer_pubkey_str).unwrap();
// Close buffers and deposit default keypair
let pre_lamports = rpc_client.get_account(&keypair.pubkey()).unwrap().lamports;
@@ -837,9 +843,8 @@ fn test_cli_program_set_buffer_authority() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -859,6 +864,8 @@ fn test_cli_program_set_buffer_authority() {
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 100 * minimum_balance_for_buffer,
};
@@ -901,7 +908,7 @@ fn test_cli_program_set_buffer_authority() {
.as_str()
.unwrap();
assert_eq!(
Pubkey::from_str(new_buffer_authority_str).unwrap(),
Pubkey::from_str(&new_buffer_authority_str).unwrap(),
new_buffer_authority.pubkey()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
@@ -928,7 +935,7 @@ fn test_cli_program_set_buffer_authority() {
.as_str()
.unwrap();
assert_eq!(
Pubkey::from_str(buffer_authority_str).unwrap(),
Pubkey::from_str(&buffer_authority_str).unwrap(),
buffer_keypair.pubkey()
);
let buffer_account = rpc_client.get_account(&buffer_keypair.pubkey()).unwrap();
@@ -950,9 +957,8 @@ fn test_cli_program_mismatch_buffer_authority() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -972,6 +978,8 @@ fn test_cli_program_mismatch_buffer_authority() {
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 100 * minimum_balance_for_buffer,
};
@@ -1039,9 +1047,8 @@ fn test_cli_program_show() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -1064,6 +1071,8 @@ fn test_cli_program_show() {
// Airdrop
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 100 * minimum_balance_for_buffer,
};
@@ -1101,7 +1110,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
buffer_keypair.pubkey(),
Pubkey::from_str(address_str).unwrap()
Pubkey::from_str(&address_str).unwrap()
);
let authority_str = json
.as_object()
@@ -1112,7 +1121,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
authority_keypair.pubkey(),
Pubkey::from_str(authority_str).unwrap()
Pubkey::from_str(&authority_str).unwrap()
);
let data_len = json
.as_object()
@@ -1161,7 +1170,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
program_keypair.pubkey(),
Pubkey::from_str(address_str).unwrap()
Pubkey::from_str(&address_str).unwrap()
);
let programdata_address_str = json
.as_object()
@@ -1176,7 +1185,7 @@ fn test_cli_program_show() {
);
assert_eq!(
programdata_pubkey,
Pubkey::from_str(programdata_address_str).unwrap()
Pubkey::from_str(&programdata_address_str).unwrap()
);
let authority_str = json
.as_object()
@@ -1187,7 +1196,7 @@ fn test_cli_program_show() {
.unwrap();
assert_eq!(
authority_keypair.pubkey(),
Pubkey::from_str(authority_str).unwrap()
Pubkey::from_str(&authority_str).unwrap()
);
let deployed_slot = json
.as_object()
@@ -1219,9 +1228,8 @@ fn test_cli_program_dump() {
pathbuf.set_extension("so");
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -1244,6 +1252,8 @@ fn test_cli_program_dump() {
// Airdrop
config.signers = vec![&keypair];
config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 100 * minimum_balance_for_buffer,
};

View File

@@ -10,13 +10,15 @@ use solana_sdk::{
#[test]
fn test_cli_request_airdrop() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let mut bob_config = CliConfig::recent_for_tests();
bob_config.json_rpc_url = test_validator.rpc_url();
bob_config.command = CliCommand::Airdrop {
faucet_host: None,
faucet_port: faucet_addr.port(),
pubkey: None,
lamports: 50,
};

File diff suppressed because it is too large Load Diff

View File

@@ -16,16 +16,14 @@ use solana_sdk::{
nonce::State as NonceState,
pubkey::Pubkey,
signature::{keypair_from_seed, Keypair, NullSigner, Signer},
stake,
};
#[test]
fn test_transfer() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -40,7 +38,8 @@ fn test_transfer() {
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
request_and_confirm_airdrop(&rpc_client, &config, &sender_pubkey, 50_000).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000, &config)
.unwrap();
check_recent_balance(50_000, &rpc_client, &sender_pubkey);
check_recent_balance(0, &rpc_client, &recipient_pubkey);
@@ -58,7 +57,6 @@ fn test_transfer() {
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -79,7 +77,6 @@ fn test_transfer() {
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -96,7 +93,7 @@ fn test_transfer() {
process_command(&offline).unwrap_err();
let offline_pubkey = offline.signers[0].pubkey();
request_and_confirm_airdrop(&rpc_client, &offline, &offline_pubkey, 50).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 50, &config).unwrap();
check_recent_balance(50, &rpc_client, &offline_pubkey);
// Offline transfer
@@ -112,7 +109,6 @@ fn test_transfer() {
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -134,7 +130,6 @@ fn test_transfer() {
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -153,7 +148,6 @@ fn test_transfer() {
nonce_account: 1,
seed: None,
nonce_authority: None,
memo: None,
amount: SpendAmount::Some(minimum_nonce_balance),
};
process_command(&config).unwrap();
@@ -185,7 +179,6 @@ fn test_transfer() {
),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -208,7 +201,6 @@ fn test_transfer() {
config.command = CliCommand::AuthorizeNonceAccount {
nonce_account: nonce_account.pubkey(),
nonce_authority: 0,
memo: None,
new_authority: offline_pubkey,
};
process_command(&config).unwrap();
@@ -237,7 +229,6 @@ fn test_transfer() {
blockhash_query: BlockhashQuery::None(nonce_hash),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -261,7 +252,6 @@ fn test_transfer() {
),
nonce_account: Some(nonce_account.pubkey()),
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -275,30 +265,32 @@ fn test_transfer() {
fn test_transfer_multisession_signing() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
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::recent_for_tests();
// Setup accounts
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
request_and_confirm_airdrop(
&rpc_client,
&CliConfig::recent_for_tests(),
&faucet_addr,
&offline_from_signer.pubkey(),
43,
&config,
)
.unwrap();
request_and_confirm_airdrop(
&rpc_client,
&CliConfig::recent_for_tests(),
&faucet_addr,
&offline_fee_payer_signer.pubkey(),
3,
&config,
)
.unwrap();
check_recent_balance(43, &rpc_client, &offline_from_signer.pubkey());
@@ -327,7 +319,6 @@ fn test_transfer_multisession_signing() {
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -358,7 +349,6 @@ fn test_transfer_multisession_signing() {
blockhash_query: BlockhashQuery::None(blockhash),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -386,7 +376,6 @@ fn test_transfer_multisession_signing() {
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -402,9 +391,8 @@ fn test_transfer_multisession_signing() {
fn test_transfer_all() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -418,7 +406,8 @@ fn test_transfer_all() {
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
request_and_confirm_airdrop(&rpc_client, &config, &sender_pubkey, 50_000).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000, &config)
.unwrap();
check_recent_balance(50_000, &rpc_client, &sender_pubkey);
check_recent_balance(0, &rpc_client, &recipient_pubkey);
@@ -436,7 +425,6 @@ fn test_transfer_all() {
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -450,9 +438,8 @@ fn test_transfer_all() {
fn test_transfer_unfunded_recipient() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -466,7 +453,8 @@ fn test_transfer_unfunded_recipient() {
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
request_and_confirm_airdrop(&rpc_client, &config, &sender_pubkey, 50_000).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000, &config)
.unwrap();
check_recent_balance(50_000, &rpc_client, &sender_pubkey);
check_recent_balance(0, &rpc_client, &recipient_pubkey);
@@ -484,7 +472,6 @@ fn test_transfer_unfunded_recipient() {
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -498,9 +485,8 @@ fn test_transfer_unfunded_recipient() {
fn test_transfer_with_seed() {
solana_logger::setup();
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_custom_fees(mint_keypair.pubkey(), 1);
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_custom_fees(mint_pubkey, 1, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -514,7 +500,7 @@ fn test_transfer_with_seed() {
let sender_pubkey = config.signers[0].pubkey();
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
let derived_address_seed = "seed".to_string();
let derived_address_program_id = stake::program::id();
let derived_address_program_id = solana_stake_program::id();
let derived_address = Pubkey::create_with_seed(
&sender_pubkey,
&derived_address_seed,
@@ -522,8 +508,9 @@ fn test_transfer_with_seed() {
)
.unwrap();
request_and_confirm_airdrop(&rpc_client, &config, &sender_pubkey, 1).unwrap();
request_and_confirm_airdrop(&rpc_client, &config, &derived_address, 50_000).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 1, &config).unwrap();
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &derived_address, 50_000, &config)
.unwrap();
check_recent_balance(1, &rpc_client, &sender_pubkey);
check_recent_balance(50_000, &rpc_client, &derived_address);
check_recent_balance(0, &rpc_client, &recipient_pubkey);
@@ -542,7 +529,6 @@ fn test_transfer_with_seed() {
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: Some(derived_address_seed),
derived_address_program_id: Some(derived_address_program_id),

View File

@@ -19,9 +19,8 @@ use solana_vote_program::vote_state::{VoteAuthorize, VoteState, VoteStateVersion
#[test]
fn test_vote_authorize_and_withdraw() {
let mint_keypair = Keypair::new();
let mint_pubkey = mint_keypair.pubkey();
let test_validator = TestValidator::with_no_fees(mint_keypair.pubkey());
let faucet_addr = run_local_faucet(mint_keypair, None);
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
let rpc_client =
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
@@ -31,8 +30,14 @@ fn test_vote_authorize_and_withdraw() {
config.json_rpc_url = test_validator.rpc_url();
config.signers = vec![&default_signer];
request_and_confirm_airdrop(&rpc_client, &config, &config.signers[0].pubkey(), 100_000)
.unwrap();
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();
@@ -45,7 +50,6 @@ fn test_vote_authorize_and_withdraw() {
authorized_voter: None,
authorized_withdrawer: Some(config.signers[0].pubkey()),
commission: 0,
memo: None,
};
process_command(&config).unwrap();
let vote_account = rpc_client
@@ -73,7 +77,6 @@ fn test_vote_authorize_and_withdraw() {
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
nonce_account: None,
nonce_authority: 0,
memo: None,
fee_payer: 0,
derived_address_seed: None,
derived_address_program_id: None,
@@ -83,48 +86,12 @@ fn test_vote_authorize_and_withdraw() {
check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey);
// Authorize vote account withdrawal to another signer
let first_withdraw_authority = Keypair::new();
let withdraw_authority = Keypair::new();
config.signers = vec![&default_signer];
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey: first_withdraw_authority.pubkey(),
vote_authorize: VoteAuthorize::Withdrawer,
memo: None,
authorized: 0,
new_authorized: None,
};
process_command(&config).unwrap();
let vote_account = rpc_client
.get_account(&vote_account_keypair.pubkey())
.unwrap();
let vote_state: VoteStateVersions = vote_account.state().unwrap();
let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer;
assert_eq!(authorized_withdrawer, first_withdraw_authority.pubkey());
// Authorize vote account withdrawal to another signer with checked instruction
let withdraw_authority = Keypair::new();
config.signers = vec![&default_signer, &first_withdraw_authority];
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey: withdraw_authority.pubkey(),
vote_authorize: VoteAuthorize::Withdrawer,
memo: None,
authorized: 1,
new_authorized: Some(1),
};
process_command(&config).unwrap_err(); // unsigned by new authority should fail
config.signers = vec![
&default_signer,
&first_withdraw_authority,
&withdraw_authority,
];
config.command = CliCommand::VoteAuthorize {
vote_account_pubkey,
new_authorized_pubkey: withdraw_authority.pubkey(),
vote_authorize: VoteAuthorize::Withdrawer,
memo: None,
authorized: 1,
new_authorized: Some(2),
};
process_command(&config).unwrap();
let vote_account = rpc_client
@@ -142,7 +109,6 @@ fn test_vote_authorize_and_withdraw() {
withdraw_authority: 1,
withdraw_amount: SpendAmount::Some(100),
destination_account_pubkey: destination_account,
memo: None,
};
process_command(&config).unwrap();
check_recent_balance(expected_balance - 100, &rpc_client, &vote_account_pubkey);
@@ -155,7 +121,6 @@ fn test_vote_authorize_and_withdraw() {
vote_account_pubkey,
new_identity_account: 2,
withdraw_authority: 1,
memo: None,
};
process_command(&config).unwrap();
}

View File

@@ -1,6 +1,6 @@
[package]
name = "solana-client"
version = "1.7.8"
version = "1.6.2"
description = "Solana Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
@@ -24,23 +24,21 @@ semver = "0.11.0"
serde = "1.0.122"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "=1.7.8" }
solana-clap-utils = { path = "../clap-utils", version = "=1.7.8" }
solana-faucet = { path = "../faucet", version = "=1.7.8" }
solana-net-utils = { path = "../net-utils", version = "=1.7.8" }
solana-sdk = { path = "../sdk", version = "=1.7.8" }
solana-transaction-status = { path = "../transaction-status", version = "=1.7.8" }
solana-version = { path = "../version", version = "=1.7.8" }
solana-vote-program = { path = "../programs/vote", version = "=1.7.8" }
solana-account-decoder = { path = "../account-decoder", version = "=1.6.2" }
solana-clap-utils = { path = "../clap-utils", version = "=1.6.2" }
solana-net-utils = { path = "../net-utils", version = "=1.6.2" }
solana-sdk = { path = "../sdk", version = "=1.6.2" }
solana-transaction-status = { path = "../transaction-status", version = "=1.6.2" }
solana-version = { path = "../version", version = "=1.6.2" }
solana-vote-program = { path = "../programs/vote", version = "=1.6.2" }
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
tungstenite = "0.10.1"
url = "2.1.1"
[dev-dependencies]
assert_matches = "1.3.0"
jsonrpc-http-server = "17.0.0"
solana-logger = { path = "../logger", version = "=1.7.8" }
solana-logger = { path = "../logger", version = "=1.6.2" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@@ -361,7 +361,7 @@ mod tests {
let nonce_pubkey = Pubkey::new(&[4u8; 32]);
let rpc_nonce_account = UiAccount::encode(
&nonce_pubkey,
&nonce_account,
nonce_account,
UiAccountEncoding::Base64,
None,
None,

View File

@@ -1,6 +1,5 @@
use {
crate::{rpc_request, rpc_response},
solana_faucet::faucet::FaucetError,
crate::rpc_request,
solana_sdk::{
signature::SignerError, transaction::TransactionError, transport::TransportError,
},
@@ -24,30 +23,10 @@ pub enum ClientErrorKind {
SigningError(#[from] SignerError),
#[error(transparent)]
TransactionError(#[from] TransactionError),
#[error(transparent)]
FaucetError(#[from] FaucetError),
#[error("Custom: {0}")]
Custom(String),
}
impl ClientErrorKind {
pub fn get_transaction_error(&self) -> Option<TransactionError> {
match self {
Self::RpcError(rpc_request::RpcError::RpcResponseError {
data:
rpc_request::RpcResponseErrorData::SendTransactionPreflightFailure(
rpc_response::RpcSimulateTransactionResult {
err: Some(tx_err), ..
},
),
..
}) => Some(tx_err.clone()),
Self::TransactionError(tx_err) => Some(tx_err.clone()),
_ => None,
}
}
}
impl From<TransportError> for ClientErrorKind {
fn from(err: TransportError) -> Self {
match err {
@@ -67,7 +46,6 @@ impl From<ClientErrorKind> for TransportError {
ClientErrorKind::RpcError(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::SerdeJson(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::SigningError(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::FaucetError(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::Custom(err) => Self::Custom(format!("{:?}", err)),
}
}
@@ -104,10 +82,6 @@ impl ClientError {
pub fn kind(&self) -> &ClientErrorKind {
&self.kind
}
pub fn get_transaction_error(&self) -> Option<TransactionError> {
self.kind.get_transaction_error()
}
}
impl From<ClientErrorKind> for ClientError {
@@ -188,13 +162,4 @@ impl From<TransactionError> for ClientError {
}
}
impl From<FaucetError> for ClientError {
fn from(err: FaucetError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
pub type Result<T> = std::result::Result<T, ClientError>;

View File

@@ -1,9 +0,0 @@
use crate::{fee_calculator::FeeCalculator, hash::Hash};
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Fees {
pub blockhash: Hash,
pub fee_calculator: FeeCalculator,
pub last_valid_block_height: u64,
}

View File

@@ -7,25 +7,13 @@ use {
rpc_sender::RpcSender,
},
log::*,
reqwest::{
self,
header::{CONTENT_TYPE, RETRY_AFTER},
StatusCode,
},
std::{
sync::{
atomic::{AtomicU64, Ordering},
Arc,
},
thread::sleep,
time::Duration,
},
reqwest::{self, header::CONTENT_TYPE, StatusCode},
std::{thread::sleep, time::Duration},
};
pub struct HttpSender {
client: Arc<reqwest::blocking::Client>,
client: reqwest::blocking::Client,
url: String,
request_id: AtomicU64,
}
impl HttpSender {
@@ -34,22 +22,12 @@ impl HttpSender {
}
pub fn new_with_timeout(url: String, timeout: Duration) -> Self {
// `reqwest::blocking::Client` panics if run in a tokio async context. Shuttle the
// request to a different tokio thread to avoid this
let client = Arc::new(
tokio::task::block_in_place(move || {
reqwest::blocking::Client::builder()
.timeout(timeout)
.build()
})
.expect("build rpc client"),
);
let client = reqwest::blocking::Client::builder()
.timeout(timeout)
.build()
.expect("build rpc client");
Self {
client,
url,
request_id: AtomicU64::new(0),
}
Self { client, url }
}
}
@@ -62,57 +40,39 @@ struct RpcErrorObject {
impl RpcSender for HttpSender {
fn send(&self, request: RpcRequest, params: serde_json::Value) -> Result<serde_json::Value> {
let request_id = self.request_id.fetch_add(1, Ordering::Relaxed);
let request_json = request.build_request_json(request_id, params).to_string();
// Concurrent requests are not supported so reuse the same request id for all requests
let request_id = 1;
let request_json = request.build_request_json(request_id, params);
let mut too_many_requests_retries = 5;
loop {
// `reqwest::blocking::Client` panics if run in a tokio async context. Shuttle the
// request to a different tokio thread to avoid this
let response = {
let client = self.client.clone();
let request_json = request_json.clone();
tokio::task::block_in_place(move || {
client
.post(&self.url)
.header(CONTENT_TYPE, "application/json")
.body(request_json)
.send()
})
};
match response {
match self
.client
.post(&self.url)
.header(CONTENT_TYPE, "application/json")
.body(request_json.to_string())
.send()
{
Ok(response) => {
if !response.status().is_success() {
if response.status() == StatusCode::TOO_MANY_REQUESTS
&& too_many_requests_retries > 0
{
let mut duration = Duration::from_millis(500);
if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
if let Ok(retry_after) = retry_after.to_str() {
if let Ok(retry_after) = retry_after.parse::<u64>() {
if retry_after < 120 {
duration = Duration::from_secs(retry_after);
}
}
}
}
too_many_requests_retries -= 1;
debug!(
"Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
response, too_many_requests_retries, duration
"Server responded with {:?}, {} retries left",
response, too_many_requests_retries
);
sleep(duration);
// Sleep for 500ms to give the server a break
sleep(Duration::from_millis(500));
continue;
}
return Err(response.error_for_status().unwrap_err().into());
}
let response_text = tokio::task::block_in_place(move || response.text())?;
let json: serde_json::Value = serde_json::from_str(&response_text)?;
let json: serde_json::Value = serde_json::from_str(&response.text()?)?;
if json["error"].is_object() {
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone())
{
@@ -162,22 +122,3 @@ impl RpcSender for HttpSender {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn http_sender_on_tokio_multi_thread() {
let http_sender = HttpSender::new("http://localhost:1234".to_string());
let _ = http_sender.send(RpcRequest::GetVersion, serde_json::Value::Null);
}
#[tokio::test(flavor = "current_thread")]
#[should_panic(expected = "can call blocking only when running on the multi-threaded runtime")]
async fn http_sender_ontokio_current_thread_should_panic() {
// RpcClient::new() will panic in the tokio current-thread runtime due to `tokio::task::block_in_place()` usage, and there
// doesn't seem to be a way to detect whether the tokio runtime is multi_thread or current_thread...
let _ = HttpSender::new("http://localhost:1234".to_string());
}
}

View File

@@ -13,10 +13,8 @@ pub mod rpc_cache;
pub mod rpc_client;
pub mod rpc_config;
pub mod rpc_custom_error;
pub mod rpc_deprecated_config;
pub mod rpc_filter;
pub mod rpc_request;
pub mod rpc_response;
pub mod rpc_sender;
pub mod thin_client;
pub mod tpu_client;

View File

@@ -124,8 +124,6 @@ impl RpcSender for MockSender {
}
RpcRequest::GetTransactionCount => Value::Number(Number::from(1234)),
RpcRequest::GetSlot => Value::Number(Number::from(0)),
RpcRequest::GetMaxShredInsertSlot => Value::Number(Number::from(0)),
RpcRequest::RequestAirdrop => Value::String(Signature::new(&[8; 64]).to_string()),
RpcRequest::SendTransaction => {
let signature = if self.url == "malicious" {
Signature::new(&[8; 64]).to_string()

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